Spring boot 2.0 解决 RequestBody 和 ResponseBody 重复读取问题

为什么 RequestBody 只能读取一次?

方法一

1.创建一个自定义 HttpServletRequestWrapper

import org.springframework.util.StreamUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;

/**
 * @author yudong
 * @version 1.0
 * @date 2020/3/20 3:04 下午
 * @modified By
 */
public class BodyReaderRequestWrapper extends HttpServletRequestWrapper {
    private final byte [] body;

    /**
     *
     * @param request
     */
    public BodyReaderRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        body = StreamUtils.copyToByteArray(request.getInputStream());
    }

    @Override
    public BufferedReader getReader() {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream(){
        final ByteArrayInputStream byteArrayIns = new ByteArrayInputStream(body);
        ServletInputStream servletIns = new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }

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

            @Override
            public void setReadListener(ReadListener readListener) {}

            @Override
            public int read() {
                return byteArrayIns.read();
            }
        };
        return  servletIns;
    }
}

2.创建一个 filter

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * @author yudong
 * @version 1.0
 * @date 2020/3/20 3:07 下午
 * @modified By
 */
@Component
@Order
@WebFilter(filterName="bodyReader", urlPatterns="/**")
public class BodyReaderFilter implements Filter  {

    private final static Logger logger = LoggerFactory.getLogger(BodyReaderFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        logger.info("filter init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest)servletRequest;
        BodyReaderRequestWrapper requestWrapper  = new BodyReaderRequestWrapper(req);
        filterChain.doFilter(requestWrapper, servletResponse);
    }

    @Override
    public void destroy() {

    }

}

3.测试

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.nio.charset.Charset;

/**
 * 重复读取测试
 * @author yudong
 * @version 1.0
 * @date 2020/2/11 2:38 下午
 * @modified By
 */
@ResponseBody
@Controller
public class TestController {

    @Autowired
    private Test test;

  @PostMapping("test")
  public String test(HttpServletRequest httpServletRequest, @RequestBody String ss)throws Exception{
      ServletInputStream inputStream = httpServletRequest.getInputStream();
      String s = StreamUtils.copyToString(inputStream, Charset.forName("UTF-8"));
      return s;
   }


}

方法二

1.创建一个 filter

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * @author yudong
 * @version 1.0
 * @date 2020/3/20 3:07 下午
 * @modified By
 */
@Component
@Order
@WebFilter(filterName="bodyReader", urlPatterns="/**")
public class BodyReaderFilter implements Filter  {

    private final static Logger logger = LoggerFactory.getLogger(BodyReaderFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        logger.info("filter init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest)servletRequest;
        ContentCachingRequestWrapper contentCachingRequestWrapper = new ContentCachingRequestWrapper(req);
        filterChain.doFilter(contentCachingRequestWrapper, servletResponse);
    }

    @Override
    public void destroy() {

    }

}

2.编写测试 controller

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.http.HttpServletRequest;

/**
 * @author yudong
 * @version 1.0
 * @date 2020/2/11 2:38 下午
 * @modified By
 */
@ResponseBody
@Controller
public class TestController {


  @PostMapping("test")
  public String test(HttpServletRequest httpServletRequest, @RequestBody String ss)throws Exception{
      ContentCachingRequestWrapper contentCachingRequestWrapper = (ContentCachingRequestWrapper)httpServletRequest;
      byte[] contentAsByteArray = contentCachingRequestWrapper.getContentAsByteArray();
      String body = new String(contentAsByteArray);
      return body ;
   }


}

ResponseBody 重复读取

    ContentCachingResponseWrapper responseToCache = new ContentCachingResponseWrapper(httpServletResponse);
      //读取值
      String responseBody = new String(responseToCache.getContentAsByteArray());
      //重写写入到responseBody中
      responseToCache.copyBodyToResponse();
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    732 引用 • 1290 回帖 • 711 关注
  • HTTP
    54 引用 • 112 回帖
回帖
请输入回帖内容...