JAVA面试题分享五百三十:Springboot接口能用两个@RequestBody修饰入参吗?

目录

多个@RequestBody验证(Map类型)

多个@RequestBody验证(Bean类型)

跟踪源码,看看为什么不行?

不能有两个@RequestBody的原理

支持两个@RequestBody!!!!!!


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;
@Slf4jpublic 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;
@Configurationpublic 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;    }}

再次请求:

图片

当当!!已经可以了!!!

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

之乎者也·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值