【问题标题】:LDAP: How to return more than 1000 results (java)LDAP:如何返回超过 1000 个结果(java)
【发布时间】:2016-01-09 03:19:54
【问题描述】:

我正在使用来自此站点的 LDAP SDK:https://www.unboundid.com/products/ldap-sdk/。 我想做一个返回很多条目的搜索操作。

根据常见问题解答的网站,(https://www.unboundid.com/products/ldap-sdk/docs/ldapsdk-faq.php#search)我必须使用 SearchResultListener 实现。

这就是我所做的:

 public class UpdateThread extends Thread implements SearchResultListener {
 ...
 // create request
 final SearchRequest request = new SearchRequest(this, instance.getBaseDN(),SearchScope.SUB, filter);
 // Setting size limit of results.
 request.setSizeLimit(2000);

 ...

 // Get every result one by one.
 @Override
public void searchEntryReturned(SearchResultEntry arg0) {
    System.out.println("entry "+arg0.getDN());

}

问题是“searchEntryReturned”最多返回 1000 个结果。即使我将大小限制设置为“2000”。

【问题讨论】:

    标签: java ldap unboundid-ldap-sdk


    【解决方案1】:

    使用标准 java 实现分页 LDAP 查询非常简单,方法是使用将 PagedResultsControl 添加到 LdapContext,而不使用上面 Neil 的回答的第三方 API。

    Hashtable<String, Object> env = new Hashtable<String, Object>(11);
    env
        .put(Context.INITIAL_CONTEXT_FACTORY,
            "com.sun.jndi.ldap.LdapCtxFactory");
    
    /* Specify host and port to use for directory service */
    env.put(Context.PROVIDER_URL,
        "ldap://localhost:389/ou=People,o=JNDITutorial");
    
    try {
      LdapContext ctx = new InitialLdapContext(env, null);
    
      // Activate paged results
      int pageSize = 5;
      byte[] cookie = null;
      ctx.setRequestControls(new Control[] { new PagedResultsControl(pageSize,
          Control.NONCRITICAL) });
      int total;
    
      do {
        /* perform the search */
        NamingEnumeration results = ctx.search("", "(objectclass=*)",
            new SearchControls());
    
        /* for each entry print out name + all attrs and values */
        while (results != null && results.hasMore()) {
          SearchResult entry = (SearchResult) results.next();
          System.out.println(entry.getName());
        }
    
        // Examine the paged results control response
        Control[] controls = ctx.getResponseControls();
        if (controls != null) {
          for (int i = 0; i < controls.length; i++) {
            if (controls[i] instanceof PagedResultsResponseControl) {
              PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];
              total = prrc.getResultSize();
              if (total != 0) {
                System.out.println("***************** END-OF-PAGE "
                    + "(total : " + total + ") *****************\n");
              } else {
                System.out.println("***************** END-OF-PAGE "
                    + "(total: unknown) ***************\n");
              }
              cookie = prrc.getCookie();
            }
          }
        } else {
          System.out.println("No controls were sent from the server");
        }
        // Re-activate paged results
        ctx.setRequestControls(new Control[] { new PagedResultsControl(
            pageSize, cookie, Control.CRITICAL) });
    
      } while (cookie != null);
    
      ctx.close();
    

    here复制的示例。

    【讨论】:

      【解决方案2】:

      虽然几乎可以肯定服务器强制执行 1000 个条目的大小限制,但有可能通过分多个部分发出请求来解决这个问题。

      如果服务器支持使用简单的分页结果控件(在 RFC 2696 中定义并在 LDAP SDK 中根据 https://docs.ldap.com/ldap-sdk/docs/javadoc/com/unboundid/ldap/sdk/controls/SimplePagedResultsControl.html 支持),那么您可以使用它来遍历包含指定的条目数。

      或者,可以使用虚拟列表视图 (VLV) 请求控件 (https://www.unboundid.com/products/ldap-sdk/docs/javadoc/index.html?com/unboundid/ldap/sdk/controls/VirtualListViewRequestControl.html),但我可能只建议如果服务器不支持简单的分页结果控件,因为 VLV 请求控件也需要对结果进行排序,这可能需要在服务器中进行特殊配置或进行一些非常昂贵的处理才能为请求提供服务。

      【讨论】:

        【解决方案3】:

        我像 @PeterK 一样解决了,但做了一些修改

            public List<MyUser> listUsers() {
            LOG.info("listUsers() inicio");
            List<MyUser> users = new ArrayList<MyUser>();
        
            Hashtable env = new Hashtable();
            env.put(Context.INITIAL_CONTEXT_FACTORY, INITIAL_CTX);
            env.put(Context.PROVIDER_URL, 'ldap://192.168.10.10:389');
            env.put(Context.SECURITY_AUTHENTICATION, CONNECTION_TYPE);
            env.put(Context.SECURITY_PRINCIPAL, USER_ADMIN_PASSWORD);
            env.put(Context.SECURITY_CREDENTIALS, USER_ADMIN);
        
            try {
                LdapContext ctx = new InitialLdapContext(env, null);
        
                // Activate paged results
                int pageSize = 1000;
                byte[] cookie = null;
                ctx.setRequestControls(new Control[] { new PagedResultsControl(pageSize, Control.NONCRITICAL) });
                int total;
        
                do {
                    /* perform the search */
                    SearchControls sc = new SearchControls();
                    sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
                    String filtro = "(&(sAMAccountName=*)&(objectClass=user))";
                    NamingEnumeration results = ctx.search(getBaseDn(ctx), filtro, sc);
        
                    /* for each entry */
                    while (results.hasMoreElements()) {
                        SearchResult result = (SearchResult) results.nextElement();
                        Attributes attributes = result.getAttributes();
                        //convert to MyUser class
                        MyUser user = toUser(attributes);
                        users.add(user);
                    }
        
                    // Examine the paged results control response
                    Control[] controls = ctx.getResponseControls();
                    if (controls != null) {
                        for (int i = 0; i < controls.length; i++) {
                            if (controls[i] instanceof PagedResultsResponseControl) {
                                PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];
                                total = prrc.getResultSize();
                                if (total != 0) {
                                    System.out.println("***************** END-OF-PAGE " + "(total : " + total + ") *****************\n");
                                } else {
                                    System.out.println("***************** END-OF-PAGE " + "(total: unknown) ***************\n");
                                }
                                cookie = prrc.getCookie();
                            }
                        }
                    } else {
                        System.out.println("No controls were sent from the server");
                    }
                    // Re-activate paged results
                    ctx.setRequestControls(new Control[] { new PagedResultsControl(pageSize, cookie, Control.CRITICAL) });
        
                } while (cookie != null);
        
                ctx.close();
        
            } catch (NamingException e) {
                System.err.println("PagedSearch failed.");
                e.printStackTrace();
            } catch (IOException ie) {
                System.err.println("PagedSearch failed.");
                ie.printStackTrace();
            } catch (Exception ie) {
                System.err.println("PagedSearch failed.");
                ie.printStackTrace();
            }
        
            LOG.info("listUsers() size = " + (users.size()));
            LOG.info("listUsers() fim");
        
            return users;
        }
        
        
        private MyUser toUser(Attributes attributes) throws NamingException {
            if (attributes != null) {
                String fullName = attributes.get("distinguishedName") != null ? attributes.get("distinguishedName").get().toString() : null;
                String mail = attributes.get("mail") != null ? attributes.get("mail").get().toString() : null;
                String userName = attributes.get("cn") != null ? attributes.get("cn").get().toString() : null;
                String userPrincipalName = attributes.get("userPrincipalName") != null ? attributes.get("userPrincipalName").get().toString() : null;
        
                if (userPrincipalName != null) {
                    String[] user = userPrincipalName.split("@");
                    if (user != null && user.length > 0) {
                        userName = user[0];
                    }
                }
        
                MyUser user = new MyUser();
                user.setFullName(fullName);
                user.setEmail(mail);
                user.setName(userName);
                user.setUserPrincipalName(userPrincipalName);
                user.setRoles(getRolesUser(attributes));
        
                return user;
            }
        
            return null;
        }
        

        【讨论】:

        • PeterK 永远不会像您那样看到您的消息
        • 您将在他的回答下输入评论。请记住:在您的答案下,当您在您的答案下发表评论时,以下人员会收到警报......(1)我认为但不要让我坚持的操作,(2)如果那个人是唯一的像我这样的评论者有评论线程的人,因为没有其他人在评论,(3)您@theirName 的人已经在您的评论或操作中的答案下
        • 只是因为 (2) 是上述情况,我才被提醒您在“如何做到这一点?”上方写了这条评论。 ...否则,如果有第三个人发表评论,我将不会收到警报。很多人认为他们在 cmets 中的 SO 上被忽略了,但实际上他们不知道由于它的工作方式而与他们交谈
        • 感谢@Drew,但我上面发布的代码不适合评论空间。
        • 我听到了。您似乎在上面有一个很好的答案。我只是提醒您注意人们如何被 ping 的现实
        【解决方案4】:

        LDAP 客户端将“客户端请求”的大小限制设置为 2000。此客户端请求的限制不能覆盖服务器配置中设置的限制。无论客户端请求的大小限制是什么,服务器的大小限制都会覆盖它。请联系您的目录服务器管理员并要求增加大小限制。

        【讨论】:

        • 如果您无法在请求中更改它,“Active Directory 用户和计算机”也将无法工作。当我收到有关该工具的 2000 个条目限制的消息时,我将设置更改为更高的价值,它的工作原理。所以你写的对我来说听起来不正确。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-05-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-13
        相关资源
        最近更新 更多