1. 程式人生 > 實用技巧 >過濾器和攔截器

過濾器和攔截器

過濾器 MyFilter.java

@Component
public class MyFilter implements Filter {

    public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {
        System.out.println("filter init");
    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws
IOException, ServletException { System.out.println("filter before"); filterChain.doFilter(servletRequest, servletResponse); System.out.println("filter after"); } public void destroy() { System.out.println("filter destroy"); } }

攔截器 MyInterceptor.java

@Component
public class MyInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("interceptor preHandle"); return true; } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws
Exception { System.out.println("interceptor postHandle"); } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("interceptor afterCompletion"); } }

攔截器註冊 WebMvcConfig.java

@Component
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private MyInterceptor interceptor;

    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(interceptor)
                .addPathPatterns("/run");
    }
}

App.java

@RestController
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class);
    }

    @RequestMapping(value = "/run")
    public String run() {
        System.out.println("business code running...");
        return "OK";
    }
}

執行結果

[伺服器啟動]
...
filter init
...
[請求api]
filter before
interceptor preHandle
business code running...
interceptor postHandle
interceptor afterCompletion
filter after

過濾器(Filter)

是JavaEE的標準,依賴於Servlet容器。隨web應用啟動而啟動的,只初始化一次,以後就可以攔截相關請求,只有當web應用停止或重新部署的時候才銷燬。

用途
設定字符集、控制權限、控制轉向、做一些業務邏輯判斷等。

切入點
對使用者請求進行預處理,對響應進行後處理,是個典型的處理鏈:
在HttpServletRequest到達Servlet之前,攔截客戶的HttpServletRequest:
根據需要檢查HttpServletRequest,也可以修改HttpServletRequest頭和資料。
在HttpServletResponse到達客戶端之前,攔截HttpServletResponse:
根據需要檢查HttpServletResponse,也可以修改HttpServletResponse頭和資料。

種類
使用者授權的Filter:Filter負責檢查使用者請求,根據請求過濾使用者非法請求;
日誌Filter:詳細記錄某些特殊的使用者請求;
負責解碼的Filter:包括對非標準編碼的請求解碼;
能改變XML內容的XSLTFilter等。

主要介面
init(FilterConfig config):
用於完成Filter的初始化。
destory():
用於Filter銷燬前,完成某些資源的回收。
doFilter(ServletRequest request,ServletResponse response,FilterChain chain):
實現過濾功能,該方法就是對每個請求及響應增加的額外處理。該方法可以實現對使用者請求進行預處理(ServletRequest request),也可實現對伺服器響應進行後處理(ServletResponse response)—它們的分界線為是否呼叫了chain.doFilter(),執行該方法之前,即對使用者請求進行預處理;執行該方法之後,即對伺服器響應進行後處理。


攔截器(Interceptor)

不依賴Servlet容器,依賴Spring等Web框架,是AOP的一種應用,底層採用Java的反射機制來實現的。與過濾器一個很大的區別是在攔截器中可以注入Spring的Bean,能夠獲取到各種需要的Service來處理業務邏輯,而過濾器則不行。

主要介面
preHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandle):
在handler執行之前,返回boolean值,true表示繼續執行,false為停止執行並返回。SpringMVC中的Interceptor是鏈式的呼叫的,在一個應用中或者說是在一個請求中可以同時存在多個Interceptor。每個Interceptor的呼叫會依據它的宣告順序依次執行,而且最先執行的都是Interceptor中的preHandle方法,所以可以在這個方法中進行一些前置初始化操作或者是對當前請求的一個預處理,也可以在這個方法中進行一些判斷來決定請求是否要繼續進行下去。該方法的返回值是布林值Boolean型別的,當它返回為false時,表示請求結束,後續的Interceptor和Controller都不會再執行;當返回值為true時就會繼續呼叫下一個Interceptor的preHandle方法,如果已經是最後一個Interceptor的時候就會是呼叫當前請求的Controller方法。
postHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandle,ModelAndViewmodelAndView):
在handler執行之後,可以在返回之前對返回的結果進行修改。該方法(/afterCompletion方法)都只能是在當前所屬的Interceptor的preHandle方法的返回值為true時才能被呼叫。postHandle方法在Controller方法呼叫之後執行,但是它會在DispatcherServlet進行檢視返回渲染之前被呼叫,所以可以在這個方法中對Controller處理之後的ModelAndView物件進行操作。postHandle方法被呼叫的方向跟preHandle是相反的,也就是說先宣告的Interceptor的postHandle方法反而會後執行。
afterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandle,Exceptionex):
在請求完全結束後呼叫,可以用來統計請求耗時等等。
方法,該方法也是需要當前對應的Interceptor的preHandle方法的返回值為true時才會執行。該方法將在整個請求結束之後,也就是在DispatcherServlet渲染了對應的檢視之後執行。這個方法的主要作用是用於進行資源清理工作的。

執行順序
request -> DispatcherServlet -> Interceptor -> preHandle -> Controller -> postHandle -> response