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);
}
}