JAVA变成拦截器、过滤器
一、拦截器
1、简介说明
相关解释:拦截器依赖于页面有访问controller的操作,且属于SpringMVC体系的动态拦截调用机制,是java中AOP思想的运用。
来看看源码作者的注释:
其中倒数第二段话,描述其类似于过滤器,但其特点只允许使用自定义预处理,不能处理程序本身。此处可体现AOP思想。
过滤器是在web.xml中配置,web.xml是应用程序上下文中的HandlerInterceptor。
最后一段话,则体现了拦截器常用情况,如常见处理程序代码和授权检查。
而过滤器非常适合请求内容和视图内容处理,如多部分表单和GZIP压缩。
2、源码及方法说明
HandlerInterceptor
HandlerInterceptor接口中有3个方法:
preHandler():该方法会在控制器方法前执行,其返回值表示是否中断后续操作。当其返回值为true时,表示继续向下执行;当其返回值为false时,会中断后续的所有操作。
postHandle():该方法会在控制器方法调用之后,且解析视图之前执行。可以通过此方法对请求域中的模型和视图做出进一步的修改。
afterCompletion():该方法会在整个请求完成,即视图渲染结束之后执行。可以通过此方法实现一些资源清理、记录日志信息等工作。
3、拦截器自定义应用
实现 org.springframework.web.servlet.HandlerInterceptor 接口
如常见的白名单控制
packagecom.framework;importcom.alibaba.fastjson.JSON;importorg.springframework.stereotype.Component;importorg.springframework.web.servlet.HandlerInterceptor;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;@ComponentpublicclassWhiteRosterInterceptorimplementsHandlerInterceptor{@OverridepublicbooleanpreHandle(HttpServletRequest request,HttpServletResponse response,Object handler)throwsException{if(checkWhiteList()){returntrue;}
response.setContentType("application/json; charset=utf-8");
response.setCharacterEncoding("UTF-8");
response.getWriter().append(JSON.toJSONString("白名单暂未设置"));returnfalse;}privateBooleancheckWhiteList(){//业务处理returntrue;}}
二、过滤器
1、简介说明
相关解释:java过滤器能够对目标资源的请求和响应进行截取。
来看看源码作者的注释:
其描述中说明该过滤器为基于(a servlet or static content)。
同时也将其现有应用场景进行了说明,如权限过滤,加密过滤,图像转换过滤等等。
2、源码及方法说明
Filter
Filter接口中有3个方法:
init():初始化参数,在创建Filter时自动调用,如需要设置初始化参数,可写到该方法中。
doFilter():拦截到要执行的请求时,doFilter就会执行。写对请求和响应的预处理。
destroy():销毁时Filter自动调用。
init()和destroy(),为default方法,可不实现,但doFilter()必须实现,且方法中传进来的FilterChain对象用来调用下一个过滤器。
3、过滤器的自定义应用
实现javax.servlet.Filter 接口
如常见的加解密过滤器
packagecom.framework;importcom.AesUtil;importcom.response.ResponseWrapper;importorg.springframework.stereotype.Component;importjavax.servlet.Filter;importjavax.servlet.FilterChain;importjavax.servlet.FilterConfig;importjavax.servlet.ServletException;importjavax.servlet.ServletRequest;importjavax.servlet.ServletResponse;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.io.PrintWriter;@ComponentpublicclassEncryptFilterimplementsFilter{@Overridepublicvoidinit(FilterConfig filterConfig)throwsServletException{}@OverridepublicvoiddoFilter(ServletRequest request,ServletResponse response,FilterChain chain)throwsIOException,ServletException{if(isExcept(request)){
chain.doFilter(request, response);return;}
response.setContentType("application/json; charset=utf-8");
response.setCharacterEncoding("UTF-8");ResponseWrapper responseWrapper =newResponseWrapper((HttpServletResponse) response);
chain.doFilter(request, responseWrapper);byte[] resData = responseWrapper.getResponseData();String encrypt =AesUtil.encrypt(newString(resData,"utf-8"),"AesKey");PrintWriter out = response.getWriter();
out.print(encrypt.replaceAll("[\\s*\t\n\r]",""));
out.flush();
out.close();}privateBooleanisExcept(ServletRequestHttpRequest){//业务处理,是否不加密returntrue;}@Overridepublicvoiddestroy(){}}
依赖的 ResponseWrapper.java
packagecom.response;importjavax.servlet.ServletOutputStream;importjavax.servlet.WriteListener;importjavax.servlet.http.HttpServletResponse;importjavax.servlet.http.HttpServletResponseWrapper;importjava.io.ByteArrayOutputStream;importjava.io.IOException;importjava.io.OutputStreamWriter;importjava.io.PrintWriter;publicclassResponseWrapperextendsHttpServletResponseWrapper{privateByteArrayOutputStream byteArrayOutputStream =null;privateServletOutputStream servletOutputStream =null;privatePrintWriter printWriter =null;publicResponseWrapper(HttpServletResponse response)throwsIOException{super(response);
byteArrayOutputStream =newByteArrayOutputStream();
servletOutputStream =newWrapperOutputStream(byteArrayOutputStream);
printWriter =newPrintWriter(newOutputStreamWriter(byteArrayOutputStream,this.getCharacterEncoding()));}privateclassWrapperOutputStreamextendsServletOutputStream{privateByteArrayOutputStream bos =null;publicWrapperOutputStream(ByteArrayOutputStream stream)throwsIOException{
bos = stream;}@Overridepublicvoidwrite(int b)throwsIOException{
bos.write(b);}@Overridepublicvoidwrite(byte[] b)throwsIOException{
bos.write(b,0, b.length);}@OverridepublicbooleanisReady(){returnfalse;}@OverridepublicvoidsetWriteListener(WriteListener writeListener){}}}
当需要使用多个过滤器时,需要设置过滤器先后顺序。
即在EncryptFilter类中使用 @Order() 注解,数值越小,优先级越高,执行顺序越靠前。
加密相关链接:
Springboot项目报文加密(采用AES、RSA动态加密策略):
https://blog.csdn.net/qq_38254635/article/details/129275971
Springboot集成AES加密:
https://blog.csdn.net/qq_38254635/article/details/129622075
三、Springboot中的WebMvcConfigurer
1、简介
为Spring内部的配置方式,通过JavaBean的方式来替代传统的xml配置文件形式,可自定义一些Handler,Interceptor,ViewResolver,MessageConverter,需创建配置类并实现WebMvcConfigurer接口
2、主要方法
addViewControllers:将一个请求转到一个页面。
addResourceHandlers:静态资源的地址映射。
configureMessageConverters:将@ResponseBody实体转FastJson字符串返回,可以返回实体进行重写。
addCorsMappings:实现ajax跨域请求。
addInterceptors:添加拦截器。
3、添加拦截器
1、自定义一个注解,用作手动单个接口忽略拦截
packagecom.annotation;importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@interfaceIgnoreInterceptor{}
2、自定义配置,用作某路径下的请求批量忽略拦截
放置在yml配置文件中。
SpringBoot加载自定义yml中的配置参数:https://blog.csdn.net/qq_38254635/article/details/112033193
3、编写拦截器类 WebMvcConfig.java
packagecom.config;importcom.alibaba.fastjson.JSON;importcom.annotation.IgnoreInterceptor;importcom.framework.WhiteRosterInterceptor;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.method.HandlerMethod;importorg.springframework.web.servlet.HandlerInterceptor;importorg.springframework.web.servlet.ModelAndView;importorg.springframework.web.servlet.config.annotation.InterceptorRegistry;importorg.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;importorg.springframework.web.servlet.config.annotation.ViewControllerRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;importjavax.annotation.Resource;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.util.List;@ConfigurationpublicclassWebMvcConfigimplementsWebMvcConfigurer{@Value("#{'${spring.excludePath}'.split(',')}")privateList<String> excludePath;@ResourceprivateWhiteRosterInterceptor whiteRosterInterceptor;@OverridepublicvoidaddViewControllers(ViewControllerRegistry registry){
registry.addViewController("/").setViewName("index");}@OverridepublicvoidaddResourceHandlers(ResourceHandlerRegistry registry){
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");}@OverridepublicvoidaddInterceptors(InterceptorRegistry registry){
registry.addInterceptor(newHandlerInterceptor(){@OverridepublicbooleanpreHandle(HttpServletRequest request,HttpServletResponse response,Object handler)throwsException{if(handler instanceofHandlerMethod){HandlerMethod method =(HandlerMethod) handler;IgnoreInterceptor methodAnnotation = method.getMethodAnnotation(IgnoreInterceptor.class);if(null!= methodAnnotation)returntrue;if(!isLogin(request)){
response.setContentType("application/json; charset=utf-8");
response.setCharacterEncoding("UTF-8");
response.getWriter().append(JSON.toJSONString("未登录"));returnfalse;}refreshLogin(request);returntrue;}returntrue;}privateBooleanisLogin(HttpServletRequest request){//判断用户是否登录returntrue;}privatevoidrefreshLogin(HttpServletRequest request){//刷新登录信息}@OverridepublicvoidpostHandle(HttpServletRequest request,HttpServletResponse response,Object handler,ModelAndView modelAndView)throwsException{//处理完业务后,清除用户的登录相关信息,永远放在最后处理}}).addPathPatterns("/**").excludePathPatterns(excludePath);
registry.addInterceptor(whiteRosterInterceptor).addPathPatterns("/api/**");}}
4、说明
拦截器方式addInterceptors中,可实现多个拦截器。
可通过 registry.addInterceptor()增加拦截器,如上接口,增加了文中白名单拦截器。
addPathPatterns:拦截路径,**表示匹配后续所有路径
excludePathPatterns:忽略路径,接口中excludePath使用yml配置的路径,进行忽略操作。
IgnoreInterceptor:自定义注解,手动忽略某请求,在拦截器做了单独处理。
如自定义拦截器,可通过注入的方式添加。
执行顺序也根据配置的顺序,依次执行。
四、区别
1、原理
拦截器方法都是通过代理的方式来调用的,是基于反射机制实现的,依赖于web框架。
过滤器的实现是基于回调函数的。依赖于Servlet容器。
2、触发
如1.1中源码注释所说。
拦截器:对请求在handler【Controller】前后进行处理,属于应用上下文。
过滤器:对请求在进入后Servlet之前或之后进行处理,允许交换请求和响应对象,使用web.xml配置。
拦截器和过滤器执行顺序:
1、Filter.init();
2、Filter.doFilter(); before doFilter
3、HandlerInterceptor.preHandle();
4、Controller方法执行
5、HandlerInterceptor.postHandle();
6、DispatcherServlet视图渲染
7、HandlerInterceptor.afterCompletion();
8、Filter.doFilter(); after doFilter
9、Filter.destroy();
3、其他
过滤器:每一次都传入FilterChain对象,达到最后接口回调的效果。
拦截器:任何一个拦截器的preHandle为false,则其后的所有拦截器都不会执行。只有所有的拦截器preHandler都为true,postHandle才会执行。
多个过滤器设置执行顺序:增加 @Order() 注解,数值越小,优先级越高,执行顺序越靠前。
多个拦截器设置执行顺序:可通过实现Ordered接口来实现。
相关链接:
SpringBoot过滤器获取请求的参数:https://blog.csdn.net/qq_38254635/article/details/136041159
SpringBoot过滤器获取响应的参数:https://blog.csdn.net/qq_38254635/article/details/136041183
参考链接:
https://baijiahao.baidu.com/s?id=1677716748772601748
https://blog.csdn.net/m0_53123540/article/details/124924596
https://blog.csdn.net/king101125s/article/details/104372380
版权归原作者 message丶小和尚 所有, 如有侵权,请联系我们删除。