SpringBoot攔截器的使用介紹
定義攔截器
攔截器:所謂攔截器,就是能夠在進行某個操作之前攔截請求,如果請求符合條件就允許在往下執行。比如說,海關就是一個攔截器,他攔截進出口的貨物,如果貨物滿足進出口條件,則放行,否則就攔截,退回處理。
定義攔截器的幾種方式:
實現HandleInterceptor接口
自定義攔截器類實現HandleInterceptor接口,並使用@Component註解標註為一個組件。
public class MySelfInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("在業務處理器處理請求之前被調用"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("在業務處理器處理請求執行完成後,生成視圖之前執行"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("在DispatcherServlet完全處理完請求後被調用"); } }
根據三種情況,可以在不同的方法針對請求進行額外的處理。
在preHandle中,可以進行權限校驗,安全控制。
在postHandle中,可以對返回來的ModelAndView進行處理,這個時候還未渲染視圖。
在afterCompletion中,請求已經完成,頁面已經渲染,數據已經返回。這個時候可以做一些資源清理,或者記錄請求調用時間,做性能監控
繼承HandleInterceptorAdapter類
自定義攔截器類繼承HandleInterceptor接口的實現類HandleInterceptorAdapter來定義,並使用@Component註解標註為一個組件。建議使用此方式可以根據需要覆蓋一些方法
@Component public class MyInterceptor extends HandlerInterceptorAdapter { public SingleLoginInterceptor() { super(); } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return super.preHandle(request, response, handler); } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { super.postHandle(request, response, handler, modelAndView); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { super.afterCompletion(request, response, handler, ex); } @Override public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { super.afterConcurrentHandlingStarted(request, response, handler); } }
可以看到HandlerInterceptorAdapter類底層是實現瞭HandlerInterceptor接口,多瞭兩個方法,要比
實現HandlerInterceptor接口的方式功能強大。
這兩個方法都是HandlerInterceptorAdapter類實現的org.springframework.web.servlet.AsyncHandlerInterceptor接口提供的,而AsyncHandlerInterceptor接口又繼承瞭HandlerInterceptor接口,所以HandlerInterceptorAdapter底層是實現類HandlerInterceptor接口。
實現WebRequestInterceptor接口
自定義攔截器類實現WebRequestInterceptor接口,並使用@Component註解標註為一個組件。
@Component public class MyInterceptor implements WebRequestInterceptor { @Override public void preHandle(WebRequest webRequest) throws Exception { } @Override public void postHandle(WebRequest webRequest, ModelMap modelMap) throws Exception { } @Override public void afterCompletion(WebRequest webRequest, Exception e) throws Exception { } }
兩個實現接口方式的異同點 相同點 都可以實現controller層的攔截請求 不同點
1.WebRequestInterceptor的入參WebRequest是包裝瞭HttpServletRequest 和HttpServletResponse的,通過WebRequest獲取Request中的信息更簡便。
2.WebRequestInterceptor的preHandle是沒有返回值的,說明該方法中的邏輯並不影響後續的方法執行,所以這個接口實現就是為瞭獲取Request中的信息,或者預設一些參數供後續流程使用。
3.HandlerInterceptor的功能更強大也更基礎,可以在preHandle方法中就直接拒絕請求進入controller方法。
4.使用場景:這個在上條已經說瞭,如果想更方便獲取HttpServletRequest的信息就使用WebRequestInterceptor,當然這些HandlerInterceptor都能做,隻不過要多寫點代碼
實現RequestInterceptor接口
自定義類實現RequestInterceptor接口,此方式為微服務Feign調用的自定義攔截器,實現各個微服務之間的參數傳遞。
@Configuration public class CenterinsRequestInterceptor implements RequestInterceptor { @Override public void apply(RequestTemplate requestTemplate) { } }
小插曲 @Configuration和@Component區別
這裡使用瞭@Configuration註解而不是@Component,其實@Configuration本質上也是一個@Component,隻不過前者描述的類中所有用@Bean標記的方法都會由CGLIB動態代理執行,在首次調用的時候會執行,然後把執行結果放到Spring上下文,之後對該方法的調用都是從Spring上下文上取的結果,所以都是指同一個實例。而使用瞭@Component,所有用@Bean標記的方法都是純Java調用,每次都是生成不同的實例對象。如果要讓使用瞭@Compnent註解的類中其@Bean標記的方法生成都是同一個實例,隻需要使用@AutoWired標記屬性,自動註入即可。
@Configuration public class MyBeanConfig { @Bean public Country country(){ return new Country(); } @Bean public UserInfo userInfo(){ return new UserInfo(country()); } } // 以上代碼 等同於以下代碼 // 以下代碼去掉Autowired註入,則country方法是不同的實例對象。 @Component public class MyBeanConfig { @Autowired private Country country; @Bean public Country country(){ return new Country(); } @Bean public UserInfo userInfo(){ return new UserInfo(country); } }
註冊攔截器
註冊攔截器在springboot中直接使用註解便可實現。
繼承WebMvcConfigurerAdapter類
1.創建一個自定義類,繼承WebMvcConfigurerAdapter類重寫addInterceptors方法。
@Configuration public class WebCofiguration extends WebMvcConfigurerAdapter { public void addInterceptors(InterceptorRegistry registry) { // 將自己定義的攔截器註入進來進行攔截操作 registry.addInterceptor(new MySelfInterceptor ()) .addPathPatterns("/**") .excludePathPatterns("/logout"); //過濾器可以添加多個,這裡的addPathPatterns的/**是對所有的請求都做攔截。 //excludePathPatterns代表排除url的攔截路徑,即不攔截 } }
此類在SpringBoot2.0以後已經廢除,但仍可使用。推薦使用以下兩種方式來代替此方式。
繼承WebMvcConfigurationSupport類
2.創建一個自定義類繼承WebMvcConfigurationSupport類,實現addInterceptors。
@Configuration public class MyInterceptorConfig extends WebMvcConfigurationSupport { @Override protected void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**"); super.addInterceptors(registry); } }
此方式會導致默認的靜態資源被攔截,這就需要我們手動將靜態資源放開。
除瞭重寫方法外還需要重寫addResourceHandlers方法來釋放靜態資源
@Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**").addResourceLocations("classpath:/static/"); super.addResourceHandlers(registry); }
實現WebMvcConfigurer接口
3.創建一個自定義類實現WebMvcConfigurer接口,重寫addInterceptors方法。
@Configuration public class MyInterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { // 實現WebMvcConfigurer不會導致靜態資源被攔截 registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**"); } }
此方式不會攔截靜態資源
應用場景
由於這兩種方式的不同:
繼承 WebMvcConfigurationSupport類的方式推薦用在前後端分離的項目中,後臺不需要訪問靜態資源(就不需要放開靜態資源瞭),當然也可以在前後端不分離中,如果需要訪問靜態資源使用上面的方式重寫addResourceHandlers方法即可;
實現 WebMvcConfigure接口的方式推薦用在非前後端分離的項目中,因為需要讀取一些圖片、css、js文件等等,當然也可以使用在前後端分離項目。
攔截器執行流程
單個攔截器
對單個攔截器執行流程解釋如下:
程序首先會執行攔截器類中的preHandle()方法,如果該方法返回true,則程序會繼續向下執行處理器中的方法,否則程序將不再往下繼續執行。在業務處理器(即控制器Controller類)處理完請求後,會執行postHandle()方法,然後會通過DispatcherServlet向客戶端返回響應,在DispatcherServlet處理完請求後,才會執行afterCompletion()方法。
因此單個攔截器的執行流程:
prehandle()——Handle(也就是控制器裡的方法)——postHandle()——afterCompletion()。
多個攔截器
在大型的企業級項目中,通常會配置多個攔截器來實現不同的功能。例如我們自定義瞭三個攔截器A、B、C。並將它們都註冊到同一個攔截器配置類中,如下圖
@Configuration public class InterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AInterceptor()) .addPathPatterns("/**"); registry.addInterceptor(new BInterceptor()) .addPathPatterns("/**"); registry.addInterceptor(new CInterceptor()) .addPathPatterns("/**"); } }
它們的preHandle()方法會按照配置文件中攔截器的配置順序執行,而它們的postHandle()和afterCompletion()方法則會按照配置順序的反序執行。
因此當前我們的三個攔截器執行順序如下:
preHandleA——preHandleB——preHandleC——Handle——postHandleC——postHandleB——postHandleA——afterCompletionC——afterCompletionB——afterCompletionA
總結
到此這篇關於SpringBoot攔截器的使用介紹的文章就介紹到這瞭,更多相關SpringBoot攔截器內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 詳解SpringMVC的攔截器鏈實現及攔截器鏈配置
- 詳解Spring 攔截器流程及多個攔截器的執行順序
- SpringBoot 攔截器妙用你真的瞭解嗎
- Spring中自定義攔截器的使用
- SpringBoot使用Interceptor攔截器的實例