Spring的理解:Filter與Intercepter

Filter是Servlet的規(guī)范旨别,它的定義如下:

public interface Filter {

public void init(FilterConfig filterConfig)throwsServletException;

public void doFilter(ServletRequest request,ServletResponse response, FilterChain chain)throwsIOException,ServletException;

public void destroy();

主要作用就是苍姜,對(duì)ServletRequest做預(yù)處理,執(zhí)行過程中任何時(shí)候都可以打斷炊苫,只要不執(zhí)行chain.doFilter()就不會(huì)再執(zhí)行后面的過濾器和請(qǐng)求的內(nèi)容。而在實(shí)際使用時(shí)冰沙,就要特別注意過濾鏈的執(zhí)行順序問題

而Spring MVC是基于Servlet來響應(yīng)用戶請(qǐng)求對(duì)侨艾,所以,在Spring中可以可以用Filter來干預(yù)Http請(qǐng)求拓挥,解決諸如跨域蒋畜、認(rèn)證方面的要求。例子如下:

@Component

public classSimpleCORSFilterimplementsFilter {

public voiddoFilter(ServletRequest req,ServletResponse res,FilterChain chain)throwsIOException,

ServletException {

HttpServletResponse response = (HttpServletResponse) res;

response.setHeader("Access-Control-Allow-Origin","*");

response.setHeader("Access-Control-Allow-Methods","POST, GET, OPTIONS, DELETE");

response.setHeader("Access-Control-Max-Age","3600");

response.setHeader("Access-Control-Allow-Headers","Token,Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since");

chain.doFilter(req,res);

}

public voidinit(FilterConfig filterConfig) {}

public voiddestroy() {}

}

而攔截器撞叽,是基于Spring IOC的姻成。可以在方法級(jí)別愿棋,對(duì)流程進(jìn)行預(yù)處理科展、后處理、綜合(前后同時(shí))處理糠雨。我們需要做的就是:

1才睹、創(chuàng)建自己的攔截器實(shí)現(xiàn)HandlerInterceptor接口

2.? 加入到攔截器鏈條,繼承WebMvcConfigurerAdapter類,重寫addInterceptors方法

? ? 將攔截器加入到攔截鏈條(需要添加攔截規(guī)則)琅攘,如下:

public class CustomInterceptor implements HandlerInterceptor {

@Override

public void afterCompletion (HttpServletRequest?request, ?HttpServletResponse?response, ?Object?object, Exception?exception)throwsException?{

//在整個(gè)請(qǐng)求結(jié)束之后被調(diào)用垮庐,也就是在DispatcherServlet?渲染了對(duì)應(yīng)的視圖之后執(zhí)行(主要是用于進(jìn)行資源清理工作)

System.out.println("3.?整個(gè)請(qǐng)求結(jié)束之后被調(diào)用......CustomInterceptor1......");

}

@Override

publicvoidpostHandle(HttpServletRequest?request,?HttpServletResponse?response,?Object?object,?ModelAndView?view)

throwsException?{

//?請(qǐng)求處理之后進(jìn)行調(diào)用,但是在視圖被渲染之前

System.out.println("2.?請(qǐng)求處理之后進(jìn)行調(diào)用坞琴,但是在視圖被渲染之前......CustomInterceptor1......");

}

@Override

publicbooleanpreHandle(HttpServletRequest?request,?HttpServletResponse?response,?Object?object)throwsException?{

//?在請(qǐng)求處理之前進(jìn)行調(diào)用

System.out.println("1.?在請(qǐng)求處理之前進(jìn)行調(diào)用......CustomInterceptor1......");

//?只有返回true才會(huì)繼續(xù)向下執(zhí)行哨查,返回false取消當(dāng)前請(qǐng)求

returntrue;

}

@Configuration

publicclassWebAdapterextendsWebMvcConfigurerAdapter{

@Override

publicvoidaddInterceptors(InterceptorRegistry?registry)?{

//眾多的攔截器組成了一個(gè)攔截器鏈

/**

*?主要方法說明:

*?addPathPatterns?用于添加攔截規(guī)則

*?excludePathPatterns?用戶排除攔截

*/

registry.addInterceptor(newCustomInterceptor()).addPathPatterns("/*");

registry.addInterceptor(newCustomInterceptor2()).addPathPatterns("/*");

super.addInterceptors(registry);

}


或者直接寫一個(gè)完整的自定義攔截器

@Aspect

@Component

public classControllerInterceptor {

private static finalLoggerlogger= LoggerFactory.getLogger(ControllerInterceptor.class);

@Value("${spring.profiles}")

privateStringenv;

/**

* 定義攔截規(guī)則:攔截com.xjj.web.controller包下面的所有類中,有@RequestMapping注解的方法剧辐。

*/

@Pointcut("execution(* com.xjj.web.controller..*(..)) and @annotation(org.springframework.web.bind.annotation.RequestMapping)")

public voidcontrollerMethodPointcut(){}

/**

* 攔截器具體實(shí)現(xiàn)

*@parampjp

*@returnJsonResult(被攔截方法的執(zhí)行結(jié)果寒亥,或需要登錄的錯(cuò)誤提示。)

*/

@Around("controllerMethodPointcut()")//指定攔截器規(guī)則荧关;也可以直接把“execution(* com.xjj.........)”寫進(jìn)這里

public Object Interceptor(ProceedingJoinPoint pjp){

long beginTime = System.currentTimeMillis();

Method Signature signature = (MethodSignature) pjp.getSignature();

Method method = signature.getMethod();//獲取被攔截的方法

String methodName = method.getName();//獲取被攔截的方法名

Set allParams =newLinkedHashSet<>();//保存所有請(qǐng)求參數(shù)溉奕,用于輸出到日志中

logger.info("請(qǐng)求開始,方法:{}",methodName);

Object result =null;

Object[] args = pjp.getArgs();

for(Object arg : args){

//logger.debug("arg: {}", arg);

if(arginstanceofMap) {

//提取方法中的MAP參數(shù)忍啤,用于記錄進(jìn)日志中

@SuppressWarnings("unchecked")

Map map = (Map) arg;

allParams.add(map);

}else if(arginstanceofHttpServletRequest){

HttpServletRequest request = (HttpServletRequest) arg;

if(isLoginRequired(method)){

if(!isLogin(request)){

result =newJsonResult(ResultCode.NOT_LOGIN,"該操作需要登錄加勤!去登錄嗎?", null);

}

}

//獲取query string 或 posted form data參數(shù)

Map paramMap = request.getParameterMap();

if(paramMap!=null&& paramMap.size()>0){

allParams.add(paramMap);

}

}else if(arginstanceofHttpServletResponse){

//do nothing...

}else{

//allParams.add(arg);

}

}

try{

if(result ==null){

// 一切正常的情況下同波,繼續(xù)執(zhí)行被攔截的方法

result = pjp.proceed();

}

}catch(Throwable e) {

logger.info("exception: ",e);

result =newJsonResult(ResultCode.EXCEPTION,"發(fā)生異常:"+e.getMessage());

}

if(resultinstanceofJsonResult){

longcostMs = System.currentTimeMillis() - beginTime;

logger.info("{}請(qǐng)求結(jié)束胸竞,耗時(shí):{}ms",methodName,costMs);

}

returnresult;

}

/**

* 判斷一個(gè)方法是否需要登錄

*@parammethod

*@return

*/

private booleanisLoginRequired(Method method){

if(!env.equals("prod")){//只有生產(chǎn)環(huán)境才需要登錄

return false;

}

booleanresult =true;

if(method.isAnnotationPresent(Permission.class)){

result = method.getAnnotation(Permission.class).loginReqired();

}

returnresult;

}

//判斷是否已經(jīng)登錄

private booleanisLogin(HttpServletRequest request) {

return true;

/*String token = XWebUtils.getCookieByName(request, WebConstants.CookieName.AdminToken);

if("1".equals(redisOperator.get(RedisConstants.Prefix.ADMIN_TOKEN+token))){

return true;

}else {

return false;

}*/

}

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市参萄,隨后出現(xiàn)的幾起案子卫枝,更是在濱河造成了極大的恐慌,老刑警劉巖讹挎,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件校赤,死亡現(xiàn)場離奇詭異,居然都是意外死亡筒溃,警方通過查閱死者的電腦和手機(jī)马篮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怜奖,“玉大人浑测,你說我怎么就攤上這事⊥崃幔” “怎么了迁央?”我有些...
    開封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長滥崩。 經(jīng)常有香客問我岖圈,道長,這世上最難降的妖魔是什么钙皮? 我笑而不...
    開封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任蜂科,我火速辦了婚禮遭铺,結(jié)果婚禮上碳胳,老公的妹妹穿的比我還像新娘。我一直安慰自己优妙,他們只是感情好炎码,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開白布妹蔽。 她就那樣靜靜地躺著材鹦,像睡著了一般钥屈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上厕氨,一...
    開封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天进每,我揣著相機(jī)與錄音汹粤,去河邊找鬼命斧。 笑死,一個(gè)胖子當(dāng)著我的面吹牛嘱兼,可吹牛的內(nèi)容都是我干的国葬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼芹壕,長吁一口氣:“原來是場噩夢啊……” “哼汇四!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起踢涌,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤通孽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后睁壁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體背苦,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年潘明,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了行剂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡钳降,死狀恐怖厚宰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情遂填,我是刑警寧澤铲觉,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站吓坚,受9級(jí)特大地震影響备燃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜凌唬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一并齐、第九天 我趴在偏房一處隱蔽的房頂上張望漏麦。 院中可真熱鬧,春花似錦况褪、人聲如沸撕贞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捏膨。三九已至,卻和暖如春食侮,著一層夾襖步出監(jiān)牢的瞬間号涯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來泰國打工锯七, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留链快,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓眉尸,卻偏偏與公主長得像域蜗,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子噪猾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

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