目錄
- 代碼演示
- 過濾器Demo
- 攔截器Demo
- 過濾器
- 自定義攔截器
- 配置攔截器
- 過濾器執行原理
- 多個過濾器的執行順序
- 攔截器
- 自定義攔截器
- 注冊攔截器
- 1)注冊攔截器
- 2)配置攔截的路徑
- 3)配置不攔截的路徑
- 多個攔截器的執行順序
- 過濾器和攔截器的區別
代碼演示
我們這里先上代碼,看看攔截器和過濾器在代碼實現上的區別。
過濾器Demo
1、定義一個類,實現接口Filter
public class FilterDemo implements Filter {
}
2、實現Filter
接口的方法
public class FilterDemo implements Filter {public static int i = 0;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("執行init方法");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("執行doFilter方法 + " + i++);filterChain.doFilter(servletRequest,servletResponse);}@Overridepublic void destroy() {System.out.println("執行destroy方法");}
}
3、配置攔截路徑
1)通過web.xml文件配置
<filter><filter-name>FilterDemo</filter-name><filter-class>com.example.springboot_demo.filter.FilterDemo</filter-class>
</filter><filter-mapping><filter-name>FilterDemo</filter-name><!-- 攔截路徑 --><url-pattern>/*</url-pattern>
</filter-mapping>
2)、注解
@WebFilter("/*")
攔截器Demo
1、定義一個類實現HandlerInterceptor
并實現此接口的方法
public class InterceptorDemo implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("執行preHandle方法");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("執行postHandle方法");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("執行afterCompletion方法");}
}
2、創建一個配置類,實現WebMvcConfigurer
@Configuration
public class MyConfig implements WebMvcConfigurer {}
3、實現WebMvcConfigurer
的addInterceptors
方法
@Configuration
public class MyConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {}
}
4、將自定義的攔截器進行注冊,并配置攔截路徑和放行路徑
@Configuration
public class MyConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注冊自定義的攔截器InterceptorRegistration interceptorRegistration = registry.addInterceptor(new InterceptorDemo());// 定義攔截所有路徑interceptorRegistration.addPathPatterns("/**");// 定義排查/user/下的所有路徑interceptorRegistration.excludePathPatterns("/user/**");}
}
這就是過濾器和攔截器的代碼實現,展示了它們在代碼層面的不同。后面將會進行詳細解釋。
過濾器
過濾器是Servlet的高級特性之一,就是Web服務器在處理請求的時候會經過每一過濾器再處理請求。
自定義攔截器
自定義攔截器其實就是實現Filter
接口,然后實現他的方法。
那它的方法都有什么作用呢?
1)init方法
public void init(FilterConfig filterConfig)
- 在Web容器啟動初始化過濾器時被調用,它在 Filter 的整個生命周期只會被調用一次。
- 注意:這個方法必須執行成功,否則過濾器會不起作用。
2)doFilter方法
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
- 容器中的每一次請求都會調用該方法
- 一次請求會調用兩次,進Web容器時調用一次,出Web容器時調用一次
- 要使用
filterChain.doFilter(servletRequest, servletResponse);
來調用下一個過濾器,否則這個請求就到此結束了。
3)destroy方法
public void destroy()
- 當容器銷毀 過濾器實例時調用該方法,一般在方法中銷毀或關閉資源
- 在過濾器 Filter 的整個生命周期也只會被調用一次
public class FilterDemo implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("執行init方法");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("執行doFilter方法");filterChain.doFilter(servletRequest,servletResponse);}@Overridepublic void destroy() {System.out.println("執行destroy方法");}
}
配置攔截器
1)通過web.xml文件配置
<filter><filter-name>FilterDemo</filter-name><filter-class>com.example.springboot_demo.filter.FilterDemo</filter-class>
</filter>
- <filter-name>用于為過濾器指定一個名字,該元素的內容不能為空。
- <filter-class>元素用于指定過濾器的完整的限定類名。
- <init-param>元素用于為過濾器指定初始化參數,它的子元素<param-name>指定參數的名字,<param-value>指定參數的值。在過濾器中,可以使用FilterConfig接口對象來訪問初始化參數。
<filter-mapping><filter-name>FilterDemo</filter-name><!-- 攔截路徑 --><url-pattern>/*</url-pattern>
</filter-mapping>
- <filter-mapping>元素用于設置一個Filter 所負責攔截的資源。
- <filter-name>子元素用于設置filter的注冊名稱。該值必須是在<filter>元素中聲明過的過濾器的名字。
- <url-pattern>設置 filter 所攔截的請求路徑(過濾器關聯的URL樣式)
2)、注解
@WebFilter(filterName = "FilterDemo",urlPatterns = "/*")
- 理解了web.xml方式,注解方式看起來就一目了然了
過濾器執行原理
過濾器執行主要是通過函數回調的方式。
在我們自定義的過濾器中都會實現一個 doFilter()方法,這個方法有一個FilterChain 參數,而實際上它是一個回調接口。
所以,如果我們寫這樣的過濾器
public class FilterDemo implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("執行init方法");}@Overridepublic void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {System.out.println("準備放行");//執行這一句,說明放行(讓下一個過濾器執行,或者執行目標資源)chain.doFilter(req, resp);System.out.println("放行完成");}@Overridepublic void destroy() {System.out.println("執行destroy方法");}
}
程序在執行到chain.doFilter(req,resp)
時會執行下一個過濾器或目標資源,然后執行完成回到此方法繼續往下執行。
多個過濾器的執行順序
過濾器之間的執行順序看在web.xml文件中mapping的先后順序的,如果放在前面就先執行,放在后面就后執行!
如果是通過注解的方式配置,就比較urlPatterns的字符串優先級
攔截器
攔截器是SpringMVC自己的功能,雖然看起來和過濾器一樣,但是底層使用的是面向切面編程AOP。
自定義攔截器
前面我們直到自定義攔截器要實現HandlerInterceptor
接口,然后再實現它的方法。
那這幾個方法都有什么作用呢?
1)preHandle方法
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler);
- 再請求處理之前執行(Controller方法調用之前)
- 返回值是boolean類型,返回false表示攔截,不會讓此請求訪問Controller,返回true則可繼續執行
2)postHandle方法
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView);
- 在請求結束之后(Controller請求返回),在ModelAndView渲染之前調用
- 主要就是用來對ModelAndView對象進行操作
3)afterCompletion方法
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
- 在整個請求結束之后調用
- 主要是用于資源清理工作
public class InterceptorDemo implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("執行preHandle方法");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("執行postHandle方法");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("執行afterCompletion方法");}
}
注冊攔截器
創建一個實現WebMvcConfigurer
的攔截器,然后將自定義的攔截器注冊到其中。可以注冊多個攔截器。
實現方法addInterceptors
,通過參數InterceptorRegistry registry
來進行一系列配置
@Configuration
public class MyConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注冊自定義的攔截器InterceptorRegistration interceptorRegistration = registry.addInterceptor(new InterceptorDemo());// 定義攔截所有路徑interceptorRegistration.addPathPatterns("/**");// 定義排查/user/下的所有路徑interceptorRegistration.excludePathPatterns("/user/**");// 確定執行順序interceptorRegistration.order(1);}
}
1)注冊攔截器
InterceptorRegistration interceptorRegistration = registry.addInterceptor(new InterceptorDemo());
將自定義的攔截器對象傳入其中即可,如果要注冊多個攔截器,調用多次這個方法即可。
2)配置攔截的路徑
interceptorRegistration.addPathPatterns("/**");
如果需要攔截多個路徑,可以多次傳入一個字符串,也可以傳入一個List集合。
3)配置不攔截的路徑
interceptorRegistration.excludePathPatterns("/user/**");
這個和addPathPatterns
一樣,可以傳入字符串,也可以傳入List
多個攔截器的執行順序
多個攔截器可通過
order()
方法來確定執行順序,order()
傳入一個數字,數字越小則越先執行。
過濾器和攔截器的區別
- 適用范圍不同:Filter是Servlet容器規定的,只能使用在servlet容器中,而攔截器的使用范圍就大得多
- 使用的資源不同:攔截器是屬于spring的一個組件,因此可以使用spring的所有對象,如service對象,數據源,事務控制等,而過濾器就不行
- 深度不同:Filter還在servlet前后起作用。而攔截器能夠深入到方法前后,異常拋出前后,因此攔截器具有更大的彈性,所有在spring框架中應該優先使用攔截器