流可重复读

37 阅读1分钟

如果在拦截器或过滤器中读取请求参数的流,就会导致在controller里无法解析参数,因为request.getInputStream()只能读取一次的问题 , 使用下面的方法:流可重复读

示例中在拦截器中,打印入参。

/***
 * @date 2023-12-12
 * @decription HttpServletRequest 包装器
 * 解决: request.getInputStream()只能读取一次的问题
 * 目标: 流可重复读
 */
@Slf4j
public class RequestWrapper extends HttpServletRequestWrapper {
    /**
     * 日志
     */
    private static final Logger logger = LoggerFactory.getLogger(RequestWrapper.class);
    /**
     * 请求体
     */
    private final String body;
    public RequestWrapper(HttpServletRequest request) {
        super(request);
        body = getBody(request);
    }
    /**
     * 获取请求体
     * @param request 请求
     * @return 请求体
     */
    private String getBody(HttpServletRequest request) {
        try {
            byte[] bodyBytes = StreamUtils.copyToByteArray(request.getInputStream());
            return new String(bodyBytes, request.getCharacterEncoding());
        } catch (IOException e) {
            logger.debug(e.getMessage());
            throw new RuntimeException(e);
        }
    }
    /**
     * 获取请求体
     * @return 请求体
     */
    public String getBody() {
        return body;
    }
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
    @Override
    public ServletInputStream getInputStream() throws IOException {
        // 创建字节数组输入流
        final ByteArrayInputStream stream = new ByteArrayInputStream(body.getBytes(Charset.defaultCharset()));
        return 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 stream.read();
            }
        };
    }
}

示例:

@Slf4j
@Component
public class PrintLogInterceptor implements HandlerInterceptor {

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (StrUtil.equalsIgnoreCase(request.getMethod(), HttpMethod.POST.name())) {
            String body = new RequestWrapper(request).getBody();
            log.info("请求POST参体:{}", body);
        }
        return true;
    }

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

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}