1. 程式人生 > 其它 >Springboot筆記<7>過濾器與攔截器

Springboot筆記<7>過濾器與攔截器

過濾器 攔截器

過濾器

過濾器攔截的是URL

Spring中自定義過濾器(Filter)一般只有一個方法,返回值是void,當請求到達web容器時,會探測當前請求地址是否配置有過濾器,有則呼叫該過濾器的方法(可能會有多個過濾器),然後才呼叫真實的業務邏輯,至此過濾器任務完成。過濾器並沒有定義業務邏輯執行前、後等,僅僅是請求到達就執行。

特別注意:過濾器方法的入參有request,response,FilterChain,其中FilterChain是過濾器鏈,使用比較簡單,而request,response則關聯到請求流程,因此可以對請求引數做過濾和修改,同時FilterChain過濾鏈執行完,並且完成業務流程後,會返回到過濾器,此時也可以對請求的返回資料做處理。

兩種方法使用過濾器,注入bean到ioc容器或者使用@WebServlet註解。

「注意」:@WebFilter這個註解是Servlet3.0的規範,並不是Spring boot提供的。除了這個註解以外,我們還需在配置類中加另外一個註解:@ServletComponetScan,指定掃描的包。定義過濾器類:HelloFilter,在過濾器類上新增@WebFilter註解配置過濾器名稱、過濾路徑等屬性,通過@Order配置過濾器執行順序。注意使用@WebServlet、@WebFilter、@WebListener等servlet註解時需要在springboot的啟動類上新增@ServletComponentScan

註解,否則不會生效。@Order值越小優先順序越高。

//第一種,註冊bean
@Order(value = 2)
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        System.out.println("myFilter提示:服務啟動..........");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("myFilter提示:呼叫過濾器Filter的doFilter()方法..........");
        System.out.println("ip地址為"+servletRequest.getRemoteAddr());
        //放行通過
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

        System.out.println("myFilter提示:服務關閉..........");
    }
}




@Configuration
public class MyFilterConfig {
    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        MyFilter filter = new MyFilter();
        registrationBean.setFilter(filter);
        //設定過濾器攔截請求
        List<String> urls = new ArrayList<>();
        urls.add("/*");
        registrationBean.setUrlPatterns(urls);
        return registrationBean;
    }
}
//第二種,基於註解
@WebFilter(urlPatterns="/*", filterName = "myFilterByAnnotation")
@Order(value = 3)
public class MyFilterByAnnotation implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("myFilterByAnnotation提示:服務啟動..........");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("myFilterByAnnotation提示:呼叫過濾器Filter的doFilter()方法..........");
        System.out.println("ip地址為"+servletRequest.getRemoteAddr());
        //放行通過
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

        System.out.println("myFilterByAnnotation提示:服務關閉..........");
    }
}

@SpringBootApplication
@ServletComponentScan
@Import({Teacher.class})
public class SpringbootReviewApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(SpringbootReviewApplication.class, args);
    }

}

//myFilter提示:呼叫過濾器Filter的doFilter()方法..........
//myFilterByAnnotation提示:呼叫過濾器Filter的doFilter()方法..........

攔截器

攔截器攔截的是URL,攔截器有三個方法,相對於過濾器更加細緻,有被攔截邏輯執行前、後等。Spring中攔截器有三個方法:preHandle,postHandle,afterCompletion。分別表示如下:

  • public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o)表示被攔截的URL對應的方法執行前的自定義處理
  • public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView)表示此時還未將modelAndView進行渲染,被攔截的URL對應的方法執行後的自定義處理
  • public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e)表示此時modelAndView已被渲染,執行攔截器的自定義處理

攔截器的應用場景

1、日誌記錄:記錄請求資訊的日誌,以便進行資訊監控、資訊統計、計算PV(Page VIEW)等。
2、許可權檢查:如登入檢測,進入處理器檢測檢測是否登入,如果沒有直接返回到登入頁面;
3、效能監控:有時候系統在某段時間莫名其妙的慢,可以通過攔截器在進入處理器之前記錄開始時間,在處理完後記錄結束時間,從而得到該請求的處理時間(如果有反向代理,如apache可以自動記錄);
4、通用行為:讀取cookie得到使用者資訊並將使用者物件放入請求,從而方便後續流程使用,還有如提取Locale、Theme資訊等,只要是多個處理器都需要的即可使用攔截器實現。

攔截器使用方法

1.在任務類增加註解 @Configuration 註冊bean,繼承 WebMvcConfigurerAdapter 代表配置攔截器的介面卡

2.重寫 addInterceptors 新增需要的攔截器地址及需要排除的攔截地址

SpringMVC 攔截器攔截 /* 和 /** 的區別:

  • /* : 匹配一級,即 /add , /query 等
  • /** : 匹配多級,即 /add , /add/user, /add/user/user… 等
@Slf4j
public class MyInterceptor implements HandlerInterceptor {

    long start;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        start = System.currentTimeMillis();
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("Interceptor cost="+(System.currentTimeMillis()-start));
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}


/**
 * 1、編寫一個攔截器實現HandlerInterceptor介面
 * 2、攔截器註冊到容器中(實現WebMvcConfigurer的addInterceptors)
 * 3、指定攔截規則【如果是攔截所有,靜態資源也會被攔截】
 */
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**")  //所有請求都被攔截包括靜態資源
                .excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**"); //放行的請求
    }
}

攔截器原理

1、根據當前請求,找到HandlerExecutionChain【可以處理請求的handler以及handler的所有 攔截器】

2、先來順序執行 所有攔截器的 preHandle方法

  • 1、如果當前攔截器prehandler返回為true。則執行下一個攔截器的preHandle
  • 2、如果當前攔截器返回為false。直接 倒序執行所有已經執行了的攔截器的 afterCompletion;

3、如果任何一個攔截器返回false。直接跳出不執行目標方法

4、所有攔截器都返回True。執行目標方法

5、倒序執行所有攔截器的postHandle方法。

6、前面的步驟有任何異常都會直接倒序觸發 afterCompletion

7、頁面成功渲染完成以後,也會倒序觸發 afterCompletion

攔截器與過濾器的區別

1、攔截器是基於Java的反射機制的,而過濾器是基於函式回撥。
2、攔截器不依賴與servlet容器,過濾器依賴與servlet容器。
3、攔截器只能對ACTION請求起作用,而過濾器則可以對幾乎所有的請求起作用。
4、攔截器可以訪問ACTION上下文、值棧裡的物件,而過濾器不能訪問。
5、在ACTION的生命週期中,攔截器可以多次被呼叫,而過濾器只能在容器初始化時被呼叫一次。
6、攔截器可以獲取IOC容器中的各個bean,而過濾器就不行,這點很重要,在攔截器裡注入一個service,可以呼叫業務邏輯。過濾器 攔截器 AOP區別

AOP(面向切面)面向切面攔截的是類的元資料(包、類、方法名、引數等)相對於攔截器更加細緻,而且非常靈活,攔截器只能針對URL做攔截,而AOP針對具體的程式碼,能夠實現更加複雜的業務邏輯。三者功能類似,但各有優勢,從過濾器--》攔截器--》切面,攔截規則越來越細緻,執行順序依次是過濾器、攔截器、切面。一般情況下資料被過濾的時機越早對服務的效能影響越小,因此我們在編寫相對比較公用的程式碼時,優先考慮過濾器,然後是攔截器,最後是aop。比如許可權校驗,一般情況下,所有的請求都需要做登陸校驗,此時就應該使用過濾器在最頂層做校驗;日誌記錄,一般日誌只會針對部分邏輯做日誌記錄,而且牽扯到業務邏輯完成前後的日誌記錄,因此使用過濾器不能細緻地劃分模組,此時應該考慮攔截器,然而攔截器也是依據URL做規則匹配,因此相對來說不夠細緻,因此我們會考慮到使用AOP實現,AOP可以針對程式碼的方法級別做攔截,很適合日誌功能。

未經作者同意請勿轉載

本文來自部落格園作者:aixueforever,原文連結:https://www.cnblogs.com/aslanvon/p/15715197.html