0
点赞
收藏
分享

微信扫一扫

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

_karen 2022-04-29 阅读 28

1. @RequestBody 问题

@RequestBody 只能处理自定义对象,map, List(不可以),只能标记一个参数

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

}

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

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标记多个参数

需求重写请求流
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;
    }
举报

相关推荐

0 条评论