處理 DirContext

本節介紹如何處理 DirContext,包括前置處理和後置處理。

自定義 DirContext 前置處理和後置處理

在某些情況下,您可能希望在搜尋操作之前和之後對 DirContext 執行操作。用於此目的的介面稱為 DirContextProcessor。以下列出了 DirContextProcessor 介面

public interface DirContextProcessor {
   public void preProcess(DirContext ctx) throws NamingException;
   public void postProcess(DirContext ctx) throws NamingException;
}

LdapTemplate 類有一個接受 DirContextProcessor 的搜尋方法,如下所示

public void search(SearchExecutor se, NameClassPairCallbackHandler handler,
   DirContextProcessor processor) throws DataAccessException;

在搜尋操作之前,會呼叫給定的 DirContextProcessor 例項上的 preProcess 方法。在搜尋執行完畢並且處理完結果 NamingEnumeration 後,會呼叫 postProcess 方法。這允許您對用於搜尋的 DirContext 執行操作,並在執行搜尋後檢查 DirContext。這非常有用(例如,在處理請求和響應控制元件時)。

當您不需要自定義 SearchExecutor 時,還可以使用以下便利方法

public void search(Name base, String filter,
   SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor)

public void search(String base, String filter,
   SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor)

public void search(Name base, String filter,
   SearchControls controls, AttributesMapper mapper, DirContextProcessor processor)

public void search(String base, String filter,
   SearchControls controls, AttributesMapper mapper, DirContextProcessor processor)

public void search(Name base, String filter,
   SearchControls controls, ContextMapper mapper, DirContextProcessor processor)

public void search(String base, String filter,
   SearchControls controls, ContextMapper mapper, DirContextProcessor processor)

實現請求控制元件 DirContextProcessor

LDAPv3 協議使用“控制元件”(Controls)來發送和接收附加資料,以影響預定義操作的行為。為了簡化請求控制元件 DirContextProcessor 的實現,Spring LDAP 提供了 AbstractRequestControlDirContextProcessor 基類。此類負責從 LdapContext 中檢索當前的請求控制元件,呼叫模板方法建立請求控制元件,並將其新增到 LdapContext 中。您在子類中需要做的就是實現名為 createRequestControl 的模板方法以及在搜尋後執行所需操作的 postProcess 方法。以下列出了相關的簽名

public abstract class AbstractRequestControlDirContextProcessor implements
      DirContextProcessor {

   public void preProcess(DirContext ctx) throws NamingException {
      ...
   }

   public abstract Control createRequestControl();
}

典型的 DirContextProcessor 類似於以下示例

示例 1. 請求控制元件 DirContextProcessor 實現
public class MyCoolRequestControl extends AbstractRequestControlDirContextProcessor {
   private static final boolean CRITICAL_CONTROL = true;
   private MyCoolCookie cookie;
   ...
   public MyCoolCookie getCookie() {
      return cookie;
   }

   public Control createRequestControl() {
      return new SomeCoolControl(cookie.getCookie(), CRITICAL_CONTROL);
   }

   public void postProcess(DirContext ctx) throws NamingException {
      LdapContext ldapContext = (LdapContext) ctx;
      Control[] responseControls = ldapContext.getResponseControls();

      for (int i = 0; i < responseControls.length; i++) {
         if (responseControls[i] instanceof SomeCoolResponseControl) {
            SomeCoolResponseControl control = (SomeCoolResponseControl) responseControls[i];
            this.cookie = new MyCoolCookie(control.getCookie());
         }
      }
   }
}
使用控制元件時,請確保使用 LdapContextSourceControl 介面是 LDAPv3 特有的,要求使用 LdapContext 而不是 DirContext。如果呼叫 `AbstractRequestControlDirContextProcessor` 子類時傳遞的引數不是 LdapContext,它將丟擲 IllegalArgumentException

分頁搜尋結果

某些搜尋可能返回大量結果。當沒有簡單的方法過濾出少量結果時,讓伺服器每次呼叫時只返回一定數量的結果會很方便。這被稱為“分頁搜尋結果”(paged search results)。然後可以顯示結果的每一“頁”,並帶有指向下一頁和上一頁的連結。如果沒有此功能,客戶端必須手動將搜尋結果限制為頁面,或者檢索全部結果,然後將其分割成適當大小的頁面。前者會相當複雜,而後者會消耗不必要的記憶體。

一些 LDAP 伺服器支援 PagedResultsControl,它要求 LDAP 伺服器按指定大小的頁返回搜尋操作的結果。使用者透過控制搜尋呼叫的速率來控制頁面的返回速率。但是,您必須在呼叫之間跟蹤一個 cookie。伺服器使用此 cookie 來跟蹤上次處理分頁結果請求時停止的位置。

Spring LDAP 透過使用前述章節討論的對 LdapContext 進行前置和後置處理的概念來提供對分頁結果的支援。它透過使用 PagedResultsDirContextProcessor 類來實現這一點。PagedResultsDirContextProcessor 類建立一個帶有請求頁大小的 PagedResultsControl 並將其新增到 LdapContext 中。搜尋後,它獲取 PagedResultsResponseControl 並檢索分頁結果 cookie,這對於在連續的分頁結果請求之間保持上下文是必需的。

以下示例展示瞭如何使用分頁搜尋結果功能

示例 2. 使用 PagedResultsDirContextProcessor 實現分頁結果
public List<String> getAllPersonNames() {
  final SearchControls searchControls = new SearchControls();
  searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);

  final PagedResultsDirContextProcessor processor =
        new PagedResultsDirContextProcessor(PAGE_SIZE);

  return SingleContextSource.doWithSingleContext(
        contextSource, new LdapOperationsCallback<List<String>>() {

      @Override
      public List<String> doWithLdapOperations(LdapOperations operations) {
        List<String> result = new LinkedList<String>();

        do {
          List<String> oneResult = operations.search(
            "ou=People",
            "(&(objectclass=person))",
            searchControls,
            CN_ATTRIBUTES_MAPPER,
            processor);
          result.addAll(oneResult);
        } while(processor.hasMore());

        return result;
      }
  });
}
為了使分頁結果 cookie 保持有效,每次分頁結果呼叫都必須使用相同的底層連線。如前面的示例所示,您可以使用 SingleContextSource 來實現這一點。