java LDAP分页查询 解决1000条限制

三种解决方法:第一种不好用,希望有高手回帖。第三种没测试,希望有心人帮测。

1、 batch size

Batch Size 

When you invoke list(), listBindings(), or any of the search() methods, 
the LDAP service provider interacts with the LDAP server to retrieve the
 results and returns them in the form of a NamingEnumeration. The LDAP s
ervice provider can collect all the results before returning the NamingE
numeration, or it can return each result as the caller invokes NamingEnu
meration.next() or NamingEnumeration.nextElement(). You can control how 
the LDAP service provider behaves in this respect by using the Context.B
ATCHSIZE ("java.naming.batchsize") environment property. This property c
ontains the string representation of a decimal integer. The LDAP service
 provider uses its value to determine how many results to read from the 
server before unblocking--this number of results is called the batch siz
e--and allowing the client program to get the results by using next() or
 nextElement(). When the client program exhausts the batch, the LDAP ser
vice provider fetches another batch so that the client program can conti
nue with the enumeration. If the batch size is zero, then the service pr
ovider will block until all results have been read. If this property was
 not set, then the default batch size is 1. 

When you invoke search(), for example by using a batch size of n, the LD
AP provider will block until it reads n results from the server before r
eturning. So, setting the batch size to a smaller number allows the prog
ram to unblock sooner. However, some overhead attaches to processing eac
h batch. If you are expecting a large number of results, then you might 
want to use a larger batch size to lower the number of context switches 
between the provider and your code. On the other hand, having a large ba
tch also means that you need more memory to hold the results. These are 
the trade-offs that you'll need to consider when choosing a batch size. 


Here's an example that sets the batch size to 10. 

// Set the batch size to 10

env.put("java.naming.batchsize", "10");

// Create the initial context

DirContext ctx = new InitialDirContext(env);

// Perform the list

NamingEnumeration answer = ctx.list("ou=People"); 

Relationship to SearchControls.setCountLimit()

Note that the Context.BATCHSIZE environment property does not in any way
 affect how many results are returned or the order in which they are ret
urned. It is completely unrelated to SearchControls.setCountLimit().

经过实验,发现这种方法好象没用,不清楚为什么,等有空的时候需要研究一下。


2、paged search

A few other problems that developers come across are queries that return
 either a large number of results, or query that returns a multi-valued 
attribute that contains a large number of values.

Active Directory incorporates a number of controls, that are designed to
 ensure optimim performance of the server and to mitigate denial of serv
ice attacks.

First of all paging. By default, Active Directory restricts the total nu
mber of results that are returned from a LDAP Search to 1000. While this
 limit can be changed by modifying the LDAP Query policy, the recomended
 approach is to use paged results. Note that this ample, which queries f
or all users that have a value for the mail attribute. uses a page size 
of 10, not really an optimal use of either the server or of the network,
 but merely just to demonstrate paging.

Also, the usual security comments apply, you shouldn't hardcode credenti
als in an application, authentication should either use Kerberos (JAAS &
 GSSAPI) or if using simple authentication, secured using SSL or TLS, an
d and any sensitive information communicated between the client and the 
server should also take place over SSL or TLS.

.

/**

 * paged.java

 * 5 July 2001

 * Sample JNDI application that performs a paged search.

 * 

 */

 

import java.util.Hashtable;

import java.util.Enumeration;

 

import javax.naming.*;

import javax.naming.directory.*;

import javax.naming.ldap.*;

import com.sun.jndi.ldap.ctl.*;

 

class paged {

 

public static void main(String[] args) {

 

 

        Hashtable env = new Hashtable();

        String adminName = "CN=Administrator,CN=Users,DC=antipodes,DC=com";

        String adminPassword = "XXXXXXXX";

        String searchBase = "DC=antipodes,DC=com";

        String searchFilter = "(&(objectClass=user)(mail=*))";

        

        
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFact
ory");

 

        //set security credentials, note using simple cleartext 
authentication


        env.put(Context.SECURITY_AUTHENTICATION,"simple");

        env.put(Context.SECURITY_PRINCIPAL,adminName);

        env.put(Context.SECURITY_CREDENTIALS,adminPassword);

                

        //connect to my domain controller

        env.put(Context.PROVIDER_URL, "ldap://mydc.antipodes.com:389");

        try {

 

            // Create the initial directory context

            LdapContext ctx = new InitialLdapContext(env,null);

        

            // Create the search controls       

            SearchControls searchCtls = new SearchControls();

        

            //Specify the attributes to return

            String returnedAtts[]={"sn","givenName","mail"};

            searchCtls.setReturningAttributes(returnedAtts);

        

            //Specify the search scope

            searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);

 

            //Set the page size and initialize the cookie that we pass back 
in su
bsequent pages

            int pageSize = 10;

            byte[] cookie = null;

 

            //Request the paged results control

            Control[] ctls = new Control[]{new 
PagedResultsControl(pageSize)};

            ctx.setRequestControls(ctls);

 

            //initialize counter to total the results

            int totalResults = 0;

 

            // Search for objects using the filter

 

            do {

                NamingEnumeration results = ctx.search(searchBase, 
searchFilter, sea
rchCtls);

 

                    // loop through the results in each page

 

                    while (results != null && results.hasMoreElements()) {

                SearchResult sr = (SearchResult)results.next();

 

                //print out the name 

                System.out.println("name: " + sr.getName());

 

                //increment the counter

                totalResults++; 

 

                    }

    

    

            // examine the response controls

            cookie = parseControls(ctx.getResponseControls());

 

                    // pass the cookie back to the server for the next page

            ctx.setRequestControls(new Control[]{new 
PagedResultsControl(pageSize
, cookie, Control.CRITICAL) });

 

            } while ((cookie != null) && (cookie.length != 0));

 

    

            ctx.close();

 

            System.out.println("Total entries: " + totalResults);

 

 

            } 

        catch (NamingException e) {

            System.err.println("Paged Search failed." + e);

            }   

        catch (java.io.IOException e) {

            System.err.println("Paged Search failed." + e);

            } 

    }

 

    static byte[] parseControls(Control[] controls) throws NamingException 
{

 

        byte[] cookie = null;

 

        if (controls != null) {

 

                for (int i = 0; i < controls.length; i++) {

                if (controls[i] instanceof PagedResultsResponseControl) {

                    PagedResultsResponseControl prrc = 
(PagedResultsResponseControl)con
trols[i];

                    cookie = prrc.getCookie();

                    System.out.println(">>Next Page \n");

                }

                }

        }

 

        return (cookie == null) ? new byte[0] : cookie;

        }

}

经测试,这种方法可以解决问题

3、range search

Note that if we had requested a multi-valued attribute instead of the su
rname (sn), firstname (givenName) and e-mail (mail) attributes, and if t
hat multi-valued had more than 1000 values, then only the first 1000 val
ues would have been returned, irrespective of whether paged results had 
ben used.

Range retrieval is more evident when retrieving the list of members from
 a group. The list of members in a group is contained in the member attr
ibute. If there are more than 1000 values in the member attribute, then 
you must use range retrieval to return all the members.

Information on range retrieval can be found at http://msdn.microsoft.com
/library/default.asp?url=/library/en-us/adsi/adsi/attribute_range_retrie
val.asp

The following JNDI sample illustrates the retrieval of members from a gr
oup, using range retrieval. In this case querying for the list of member
s of a group called "All Research" in the Active Directory.

/**

 * range.java

 * December 2004

 * Sample JNDI application to demonstrate range retrieval 

 * 

 */

 

import java.util.Hashtable;

import javax.naming.*;

import javax.naming.ldap.*;

import javax.naming.directory.*;

import com.sun.jndi.ldap.ctl.*;

 

//if we were going to do this properly, should check that the server sup
ports

//the range retrieval control 1.2.840.113556.1.4.802 !

 

public class range  {

    public static void main (String[] args) {

    

        Hashtable env = new Hashtable();

        String adminName = "CN=Administrator,CN=Users,DC=ANTIPODES,DC=COM";

        String adminPassword = "XXXXXX";

        

        
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFact
ory");

        //set security credentials, note using simple cleartext 
authentication


        env.put(Context.SECURITY_AUTHENTICATION,"simple");

        env.put(Context.SECURITY_PRINCIPAL,adminName);

        env.put(Context.SECURITY_CREDENTIALS,adminPassword);

                

        //connect to my domain controller

        env.put(Context.PROVIDER_URL,"ldap://mydc.antipodes.com:389");

        

        try {

 

            // Create the initial directory context

            LdapContext ctx = new InitialLdapContext(env,null);

        

            // Create the search controls       

            SearchControls searchCtls = new SearchControls();

        

            //Specify the search scope

            searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);

 

            //specify the LDAP search filter

            String searchFilter = "(&(objectClass=group)(CN=All Research))";

 

            //Specify the Base for the search

            String searchBase = "DC=antipodes,DC=com";

 

            //initialize counter to total the group members and range values

            int totalResults = 0;

            int Start = 0;

            int Step = 10;

            int Finish = 9;

            boolean Finished = false;

            String Range;

 

            //loop through the query until we have all the results

            while (!Finished) {     

            

                //Specify the attributes to return

                Range = Start + "-" + Finish;

                String returnedAtts[]={"member;Range=" + Range};

                searchCtls.setReturningAttributes(returnedAtts);

        

                //Search for objects using the filter

                NamingEnumeration answer = ctx.search(searchBase, 
searchFilter, sear
chCtls);

 

                //Loop through the search results

                while (answer.hasMoreElements()) {

                    SearchResult sr = (SearchResult)answer.next();

 

                    System.out.println(">>>" + sr.getName());

 

                    //Print out the members

 

                    Attributes attrs = sr.getAttributes();

                    if (attrs != null) {

 

                        try {

                            for (NamingEnumeration ae = 
attrs.getAll();ae.hasMore();) {

                                Attribute attr = (Attribute)ae.next();

 

                                //check if we are finished

                                if (attr.getID().endsWith("*")) {

                                    Finished=true;

                                }

 

                                System.out.println("Attribute: " + 
attr.getID());

                                for (NamingEnumeration e = 
attr.getAll();e.hasMore();totalResult
s++) {

 

                                    System.out.println("   " + totalResults 
+ ". " + e.next());

                                }

                            }

 

                        }    

                        catch (NamingException e)   {

                            System.err.println("Problem printing 
attributes: " + e);

                        }

                

                        Start = Start + Step;

                        Finish = Finish + Step;

 

                    }

                }

            }

 

            System.out.println("Total members: " + totalResults);

            ctx.close();

 

        } 

        catch (NamingException e) {

            System.err.println("Problem searching directory: " + e);

        }

    }

}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值