說到排斥性過濾器,大家會一頭霧水,搞不明白這其中含義。何為排斥性(exclude)過濾器呢,其實是本人自己定義出來的,呵呵。
排斥性過濾器是相對於規範所定義的Filter而言的,Java EE 規範中的過濾器是對web.xml中所列出的url進行過濾,而排斥性過濾器則恰恰相反,不對這些web.xml中列出的url執行過濾,而是對除這些url外的url進行過濾邏輯操作。
作為一個多年的Java開發人員,在實際開發中遇到這種情況,這便是有此動機的原因。下面就講講這個exclude filter的原理,其實很簡單。在攔截所有請求時,我們檢查這些請求的url是否在url列表之內,如果在,那麼就不進行過濾邏輯,直接調用chain.doFilter(xxx);否則的話,我們就執行一些過濾邏輯操作,然後再chain.doFilter(xxx)。
其中,檢查url分2種方式:精確匹配(equals)和模糊比對(contains),精確匹配優先於模糊比對. 對於代碼中的URI擷取,可能要根據實際情況作些更改,代碼中URI只是使用request.getRequestURI(),得到的不是完整的URL,可視實際情況做出調整。
AbstractExcludeFilter 類將不該被override的方法都設定為了final,developer應該實現唯一的一個abstract method filter(),並且需要在該方法內部適當位置調用 chain.doFilter(xx)。
請看實現代碼:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.openthoughts.webtools.filters;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
/**
* An abstract filter provided for developer to filter the URLs that are not in excluded URLs list.
*
* Usage:
* 1.Write subclass of this abstract filter by implementing abstract method 'filter'.
* 2.Config web.xml like this:
* <filter>
* <filter-name>yourExcludeFilter</filter-name>
* <filter-class>org.openthoughts.webtools.filters.YourCustomizedExcludeFilter</filter-class>
* <init-param>
* <param-name>exactMatchExcludedURLs</param-name>
* <param-value>/abc/,/abc/index.jsp,/abc/loginServlet</param-value>
* </init-param>
* <init-param>
* <param-name>approximateMatchExcludedURLs</param-name>
* <param-value>loginServlet,upgradeServlet</param-value>
* </init-param>
* </filter>
*
* <filter-mapping>
* <filter-name>yourExcludeFilter</filter-name>
* <url-pattern>/*</url-pattern>
*</filter-mapping>
* Note: exactMatchExcludedURLs means exactly match URLs that should not be filtered,
* i.e. request.getRequestURI().equals(url);
* approximateMatchExcludedURLs means approximately math URLs that should
* not be filtered, i.e. request.getRequestURI().contains(url)
* exactMatch is prior to approximateMatch, i.e. if exactMath = true,
* not check approximateMatch
*
* @author <a href="mailto:guangquanzhang@gmail.com">gavin.zhang</a>
*/
public abstract class AbstractExcludeFilter implements Filter {
private FilterConfig config;
private List<String> exactMatchExcludedURLs = new ArrayList<String>();
private List<String> approximateMatchExcludedURLs = new ArrayList<String>();
/**
* Init filter, and load all configuration.
* @param config
* @throws javax.servlet.ServletException
*/
final public void init(FilterConfig config) throws ServletException {
this.config = config;
this.loadConfiguration(config);
}
/**
* Do filter work according to exactMatch or approximateMatch,
* This method must not be overrided.
* @param request
* @param response
* @param chain
* @throws java.io.IOException
* @throws javax.servlet.ServletException
*/
final public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
boolean is2BeFiltered = true;
String requestURI = ((HttpServletRequest) request).getRequestURI();
if (!this.exactMatchExcludedURLs.isEmpty()) {
for (String exactMatchExcludedURL : this.exactMatchExcludedURLs) {
if (requestURI.equals(exactMatchExcludedURL)) {
is2BeFiltered = false;
break;
}
}
}
if (!this.approximateMatchExcludedURLs.isEmpty() && is2BeFiltered) {
for (String approximateMatchExcludedURL : this.approximateMatchExcludedURLs) {
if (requestURI.indexOf(approximateMatchExcludedURL) != -1) {
is2BeFiltered = false;
break;
}
}
}
if (is2BeFiltered) {
this.filter(request, response, chain);
} else {
chain.doFilter(request, response);
}
}
/**
* Release all resources.
*/
final public void destroy() {
this.config = null;
this.exactMatchExcludedURLs = null;
this.approximateMatchExcludedURLs = null;
}
/**
* Do customized filter work according to exactMatch or approximateMatch,
* developer should implement this Abstract Method.
* @param request
* @param response
* @param chain
*/
public abstract void filter(ServletRequest request, ServletResponse response, FilterChain chain);
/**
* Load configuration from web.xml.
* @param config
*/
private void loadConfiguration(FilterConfig config) {
String exactMatchedURLString = config.getInitParameter("exactMatchExcludedURLs");
String approximateMatchedURLString = config.getInitParameter("approximateMatchExcludedURLs");
if(null != exactMatchedURLString) {
String[] tmps = exactMatchedURLString.split(”,”);
for (String tmp : tmps) {
tmp = tmp.trim();
if(tmp.length()>0) {
this.exactMatchExcludedURLs.add(tmp);
}
}
}
if(null != approximateMatchedURLString) {
String[] tmps = approximateMatchedURLString.split(”,”);
for (String tmp : tmps) {
tmp = tmp.trim();
if(tmp.length()>0) {
this.approximateMatchExcludedURLs.add(tmp);
}
}
}
}
}