網絡上關於Interceptor
的文章,但感覺內容都大同小異,而且知識點零零散散,不太方便閱讀。因此,整理一篇關於攔截器的文章,在此分享給大家,以供大家參考閱讀。
1.概念
java里的攔截器是動態攔截Action調用的對象,它提供了一種機制可以使開發者在一個Action執行的前后執行一段代碼,也可以在一個Action執行前阻止其執行,同時也提供了一種可以提取Action中可重用部分代碼的方式。在AOP中,攔截器用於在某個方法或者字段被訪問之前進行攔截,然后再之前或者之后加入某些操作。
談到攔截器,還有一個詞大家應該知道——攔截器鏈(Interceptor Chain,在Struts 2中稱為攔截器棧Interceptor Stack)。攔截器鏈就是將攔截器按一定的順序聯結成一條鏈。在訪問被攔截的方法或字段時,攔截器鏈中的攔截器就會按其之前定義的順序被調用。
2.攔截器的原理
大部分時候,攔截器方法都是通過代理的方式來調用的。是基於反射實現的,Struts2的攔截器實現相對簡單。當請求到達Struts2的ServletDispatcher時,Struts2會查找配置文件,並根據配置實例化相對的攔截器對象,然后串成一個列表(List),最后一個一個的調用列表中的攔截器。Struts2的攔截器是可插拔的,攔截器是AOP的一個實現。Struts2攔截器棧就是將攔截器按一定的順序連接成一條鏈。在訪問被攔截的方法或者字段時,Struts2攔截器鏈中的攔截器就會按照之前定義的順序進行調用。
3.自定義攔截器的步驟
1)、創建我們自己的攔截器類並實現 HandlerInterceptor 接口。
2)、創建一個Java類繼承WebMvcConfigurerAdapter,並重寫 addInterceptors 方法。
3)、實例化我們自定義的攔截器,然后將對像手動添加到攔截器鏈中(在addInterceptors方法中添加)。
4.代碼示例
IndexInterceptor.java類代碼:
package com.example.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; public class IndexInterceptor implements HandlerInterceptor{ @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { System.out.println(">>>IndexInterceptor>>>>>>>在整個請求結束之后被調用,也就是在DispatcherServlet 渲染了對應的視圖之后執行(主要是用於進行資源清理工作)"); } @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { System.out.println(">>>IndexInterceptor>>>>>>>請求處理之后進行調用,但是在視圖被渲染之前(Controller方法調用之后)"); } @Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { System.out.println(">>>IndexInterceptor>>>>>>>在請求處理之前進行調用(Controller方法調用之前)"); // 只有返回true才會繼續向下執行,返回false取消當前請求 return true; } }
IndexInterceptor2.java類代碼:
package com.example.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; public class IndexInterceptor2 implements HandlerInterceptor{ @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { System.out.println(">>>IndexInterceptor2>>>>>>>在整個請求結束之后被調用,也就是在DispatcherServlet 渲染了對應的視圖之后執行(主要是用於進行資源清理工作)"); } @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { System.out.println(">>>IndexInterceptor2>>>>>>>請求處理之后進行調用,但是在視圖被渲染之前(Controller方法調用之后)"); } @Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { System.out.println(">>>IndexInterceptor2>>>>>>>在請求處理之前進行調用(Controller方法調用之前)"); // 只有返回true才會繼續向下執行,返回false取消當前請求 return false; } }
SimpleWebAppConfigurer.java類代碼:
package com.example.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import com.example.interceptor.IndexInterceptor; import com.example.interceptor.IndexInterceptor2; //只要能被springboot掃描到即可 @Configuration public class SimpleWebAppConfigurer extends WebMvcConfigurerAdapter{ @Override public void addInterceptors(InterceptorRegistry registry) { // 多個攔截器組成一個攔截器鏈 // addPathPatterns 用於添加攔截規則 // excludePathPatterns 用戶排除攔截 registry.addInterceptor(new IndexInterceptor()).addPathPatterns("/**"); registry.addInterceptor(new IndexInterceptor2()).addPathPatterns("/**"); super.addInterceptors(registry); } }
5.應用場景
1、日志記錄,可以記錄請求信息的日志,以便進行信息監控、信息統計等。
2、權限檢查:如登陸檢測,進入處理器檢測是否登陸,如果沒有直接返回到登陸頁面。
3、性能監控:典型的是慢日志
6.注意點
在一個工程中,可以配置多個攔截器,使用多個攔截器,則要注意的是 :多個攔截器使用的時候,prehandler是順序執行的,而posthandler和afterhandler是倒序執行的;
所以 :如果統一日志處理器攔截器,需要改攔截器prehandler一定要返回true,且將它放在攔截器配置的第一個位置;
如果登陸認證攔截器,放在攔截器的配置中的第一個位置(有日志處理的話,放在日志處理下面);
如果有權限校驗攔截器,則放在登陸攔截器之后,因為登陸通過后,才可以進行校驗權限;