java使用过滤器/拦截器过滤response信息
触发事件:
项目中需要对用户信息进行匿名化处理,就是对接口返回的信息进行再次的处理。
处理方法①:直接在接口信息返回前,在进行返回数据的匿名处理。
处理方法②:增加过滤器,接口调用返回到前端前在进行一次过滤。
处理方法③:增加拦截器,在postHandle中处理数据。
首先说一下:
过滤器以及拦截器区别
①拦截器是基于java的反射机制的,而过滤器是基于函数回调。
②拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
③拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
④拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
⑤在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
⑥拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
SpringMVC是通过XML配置文件注册过滤器,而SpringBoot则是通过代码注解的形式进行注册。
下面说说这三种方法:
第一种方法 直接就是面向过程的,直接在方法的具体为止上处理。
第二种方法 增加过滤器:
首先需要一个返回值输出代理类。
主要是为了获取Response里面的返回信息,因为直接Response没有提供直接拿到返回值的方法。所以要通过代理来取得返回值。
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
/**
* create by liudd at 2020/07/29
*
* 主要是为了获取Response里面的返回信息,因为直接Response没有提供直接拿到返回值的方法。所以要通过代理来取得返回值。
*
*/
public class ResponseWrapper extends HttpServletResponseWrapper {
private ByteArrayOutputStream buffer;
private ServletOutputStream out;
public ResponseWrapper(HttpServletResponse httpServletResponse)
{
super(httpServletResponse);
buffer = new ByteArrayOutputStream();
out = new WrapperOutputStream(buffer);
}
@Override
public ServletOutputStream getOutputStream()
throws IOException
{
return out;
}
@Override
public void flushBuffer()
throws IOException
{
if (out != null)
{
out.flush();
}
}
public byte[] getContent()
throws IOException
{
flushBuffer();
return buffer.toByteArray();
}
class WrapperOutputStream extends ServletOutputStream
{
private ByteArrayOutputStream bos;
public WrapperOutputStream(ByteArrayOutputStream bos)
{
this.bos = bos;
}
@Override
public void write(int b)
throws IOException
{
bos.write(b);
}
@Override
public boolean isReady()
{
// TODO Auto-generated method stub
return false;
}
@Override
public void setWriteListener(WriteListener arg0)
{
// TODO Auto-generated method stub
}
}
}
下面建立Filter类 集成javax的Filter
import com.xxx.xxx.config.ResponseWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class AnonymityFilter implements Filter {
private static Logger logger = LoggerFactory.getLogger(AnonymityFilter.class);
//需要注入的bean
private ClassA xxx;
//构造函数注入所需要的的类 不需要就不用
public AnonymityFilter(Class a) {
this.xxx = a;
}
@Override
public void init(FilterConfig filterConfig) {
//初始化操作
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
logger.info("---------------> 开始匿名化过滤器处理 <-----------------");
//转换为代理类
ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) servletResponse);
//由于我是需要对返回的信息进行处理,所以先进行放行操作。
//若是需要在请求前进行相关操作,则需要在此请求前处理
filterChain.doFilter(servletRequest, responseWrapper);
//获取返回值信息
byte[] content = responseWrapper.getContent();
if (content.length > 0) {
String str = new String(content, "UTF-8");
System.out.println("返回值:" + str);
String ciphertext = null;
try {
//在此可以根据需要处理接口返回的信息
}
catch (Exception e)
{
//异常最好不要使用e.printStackTrace() 被吃掉
e.printStackTrace();
}
//把返回值输出到客户端
ServletOutputStream out = servletResponse.getOutputStream();
out.write(ciphertext.getBytes());
out.flush();
}
}
@Override
public void destroy() {
//销毁时使用
}
}
注册Filter过滤器
import com.xxx.xxx.filter.AnonymityFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
@Configuration
public class FilterConfig {
@Resource
private ClassA xxx;
@Bean
public FilterRegistrationBean firstFilter() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean(new AnonymityFilter(xxx));
//设置过滤路径:可不设置,默认过滤路径即为:/*
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(1);
return registrationBean;
}
}
springMVC使用xml注册
<filter>
<filter-name>responseFilter</filter-name>
<filter-class>com.im.filter.ResponseFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>responseFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
配置项注册类。使用@Configuration标签是为了让SpringBoot知道这个类是配置类,需要进行注册。
registrationBean.setOrder(1)是设置该过滤器执行的顺序。SpringBoot会根据order从小到大的顺序执行。
方法三 拦截器:
个人没有写拦截器过程 但我觉得写完过滤器的过程后 觉得可能拦截器要比过滤器清晰一些
过滤器是在doFilter() 方法中处理加工请求或者响应 以filterChain.doFilter()为分水岭,执行前的处理是处理请求,之后是接口返回后的处理。
拦截器更直观
preHandle():在接口运行前处理信息,即预处理
postHandle():在方法运行后处理信息,后处理。
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class InterceptorTest implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
// 预处理 返回true则往下走 false则不进行调用 可用于用户登陆验证等功能
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
// 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
// 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
}
}
注册拦截器:
import com.xxx.xxx.xxx.InterceptorTest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import java.util.Arrays;
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
private static Logger logger = LoggerFactory.getLogger(InterceptorConfig.class);
private InterceptorTest interceptorTest;
@Override
public void addInterceptors(InterceptorRegistry registry) {
initInterceptorTest(registry);
super.addInterceptors(registry);
}
private void initInterceptorTest(InterceptorRegistry registry) {
InterceptorRegistration ir = registry.addInterceptor(interceptorTest);
ir.addPathPatterns("/**");
String[] defaltExclude = "/test1,/test2".split(",");
logger.info("登录认证拦截器默认排除==> {}", Arrays.toString(defaltExclude));
ir.excludePathPatterns(defaltExclude);
logger.info("登录认证拦截器正在排除==> {}", "/test");
ir.excludePathPatterns("/test");
}
}
值得注意的是 : 项目中好像只有一个类继承 WebMvcConfigurationSupport
之前做过项目中使用swagger-ui 在注册swagger的东西的时候 会失效 就是因为只能有一个类继承WebMvcConfigurationSupport
具体为什么 欢迎大家百度 至今没明白深层次为啥
还是小白
有错误的地方欢迎批评指正。谢谢。
本文地址:https://blog.csdn.net/ldddd_/article/details/107665907
上一篇: 打印某年某月多少天
推荐阅读
-
Java IO文件过滤器对命令设计模式的使用
-
Spring Boot使用过滤器和拦截器分别实现REST接口简易安全认证示例代码详解
-
Spring Boot使用过滤器和拦截器分别实现REST接口简易安全认证示例代码详解
-
java servlet过滤器使用示例
-
浅析JAVA中过滤器、监听器、拦截器的区别
-
Zuul Filter过滤器返回信息提示getWriter() has already been called for this response
-
java servlet过滤器使用示例
-
Java拦截器和过滤器的区别分析
-
聊聊java 过滤器、监听器、拦截器的区别(终结篇)
-
java使用过滤器/拦截器过滤response信息