JavaWeb有三大組件秘症,Servlet照卦、Listener、Filter乡摹。本文將介紹Filter役耕,主要從用處、種類聪廉、使用方法等進(jìn)行介紹瞬痘。
一、用處
Filter可以認(rèn)為是Servlet的一種“加強(qiáng)版”板熊。使用Filter完整的流程是:Filter對用戶請求進(jìn)行預(yù)處理图云,接著將請求交給Servlet進(jìn)行處理并生成響應(yīng),最后Filter再對服務(wù)器響應(yīng)進(jìn)行后處理邻邮。
Filter有以下幾個用處:
- 在HttpServletRequest到達(dá)Servlet之前竣况,攔截客戶的HttpServletRequest;
- 根據(jù)需要檢查HttpServletRequest筒严,也可以修改HttpServletRequest頭和數(shù)據(jù)丹泉;
- 在HttpServletResponse到達(dá)客戶端之前,攔截HttpServletResponse鸭蛙;
- 根據(jù)需要檢查HttpServletResponse摹恨,也可以修改HttpServletResponse頭和數(shù)據(jù)。
二娶视、種類
- 用戶授權(quán)的Filter:Filter負(fù)責(zé)檢查用戶請求晒哄,根據(jù)請求過濾用戶非法請求(比如對用戶登錄狀態(tài)進(jìn)行判定);
- 日志Filter:詳細(xì)記錄某些特殊的用戶請求肪获;
- 負(fù)責(zé)解碼的Filter:包括對非標(biāo)準(zhǔn)編碼的請求解碼寝凌;
- 能改變XML內(nèi)容的XSLT Filter等;
- Filter可負(fù)責(zé)攔截多個請求或響應(yīng)孝赫;一個請求或響應(yīng)也可被多個Filter攔截较木。
三、使用方法
3.1 創(chuàng)建Filter步驟
1)創(chuàng)建Filter處理類青柄;
2)web.xml文件中配置Filter伐债,或通過注解的方式配置预侯。(順便說一下,三大組件都需要在web.xml中進(jìn)行配置)
3.2 創(chuàng)建Filter類
創(chuàng)建Filter類必須實(shí)現(xiàn)Filter接口峰锁,F(xiàn)ilter接口中包含三個方法:
- void init(FilterConfig config):用于完成Filter的初始化萎馅;
- void destroy():用于Filter銷毀前,完成某些資源的回收虹蒋;
- void doFilter(ServletRequest srq, ServletResponse srp, FilterChain chain):實(shí)現(xiàn)過濾功能校坑,該方法就是對每個請求及響應(yīng)增加的額外處理。
doFilter()方法千诬,在該方法中可實(shí)現(xiàn)對用戶請求進(jìn)行預(yù)處理耍目,也可實(shí)現(xiàn)對服務(wù)器響應(yīng)進(jìn)行后處理,分界線就是是否調(diào)用了chain.doFiler()徐绑,調(diào)用之前是請求預(yù)處理邪驮,調(diào)用之后是響應(yīng)后處理。這是因為傲茄,web服務(wù)器會檢查FilterChain對象中是否還有Filter毅访,如果有,則調(diào)用下一個Filter盘榨,沒有喻粹,則調(diào)用目標(biāo)資源。
3.3 配置Filter
與配置Servlet相似草巡,配置Filter守呜,需要配置兩個部分:
1)配置Filter名;
2)配置Filter攔截URL模式
與Servlet的區(qū)別在于:Servlet通常只配置一個URL山憨,而Filter可以同時攔截多個請求的URL查乒。因此,在配置Filter的URL模式時通常會使用模式字符串郁竟,使得Filter可以攔截多個請求玛迄。配置的方式有兩種:在Filter類中通過注解進(jìn)行配置,在web.xml文件中進(jìn)行配置棚亩。
3.3.1 注解配置
使用@WebFilter注解進(jìn)行配置蓖议,并添加屬性。常用屬性如下:
屬性 | 是否必需 | 說明 |
---|---|---|
asynSupported | 否 | 指定該Filter是否支持異步操作模式讥蟆。 |
dispatcherTypes | 否 | 指定該Filter僅對那種dispatcher模式的請求進(jìn)行過濾勒虾。該屬性支持ASTNC、ERROR攻询、FORWARD从撼、INCLUDE州弟、REQUEST這五個值的任意組合钧栖。默認(rèn)值是同時過濾5種模式的請求低零。 |
displayName | 否 | 指定該Filter的顯示名 |
filterName | 是 | 指定該Filter的名稱 |
initParams | 否 | 用于為該Filter配置參數(shù) |
servletNames | 否 | 該屬性值可指定多個Servlet的名稱,用于指定該Filter僅對這幾個Servlet執(zhí)行過濾拯杠。 |
urlPatterns/value | 否 | 這兩個屬性的作用完全相同掏婶。都指定該Filter所攔截的URL。 |
3.3.2 web.xml中進(jìn)行配置
<!-- 定義Filter -->
<filter>
<filter-name>log</filter-name>
<filter-class>filter.LogFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>log</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Filter里doFilter()方法里的代碼就是從多個Servlet的service()方法里抽出的通用代碼潭陪。通過使用Filter可以實(shí)現(xiàn)更好的代碼復(fù)用雄妥。
Filter和Servlet具有完全相同的生命周期行為,且Filter也可以通過<init-param.../>元素或@WebFilter的initParams屬性來配置初始化參數(shù)依溯,獲取Filter的初始化參數(shù)則使用FilterConfig的getInitParameter()方法老厌。
四、舉個栗子
/**
* AuthorityFilter.java
*/
@WebFilter(filterName = "authority", urlPatterns = {"/*"}, initParams = {
@WebInitParam(name = "encoding",value = "UTF-8"),
@WebInitParam(name = "loginPage",value = "/login.jsp"),
@WebInitParam(name = "proLogin",value = "proLogin.jsp")
})
public class AuthorityFilter implements Filter{
private FilterConfig config;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.config = filterConfig;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
/**
* 通過config獲取初始化參數(shù)
*/
String encoding = this.config.getInitParameter("encoding");
String loginPage = this.config.getInitParameter("loginPage");
String proLogin = this.config.getInitParameter("proLogin");
/**
* 通過獲取到的初始化參數(shù)設(shè)置解碼格式
*/
servletRequest.setCharacterEncoding(encoding);
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpSession session = httpServletRequest.getSession(true);
String requestPath = httpServletRequest.getServletPath();
/**
* 若用戶未登錄黎炉,并且請求地址不是登錄頁和處理登錄頁枝秤,跳轉(zhuǎn)到登錄頁;
* 若登錄了慷嗜,則調(diào)用filterChain.doFilter()返回資源淀弹。
*/
if (session.getAttribute("user")==null
&& !requestPath.endsWith(loginPage)
&& !requestPath.endsWith(proLogin))
{
httpServletRequest.setAttribute("tip","您還沒有登錄");
httpServletRequest.getRequestDispatcher(loginPage).forward(httpServletRequest,servletResponse);
} else {
filterChain.doFilter(httpServletRequest,servletResponse);
}
}
@Override
public void destroy() {
this.config = null;
}
}