日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

SpringMVC中过滤器和拦截器的区别

發布時間:2025/3/19 javascript 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringMVC中过滤器和拦截器的区别 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

        • 1、引言
        • 2、共同點
        • 3、區別
          • 3.1、攔截器
          • 3.2、過濾器
        • 4、具體實現
          • 4.1、攔截器
            • 4.1.1、攔截實現方式
            • 4.1.2、攔截實現
          • 4.2、過濾器
            • 4.2.1、過濾器實現方式
            • 4.2.2、過濾器實現
        • 5、過濾器中依賴注入(深坑)
          • 5.1、問題描述
          • 5.2、Filter依賴注入實現
            • 5.2.1、方法一:web.xml配置實現
            • 5.2.2、方法二:繼承WebApplicationInitializer,并注冊Filter
            • 5.2.3、方法三:實現ApplicationContextAware接口的工具
            • 5.2.4、方法四:獲取WebApplicationContext對象
        • 5、攔截器執行順序

1、引言

我們在開發過程中都會遇到需要統一處理接口或者參數的場景,這個時候我們就會用到過濾器(Filter)或者攔截器(Intercepter)。
測試代碼參考 chapter-2-springmvc-quickstart:
https://gitee.com/leo825/spring-framework-learning-example.git

2、共同點

1、都可以攔截請求和過濾請求
2、都用了責任鏈設計模式,并且都可以對請求進行預處理和后處理

3、區別

3.1、攔截器
  • 依賴于web框架實現,在我們使用的SpringMVC這種就是依賴于SpringMVC框架
  • 在實現上基于Java的反射機制,屬于面向切面(AOP)的一種應用
  • 可以在一個Controller生命周期內進行多次調用,但是只能對Controller進行攔截
  • 主要作用:由于攔截器是基于web框架的調用,因此可以使用Spring的依賴注入(DI)進行一些業務操作,并且一個攔截器可以在Controller生命周期內進行多次調用。
3.2、過濾器
  • 過濾器依賴于Servlet容器
  • 過濾器實現上基于函數回調,可以幾乎對所有請求進行過濾(包括靜態資源過濾)
  • 過濾器實例只能在容器初始化的時候調用一次
  • 主要作用:執行過濾操作,比如敏感信息、特殊請求、xss方漏洞、統一加解密參數等

4、具體實現

4.1、攔截器
4.1.1、攔截實現方式

SpringMVC攔截器(Interceptor)實現對每一個請求處理前后進行相關業務是通過HandlerInterceptor來實現的。定義一個攔截器,可以通過以下3種方式:

  • 實現Spring提供的的HandlerInterceptor接口;
  • 繼承Spring中的抽象類HandlerInterceptorAdapter,此抽象類實現了HandlerInterceptor接口;
  • 實現Spring提供的WebRequestInterceptor接口;
  • 4.1.2、攔截實現

    具體實現舉一個例子,測試代碼如下:

    package com.leo.interceptor;import com.leo.service.UserInfoService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.util.List;/*** @ClassName: HandlerInterceptor2* @Description: 測試攔截器2* 簡單說明一下:本工程是采用xml方式注冊的攔截器,因此可以直接依賴注入,* 如果是SpringBoot方式注冊攔截器,不要使用new的方式創建攔截器對象,* 要把攔截器通過@Autowired注入進來,然后注冊到Spring容器中,* 不然這個攔截器中通過依賴注入到的userInfoService永遠是null* @Author: leo825* @Date: 2020-02-03 16:05* @Version: 1.0*/ public class HandlerInterceptor2 extends HandlerInterceptorAdapter {@AutowiredUserInfoService userInfoService;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("HandlerInterceptor2 preHandle");HttpSession session = request.getSession();session.setAttribute("startTime",System.currentTimeMillis());return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("HandlerInterceptor2 postHandle");//訪問數據庫List userInfoList = userInfoService.getUserInfoList();System.out.print("HandlerInterceptor2 信息: ");System.out.println(userInfoList);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("HandlerInterceptor2 afterCompletion");HttpSession session = request.getSession();long startTime = (long)session.getAttribute("startTime");System.out.println("HandlerInterceptor2 過濾的接口耗時:" + (System.currentTimeMillis() - startTime) + "ms");} }

    spring配置文件要添加相應的配置,如下所示:

    <mvc:interceptor><!-- /* 是一級目錄下的路徑; /** 不分目錄等級, 即所有請求 --><mvc:mapping path="/test2/**"/><bean class="com.leo.interceptor.HandlerInterceptor2"></bean></mvc:interceptor>

    訪問地址:http://localhost:8080/springmvc/test2/hello,運行結果如下所示:

    HandlerInterceptor1 preHandle HandlerInterceptor2 preHandle HandlerInterceptor3 preHandle HandlerInterceptor4 preHandle HandlerInterceptor5 preHandle 使用配置實現 hello controller 跳轉到 success HandlerInterceptor5 postHandle HandlerInterceptor4 postHandle HandlerInterceptor3 postHandle HandlerInterceptor2 postHandle HandlerInterceptor2 信息: [UserInfo{id=3, name='曉玲', gender='女', age='22', remarks='工程師'}, UserInfo{id=4, name='曉玲', gender='女', age='24', remarks='工程師'}] HandlerInterceptor1 postHandle HandlerInterceptor5 afterCompletion HandlerInterceptor5 過濾的接口耗時:330ms HandlerInterceptor4 afterCompletion HandlerInterceptor4 過濾的接口耗時:330ms HandlerInterceptor3 afterCompletion HandlerInterceptor3 過濾的接口耗時:330ms HandlerInterceptor2 afterCompletion HandlerInterceptor2 過濾的接口耗時:330ms HandlerInterceptor1 afterCompletion HandlerInterceptor1 過濾的接口耗時:330ms

    具體代碼可以自行下載閱覽。

    4.2、過濾器
    4.2.1、過濾器實現方式
  • 直接實現Filter接口,這一類過濾器只有CompositeFilter;
  • 繼承抽象類GenericFilterBean,該類實現了Filter,這一類的過濾器只有一個,即DelegatingFilterProx;
  • 繼承抽象類OncePerRequestFilter,該類為GenericFilterBean的直接子類,這一類過濾器包括CharacterEncodingFilter、HiddenHttpMethodFilter、HttpPutFormContentFilter、RequestContextFilter和ShallowEtagHeaderFilter;
  • 繼承抽象類AbstractRequestLoggingFilter,該類為OncePerRequestFilter的直接子類,這一類過濾器包括CommonsRequestLoggingFilter、Log4jNestedDiagnosticContextFilter和ServletContextRequestLoggingFilter。
  • 這些類之間的關系就略了,可以參考這篇文章Spring MVC過濾器-超類

    4.2.2、過濾器實現

    過濾器的實現方法就舉一個例子了,其他的可自行參考測試

    public class MyFilter3 extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {System.out.println("MyFilter3 執行過濾");filterChain.doFilter(httpServletRequest, httpServletResponse);} }

    還有莫忘了在web.xml中增加過濾器的攔截配置

    <filter><filter-name>MyFilter3</filter-name><filter-class>com.leo.filter.MyFilter3</filter-class></filter><filter-mapping><filter-name>MyFilter3</filter-name><url-pattern>/*</url-pattern></filter-mapping>

    還可以使用注解方式去實現例如在類上添加如下注解也可以實現

    @WebFilter(urlPatterns = "/*", filterName = "myFilter3")

    5、過濾器中依賴注入(深坑)

    5.1、問題描述

    在項目中需要在filter中注入@Service注解的Service服務,但是嘗試了很多方法都無法實現(筆者也是),使用@Autowired注解注入的Service對象一致都是null,請問是這怎么回事?

    分析:既然是注入的Service對象一直是null,那就是考慮原因是否filter的創建要早于@Service注解的對象。
    嘗試:如果是Filter比Service的Bean實例更早創建,那就改變創建的順序,將@Service早一步創建不就行了。嘗試之后仍然報null,那就不是這方面的問題了。

    再次從網上查閱資料,這塊涉及web啟動的原理,web應用啟動的順序是:Listener->Filter->Servlet,因為我們在web項目中一般都會用到兩個配置文件applicationContext.xml和springmvc-servlet.xml,配置spring的時候會添加一個Listener,它會讀取applicationContext.xm配置信息對Spring Context進行配置。因此在applicationContext.xml中的bean首先被初始化和注入,然后在對Filter進行初始化,在接著對DispatcherServlet進行初始化。因此我們在Filter中注入的Bean會失敗。這里提供兩種方式獲取Bean

    5.2、Filter依賴注入實現
    5.2.1、方法一:web.xml配置實現

    通過配置代理,將自定義的Filter注入,配置代碼如下:

    <filter><filter-name>DelegatingFilterProxy</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class><init-param><param-name>targetBeanName</param-name><param-value>myFilter</param-value></init-param><init-param><param-name>targetFilterLifecycle</param-name><param-value>true</param-value><!-- 此參數必需設置--></init-param></filter><filter-mapping><filter-name>DelegatingFilterProxy</filter-name><url-pattern>/*</url-pattern></filter-mapping>

    過濾器的代碼如下:

    @Component("myFilter") public class MyFilter implements Filter {@AutowiredUserInfoService userInfoService;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("MyFilter過濾器初始化");}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("MyFilter過濾器執行過濾");//訪問數據庫List userInfoList = userInfoService.getUserInfoList();System.out.println(userInfoList);chain.doFilter(request, response);}@Overridepublic void destroy() {System.out.println("MyFilter過濾器銷毀了");} }

    以上代碼都是經過測試,真實可用的。

    5.2.2、方法二:繼承WebApplicationInitializer,并注冊Filter

    實現代碼示例:

    public class MyFilterConfig implements WebApplicationInitializer {@Overridepublic void onStartup(ServletContext servletContext) throws ServletException {DelegatingFilterProxy delegatingFilterProxy = new DelegatingFilterProxy();//Bean實例名稱String BeanId = "myFilter5";//代理的過濾器的BeandelegatingFilterProxy.setTargetBeanName(BeanId);//設置"targetFilterLifecycle"為True,則spring來管理Filter.init()和Filter.destroy();若為false,則這兩個方法失效!delegatingFilterProxy.setTargetFilterLifecycle(true);//注冊過濾器FilterRegistration filterRegistration = servletContext.addFilter(BeanId, delegatingFilterProxy);filterRegistration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/*");System.out.println("代理攔截器,將Bean注入到Web容器中");} }

    其中的myFilter5就是過濾器的Bean實例,如下:

    @Component public class MyFilter5 implements Filter {@AutowiredUserInfoService userInfoService;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("MyFilter5 執行過濾");//訪問數據庫List userInfoList = userInfoService.getUserInfoList();System.out.print("MyFilter5 信息: ");System.out.println(userInfoList);chain.doFilter(request, response);}@Overridepublic void destroy() {} }
    5.2.3、方法三:實現ApplicationContextAware接口的工具

    首先編寫ApplicationContextUtil工具類實現ApplicationContextAware接口

    @Component public class ApplicationContextUtil implements ApplicationContextAware{private static ApplicationContext applicationContext;/*** 通過bean的id獲取bean對象* @param beanName* @return*/public static Object getBean(String beanName){return applicationContext.getBean(beanName);}/*** 根據bean的id和類型獲取bean對象* @param beanName* @param clazz* @param <T>* @return*/public static <T> T getBean(String beanName,Class<T> clazz){return clazz.cast(getBean(beanName));}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;} }

    其次在攔截器中通過這個工具獲取Bean對象

    @Component @WebFilter(urlPatterns = "/*", filterName = "myFilter6") public class MyFilter6 implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("MyFilter6 執行過濾");//訪問數據庫,這個地方要注意使用的是“userInfoServiceImpl”,因為默認是按照類名首字符小寫注入Spring中的UserInfoService userInfoService = (UserInfoService) ApplicationContextUtil.getBean("userInfoServiceImpl");List userInfoList = userInfoService.getUserInfoList();System.out.print("MyFilter6 信息: ");System.out.println(userInfoList);chain.doFilter(request, response);}@Overridepublic void destroy() {} }
    5.2.4、方法四:獲取WebApplicationContext對象

    獲取WebApplicationContext對象從而獲取相應的Bean對象

    @Component @WebFilter(urlPatterns = "/*", filterName = "myFilter7") public class MyFilter7 implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("MyFilter7 執行過濾");//訪問數據庫,這個地方要注意使用的是“userInfoServiceImpl”,因為默認是按照類名首字符小寫注入Spring中的WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext());UserInfoService userInfoService = (UserInfoService) webApplicationContext.getBean("userInfoServiceImpl");List userInfoList = userInfoService.getUserInfoList();System.out.print("MyFilter7 信息: ");System.out.println(userInfoList);chain.doFilter(request, response);}@Overridepublic void destroy() {} }

    通過WebApplicationContext獲取Bean對象的方式有很多,上面只是舉了一個普通的常見方式。
    例如:WebApplicationContextUtilsContextLoader方式
    可以參考《Spring容器中獲取Bean實例的七種方式(附實戰源碼》這篇文章里面的示例。

    注意:平時都是使用 @Autowired按照類型注入UserInfoService,但是實際上Spring中注入的id=userInfoServiceImpl的Bean

    5、攔截器執行順序

    攔截器和過濾器執行順序可以根據下圖來說明

    總結

    以上是生活随笔為你收集整理的SpringMVC中过滤器和拦截器的区别的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。