在web項(xiàng)目中如何區(qū)分及使用過濾器(Filter)和攔截器(Interceptor)

一、過濾器的作用及原理

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)行后處理玻墅。


image.png

二、過濾器的簡(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)限檢查顺少、日志記錄等朋其。以下是它們的不同之處:


image.png

執(zhí)行順序如下:


image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末王浴,一起剝皮案震驚了整個(gè)濱河市脆炎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌氓辣,老刑警劉巖秒裕,帶你破解...
    沈念sama閱讀 222,378評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異钞啸,居然都是意外死亡几蜻,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門体斩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來梭稚,“玉大人,你說我怎么就攤上這事絮吵』】荆” “怎么了?”我有些...
    開封第一講書人閱讀 168,983評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵蹬敲,是天一觀的道長暇昂。 經(jīng)常有香客問我,道長伴嗡,這世上最難降的妖魔是什么急波? 我笑而不...
    開封第一講書人閱讀 59,938評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮瘪校,結(jié)果婚禮上澄暮,老公的妹妹穿的比我還像新娘名段。我一直安慰自己,他們只是感情好泣懊,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評(píng)論 6 398
  • 文/花漫 我一把揭開白布吉嫩。 她就那樣靜靜地躺著,像睡著了一般嗅定。 火紅的嫁衣襯著肌膚如雪自娩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,549評(píng)論 1 312
  • 那天渠退,我揣著相機(jī)與錄音忙迁,去河邊找鬼。 笑死碎乃,一個(gè)胖子當(dāng)著我的面吹牛姊扔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播梅誓,決...
    沈念sama閱讀 41,063評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼恰梢,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了梗掰?” 一聲冷哼從身側(cè)響起嵌言,我...
    開封第一講書人閱讀 39,991評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎及穗,沒想到半個(gè)月后摧茴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,522評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡埂陆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評(píng)論 3 342
  • 正文 我和宋清朗相戀三年苛白,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片焚虱。...
    茶點(diǎn)故事閱讀 40,742評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡购裙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鹃栽,到底是詐尸還是另有隱情躏率,我是刑警寧澤,帶...
    沈念sama閱讀 36,413評(píng)論 5 351
  • 正文 年R本政府宣布谍咆,位于F島的核電站禾锤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏摹察。R本人自食惡果不足惜恩掷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望供嚎。 院中可真熱鬧黄娘,春花似錦峭状、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至誓焦,卻和暖如春胆敞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背杂伟。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評(píng)論 1 274
  • 我被黑心中介騙來泰國打工移层, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人赫粥。 一個(gè)月前我還...
    沈念sama閱讀 49,159評(píng)論 3 378
  • 正文 我出身青樓观话,卻偏偏與公主長得像,于是被迫代替她去往敵國和親越平。 傳聞我的和親對(duì)象是個(gè)殘疾皇子频蛔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容