How to Use Multiple @RequestBody Parameters in Spring Boot 3
This article explains why a Spring Boot controller can read the request body only once, demonstrates wrapping multiple objects in a DTO, and provides a custom HttpServletRequestWrapper with a filter to enable multiple @RequestBody parameters while noting the performance impact.
1. Introduction
Using @RequestBody on a controller method binds the request body to a Java object. Only one request body can be read because the underlying ServletRequest#getInputStream can be called only once.
2. Solution
2.1 Wrap multiple objects in a DTO
public class DTO {
private User user;
private Person person;
// getter, setter
}Controller:
@PostMapping("")
public Object save(@RequestBody DTO dto) {
// TODO
return "success";
}2.2 Wrap the HttpServletRequest
Define a custom HttpServletRequestWrapper that caches the input stream so it can be read multiple times.
public class PackHttpServletRequestWrapper extends HttpServletRequestWrapper {
private ByteArrayInputStream bais;
public PackHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
StreamUtils.copy(request.getInputStream(), baos);
bais = new ByteArrayInputStream(baos.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public ServletInputStream getInputStream() throws IOException {
bais.reset();
return new ServletInputStream() {
@Override public boolean isFinished() { return false; }
@Override public boolean isReady() { return false; }
@Override public void setReadListener(ReadListener listener) {}
@Override public int read() throws IOException { return bais.read(); }
};
}
}Filter that replaces the request with the wrapper:
public class PackRequestWrapperFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
PackHttpServletRequestWrapper requestWrapper = new PackHttpServletRequestWrapper(request);
chain.doFilter(requestWrapper, resp);
}
}Register the filter in Spring Boot:
@Bean
FilterRegistrationBean<Filter> packRequestWrapperFilter() {
FilterRegistrationBean<Filter> reg = new FilterRegistrationBean<>();
reg.setFilter(new PackRequestWrapperFilter());
reg.setUrlPatterns(List.of("/*"));
return reg;
}The above configuration allows multiple @RequestBody parameters by reading the cached stream each time.
Note: Using multiple @RequestBody parameters incurs performance overhead because the request body is read and converted multiple times.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
