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

具体为什么 欢迎大家百度 至今没明白深层次为啥

还是小白
有错误的地方欢迎批评指正。谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值