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