攔截器(Interceptor)與過濾器(Filter)

程式設計師巨輪發表於2021-05-18

目錄

 

一、使用者的普通Http請求執行順序

二、過濾器、攔截器新增後的執行順序

三、攔截器(Interceptor)的基本定義

  攔截器是面向切面(AOP)程式設計中應用的一種統一處理方案,就是在你的Controller、Servie或者一個Method呼叫一個Method,或者在Method呼叫一個Method之後,統一的進行處理的方案,基於Java的反射機制。

  攔截器,在AOP(Aspect-Oriented Programming)中可以用於在某個方法或者欄位被訪問之前,進行攔截,然後在之前或者之後加入某些統一的處理方法。攔截是AOP的一種具象的實現方式。

  攔截器將很多service或者Controller中共有的行為提煉出來,在某些方法執行的前後執行,提煉為通用的處理方式,讓被攔截的方法都能享受這一共有的功能,讓程式碼更加簡潔,同時,當共有的功能需要發生調整、變動的時候,不必修改很多的類或者方法,只要修改這個攔截器就可以了,可複用性很強。

  Spring MVC 中的Interceptor攔截請求是通過HandlerInterceptor來實現的。

四、攔截器(Interceptor)必須實現的三個方法

  1)總覽

  2)preHandle(HttpServletRequest request, HttpServletResponse response, Object handle)方法

    該方法將在請求處理之前進行呼叫。SpringMVC 中的Interceptor 是鏈式的呼叫的,在一個應用中或者說是在一個請求中可以同時存在多個Interceptor 。每個Interceptor 的呼叫會依據它的宣告順序依次執行,而且最先執行的都是Interceptor 中的preHandle 方法,所以可以在這個方法中進行一些前置初始化操作或者是對當前請求的一個預處理,也可以在這個方法中進行一些判斷來決定請求是否要繼續進行下去。該方法的返回值是布林值Boolean型別的,當它返回為false 時,表示請求結束,後續的Interceptor 和Controller 都不會再執行;當返回值為true 時就會繼續呼叫下一個Interceptor 的preHandle 方法,如果已經是最後一個Interceptor 的時候就會是呼叫當前請求的Controller 方法。

  3)  postHandle (HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView) 方法  【前提:在當前所屬的Interceptor 的preHandle 方法的返回值為true 時才能被呼叫】

    在當前請求進行處理之後,也就是Controller 方法呼叫之後執行,但是它會在DispatcherServlet 進行檢視返回渲染之前被呼叫,所以我們可以在這個方法中對Controller 處理之後的ModelAndView 物件進行操作。postHandle 方法被呼叫的方向跟preHandle 是相反的,也就是說先宣告的Interceptor 的postHandle 方法反而會後執行,這和Struts2 裡面的Interceptor 的執行過程有點型別。Struts2 裡面的Interceptor 的執行過程也是鏈式的,只是在Struts2 裡面需要手動呼叫ActionInvocation 的invoke 方法來觸發對下一個Interceptor 或者是Action 的呼叫,然後每一個Interceptor 中在invoke 方法呼叫之前的內容都是按照宣告順序執行的,而invoke 方法之後的內容就是反向的。  

  4)afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)方法  【前提:在當前所屬的Interceptor 的preHandle 方法的返回值為true 時才能被呼叫】

    該方法將在整個請求結束之後,也就是在DispatcherServlet 渲染了對應的檢視之後執行。這個方法的主要作用是用於進行資源清理工作的。  

五、單個攔截器(Interceptor)的Demo實現

  1)初始化攔截器

@Component
public class UserAccessInterceptor implements HandlerInterceptor {

    private final Logger logger = LoggerFactory.getLogger(UserAccessInterceptor.class);

    @Resource
    private UserService userService;
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { //1.獲取headers裡的author-Cookie
     //2.根據cookie使用userService查詢當前user
     //3.存在且啟用 當前使用者資訊設定到ThreadLocal return true;
     //4.不存在 或 未啟用 return false; } @Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
     } @Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { //銷燬ThreadLocal的使用者資訊
}

  2)攔截器配置類

@Configuration
public class WebInterceptorConfig extends WebMvcConfigurationSupport {

    @Autowired
    private UserAccessInterceptor userAccessInterceptor;

  //不攔截的URL集合
private static List<String> exclusionUrlList=new ArrayList<>(); static { exclusionUrlList.add("/favicon.ico"); exclusionUrlList.add("/**/*.css"); exclusionUrlList.add("/**/*.js"); exclusionUrlList.add("/ok"); exclusionUrlList.add("/"); exclusionUrlList.add("/console/**"); exclusionUrlList.add("/index"); } @Override protected void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(this.userAccessInterceptor) .addPathPatterns("/**") .excludePathPatterns(exclusionUrlList); super.addInterceptors(registry); } }

六、攔截器(Interceptor)的兩種配置方式

  1)同上 -> Demo實現

  2)Spring MVC使用mvc:interceptors標籤

<mvc:interceptors>  
<!-- 使用bean定義一個Interceptor,直接定義在mvc:interceptors根下面的Interceptor將攔截所有的請求 -->  
<bean class="com.baidu.interceptor.UserAccessInterceptor"/>  
    <mvc:interceptor>  
         <mvc:mapping path="/**"/>  
         <mvc:exclude-mapping path="/parent/**"/>  
         <bean class="com.baidu.interceptor.UserAccessInterceptor" />  
    </mvc:interceptor>  
</mvc:interceptors>

七、過濾器(Filter)的基本定義

  Filter可以認為是Servlet的一種“加強版”,它主要用於對使用者請求進行預處理,也可以對HttpServletResponse進行後處理,是個典型的處理鏈。Filter也可以對使用者請求生成響應,這一點與Servlet相同,但實際上很少會使用Filter向使用者請求生成響應。使用Filter完整的流程是:Filter對使用者請求進行預處理,接著將請求交給Servlet進行處理並生成響應,最後Filter再對伺服器響應進行後處理。

  在Web中稱之為Filter,通過配置多個過濾器,Web系統可以對所有的Servlet請求進行一層一層的過濾,以完成一些特殊的功能。例如常用的資源訪問許可權控制、特殊字元以及敏感詞過濾、響應資訊壓縮等功能。

  Servlet中的過濾器Filter是實現了javax.servlet.Filter介面的伺服器端程式,主要的用途是設定字符集、控制許可權、控制轉向、做一些業務邏輯判斷等。其工作原理是,只要你在web.xml檔案配置好要攔截的客戶端請求,它都會幫你攔截到請求,此時你就可以對請求或響應(Request、Response)統一設定編碼,簡化操作;同時還可進行邏輯判斷,如使用者是否已經登陸、有沒有許可權訪問該頁面等等工作。它是隨你的web應用啟動而啟動的,只初始化一次,以後就可以攔截相關請求,只有當你的web應用停止或重新部署的時候才銷燬。

八、過濾器(Filter)必須實現的三個方法

  1)總覽

  2)default void init(FilterConfig filterConfig) throws ServletException {}

    用於完成Filter的初始化。    

  3)void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;

    實現過濾功能,該方法就是對每個請求及響應增加的額外處理。該方法可以實現對使用者請求進行預處理(ServletRequest request),也可實現對伺服器響應進行後處理(ServletResponse response)—它們的分界線為是否呼叫了chain.doFilter(),執行該方法之前,即對使用者請求進行預處理;執行該方法之後,即對伺服器響應進行後處理。

  4)  default void destroy() {}

    用於Filter銷燬前,完成某些資源的回收。

九、單個過濾器(Filter)的Demo實現

  1)TestFilter初始化

public class TestFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
 
    }
 
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("我是Filter,執行filterChain.doFilter(request,response)之前。");
        filterChain.doFilter(request,response);
        System.out.println("我是Filter,執行filterChain.doFilter(request,response)之後。");
    }
 
    @Override
    public void destroy() {
 
    }

  2)Filter配置類

@Slf4j
@Configuration
public class TestFilterConfiguration {//不攔截路徑
    private static List<String> exclusionUrlList=new ArrayList<>();
    //攔截路徑
    private static List<String> inclusionUrlList=new ArrayList<>();

    static {
        exclusionUrlList.add("/favicon.ico");
        exclusionUrlList.add("/**/*.css");
        exclusionUrlList.add("/**/*.js");
        exclusionUrlList.add("/ok");
        inclusionUrlList.add("/api/**");
    }

    @Bean
    public FilterRegistrationBean filterRegistration() {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new TestFilter());
        registration.addInitParameter(FILTER_INIT_PARAM_EXCLUSION_URLS,String.join(",", exclusionUrlList));
        registration.addInitParameter(AJAX_URL_PATTERNS,String.join(",", inclusionUrlList));
        registration.addUrlPatterns("/*");
        registration.setName("testFilter");
     return registration;
    }

}

十、過濾器(Filter)的三種配置方式

  1)通過@WebFilter註解配置

1.初始化Filter

@WebFilter(urlPatterns = "/test001") @Order(1) //order值越小,過濾器越靠前,此處配置無效 public class TestFilter implements Filter { @Override public void init(javax.servlet.FilterConfig filterConfig) throws ServletException { System.out.println("##############TestFilter init##############"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //在DispatcherServlet之前執行 System.out.println("##############doFilter before##############"); filterChain.doFilter(servletRequest, servletResponse); // 在檢視頁面返回給客戶端之前執行,但是執行順序在Interceptor之後 System.out.println("##############doFilter after##############"); } @Override public void destroy() { System.out.println("##############TestFilter destroy##############"); } }

//2.在啟動類新增 @ServletComponentScan

@SpringBootApplication
@ServletComponentScan
public class TestbootApplication {
  public static void main(String[] args) {
    SpringApplication.run(TestbootApplication.class, args);
  }
}

  2)通過@Bean來配置

//1.初始化Filter

@Component
public class TestFilter3 implements Filter{ @Override public void init(javax.servlet.FilterConfig filterConfig) throws ServletException { System.out.println("##############Filter3 init##############"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //在DispatcherServlet之前執行 System.out.println("##############doFilter3 before##############"); filterChain.doFilter(servletRequest, servletResponse); // 在檢視頁面返回給客戶端之前執行,但是執行順序在Interceptor之後 System.out.println("##############doFilter3 after##############"); } @Override public void destroy() { System.out.println("##############Filter3 destroy##############"); } }

//2.註冊到config

@Configuration
public class FilterConfig { @Bean public FilterRegistrationBean testFilter3RegistrationBean() { FilterRegistrationBean registration = new FilterRegistrationBean(new TestFilter3()); registration.addUrlPatterns("/hello"); registration.setOrder(1); // 值越小越靠前,此處配置有效 return registration; } @Bean public FilterRegistrationBean testFilter4RegistrationBean() { FilterRegistrationBean registration = new FilterRegistrationBean(new TestFilter4()); registration.addUrlPatterns("/hello"); registration.setOrder(2); return registration; } }

  3)Spring MVC在web.xml進行配置

    1.初始化Filter

    2.web.xml檔案中配置Filter

<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

十一、攔截器和過濾器的區別

十二、攔截器和過濾器的作用/用途

  過濾器用途:用於設定字元編碼、URL級別的許可權控制,敏感詞彙的過濾

  攔截器用途:攔截未登入的使用者,攔截器和過濾器的功能相近

十三、總結

  1.過濾器:所謂過濾器顧名思義是用來過濾的,在java web中,你傳入的request,response提前過濾掉一些資訊,或者提前設定一些引數,然後再傳入servlet或者struts的action進行業務邏輯,比如過濾掉非法url(不是login.do的地址請求,如果使用者沒有登陸都過濾掉),或者在傳入servlet或者struts的action前統一設定字符集,或者去除掉一些非法字元(聊天室經常用到的,一些罵人的話)。filter 流程是線性的, url傳來之後,檢查之後,可保持原來的流程繼續向下執行,被下一個filter, servlet接收等.

  2.java的攔截器 主要是用在外掛上,擴充套件件上比如 hibernate spring struts2等 有點類似面向切片的技術,在用之前先要在配置檔案即xml檔案裡宣告一段的那個東西。

十四、參考文獻

  1. https://www.cnblogs.com/panxuejun/p/7715917.html《過濾器(Filter)和攔截器(Interceptor)的執行順序和區別》
  2. https://www.cnblogs.com/junzi2099/p/8022058.html《過濾器(Filter)與攔截器(Interceptor )區別》
  3. https://blog.csdn.net/qq_34908167/article/details/80624507《過濾器和攔截器的區別和執行順序》
  4. https://www.cnblogs.com/feibazhf/p/11265145.html《過濾器、攔截器和監聽器區別》

    

相關文章