1. 程式人生 > >Filter和Interceptor

Filter和Interceptor

1. Filter(過濾器)和 Interceptor(攔截器)的區別

  • 規範不同:FilterServlet規範規定的,依賴於Servlet容器;InterceptorSpring規定的,依賴於Spring框架。
  • 實現原理不同:Filter基於函式回撥;Interceptor基於java反射。
  • 使用範圍不同:Filter依賴於Servlet容器,只能用於Web程式;Interceptor既可用於Web程式,也可以用於ApplicationSwing等程式中。
  • 使用的資源不同:InterceptorSpring的一個元件,歸Spring管理,配置在Spring檔案中,可以使用Spring
    裡的任何資源和物件,例如Service物件、資料來源、事務管理等,通過IoC注入到Interceptor既可;Filter則不能。
  • 深度不同:Filter只在Servlet前後起作用,Interceptor能夠深入到方法前後,異常丟擲前後等。在Spring中應該優先使用Interceptor

2. 多個過濾器與多個攔截器的程式碼執行順序

如果一個專案中同時有多個Filter,並且有多個Interceptor,那麼它們的呼叫順序是什麼樣的呢?

Filter1.java

package com.tao.springstarter.web.filter;

import org.springframework.
web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class Filter1 extends OncePerRequestFilter { @Override protected
void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 在DispatcherServlet之前執行 System.out.println("進入 Filter1 doFilterInternal()"); // 呼叫下一個filter filterChain.doFilter(request, response); // 在試圖頁面返回給客戶端之前執行 System.out.println("退出 Filter1 doFilterInternal()"); } }

Filter2.java

package com.tao.springstarter.web.filter;

import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class Filter2 extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 在DispatcherServlet之前執行
        System.out.println("進入 Filter2 doFilterInternal()");
        // 呼叫下一個filter
        filterChain.doFilter(request, response);
        // 在試圖頁面返回給客戶端之前執行
        System.out.println("退出 Filter2 doFilterInternal()");
    }
}

web.xml中配置Filter1Filter2

	<!-- 註冊Filter -->
    <filter>
        <filter-name>Filter1</filter-name>
        <filter-class>com.tao.springstarter.web.filter.Filter1</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Filter1</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>Filter2</filter-name>
        <filter-class>com.tao.springstarter.web.filter.Filter2</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Filter2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

Interceptor1.java

package com.tao.springstarter.web.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Interceptor1 implements HandlerInterceptor {

    /**
     * 在DispatcherServlet之前執行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("執行 Interceptor1 preHandle()");
        return true;
    }

    /**
     * 在Controller執行之後執行
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("執行 Interceptor1 postHandle()");
    }

    /**
     * 在頁面渲染完成返回給客戶端之前執行
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("執行 Interceptor1 afterCompletion()");
    }
}

Interceptor2.java

package com.tao.springstarter.web.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Interceptor2 implements HandlerInterceptor {
    /**
     * 在DispatcherServlet之前執行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("執行 Interceptor2 preHandle()");
        return true;
    }

    /**
     * 在Controller執行之後執行
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("執行 Interceptor2 postHandle()");
    }

    /**
     * 在頁面渲染完成返回給客戶端之前執行
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("執行 Interceptor2 afterCompletion()");
    }
}

spring-servlet.xml中配置Interceptor1Interceptor2

	<mvc:interceptors>
        <!-- 公共攔截器Interceptor1, 對所有請求都攔截 -->
        <bean name="interceptor1" class="com.tao.springstarter.web.interceptor.Interceptor1"/>
        <!-- 特定攔截器Interceptor2 -->
        <mvc:interceptor>
            <!-- 對/test進行攔截 -->
            <mvc:mapping path="/test"/>
            <!-- 特定請求的攔截器只能有一個 -->
            <bean name="interceptor2" class="com.tao.springstarter.web.interceptor.Interceptor2"/>
        </mvc:interceptor>
    </mvc:interceptors>

測試用的TestController:

package com.tao.springstarter.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class TestController {

    @RequestMapping("/test")
    @ResponseBody
    public String filterAndInterceptor1() {
        System.out.println("呼叫 TestController#filterAndInterceptor1()");
        return "filterAndInterceptor1";
    }

    @RequestMapping("/haha")
    @ResponseBody
    public String filterAndInterceptor2() {
        System.out.println("呼叫 TestController#filterAndInterceptor2()");
        return "filterAndInterceptor2";
    }
}

請求http://localhost:8080/ss/test
在這裡插入圖片描述

請求http://localhost:8080/ss/haha
在這裡插入圖片描述
可以看到此時Interceptor2沒有起作用。

其最終的執行流程就如下圖所示:
在這裡插入圖片描述