过滤器和拦截器
介绍
过滤器和拦截器都是基于AOP面向切面编程思想实现的,用来解决项目中某一类问题的两种“工具”。
过滤器与拦截器的区别
过滤器关注的是web请求,对所有访问进行增强,做请求前和响应后处理
拦截器关注的是方法调用,做方法增强,围绕处理器前后使用
Filter 属于Servlet技术,基于函数回调,依赖Tomcat等容器,只能在web程序中使用
Interceptor属于SpringMVC技术,基于反射,是一个Spring组件,由spring容器管理,不依赖Tomat等容器,可以单独使用,不仅能在web程序中,也可以用于Application等程序。
过滤器是在请求进入容器后但在进入servlet之前进行预处理,请求结束是在servlet处理完成之后。
拦截器Interceptor是在请求进入servlet后,在进入Controller之前进行预处理,Controller完成后,后置处理完请求结束
过滤器
主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理。
依赖于servlet容器,对所有请求起作用,在一个Action周期中,只能在容器初始化时调用一次
使用Filter的完整流程:
Filter对用户请求进行预处理
将请求交给servlet进行处理并生成响应
最后Filter对服务器进行后处理
Filter 功能:
- 在HttpServletRequest 到达 Servlet 之前,拦截客户的 HttpServletRequest 。 根据需要检查 HttpServletRequest ,也可以修改HttpServletRequest 头和数据。
- 在HttpServletResponse 到达客户端之前,拦截HttpServletResponse 。 根据需要检查 HttpServletResponse ,也可以修改HttpServletResponse头和数据。
Filter接口中有一个doFilter方法,当开发人员编写好Filter,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前,都会先调用一下filter的doFilter方法,因此,在该方法内编写代码可达到如下目的
- 调用目标资源之前,让一段代码执行。
- 是否调用目标资源(即是否让用户访问web资源)
web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,否则web资源不会被访问。
常见场景
- 统一设置编码格式
- 身份验证
- 访问权限控制
- 日志记录
- 敏感数据过滤
- 防止XSS攻击的过滤
实现
实现方式一:使用配置版
在web.xml文件中进行配置 <filter> <filter-name>testFilter</filter-name> <filter-class>com.bj.filter.TestFilter</filter-class> </filter> <filter-mapping> <filter-name>testFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
实现方式二:使用@WebFilter注解配置 并通过@Order指定执行顺序
常用OverWrite =》 init、doFilter、destroy
init:filter初始化方法
dofilter:具体的过滤逻辑,FilterChian参数是用来调用下一个过滤器或者执行下一个流程 形成过滤链
destroy:用于filter销毁前完成相关资源的回收
import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; @Component @WebFilter(urlPatterns = "/*") public class TestFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("过滤器:执行 init 方法。"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("过滤器:开始执行 doFilter 方法。"); // 请求放行 filterChain.doFilter(servletRequest, servletResponse); System.out.println("过滤器:结束执行 doFilter 方法。"); } @Override public void destroy() { System.out.println("过滤器:执行 destroy 方法。"); } } 作者:Java中文社群 链接:https://juejin.cn/post/7155069405993369631 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
执行具体逻辑
在某个类上进行使用注解即可 @WebFilter( filterName = "characterFilter", urlPatterns = "/*", initParams = { @WebInitParam(name = "encoding", value = "UTF-8") }) 或者直接 @WebFilter("/*") 案列配置拦截地址 //进行判断Session是否有数据 HttpServletRequest httpRequest=(HttpServletRequest)request; HttpServletResponse httpResponse=(HttpServletResponse)response; String name=(String)httpRequest.getSession().getAttribute("name"); String pwd= (String)httpRequest.getSession().getAttribute("pwd"); String url=httpRequest.getRequestURI(); if(name !=null && pwd !=null) { chain.doFilter(request, response); }else if(url.contains("TestLongServlet")) { chain.doFilter(request, response); }else if(url.contains("TestImgServlet")) { chain.doFilter(request, response); }else { System.out.println("@WebFilter: httpRequest.getRequestDispatcher(\"list.jsp\").forward(request, response); "); httpRequest.getRequestDispatcher("/list.jsp").forward(request, response); } }
字符集过滤器
地址过滤器
拦截器Interceptor
参考:https://juejin.cn/post/6844903550829461511
基于java反射原理实现
不依赖与servlet容器
针对Action ,方法调用,可以多次使用 如:在Controller前后增加拦截器进行调用方法时的前后处理逻辑 即增强方法
拦截器的加载时间点是在springContext之前
应用场景
1)、日志记录:可以记录请求信息的日志,以便进行信息监控、信息统计等。
2)、权限检查:如登录检测,进入处理器检测是否登录,如果没有直接返回到登录页面。
3)、性能监控:典型的是慢日志。
源码
SpringMVC下
//继承spring的拦截接口,实现以下三个方法 public interface HandlerInterceptor { // 在业务处理器处理请求之前被调用 boolean preHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception; // 在业务处理器处理请求完成之后,生成视图之前执行 void postHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3, ModelAndView var4) throws Exception; // 在DispatcherServlet完全处理完请求之后被调用,可用于清理资源,日志打印 void afterCompletion(HttpServletRequest var1, HttpServletResponse var2, Object var3, Exception var4) throws Exception; }
实现
实现HandlerInterceptor或者继承HandlerInterceptorAdapter,重写preHandle() 自定义拦截器
实现WebMvcConfigurer,重写addCorsMappings()方法和addInterceptor()方法 注册拦截器
(HandlerInterceptorAdapter已经废弃,推荐直接实现WebMvcConfigurer或者继承WebMvcConfigurationSupport)
WebMvcConfigurer是MVC的注解配置方式等同于xml配置
- addInterceptors:添加拦截器
- addCorsMappings:跨域
- addViewControllers:页面跳转(不用像现在我们要写一个Controller进行映射就可实现跳转)
- addResourceHandlers:静态资源(自定义静态资源映射目录)
- configureDefaultServletHandling:默认静态资源处理器
- configureViewResolvers:视图解析器(配置请求视图映射,配置了以后我们返回一个页面路径的字符串时,解析器会帮我们拼装前缀和后缀等信息)
- configureMessageConverters:信息转换器(比如我们入参的信息直接转换成json或者转换成对应的bean类就具体在这里配置)
/** * @author yhwang * 自定义拦截器 判断用户是否登录 * @date 2021年06月28日 19:03 */ public class LoginInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("执行了Interceptor的preHandle方法"); try { //统一拦截(查询当前session是否存在Usser用户信息)(这里User会在每次登陆成功后,写入session) User user = (User) request.getSession().getAttribute("User"); if (user != null) { return true; } //这里设置拦截以后重定向的页面,一般设置为登陆页面地址 response.sendRedirect(request.getContextPath() + "/demo/loginPage"); } catch (IOException e) { e.printStackTrace(); } return true;//如果设置为false时,被请求时,拦截器执行到此处将不会继续操作 //如果设置为true时,请求将会继续执行后面的操作 } /*** * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后) */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("执行了拦截器的postHandle方法"); } /*** * 整个请求结束之后被调用,也就是在DispatchServlet渲染了对应的视图之后执行(主要用于进行资源清理工作) */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("执行了拦截器的afterCompletion方法"); } } 作者:yhwang0505 链接:https://juejin.cn/post/7038396711047266317 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
@Configuration //标识此为一个配置类 public class MyWebConfigurer implements WebMvcConfigurer { /** * 重写addInterceptors()实现拦截器 * 配置:要拦截的路径以及不拦截的路径 * @param registry */ @Override public void addInterceptors(InterceptorRegistry registry) { InterceptorRegistration registration = registry. addInterceptor (new LoginInterceptor()) ; //addPathPatterns() 方法 添加需要拦截的路径 registration.addPathPatterns("/**"); //addPathPatterns() 方法 添加不需要拦截的路径 registration.excludePathPatterns( "/**/*.html", "/**/*.js" ); } /** * 重写addCorsMapping()解决跨域问题 * 配置:允许http请求进行跨域访问 * @param registry */ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**")//指哪些接口url需要藏家跨域设置 .allowedOrigins("*")//指的是前端哪些页面允许被跨域 .allowCredentials(true)//需要嗲cookie等凭证,设置为true,就会把cookie的相关信息带上 .allowedMethods("GET","POST","PUT","DELETE","OPTIONS","HEAD")//指的是允许哪些方法 .maxAge(3600);//cookie的失效时间,单位为秒(s),若设置为-1,则关闭浏览器就会失效 } } 作者:yhwang0505 链接:https://juejin.cn/post/7038396711047266317 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
作者: deity-night
出处: https://www.cnblogs.com/deity-night/
关于作者:码农
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出, 原文链接 如有问题, 可邮件(***@163.com)咨询.