全注解实现自定义过滤器与拦截请求参数

全注解实现自定义过滤器与拦截请求参数

环境

springboot工程

步骤

1、在主Application上添加注解@ServletComponentScan使得@WebFilter注解生效

@SpringBootApplication
@ServletComponentScan
public class DemoApplication {

2、添加自定义过滤器

@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = null;
        if (servletRequest instanceof HttpServletRequest) {
            request = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) servletRequest);
        }
        JSONObject requestBody = new JSONObject();
        //解析post请求体
        if (RequestMethod.POST.name().equals(request.getMethod())) {
            String body = HttpContentUtils.Reader.readPostBodyAsString(request);
            if (StringUtils.isNotEmpty(body)) {
                requestBody.putAll(JSONObject.parseObject(body));
            }
        }
        //解析get请求体
        Map<String, String[]> paramMap = request.getParameterMap();
        if (paramMap != null && paramMap.size() > 0) {
            for (Map.Entry<String, String[]> entry : paramMap.entrySet()) {
                if (entry.getValue() != null && entry.getValue().length > 0) {
                    requestBody.put(entry.getKey(), entry.getValue()[0]);
                }
            }
        }
        //自定义过滤条件 默认通过
        filterChain.doFilter(request, servletResponse);
    }

    @Override
    public void destroy() {

    }
}

3、因为要获取请求体内容,获取请求体的工具类如下:

public class HttpContentUtils {

    public static class Reader {

        public static String readPostBodyAsString(HttpServletRequest request)
        {
            BufferedReader br = null;
            StringBuilder sb = new StringBuilder("");
            try
            {
                br = request.getReader();
                String str;
                while ((str = br.readLine()) != null)
                {
                    sb.append(str);
                }
                //br.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            finally
            {
                if (null != br)
                {
                    try
                    {
                        br.close();
                    }
                    catch (IOException e)
                    {
                        e.printStackTrace();
                    }
                }
            }
            return sb.toString();
        }
    }
}

4、请求流只能读一次,无法重复读,所以需要先读出来,然后存储下来,留作以后重复读使用,通过继承HttpServletRequestWrapper类,重写getInputStream()方法,来实现数据重复读。

public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {

    private byte[] requestBody = null;//用于将流保存下来

    public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        requestBody = StreamUtils.copyToByteArray(request.getInputStream());
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {

        final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);

        return new ServletInputStream() {

            @Override
            public int read() throws IOException {
                return bais.read();
            }

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

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

            @Override
            public void setReadListener(ReadListener readListener) {

            }
        };
    }

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

其他描述:
为什么不能通过拦截器实现解析请求体,然后进行拦截?
拦截器是spring基于aop反射实现的请求拦截,在这个过程中我们将request请求转换成我们的自定义的能够多次读取的请求类,无法将这个类传递下去。
过滤器是基于函数回调实现的请求拦截,我们在这个过程中替换掉请求体为我们自定义的请求体,能够做到对象替换,在这之后使用的getInputStream为我们重写的方法,能够实现重复读取流数据,流数据的生命周期和请求一致,所以使用过滤器来实现基于请求体参数过滤请求的功能。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值