Xử Lý Dữ Liệu @RequestBody Trong Spring Boot Mà Không Làm Mất Dữ Liệu

Khi xử lý dữ liệu JSON qua @RequestBody trong Spring Boot, luồng đầu vào chỉ được đọc một lần. Nếu không xử lý đúng cách, các thành phần phía sau sẽ không nhận được dữ liệu. Giải pháp là tạo wrapper lưu trữ luồng và cung cấp lại cho các thành phần tiếp theo.

public class CustomRequestWrapper extends HttpServletRequestWrapper { private final String payload; public CustomRequestWrapper(HttpServletRequest request) throws IOException { super(request); StringBuilder content = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8))) { char[] buffer = new char[2048]; int length; while ((length = reader.read(buffer)) != -1) { content.append(buffer, 0, length); } } payload = content.toString(); } @Override public ServletInputStream getInputStream() throws IOException { ByteArrayInputStream input = new ByteArrayInputStream(payload.getBytes(StandardCharsets.UTF_8)); return new ServletInputStream() { @Override public int read() throws IOException { return input.read(); } @Override public boolean isFinished() { return input.available() == 0; } @Override public boolean isReady() { return true; } @Override public void setReadListener(ReadListener listener) { } }; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream(), StandardCharsets.UTF_8)); } public String getPayload() { return payload; } }

Áp dụng trong filter để ghi log và xử lý tiếp:

@Component public class RequestDataFilter implements Filter { private static final Logger log = LoggerFactory.getLogger(RequestDataFilter.class); @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpReq = (HttpServletRequest) req; String path = httpReq.getRequestURI(); String httpMethod = httpReq.getMethod(); CustomRequestWrapper wrappedRequest = new CustomRequestWrapper(httpReq); String paramData = JsonUtils.serialize(httpReq.getParameterMap()); log.info("URI: {}, Method: {}, Params: {}, Body: {}", path, httpMethod, paramData, wrappedRequest.getPayload()); chain.doFilter(wrappedRequest, res); } }

Có thể sử dụng interceptor cho các controller, nhưng filter thường được ưa chuộng hơn.

Thẻ: spring-boot servlet-filter json-processing request-wrapper spring-mvc

Đăng vào ngày 27 tháng 8 lúc 05:14