欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

java使用过滤器/拦截器过滤response信息

程序员文章站 2022-10-03 14:48:26
触发事件:项目中需要对用户信息进行匿名化处理,就是对接口返回的信息进行再次的处理。处理方法①:直接在接口信息返回前,在进行返回数据的匿名处理。处理方法②:增加过滤器,接口调用返回到前端前在进行一次过滤。处理方法③:增加拦截器,在postHandle中处理数据。首先说一下:过滤器以及拦截器区别①拦截器是基于java的反射机制的,而过滤器是基于函数回调。②拦截器不依赖与servlet容器,过滤器依赖与servlet容器。③拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用...

触发事件:
项目中需要对用户信息进行匿名化处理,就是对接口返回的信息进行再次的处理。

处理方法①:直接在接口信息返回前,在进行返回数据的匿名处理。
处理方法②:增加过滤器,接口调用返回到前端前在进行一次过滤。
处理方法③:增加拦截器,在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 过滤器