SpringBoot读取多次RequestBody


一. 编写相关类

1. Request包装器

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringReader;

/**
 * @author TheEnd
 */
public class RequestWrapper extends HttpServletRequestWrapper {
    private String requestBody;

    public RequestWrapper(HttpServletRequest request) {
        super(request);
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new StringReader(getRequestBody()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        return new ServletInputStreamWrapper(requestBody.getBytes());
    }
    private static class ServletInputStreamWrapper extends ServletInputStream {

        private final ByteArrayInputStream inputStream;

        public ServletInputStreamWrapper(byte[] body) {
            inputStream = new ByteArrayInputStream(body);
        }

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

        @Override
        public boolean isFinished() {
            return inputStream.available() == 0;
        }

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

        @Override
        public void setReadListener(ReadListener listener) {

        }
    }

    private String getRequestBody() throws IOException {
        if (requestBody == null) {
            StringBuilder requestBodyBuilder = new StringBuilder();
            BufferedReader reader = super.getReader();
            String line;
            while ((line = reader.readLine()) != null) {
                requestBodyBuilder.append(line);
            }
            requestBody = requestBodyBuilder.toString();
        }
        return requestBody;
    }
}

2. 编写工具类


import cn.hutool.core.util.StrUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author TheEnd
 */
public class ContentTypeUtil {

    public static boolean isBinaryContent(HttpServletRequest request) {
        String contentType = request.getContentType();
        return isBinaryContent(contentType);
    }
    public static boolean isBinaryContent(HttpServletResponse response) {
        String contentType = response.getContentType();
        return isBinaryContent(contentType);
    }
    public static boolean isBinaryContent(String contentType) {
        if (StrUtil.isEmpty(contentType)) {
            return false;
        }
        return contentType.startsWith("image/")
                || contentType.startsWith("audio/")
                || contentType.startsWith("video/")
                || contentType.startsWith("application/octet-stream");
    }

}

3. 编写过滤器, 并在过滤器中替换原始Request对象

import cn.hncht.plug.config.util.ContentTypeUtil;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

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

/**
 * @author TheEnd
 */
@Component
@Order(1)
public class HttpServletRequestWrapperFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        if (!(servletRequest instanceof HttpServletRequest)) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        if (ContentTypeUtil.isBinaryContent(request) || request.getContentLength() < 1) {
            filterChain.doFilter(request, servletResponse);
            return;
        }
        filterChain.doFilter(new RequestWrapper(request), servletResponse);
    }
}

4. 编写拦截器,读取请求体数据

@Slf4j
public class ApiLogSerializableInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String body = readBody(request);
        log.info("{}", body);
        return true;
    }

    private String readBody(HttpServletRequest request) {
        // 如果请求体是二进制流,不读取
        if (isBinaryContent(request)) {
            return "";
        }
        // 如果请求体是空的,不读取
        if (request.getContentLength() <= 0) {
            return "";
        }

        BufferedReader reader = null;
        try {
            reader = request.getReader();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        Stream<String> lines = reader.lines();
        return lines.collect(Collectors.joining(System.lineSeparator()));
    }
}

二. 配置拦截器生效

@Configuration
public class ConfigWebMvc implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new ApiLogSerializableInterceptor(sysLogService));
        WebMvcConfigurer.super.addInterceptors(registry);
    }
}

发表评论