SpringMVC requestBody和responseBody重复获取

5 篇文章 0 订阅
4 篇文章 0 订阅

SpringMVC requestBody和responseBody重复获取

最近有个需求,要根据响应结果来判断,是否需要保存requestBody的内容到数据库。
想法使用拦截器HandlerInterceptor,拦截需要处理的url,根据响应结果判断是否需要保存内容到数据库。

遇到问题

  • requestBody不能重复获取问题
  • responseBody 在HandlerInterceptor afterCompletion无法获取到内容

其实际都是因为requestBody、responseBody 对应只能读取一次的问题,这里要解决的是,让requestBody、responseBody 可以重复读取。

解决思路

查资料发现 Spring提供了ContentCachingRequestWrapperContentCachingResponseWrapper 实现重复读取body的功能。
只需配置了一个过滤器,对需要处理的url,做requestServlet、response的封装,然后在HandlerInterceptor就可以读取到body的内容了。

@WebFilter(filterName = "httpServletFilter",urlPatterns = "/")
public class HttpServletFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest requestToCache = new ContentCachingRequestWrapper((HttpServletRequest) servletRequest);
        HttpServletResponse responseToCache = new ContentCachingResponseWrapper((HttpServletResponse) servletResponse);
        filterChain.doFilter(requestToCache, responseToCache);
    }

    @Override
    public void destroy() {

    }
}

备注,这里过滤器的使用,踩了个小坑,同时使用了@Component、@WebFilter 2个注解,实际是实例化了2个,@Component 是对所有url生成 ,@WebFilter是对配置里的url生效。 使用@WebFilter + @ServletComponentScan(放在启动类上) ,就只对@WebFilter是对配置里的url生效。

处理业务

拦截里有2个方法,用获取request、response的body内容,主要依赖其包装类的getContentAsByteArray()方法,获取字节数组,转化实际的内容,我这里是需要Json字符串,所以转成String就可以了。

public class BusinessHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        String responseBody=this.getResponseData(response);
        //todo 做业务判断是否需要保存requestBody

        String requestBody=this.getRequestData(request);
        //todo 保存数据到数据库

    }


    private String getRequestData(final HttpServletRequest request) throws UnsupportedEncodingException {
        String payload = null;
        ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
        if (wrapper != null) {
            byte[] buf = wrapper.getContentAsByteArray();
            if (buf.length > 0) {
                payload = new String(buf, 0, buf.length, wrapper.getCharacterEncoding());
            }
        }
        return payload;
    }

    private String getResponseData(final HttpServletResponse response) throws UnsupportedEncodingException, IOException {
        String payload = null;
        ContentCachingResponseWrapper wrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        if (wrapper != null) {
            byte[] buf = wrapper.getContentAsByteArray();
            if (buf.length > 0) {
                payload = new String(buf, 0, buf.length, StandardCharsets.UTF_8.name());
            }
            //将内容复制回响应体
            wrapper.copyBodyToResponse();   // in other case you send null to the response
        }
        return payload;
    }


}

参考 https://stackoverflow.com/questions/26380214/java-spring-get-body-of-post-request

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值