本節課對SpringBoot2.0以及之前版本的攔截器進行講解
在SpringBoot1.x的版本中實作攔截器,首先寫一個自定義攔截器實作addInterceptors接口,實作其三個方法:
package com.qzsun.springbootdemo.intecpter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class LoginIntercepter implements HandlerInterceptor{
/**
* 進入controller方法之前
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println("LoginIntercepter------->preHandle");
// String token = request.getParameter("access_token");
//
// response.getWriter().print("fail");
return HandlerInterceptor.super.preHandle(request, response, handler);
}
/**
* 調用完controller之後,視圖渲染之前
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("LoginIntercepter------->postHandle");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
/**
* 整個完成之後,通常用于資源清理
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("LoginIntercepter------->afterCompletion");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
然後寫一個配置類繼承WebMvcConfigurerAdapter,然後重寫其addInterceptors()方法,并将剛剛寫的攔截器注冊進去,并加上攔截規則:
package com.qzsun.springbootdemo.intecpter;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* @author sunqizheng
* @Title: CustomOldWebMvcConfigurer
* @ProjectName springbootdemo
* @Description: 2.0版本之前攔截器,方法過時了
* @date 2019/1/3113:34
*/
//@Configuration
public class CustomOldWebMvcConfigurer extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginIntercepter()).addPathPatterns("/api/");
super.addInterceptors(registry);
}
}
但是該寫法在2.0版本中已經過時了,我們點進源碼檢視發現其已被@Deprecated掉了,原因在源碼的注釋上已經寫清楚了:
@deprecated從Spring5.0開始{@link WebMvcConfigurer}具有預設方法(由Java 8基線實作),可以直接實作而無需此擴充卡
下面我們進行新版本攔截器的實作,第一步也是寫一個自定義攔截器,就沿用剛剛寫的攔截器,然後寫一個配置類實作WebMvcConfigurer接口,重寫addInterceptors()方法,注意加上注解@Configuration納入容器管理,然後在裡面注冊之前寫好的LoginIntercepter,然後加上攔截路徑,注意:如果是攔截所有的話就是":
/**
* @author sunqizheng
* @Title: CustomWebMvcConfigurer
* @ProjectName springbootdemo
* @Description: 攔截器配置,類似于以前mvc項目的Spring配置檔案中配置攔截器
* @date 2019/1/3113:57
*/
@Configuration
public class CustomWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//攔截器最後路徑一定要 “/**”, 如果是目錄的話則是 /*/
//如果是攔截所有的話就是"/**"
registry.addInterceptor(new LoginIntercepter()).addPathPatterns("/api/*/**");
WebMvcConfigurer.super.addInterceptors(registry);
}
}
然後在controller中加一個接口供測試使用:
@RequestMapping("/api/test/intercepter")
public String intercepter(){
System.out.println("--------測試攔截器-----");
return "index";
}
啟動并通路http://localhost:8081/api/test/intercepter
攔截器起作用了, preHandle()在進入controller方法之前調用,postHandle()在調用完controller之後,視圖渲染之前調用
,afterCompletion()在整個請求完成之後,通常用于資源清理
如果是兩個攔截器,他們的順序是先定義的先攔截,下面我們再自定義一個攔截器,并注冊到配置類中:
package com.qzsun.springbootdemo.intecpter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class TwoIntercepter implements HandlerInterceptor{
/**
* 進入對應的controller方法之前
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println("TwoIntercepter------>preHandle");
return HandlerInterceptor.super.preHandle(request, response, handler);
}
/**
* controller處理之後,傳回對應的視圖之前
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("TwoIntercepter------>postHandle");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
/**
* 整個請求結束後調用,視圖渲染後,主要用于資源的清理
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("TwoIntercepter------>afterCompletion");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
@Configuration
public class CustomWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//攔截器最後路徑一定要 “/**”, 如果是目錄的話則是 /*/
//如果是攔截所有的話就是"/**"
registry.addInterceptor(new LoginIntercepter()).addPathPatterns("/api/*/**");
registry.addInterceptor(new TwoIntercepter()).addPathPatterns("/api/*/**");
WebMvcConfigurer.super.addInterceptors(registry);
}
}
啟動運作,我們發現果真是先定義的先執行,但是在執行完handle方法之後就是先定義的後執行了,就像兩個同心圓,handle方法在最裡面,外面一層是攔截器2,最外面一層是攔截器1。
補充:我們可以使用.excludePathPatterns()方法排除掉不需要攔截的路徑:
Filter與Intercepter的差別:
Filter
是基于函數回調 doFilter(),而Interceptor則是基于AOP思想
Filter在隻在Servlet前後起作用,而Interceptor夠深入到方法前後、異常抛出前後等
依賴于Servlet容器即web應用中,而Interceptor不依賴于Servlet容器是以可以運作在多種環境。
在接口調用的生命周期裡,Interceptor可以被多次調用,而Filter隻能在容器初始化時調用一次。
Filter和Interceptor的執行順序
過濾前->攔截前->action執行->攔截後->過濾後
源碼位址:https://gitee.com/xuxinsunqizheng/SpringBoot2.0.git