目录
Springboot可以用多个@RequestBody吗?且看网上的文章是怎么说的:
人家说了:
@RequestBody最多只能有一个,而@RequestParam()可以有多个。
实际是不是这样呢,听人家说100句,不如自己动手做一次。
先说结论:
Springboot默认只能读取一个@RequestBody,但是可以自己实现多个@RequestBody。
多个@RequestBody验证(Map类型)
这边来个测试例子:
发起请求:
结果直接报错:
Required request body is missing: public java.util.Map<java.lang.String, java.lang.Object> com.xy.controller.TestController.tt(java.util.Map<java.lang.String, java.lang.Object>,java.util.Map<java.lang.String, java.lang.Object>)
说明确实不能用两个@RequestBody.
多个@RequestBody验证(Bean类型)
bean:
两个bean入参:
不信邪,再用两个bean试试。也一样的报错:
跟踪源码,看看为什么不行?
重要源码节点:获取方法参数值
InvocableHandlerMethod.getMethodArgumentValues
我们看看这里能获取到两个入参类型,是我们的bean没错
并且这里也能获取到我们给的值:
接下来报错出现了,当要给第二个参数填值的时候,报错了:
报错在这里:可以看到报错信息了。
RequestResponseBodyMethodProcessor.readWithMessageConverters
不能有两个@RequestBody的原理
http请求后会有一个输入流InputStream,我们猜测,它是流读取完后,因为流需求关闭,所以当要对第二个参数进行填值的时候,就读取不到内容了。
源码进入到下面这个位置,读取内容为空:
支持两个@RequestBody!!!!!!
知道了原理,那就解决吧,能实现支持两个@RequestBody吗?
能能能!!!!
能能能!!!!
能能能!!!!
所以下次见到别人的项目里有两个@RequestBody,不要感觉到奇怪了。
请求实现重写:
RepeatedlyRequestWrapper.java
package com.xy.config;
import cn.hutool.core.io.IoUtil;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletResponse;
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.InputStreamReader;
public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException {
super(request);
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
body = IoUtil.readBytes(request.getInputStream(), false);
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
@Override
public int available() throws IOException {
return body.length;
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
}
过滤器:
RequestFilter.java
package com.xy.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
public class RequestFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
if (request instanceof HttpServletRequest
&& StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) {
requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response);
}
if (null == requestWrapper) {
chain.doFilter(request, response);
} else {
chain.doFilter(requestWrapper, response);
}
}
}
过滤器配置:
FilterConfig.java
package com.xy.config;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@SuppressWarnings({"rawtypes", "unchecked"})
@Bean
public FilterRegistrationBean someFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new RequestFilter());
registration.addUrlPatterns("/*");
registration.setName("requestFilter");
registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
return registration;
}
}
再次请求:
当当!!已经可以了!!!