Spring Boot之攔截器與過濾器(完整版)


作者:liuxiaopeng

鏈接:http://www.cnblogs.com/paddix

 

作者:藍精靈lx
原文:https://blog.csdn.net/liuxiao723846/article/details/80656492

參考以上兩位作者文章鏈接進行實驗整合,僅供學習交流

 

一、攔截器與過濾器

先理解一下AOP的概念,AOP不是一種具體的技術,而是一種編程思想。

在面向對象編程的過程中,我們很容易通過繼承、多態來解決縱向擴展。

但是對於橫向的功能,比如,在所有的service方法中開啟事務,或者統一記錄日志等功能,面向對象的是無法解決的。所以AOP——面向切面編程其實是面向對象編程思想的一個補充。而我們今天講的過濾器和攔截器都屬於面向切面編程的具體實現。

過濾器(Filter)與攔截器()主要區別包括以下幾個方面:

  • Filter是依賴於Servlet容器,屬於Servlet規范的一部分,而攔截器則是獨立存在的,可以在任何情況下使用。

  • Filter的執行由Servlet容器回調完成,而攔截器通常通過動態代理的方式來執行。

  • Filter的生命周期由Servlet容器管理,而攔截器則可以通過IoC容器來管理,因此可以通過注入等方式來獲取其他Bean的實例,使用更方便。

二、過濾器的實現

(1)自定義一個實現javax.servlet.Filter接口的過濾器類

package com.test.domain;

import javax.servlet.*;
import java.io.IOException;

public class LogCostFilter implements Filter {

  //servlet容器初始化時 @Override
public void init(FilterConfig filterConfig) throws ServletException {      }
  //servlet容器存在時 @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { long start = System.currentTimeMillis(); filterChain.doFilter(servletRequest,servletResponse); System.out.println("Execute cost="+(System.currentTimeMillis()-start)); }
  //servlet容器銷毀時 @Override
public void destroy() { } }

這段代碼的邏輯比較簡單,就是在方法執行前先記錄時間戳,然后通過過濾器鏈完成請求的執行,在返回結果之間計算執行的時間。這里需要主要,這個類必須繼承Filter類。

可以看出,Filter的生命周期由Servlet容器相關

 

 (2)在Spring boot中,我們需要FilterRegistrationBean來完成配置。其實現過程如下:

package com.test.config;
import com.test.domain.LogCostFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration
public class FilterConfig { @Bean public FilterRegistrationBean registration(){ FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); filterRegistrationBean.setFilter(new LogCostFilter());//實例化Filter類 filterRegistrationBean.addUrlPatterns("/*");//設置匹配模式,這里設置為所有,可以按需求設置為"/hello"等等 filterRegistrationBean.setName("LogCostFilter");//設置過濾器名稱 filterRegistrationBean.setOrder(1);//設置執行順序 return filterRegistrationBean; } }

 啟動服務器訪問任意URL皆可得到打印的時間戳

 

過濾器的另一種實現方法:可以在啟動類上使用 @ServletComponentScan("com.test.domian.FilterCostConfig")和實現了Filter接口的自定義類上使用注解 @WebFilter(urlPatterns = "/*",filterName = "LogCostFilter"),不過@WebFilter這個注解是Servlet3.0的規范,且並沒有指定執行的順序,其執行順序依賴於Filter的名稱,是根據Filter類名(注意不是配置的filter的名字)的字母順序倒序排列,並且@WebFilter指定的過濾器優先級都高於FilterRegistrationBean配置的過濾器。

 

三、攔截器的實現

使用攔截器來實現上面同樣的功能,記錄請求的執行時間。

(1)自定義一個實現HandlerInterceptor 接口的攔截器類:

package com.test.interceptor;

import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LogcostInterceptor implements HandlerInterceptor {
    long start = System.currentTimeMillis();
    //preHandle是在請求執行前執行的
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        start = System.currentTimeMillis();
        return true;
        //返回true,postHandler和afterCompletion方法才能執行
        // 否則false為拒絕執行,起到攔截器控制作用
    }

    //postHandler是在請求結束之后,視圖渲染之前執行的,但只有preHandle方法返回true的時候才會執行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        System.out.println("Interception cost="+(System.currentTimeMillis()-start));
    }

    //afterCompletion是視圖渲染完成之后才執行,同樣需要preHandle返回true,
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        //該方法通常用於清理資源等工作
    }
}

這里我們需要自定義一個類來實現HandlerInterceptor這個接口,實現里面的三個方法,具體說明已寫在方法注釋中

 

(2)攔截器類的配置:

package com.test.config;

import com.test.interceptor.LogcostInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
    /**
     * 靜態資源配置
     */
    /*@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/img/**")
                .addResourceLocations("classpath:/imgs/");

        super.addResourceHandlers(registry);
    }*/

    /**
     * 默認首頁配置
     */
//    @Override
//    public void addViewControllers(ViewControllerRegistry registry) {
//        registry.addViewController("/").setViewName("forward:/index");
//        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
//        super.addViewControllers(registry);
//    }

    /**
     * interceptor配置
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogcostInterceptor())
                //添加需要驗證登錄用戶操作權限的請求
                .addPathPatterns("/**")
                //這里add為“/**”,下面的exclude才起作用,且不管controller層是否有匹配客戶端請求,攔截器都起作用攔截
//                .addPathPatterns("/hello")
                //如果add為具體的匹配如“/hello”,下面的exclude不起作用,且controller層不匹配客戶端請求時攔截器不起作用

                //排除不需要驗證登錄用戶操作權限的請求
                .excludePathPatterns("/wang")
                .excludePathPatterns("/css/**")
                .excludePathPatterns("/js/**")
                .excludePathPatterns("/images/**");
        //這里可以用registry.addInterceptor添加多個攔截器實例,后面加上匹配模式
        super.addInterceptors(registry);//最后將register往這里塞進去就可以了
    }
}

這里我們重寫了addInterceptors這個方法,進行攔截器的配置,主要配置項就兩個,一個是指定攔截器(定義方法行為),第二個是指定攔截的URL(模式匹配)。

注釋部分的靜態資源配置和默認首頁配置本人還未做實驗,應該沒問題的

再啟動系統訪問任意一個URL即可得到打印的時間戳

 

現在我們權限和認證更多的是在Spring Boot中整合使用shiro或者Spring Security來完成,比較少用自定義攔截器了,不過可以用攔截器實現其他功能,比如ip黑名單等等特殊場景


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM