springBoot使用两个@RequestBody修饰入参

使用springboot实现用两个@RequestBody修饰入参

最近遇到Controller中需要多个@RequestBody的情况,但是发现并不支持这种写法,

这样导致

1、单个字符串等包装类型都要写一个对象才可以用@RequestBody接收;

2、多个对象需要封装到一个对象里才可以用@RequestBody接收。

结论:@RequestBody最多只能有一个,而@RequestParam()可以有多个。

但是可以自己实现多个@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入参:

在这里插入图片描述

报错:

在这里插入图片描述

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

重要源码节点:获取方法参数值

InvocableHandlerMethod.getMethodArgumentValues

我们看看这里能获取到两个入参类型,是我们的bean没错

在这里插入图片描述

并且这里也能获取到我们给的值:

在这里插入图片描述

接下来报错出现了,当要给第二个参数填值的时候,报错了:

在这里插入图片描述

报错在这里:可以看到报错信息了。

RequestResponseBodyMethodProcessor.readWithMessageConverters

在这里插入图片描述

在这里插入图片描述

不能有两个@RequestBody的原理

http请求后会有一个输入流InputStream,我们猜测,它是流读取完后,因为流需求关闭,所以当要对第二个参数进行填值的时候,就读取不到内容了。

源码进入到下面这个位置,读取内容为空:

在这里插入图片描述

支持两个@RequestBody解决方案

请求实现重写:

RepeatedlyRequestWrapper.java

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

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

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

再次请求:

在这里插入图片描述

已经可以了!!!

但是在接收请求参数的时候如果需要同时接收两个类,也建议封装为一个DTO对象进行接收!

  • 24
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值