2011-08-25 134 views
29

我希望能夠以不同於web.xml的方式修改/配置過濾器。這是2個過濾器的靜態配置。我希望能夠靜態配置一個過濾器並允許該過濾器加載額外的過濾器。我只是想知道是否有人知道lib已經有這個。如何在不修改web.xml的情況下向servlet添加過濾器

使用Servlet API的2.5

<web-app> 
    ... 
    <filter> 
    <filter-name>MyFilter1</filter-name> 
    <filter-class>com.me.MyFilter1</filter-class> 
    </filter> 
    <filter-mapping> 
    <filter-name>MyFilter1</filter-name> 
    <url-pattern>/*</url-pattern> 
    </filter-mapping> 
    ... 
    <filter> 
    <filter-name>MyFilter2</filter-name> 
    <filter-class>com.me.MyFilter2</filter-class> 
    </filter> 
    <filter-mapping> 
    <filter-name>MyFilter2</filter-name> 
    <url-pattern>/*</url-pattern> 
    </filter-mapping> 
    ... 
</web-app> 

我已經看到了這個吉斯做與GuiceFilter當過濾器在運行時配置。

+0

這將取決於servlet容器的,所以您在使用 – SJuan76

+0

哪一個必須依賴你應該告訴我們什麼? GuiceFilter是否依賴於容器? – TJR

+0

Guice爲自己的映射機制創建了一個類似於web.xml映射的映射機制 - 對於web容器,所有請求都以'GuiceFilter'結束。如果你想要Guice,只需使用它:) –

回答

35

只要做容器已經做的相同的工作。即在servlet過濾器所使用的覆蓋範圍內重新設計了chain of responsibility設計模式。

public class GodFilter implements Filter { 

    private Map<Pattern, Filter> filters = new LinkedHashMap<Pattern, Filter>(); 

    @Override 
    public void init(FilterConfig config) throws ServletException { 
     Filter1 filter1 = new Filter1(); 
     filter1.init(config); 
     filters.put(new Pattern("/foo/*"), filter1); 

     Filter2 filter2 = new Filter2(); 
     filter2.init(config); 
     filters.put(new Pattern("*.bar"), filter2); 

     // ... 
    } 

    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { 
     HttpServletRequest hsr = (HttpServletRequest) request; 
     String path = hsr.getRequestURI().substring(hsr.getContextPath().length()); 
     GodFilterChain godChain = new GodFilterChain(chain); 

     for (Entry<Pattern, Filter> entry : filters.entrySet()) { 
      if (entry.getKey().matches(path)) { 
       godChain.addFilter(entry.getValue()); 
      } 
     } 

     godChain.doFilter(request, response); 
    } 

    @Override 
    public void destroy() { 
     for (Filter filter : filters.values()) { 
      filter.destroy(); 
     } 
    } 

} 

與那些小助手類(可以根據需要進行private static嵌套類以上GodFilter的):

public class Pattern { 

    private int position; 
    private String url; 

    public Pattern(String url) { 
     this.position = url.startsWith("*") ? 1 
         : url.endsWith("*") ? -1 
         : 0; 
     this.url = url.replaceAll("/?\\*", ""); 
    } 

    public boolean matches(String path) { 
     return (position == -1) ? path.startsWith(url) 
      : (position == 1) ? path.endsWith(url) 
      : path.equals(url); 
    } 

} 

public class GodFilterChain implements FilterChain { 

    private FilterChain chain; 
    private List<Filter> filters = new ArrayList<Filter>(); 
    private Iterator<Filter> iterator; 

    public GodFilterChain(FilterChain chain) { 
     this.chain = chain; 
    } 

    @Override 
    public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { 
     if (iterator == null) { 
      iterator = filters.iterator(); 
     } 

     if (iterator.hasNext()) { 
      iterator.next().doFilter(request, response, this); 
     } else { 
      chain.doFilter(request, response); 
     } 
    } 

    public void addFilter(Filter filter) { 
     if (iterator != null) { 
      throw new IllegalStateException(); 
     } 

     filters.add(filter); 
    } 

} 

,你可以在必要時也喂帶有所有可能的過濾器的XML配置文件,以便最終配置更簡單。您可以使用反射在您的GodFilterinit()中創建濾鏡。

哦沒關係,那是什麼web.xml,並已經容器是做...

+0

Should not GodFilterChain.doFilter()loop over所有添加的過濾器比只使用第一個? – MRalwasser

+0

@MRalwasser:呃,沒有。也許你錯過了「責任鏈」設計模式的工作原理?過濾器實現中的'chain.doFilter()'調用會再次調用'GodFilterChain#doFilter()'(因爲它是作爲'FilterChain'參數傳遞的),然後迭代器會前進到下一個元素,等等。 – BalusC

+0

啊,我完全錯過了後面的iterator.next()調用將在更深的「鏈級」內完成。感謝您指出了這一點。 – MRalwasser

15

Servlet 3.0有@WebFilter註釋來定義過濾器。無需再在web.xml中聲明它。

但不支持從過濾器加載過濾器。你可以自己實現它:它只是「責任鏈模式」,但你爲什麼要這樣做?

+2

刪除我的回答,擊敗我30秒>:| – Dave

+2

@JB Nizet:TJR沒有要求版本servlet 3.0,他是特定的servlet 2.5 – developer

+0

@JB,我已經添加到我使用2.5的問題。 3.0功能確實讓我開心。 – TJR

4

它可以簡單的步驟來實現,即使是前3.0 Servlet規範:

  1. 添加包含類的靜態&有序集合(鏈)的過濾器。
  2. 映射過濾器以攔截每個流量。
  3. 操縱訂單&存在您的幫助類(在攔截流量時由您的過濾器私下調用這些類)。

Ref:Xstream使用相同類型的串行器模式,儘管沒有使用Servlet/Filter。 :)

相關問題