解决SpringSpringBoot@RequestParam注解⽆法读取applicat。。。
Emmmm…最近在做项⽬的途中,有遇到⼀个⽅法需要接收的参数只有⼀个或者较少的时候就懒得写实体类去接收,使⽤spring框架都知道,接收单个参数就使⽤@RequestParam注解就好了,但是前端对应的Content-type是需要改成application/x-www-form-urlencoded,所以在接⼝⽂档上⾯特地标记了。但是…不知道前端是格式改了但是参数还是⽤的json格式没有改成键值对的⽅式传递还是什么原因,就⼀直说参数传不过来,叫我改回json格式的。。我也实在是懒,另外⼀个也觉得没必要,就⼀两个参数就新建⼀个实体,太浪费,但是这个问题让我觉得不灵活蛮久了,也⼀直没到办法,所以借这个机会,打开了我的开发神器,www.baidu…输⼊我的问题,了好久也没到有解决的⽅案,然后就想着看下Spring内部是怎么处理的吧,就稍微跟了下源码,下⾯就说下我解决的⽅案。
⼀、RequestMappingHandlerAdapter
RequestMappingHandlerAdapter实现了HandlerAdapter接⼝,顾名思义,表⽰handler的adapter,这⾥的handler指的是Spring处理具体请求的某个Controller的⽅法,也就是说HandlerAdapter指的是将当前请求适配到某个Handler的处理器。RequestMappingHandlerAdapter是HandlerAdapter的⼀个具体实现,主要⽤于将某个请求适配给@RequestMapping类型的Handler 处理,这⾥⾯就包含着请求数据和响应数据的处理。
/
/ 这⾥可以获取到处理程序⽅法参数解析器的⼀个列表
List<HandlerMethodArgumentResolver> argumentResolvers =
如果是想处理响应参数的话就使⽤
//这⾥可以获取到处理程序⽅法返回值的处理器
List<HandlerMethodReturnValueHandler> originalHandlers =
能获取到这个列表了,那需要加⼊我们⾃⼰定义的处理器应该不太⿇烦了吧?(这⾥不讲返回数据的⾃定义策略处理,⽹上也有其他⽂章,如果需要可以下)
⼆、HandlerMethodArgumentResolver
策略接⼝解决⽅法参数代⼊参数值在给定请求的上下⽂(翻译的源码注释)
简单的理解为:它负责处理你Handler⽅法⾥的所有⼊参:包括⾃动封装、⾃动赋值、校验等等。——————————————————————————————————————————
那么这个时候我已经知道了第⼀步获取到的那个列表中存放的类型是什么了,简⽽⾔之,我们只需要实现这个策略类,编写我们⾃⼰的算法或逻辑就⾏了
这个接⼝⾥⾯有两个⽅法需要实现:
第⼀个⽅法的作⽤:是否与给定⽅法的参数是由该解析器的⽀持。(如果返回true,那么就使⽤该类进⾏参数转换,如果返回false,那么继续下⼀个策略类)
第⼆个⽅法的作⽤:解决⽅法参数成从给定请求的⾃变量值。 由WebDataBinderFactory提供了⼀个⽅
法来创建⼀个WebDataBinder所需数据绑定和类型转换⽬的时实例。(简单来讲,就是转换参数值的,返回的就是解析的参数值)
三、RequestParamMethodArgumentResolver
这个类就是⽤来处理Controller的⽅法上有加@RequestParam注解的具体处理器。
⾸先会调⽤这个⽅法来确定是否使⽤这个处理器解析参数,那么我们也看到了,如果参数有RequestParam注解,那么则会使⽤该类进⾏处理,那么我们能不能效仿呢?
四、MyHandlerMethodArgumentResolver
这个没啥好说,就⾃⼰定义的参数解析器。
直接上代码吧
/**
* @BelongsProject:
* @BelongsPackage:
* @Author: hef
* @CreateTime: 2020-06-20 18:49
* @Description: 描述
*/
public class MyHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
/**
* 这个是处理@RequestParam注解的原本策略类
*/
private RequestParamMethodArgumentResolver requestParamMethodArgumentResolver;
/**
* 全参构造
*/
public MyHandlerMethodArgumentResolver(RequestParamMethodArgumentResolver requestParamMethodArgumentResolver){ questParamMethodArgumentResolver = requestParamMethodArgumentResolver;
}
/**
* 当参数前有@RequestParam注解时,会使⽤此解析器
* <p>
* 注:此⽅法的返回值将决定:是否使⽤此解析器解析该参数
*/
@Override
public boolean supportsParameter(MethodParameter methodParameter){
//很明显,就是判断是否有这个注解
return methodParameter.hasParameterAnnotation(RequestParam.class);
}
/**
* 解析参数
*/
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
final String applicationJson ="application/json";
HttpServletRequest request = NativeRequest(HttpServletRequest.class);
if(request == null){
throw new RuntimeException(" request must not be null!");
}
//获取到内容类型
String contentType = ContentType();
//如果类型是属于json 那么则跑⾃⼰解析的⽅法
if(null != contentType && ains(applicationJson )){
//获取参数名称
String parameterName = ParameterName();
//获取参数类型
Class<?> parameterType = ParameterType();
//因为json数据是放在流⾥⾯,所以要去读取流,
//但是ServletRequest的getReader()和getInputStream()两个⽅法只能被调⽤⼀次,⽽且不能两个都调⽤。
//所以这⾥是需要写个⾃定义的HttpServletRequestWrapper,主要功能就是需要重复读取流数据
String read =Reader());
//转换json
JSONObject jsonObject = JSON.parseObject(read);
Object o1;
if(jsonObject == null){
//这⾥有⼀个可能性就是⽐如get请求,参数是拼接在URL后⾯,但是如果我们还是去读流⾥⾯的数据就会读取不到
Map<String, String[]> parameterMap = ParameterMap();
Map<String, String[]> parameterMap = ParameterMap();
o1 = (parameterName);
}else{
o1 = (parameterName);
}
Object arg = null;
//如果已经获取到了值的话那么再做类型转换
if(o1 != null){
WebDataBinder binder = ateBinder(nativeWebRequest, null, parameterName);                arg = vertIfNecessary(o1, parameterType, methodParameter);
}
return arg;
}
//否则跑原本的策略类.
Object o = solveArgument(methodParameter,
modelAndViewContainer, nativeWebRequest, webDataBinderFactory);
return o;
}
/**
* 流转字符串
*
* @param bf
* @return
*/
private static String getRead(BufferedReader bf){
StringBuilder sb =new StringBuilder();
try{
char[] buff =new char[1024];
int len;
while((len = bf.read(buff))!=-1){
sb.append(buff,0, len);
}
}catch(IOException e){
e.printStackTrace();
}
String();
}
}
四、ConfigArgumentResolvers
springboot框架的作用⾃⼰的策略类已经写好了,那么怎么加⼊到配置中去呢?

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。