写在前面

过滤器的作用就是在业务逻辑执行前/后对请求和响应进行相应的处理,如果能配合HttpServletRequestWrapper和HttpServletResponseWrapper使用更加完美。
HttpServletRequestWrapper是SERVLET规范中定义的包装器,通过重新方法提供了扩展和增强HttpServletRequest的能力。HttpServletRequestWrapper中持有一个HttpServletRequest对象,然后实现HttpServletRequest接口的所有方法,所有方法实现中都是调用持有的HttpServletRequest对象的相应的方法。

使用场景

A. 在过滤器中替换掉默认的Request对象;
B. 在拦截器中读取参数进行处理后再将参数回写;
C. 自定义SESSION的处理逻辑。

使用目的

SpringBoot通过拦截器/过滤器获取参数有两种方式,一种通过request.getParameter获取Get方式传递的参数,另外一种是通过request.getInputStream或reques.getReader获取通过POST/PUT/DELETE/PATCH传递的参数。后端服务针对前端传递过来的参数是通过IO流来进行解析的,默认情况下IO流读一次就结束了,数据就没有了,而有些业务场景需要我们多次读取请求参数,在这个场景下,利用装饰者模式对 HttpServletRequest 的功能进行增强就是一个很好的解决方案。
因为IO流和迭代器一样都是单流向的,如果已经读到末尾位置了,肯定不能在再读数据了。所以需要加个代理包装一下创建一个新的IO流,这样就可以继续读取数据了。

如何使用

/**
 * 防重复提交过滤器
 * @author ROCKY
 */
public class RepeatableFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        ServletRequest requestWrapper = null;
        if (request instanceof HttpServletRequest
                && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) {
            requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response);
        }
        if (null == requestWrapper) {
            chain.doFilter(request, response);
        } else {
            chain.doFilter(requestWrapper, response);
        }
    }
    @Override
    public void destroy() {
    }
}
/**
 * 构建可重复读取inputStream的request
 *
 * @author ROCKY
 */
public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
    private final byte[] body;

    public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException {
        super(request);
        request.setCharacterEncoding(Constants.UTF8);
        response.setCharacterEncoding(Constants.UTF8);
        body = HttpHelper.getBodyString(request).getBytes(Constants.UTF8);
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return bais.read();
            }

            @Override
            public int available() throws IOException {
                return body.length;
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }
        };
    }
}
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐