一、過濾器的作用及原理
Servlet中的過濾器Filter是實(shí)現(xiàn)了javax.servlet.Filter接口的服務(wù)器端程序道川,主要的用途是設(shè)置字符集蒋腮、控制權(quán)限、控制轉(zhuǎn)向嘿辟、做一些業(yè)務(wù)邏輯判斷等舆瘪。在web.xml文件配置過濾器參數(shù),在用戶請(qǐng)求時(shí)會(huì)攔截到請(qǐng)求红伦,可以對(duì)對(duì)請(qǐng)求或響應(yīng)(Request英古、Response)統(tǒng)一設(shè)置編碼,簡(jiǎn)化操作昙读,同時(shí)還可進(jìn)行邏輯判斷召调,如用戶是否已經(jīng)登陸、有沒有權(quán)限訪問該頁面等等工作蛮浑。如下圖唠叛,F(xiàn)ilter可以理解成一種Servlet,主要用于對(duì)用戶請(qǐng)求進(jìn)行預(yù)處理陵吸,也可以對(duì)HttpServletResponse進(jìn)行后處理玻墅。
二、過濾器的簡(jiǎn)單實(shí)現(xiàn)
ilter接口中有一個(gè)doFilter方法壮虫,當(dāng)我們編寫好Filter澳厢,并配置對(duì)哪個(gè)web資源進(jìn)行攔截后,WEB服務(wù)器每次在調(diào)用web資源的service方法之前囚似,都會(huì)先調(diào)用一下filter的doFilter方法剩拢,因此,在該方法內(nèi)編寫代碼可達(dá)到如下目的:
1饶唤、調(diào)用目標(biāo)資源之前徐伐,讓一段代碼執(zhí)行。
2募狂、是否調(diào)用目標(biāo)資源(即是否讓用戶訪問web資源)办素。
3、調(diào)用目標(biāo)資源之后祸穷,讓一段代碼執(zhí)行性穿。
web服務(wù)器在調(diào)用doFilter方法時(shí),會(huì)傳遞一個(gè)filterChain對(duì)象進(jìn)來雷滚,filterChain對(duì)象是filter接口中最重要的一個(gè)對(duì) 象需曾,它也提供了一個(gè)doFilter方法,開發(fā)人員可以根據(jù)需求決定是否調(diào)用此方法,調(diào)用該方法呆万,則web服務(wù)器就會(huì)調(diào)用web資源的service方 法商源,即web資源就會(huì)被訪問,否則web資源不會(huì)被訪問谋减。
package me.gacl.web.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* @ClassName: FilterDemo01
* @Description:filter的三種典型應(yīng)用:
* 1牡彻、可以在filter中根據(jù)條件決定是否調(diào)用chain.doFilter(request, response)方法,
* 即是否讓目標(biāo)資源執(zhí)行
* 2逃顶、在讓目標(biāo)資源執(zhí)行之前讨便,可以對(duì)request\response作預(yù)處理充甚,再讓目標(biāo)資源執(zhí)行
* 3以政、在目標(biāo)資源執(zhí)行之后,可以捕獲目標(biāo)資源的執(zhí)行結(jié)果伴找,從而實(shí)現(xiàn)一些特殊的功能
* @author: 孤傲蒼狼
* @date: 2014-8-31 下午10:09:24
*/
public class FilterDemo01 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("----過濾器初始化----");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//對(duì)request和response進(jìn)行一些預(yù)處理
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
System.out.println("FilterDemo01執(zhí)行前S!技矮!");
chain.doFilter(request, response); //讓目標(biāo)資源執(zhí)行抖誉,放行
System.out.println("FilterDemo01執(zhí)行后!Kゾ搿袒炉!");
}
@Override
public void destroy() {
System.out.println("----過濾器銷毀----");
}
}
三、攔截器的作用及原理
攔截器是在面向切面編程中應(yīng)用的樊零,就是在你的service或者一個(gè)方法前調(diào)用一個(gè)方法我磁,或者在方法后調(diào)用一個(gè)方法,是基于JAVA的反射機(jī)制實(shí)現(xiàn)的驻襟。 攔截器將Action共用的行為獨(dú)立出來夺艰,在Action執(zhí)行前后執(zhí)行。這也就是我們所說的AOP沉衣,它是分散關(guān)注的編程方法郁副,它將通用需求功能從不相關(guān)類之中分離出來;同時(shí)豌习,能夠共享一個(gè)行為存谎,一旦行為發(fā)生變化,不必修改很多類肥隆,只要修改這個(gè)行為就可以既荚。當(dāng)你提交對(duì)Action(默認(rèn)是.action結(jié)尾的url)的請(qǐng)求時(shí),ServletDispatcher會(huì)根據(jù)你的請(qǐng)求巷屿,去調(diào)度并執(zhí)行相應(yīng)的Action固以。在Action執(zhí)行之前,調(diào)用被Interceptor截取,Interceptor在Action執(zhí)行前后執(zhí)行憨琳。
SpringMVC 中的Interceptor 攔截請(qǐng)求是通過HandlerInterceptor 來實(shí)現(xiàn)的诫钓。在SpringMVC 中定義一個(gè)Interceptor 非常簡(jiǎn)單,主要有兩種方式篙螟,第一種方式是要定義的Interceptor類要實(shí)現(xiàn)了Spring 的HandlerInterceptor 接口菌湃,或者是這個(gè)類繼承實(shí)現(xiàn)了HandlerInterceptor 接口的類,比如Spring 已經(jīng)提供的實(shí)現(xiàn)了HandlerInterceptor 接口的抽象類HandlerInterceptorAdapter 遍略;第二種方式是實(shí)現(xiàn)Spring的WebRequestInterceptor接口惧所,或者是繼承實(shí)現(xiàn)了WebRequestInterceptor的類。
四绪杏、攔截器簡(jiǎn)單實(shí)現(xiàn)
攔截器主要實(shí)現(xiàn)以下三個(gè)方法:
1下愈、preHandle (HttpServletRequest request, HttpServletResponse response, Object handle) 方法,顧名思義蕾久,該方法將在請(qǐng)求處理之前進(jìn)行調(diào)用势似。SpringMVC 中的Interceptor 是鏈?zhǔn)降恼{(diào)用的,在一個(gè)應(yīng)用中或者說是在一個(gè)請(qǐng)求中可以同時(shí)存在多個(gè)Interceptor 僧著。每個(gè)Interceptor 的調(diào)用會(huì)依據(jù)它的聲明順序依次執(zhí)行履因,而且最先執(zhí)行的都是Interceptor 中的preHandle 方法,所以可以在這個(gè)方法中進(jìn)行一些前置初始化操作或者是對(duì)當(dāng)前請(qǐng)求的一個(gè)預(yù)處理盹愚,也可以在這個(gè)方法中進(jìn)行一些判斷來決定請(qǐng)求是否要繼續(xù)進(jìn)行下去栅迄。該方法的返回值是布爾值Boolean類型的,當(dāng)它返回為false 時(shí)皆怕,表示請(qǐng)求結(jié)束毅舆,后續(xù)的Interceptor 和Controller 都不會(huì)再執(zhí)行;當(dāng)返回值為true 時(shí)就會(huì)繼續(xù)調(diào)用下一個(gè)Interceptor 的preHandle 方法端逼,如果已經(jīng)是最后一個(gè)Interceptor 的時(shí)候就會(huì)是調(diào)用當(dāng)前請(qǐng)求的Controller 方法朗兵。
2、postHandle (HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView) 方法顶滩,由preHandle 方法的解釋我們知道這個(gè)方法包括后面要說到的afterCompletion 方法都只能是在當(dāng)前所屬的Interceptor 的preHandle 方法的返回值為true 時(shí)才能被調(diào)用余掖。postHandle 方法,顧名思義就是在當(dāng)前請(qǐng)求進(jìn)行處理之后礁鲁,也就是Controller 方法調(diào)用之后執(zhí)行盐欺,但是它會(huì)在DispatcherServlet 進(jìn)行視圖返回渲染之前被調(diào)用,所以我們可以在這個(gè)方法中對(duì)Controller 處理之后的ModelAndView 對(duì)象進(jìn)行操作仅醇。postHandle 方法被調(diào)用的方向跟preHandle 是相反的冗美,也就是說先聲明的Interceptor 的postHandle 方法反而會(huì)后執(zhí)行,這和Struts2 里面的Interceptor 的執(zhí)行過程有點(diǎn)類型析二。Struts2 里面的Interceptor 的執(zhí)行過程也是鏈?zhǔn)降姆弁荩皇窃赟truts2 里面需要手動(dòng)調(diào)用ActionInvocation 的invoke 方法來觸發(fā)對(duì)下一個(gè)Interceptor 或者是Action 的調(diào)用节预,然后每一個(gè)Interceptor 中在invoke 方法調(diào)用之前的內(nèi)容都是按照聲明順序執(zhí)行的,而invoke 方法之后的內(nèi)容就是反向的属韧。
3安拟、afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法,該方法也是需要當(dāng)前對(duì)應(yīng)的Interceptor 的preHandle 方法的返回值為true 時(shí)才會(huì)執(zhí)行宵喂。顧名思義糠赦,該方法將在整個(gè)請(qǐng)求結(jié)束之后,也就是在DispatcherServlet 渲染了對(duì)應(yīng)的視圖之后執(zhí)行锅棕。這個(gè)方法的主要作用是用于進(jìn)行資源清理工作的拙泽。
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("攔截器啟動(dòng)!!");
//獲取請(qǐng)求的URL
String url = request.getRequestURI();
System.out.println(url);
//URL:login.jsp是公開的;這個(gè)demo是除了login.jsp是可以公開訪問的,其它的URL都進(jìn)行攔截控制
if(url.indexOf("AnalogLogin")>=0){
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
log.info(ConfigConstants.ExecutionOrderTwo);
//System.out.println(TestInterface.findPrison().toString());
if(modelAndView != null){ //加入當(dāng)前時(shí)間
modelAndView.addObject("var", ConfigConstants.TestPostHandle);
}
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
log.info(ConfigConstants.ExecutionOrderThree);
}
}
五裸燎、攔截器(Interceptor)和過濾器(Filter)的區(qū)別
Spring的Interceptor(攔截器)與Servlet的Filter有相似之處顾瞻,比如二者都是AOP編程思想的體現(xiàn),都能實(shí)現(xiàn)權(quán)限檢查顺少、日志記錄等朋其。以下是它們的不同之處:
執(zhí)行順序如下: