赞
踩
过滤器和拦截器在日常业务开发中不是经常用到,近来项目中偶尔遇到了,对过滤器和拦截器进行了一次系统学习,现总结如下。
过滤器是Servlet的高级特性之一,是实现Filter接口的Java类。其基本功能就是对servlet的调用进行干预,在servl请求和响应的过程中增加一些特定的功能。可以使用过滤器实现的功能有:统一编码,URL级别的权限访问控制,过滤敏感词汇,压缩请求信息。
通过看Filter接口代码,其有三个方法:
- public interface Filter {
- default void init(FilterConfig filterConfig) throws ServletException {
- }
-
- void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
-
- default void destroy() {
- }
- }
init(FilterConfig conf)方法:用于执行过滤器的初始化工作,web容器会在web项目启动时自动调用该方法。
doFilter(ServletRequest request,SerlvetResponse response,FilterChain chain)方法:当请求和响应被过滤器拦截后,都会交给doFilter来处理:其中两个参数分别是被拦截request和response对象,可以使用chain的doFliter方法来放行。
destroy()方法:用于释放关闭Filter对象打开的资源,在web项目关闭时,由web容器自动调用该方法。
开发一个过滤器比较简单,第一步实现Filter接口,第二步配置过滤器
开发一个简单的filter代码如下:
- package com.lsl.mylsl.filter;
-
- import org.springframework.http.HttpHeaders;
- import org.springframework.http.ResponseCookie;
-
- import javax.servlet.*;
- import javax.servlet.annotation.WebFilter;
- import javax.servlet.http.Cookie;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.io.IOException;
- import java.util.Enumeration;
-
- @Component
- @WebFilter(filterName = "myFilter",urlPatterns = {"/*"})
- public class MyFilter implements Filter {
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
-
- //获取filter名字
- String filterName = filterConfig.getFilterName();
-
- //获取filter里配置的init-param配置指定参数的值,如果参数不存在,则返回 null
- String email = filterConfig.getInitParameter("email");
-
- //获取filter里配置的init-param配置所有参数值,如果过滤器没有初始化参数,则返回一个空的 Enumeration
- Enumeration<String> initParameterNames = filterConfig.getInitParameterNames();
-
- //返回对调用者在其中执行操作的 ServletContext 的引用。
- ServletContext servletContext = filterConfig.getServletContext();
- }
-
- @Override
- public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
- HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
- HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
-
- //统一编码处理
- httpRequest.setCharacterEncoding("UTF-8");
- httpResponse.setContentType("text/html;charset=UTF-8");
-
- //添加name属性
- httpRequest.setAttribute("name", "tom");
-
- //获取请求中的所有cookie
- Cookie[] cookies = httpRequest.getCookies();
- if (cookies != null) {
- StringBuilder sb = new StringBuilder();
- for (Cookie cookie : cookies) {
- String cookieName = cookie.getName();
- String cookieValue = cookie.getValue();
- //设置cookie的相关属性
- ResponseCookie lastCookie = ResponseCookie.from(cookieName, cookieValue).httpOnly(true).sameSite("Lax").build();
- httpResponse.addHeader(HttpHeaders.SET_COOKIE, lastCookie.toString());
- }
-
- filterChain.doFilter(httpRequest, httpResponse);
- }
- }
-
- @Override
- public void destroy() {
-
- }
- }
第二步配置filter:
filter配置有三种方式,上面的代码中是其中一种配置(注解配置)。
第一种:在web.xml配置
- <filter>
- <filter-name>myFilter</filter-name>
- <filter-class>com.lsl.mylsl.filter.MyFilter</filter-class>
- <init-param>
- <param-name>email</param-name>
- <param-value>15***011@qq.com</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>myFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
<filter>配置
fliter-name:指为过滤器的名字
filter-class:过滤器的完整类名
init-param:用于为过滤器指定初始化参数,它的子元素指定参数的名字
filter-name:你在<fliter>中声明的filter-name
url-patten:设置 filter 所拦截的请求路径(过滤器关联的URL样式)
第二种:注解配置,这边比较简单,定义filter上的注解
@WebFilter(filterName = "myFilter",urlPatterns = {"/*"})
第三种:利用配置类,相关代码如下
- package com.lsl.mylsl.filter;
-
- import org.springframework.boot.web.servlet.FilterRegistrationBean;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
-
- @Configuration
- public class MyFilterConfig {
-
- @Bean
- public FilterRegistrationBean myFilter(){
- FilterRegistrationBean fb = new FilterRegistrationBean();
- //设置filter启动顺序
- fb.setOrder(1);
- fb.setFilter(new MyFilter());
- fb.addInitParameter("email","15***11@qq.com");
- //设置拦截请求规则,这里拦截所有请求
- fb.addUrlPatterns("/*");
- return fb;
- }
- }
这里简单说下这三种filter配置的优缺点:
第一种xml的配置需要在xml中写配置,但是现在大部分是springboot项目开发,都是重注解轻配置,现在不怎么使用了。如果xml中配置了多个filter,那么按上下先后顺序依次起作用。
第二种注解配置,写法比较简单,但是有一个缺点,多个filter没法控制先后顺序。如果想用这个注解,但是还想控制filter的先后顺序,网上有个说法,就是按filter的名字首字母顺序来确定先后顺序,比如有多个filter的名字是AdminFilter和UserFilter,那么就是前者先生效后者后生效。
第三种配置类配置,我个人比较倾向于这个(当然如果就是一个简单filter,用注解最简单方便),有xml配置的所有功能。可以定义启动顺序,初始化参数等。
Spring MVC
中的拦截器( Interceptor
)类似于ServLet中的过滤器( Filter
),它主要用于拦截用户请求并作出相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。
一个拦截器,只有 preHandle 方法返回 true , postHandle 、 afterCompletion 才有可能被执行;如果 preHandle 方法返回 false ,则该拦截器的 postHandle 、 afterCompletion 必然不会被执行。拦截器不是Filter,却实现了Filter的功能,其原理在于:
所有的拦截器 (Interceptor) 和处理器 (Handler) 都注册在 HandlerMapping 中。
Spring MVC 中所有的请求都是由 DispatcherServlet 分发的。
当请求进入 DispatcherServlet.doDispatch() 时候,首先会得到处理该请求的 Handler (即 Controller 中对应的方法)以及所有拦截该请求的拦截器。拦截器就是在这里被调用开始工作的。
拦截器本质上是面向切面编程(AOP),符合横切关注点的功能都可以放在拦截器中来实现,主要的应用场景包括:
-登录验证,判断用户是否登录。
-权限验证,判断用户是否有权限访问资源,如校验token
- 日志记录,记录请求操作日志(用户ip,访问时间等),以便统计请求访问量。
-处理cookie、本地化、国际化、主题等。
-性能监控,监控请求处理时长等。
- package org.springframework.web.servlet;
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.springframework.lang.Nullable;
-
- public interface HandlerInterceptor {
- default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
- return true;
- }
-
- default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
- }
-
- default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
- }
- }
从代码可以看出,拦截器接口有三个方法,分别的作用是:
preHandle方法:叫做预处理方法,本方法在控制器方法(MyController的方法)之前执 行,用户的请求最先到达此方法,在这个方法中可以获取请求的信息,验证请求是否符合要求。以验证用户是否登录,验证用户是否有权限访问某个链接地址(url)。如果返回true则放行,返回false则拦截。
postHandle方法:叫做后处理方法。在controller中的方法之后执行的。能够获取到处理器方法的返回值 mv,可以修改mv中的数据和视图。可以影响到最后的执行结果。主要是对原来的执行结果做二次修正
afterCompletion方法:最后执行的方法,在页面渲染之后执行。在请求处理完成后执行的,框架中规定是当你的视图处理完成后,对视图进行了forword。就任务请求处理完成。一般做资源回收工作的,程序请求过程中创建了一些对象。在这里可以删除,吧占用的内存回收
开发一个拦截器也需要2步,第一步是实现HandlerInterceptor接口来定义一个拦截器,第二步就是配置拦截器了
第一步定义一个拦截器
- package com.lsl.mylsl.interceptor;
-
- import org.springframework.web.servlet.HandlerInterceptor;
- import org.springframework.web.servlet.ModelAndView;
-
- import javax.servlet.http.Cookie;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-
-
- public class MyInterceptor implements HandlerInterceptor {
-
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
-
- //在拦截的请求了添加属性,在对应请求的controller中的request中就可以获取该参数了
- //比如String userName = (String)request.getAttribute("userName");
- request.setAttribute("userName","lsl");
-
- //获取cookie
- Cookie[] cookies = request.getCookies();
-
- //设置header属性
- response.addHeader("SameSite","Lax");
-
- //添加cookie
- Cookie cookie = new Cookie("name","lsl");
- response.addCookie(cookie);
-
- return true;
- }
-
- @Override
- public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
- HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
- }
-
- @Override
- public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
- HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
- }
- }
第二步:配置拦截器
- package com.lsl.mylsl.interceptor;
-
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
- import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
- /**
- * 拦截器配置类
- */
- @Configuration
- public class MyInterceptorConfig implements WebMvcConfigurer {
-
- /**
- * 配置拦截器
- * @param registry
- */
- @Override
- public void addInterceptors(InterceptorRegistry registry){
- registry.addInterceptor(myInterceptor())
- .addPathPatterns("/api/lsl/**")//需要拦截的请求
- .addPathPatterns("/api/mjx/**")//需要拦截的请求
- .excludePathPatterns("/api/debug/**")//不拦截的请求
- .excludePathPatterns("api/lsl/getName");//不拦截的请求
- }
-
- /**
- * 注入拦截器到spring容器
- * @return
- */
- @Bean
- public MyInterceptor myInterceptor(){
- return new MyInterceptor();
- }
- }
1、拦截器是基于java的反射机制的,而过滤器是基于函数回调(职责链)
2、过滤器依赖与servlet容器,而拦截器不依赖与servlet容器
3、拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用
4、拦截器可以访问action上下文、值栈里的对象,而过滤器不能
5、在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次
6、拦截器可以获取IOC容器中的各个bean,而过滤器不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
7、过滤器属于Servlet,而拦截器属于springmvc
8、过滤器可以拦截所有请求,包括访问静态资源的请求,拦截器只能拦截action请求,即访问controller的请求。
通俗理解:
(1)过滤器(Filter):当你有一堆东西的时候,你只希望选择符合你要求的某一些东西。定义这些要求的工具,就是过滤器。(理解:就是一堆字母中取一个B)
(2)拦截器(Interceptor):在一个流程正在进行的时候,你希望干预它的进展,甚至终止它进行,这是拦截器做的事情。(理解:就是一堆字母中,干预它,通过验证的少点,顺便干点别的东西
过滤器和拦截器图解
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。