controller方法中简单参数@RequestBody无法处理

1. @RequestBody 问题
@RequestBody 只能处理自定义对象、map,、List,只能标记方法的一个参数对象,如果方法内有多个对象用@RequestBody 标记,需要重写Request头,来多次读取。@RequestBody 无法处理简单类型参数
2. 自定义注解@RequestSingleBody解决单个参数

自定义注解@RequestSingleBody

import org.springframework.core.annotation.AliasFor;
import org.springframework.web.bind.annotation.ValueConstants;

import java.lang.annotation.*;
/**
 * @RequestSingleBody 注解,接收单个参数
 *
 * @author liuxb
 * @date 2021/11/18 8:51
 */ 
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestSingleBody {

    @AliasFor("name")
    String value() default "";

    @AliasFor("value")
    String name() default "";

    boolean required() default true;

    String defaultValue() default ValueConstants.DEFAULT_NONE;
}

RequestSingleBodyHandler解析注解@RequestSingleBody

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cmbchina.base.Separators;
import com.cmbchina.base.annotation.RequestSingleBody;
import org.apache.commons.beanutils.ConvertUtils;
import org.springframework.core.MethodParameter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.util.Objects;

/**
 * 解析注解 @RequestSingleBody,解决@RequestBody无法处理单json参数
 *
 * @author liuxb
 * @date 2021/11/18 9:03
 */
public class RequestSingleBodyHandler implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(RequestSingleBody.class) && parameter.getParameterAnnotation(RequestSingleBody.class).required();
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        RequestSingleBody requestSingleParam = parameter.getParameterAnnotation(RequestSingleBody.class);
        //获取方法的参数名
        String name = (requestSingleParam != null && org.springframework.util.StringUtils.hasLength(requestSingleParam.name()) ?
                requestSingleParam.name() : parameter.getParameterName());
        Assert.state(name != null, "Unresolvable parameter name");

        //获取方法的参数类型
        Class<?> parameterType = parameter.getParameterType();

        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        BufferedReader reader = request.getReader();
        StringBuilder sb = new StringBuilder();
        char[] buf = new char[1024];
        int rd;
        while ((rd = reader.read(buf)) != -1) {
            sb.append(buf, 0, rd);
        }
        //只处理对象,数组形式不处理
        if (sb.toString().startsWith(Separators.CURLY_BRAKET_OPEN)) {
            //单字段只支持基本类型,包装类,字符串类型
            Assert.isTrue(ClassUtils.isPrimitiveOrWrapper(parameterType) || parameterType.equals(String.class) ,
                    "@RequestSingleBody只支持简单类型,不支持复杂类型:" + parameterType.getName());

            JSONObject jsonObject = JSONObject.parseObject(sb.toString());
            return jsonObject.getObject(name, parameterType);
        }
        return null;
    }

}

Separators 类


/**
 * 分隔符类
 *
 * @author liuxb
 * @date 2021/11/13 10:15
 */
public interface Separators {
    /**
     * 下划线
     */
    String UNDERLINE = "_";
    /**
     * 中间杠
     */
    String HYPHEN = "-";
    /**
     * 英文逗号
     */
    String COMMA = ",";
    /**
     * 左斜杠
     */
    String LSLASH = "/";

    /**
     * windwows文件路径分隔符
     */
    String RSLASH = "\\";
    /**
     * 单冒号
     */
    String COLON = ":";
    /**
     * 双冒号
     */
    String DOUBLE_COLON = "::";
    /**
     * 单竖线
     */
    String LINE = "|";
    /**
     * 双竖线
     */
    String DOUBLE_LINE = "||";
    /**
     * 英文分号
     */
    String SEMICOLON = ";";
    /**
     * 点
     */
    String DOT = ".";
    /**
     * and符号
     */
    String AND = "&";
    /**
     * @符号
     */
    String AT = "@";
    /**
     * 星号
     */
    String StAR = "*";
    /**
     * #符号
     */
    String Comment_Sign = "#";
    /**
     * $符号
     */
    String Dollar_Sign = "$";
    /**
     * 问号
     */
    String QUESTION_MARK = "?";
    /**
     * 等于号
     */
    String EQUAL = "=";
    /**
     * 左小括号
     */
    String PARENTHESIS_OPEN = "(";
    /**
     * 右小括号
     */
    String PARENTHESIS_CLOSE = ")";
    /**
     * 左大括号
     */
    String CURLY_BRAKET_OPEN = "{";
    /**
     * 右大括号
     */
    String CURLY_BRAKET_CLOSE = "}";
    /**
     * 左括号
     */
    String BRAKET_OPEN = "[";
    /**
     * 右中括号
     */
    String BRAKET_CLOSE = "]";
    /**
     * 空格
     */
    String SPACE = " ";
    /**
     * 换行符
     */
    String LINE_BREAK = "\n";
    /**
     * 换行符
     */
    String R_BREAK = "\r";
}

注册注册自定义的参数解析器,过滤器可保证流多次读取

import com.cmbchina.base.handle.RequestSingleBodyHandler;
import com.cmbchina.base.converter.BodyReaderRequestFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;


/**
 * webmvc配置
 *
 * @author liuxb
 * @date 2021/11/13 17:19
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    /**
     * 注册自定义的参数解析器
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new RequestSingleBodyHandler());
        WebMvcConfigurer.super.addArgumentResolvers(argumentResolvers);
    }

    @Bean
    public FilterRegistrationBean filterRegist() {
        FilterRegistrationBean frBean = new FilterRegistrationBean();
        frBean.setFilter(new BodyReaderRequestFilter());
        //多个过滤器时指定过滤器的执行顺序
        frBean.setOrder(1);
        frBean.addUrlPatterns("/*");
        return frBean;
    }

}

controller的方法中使用

    /**
     * 根据ID查询单条记录
     *
     * @param id id
     * @return
     */
    @PostMapping("/findById")
    public RetResult<RewardInfo> findById(@RequestSingleBody @NotNull(message="id不能为空") Integer id) {
        return RetModel.ok().setData(rewardInfoService.findById(id));
    }
3. @RequestBody标记多个参数

重写Request头
BodyReaderRequestFilter 过滤器

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
* BodyReaderRequestFilter 过滤器 处理httpRequest包装类,实现request多次读取
*
* @author liuxb
* @date 2021/12/9 10:00
*/
public class BodyReaderRequestFilter implements Filter {
   @Override
   public void init(FilterConfig filterConfig) throws ServletException {

   }

   @Override
   public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
       HttpServletRequest request = (HttpServletRequest) req;
       HttpServletResponse response = (HttpServletResponse) res;
       BodyReaderRequestWrapper requestWrapper = new BodyReaderRequestWrapper(request);
       if (requestWrapper == null) {
           filterChain.doFilter(request, response);
       } else {
           filterChain.doFilter(requestWrapper, response);
       }
   }

   @Override
   public void destroy() {

   }
}

BodyReaderRequestWrapper 包装类

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;

/**
 * HttpServletRequest 包装类,实现多次从request中读取流
 *
 * @author liuxb
 * @date 2021/12/4 18:37
 */
public class BodyReaderRequestWrapper extends HttpServletRequestWrapper {
    private final String body;

    /**
     * 构造器
     * @param request
     * @throws IOException
     */
    public BodyReaderRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        StringBuilder sb = new StringBuilder();
        InputStream ins = request.getInputStream();
        BufferedReader isr = null;
        try {
            if (ins != null) {
                isr = new BufferedReader(new InputStreamReader(ins));
                char[] charBuffer = new char[128];
                int readCount = 0;
                while ((readCount = isr.read(charBuffer)) != -1) {
                    sb.append(charBuffer, 0, readCount);
                }
            } else {
                sb.append("");
            }
        } catch (IOException e) {
            throw e;
        } finally {
            if (isr != null) {
                isr.close();
            }
        }

        sb.toString();
        body = sb.toString();
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayIns = new ByteArrayInputStream(body.getBytes());
        ServletInputStream servletIns = new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }

            @Override
            public int read() throws IOException {
                return byteArrayIns.read();
            }
        };
        return servletIns;
    }
}

注册过滤器

    @Bean
    public FilterRegistrationBean filterRegist() {
        FilterRegistrationBean frBean = new FilterRegistrationBean();
        frBean.setFilter(new BodyReaderRequestFilter());
        //多个过滤器时指定过滤器的执行顺序
        frBean.setOrder(1);
        frBean.addUrlPatterns("/*");
        return frBean;
    }
4. 测试
@Validated
@RestController
@RequestMapping("/activityInfo")
public class ActivityInfoController {
    @Autowired
    private ActivityInfoService activityInfoService;
    /**
     * 分页查询
     *
     * @param activityInfo
     * @return
     */
    @PostMapping("/findByPage")
    public RetResult<PageResult<ActivityInfo>> findByPage(@RequestBody ActivityInfo activityInfo, @RequestBody Page page) {
        return RetModel.ok().setData(activityInfoService.findByPage(activityInfo, page));
    }

    /**
     * 根据id查询单条记录
     *
     * @param id id
     * @return
     */
    @PostMapping("/findById")
    public RetResult<ActivityInfo> findById(@RequestSingleBody @NotBlank(message = "id不能为空") String id) {
        return RetModel.ok().setData(activityInfoService.findById(id));
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值