springboot自定义参数解析器
创始人
2024-03-17 23:07:35
0

springboot自定义参数解析器

  • 1.前言
  • 2.springMVC参数解析器
  • 3.如何自定义参数解析器
  • 4测试

1.前言

1.springMVC是如何把参数解析完毕后注入到controller方法参数上的呢?在javaweb阶段,我们都学过使用HttpServletRequest这个对象获取参数,比如 request.getParameter(parameterName);那么springMVC其实也是用于这个来进行获取原始的参数的。

比如:@RequestBody,@RequestParam注解等

2.springMVC参数解析器

在请求经过原生的servlet过后,会将请求通过DispatchServlet将请求分发下去,然后执行到InvocableHandlerMethod.invokeForRequest()方法的时候,其中 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); 这一行就是获取请求参数的。最终会来到getMethodArgumentValues()这个方法,这个方法,最关键的其中一行就是 this.resolvers.supportsParameter(parameter) ,这个会找所有实现了 HandlerMethodArgumentResolver 接口的bean,挨个循环调用supportsParameter()这个方法,看看那个解析器能解析这个参数。如果能解析,然后执行 this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); 解析完获取到指定的参数然后返回。最后会根据请求路径找到对应的controller的method对象,然后通过反射的方式调用,并且把解析完毕的参数传递进去,这样走到我们controller的时候,controller参数就被绑定上了。

通过debug可以看到 最开始的参数解析器有31个,其中标记红色的那个是我自定义的。

image-20221204200429632

HandlerMethodArgumentResolver接口就是参数解析器,supportsParameter表示是否支持解析,resolveArgument()是执行具体的解析逻辑。


public interface HandlerMethodArgumentResolver {/*** Whether the given {@linkplain MethodParameter method parameter} is* supported by this resolver.* @param parameter the method parameter to check* @return {@code true} if this resolver supports the supplied parameter;* {@code false} otherwise*/boolean supportsParameter(MethodParameter parameter);/*** Resolves a method parameter into an argument value from a given request.* A {@link ModelAndViewContainer} provides access to the model for the* request. A {@link WebDataBinderFactory} provides a way to create* a {@link WebDataBinder} instance when needed for data binding and* type conversion purposes.* @param parameter the method parameter to resolve. This parameter must* have previously been passed to {@link #supportsParameter} which must* have returned {@code true}.* @param mavContainer the ModelAndViewContainer for the current request* @param webRequest the current request* @param binderFactory a factory for creating {@link WebDataBinder} instances* @return the resolved argument value, or {@code null} if not resolvable* @throws Exception in case of errors with the preparation of argument values*/@NullableObject resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;}

可以看到这个接口有很多的实现类,比如::@RequestBody,@RequestParam,@CookieValue等注解,都是有对应实现的

image-20221204200645733

3.如何自定义参数解析器

因为我们知道POST请求使用@RequestBody是可以接收json格式的数据直接绑定到对应的参数名对象上,而GET请求是不可以的,那接下来我们就实现一个@JsonParam注解,然后让GET请求也支持json格式的参数传递。

@JsonParam:

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface JsonParam {String value() default "";String name() default "";boolean required() default true;String defaultValue() default ValueConstants.DEFAULT_NONE;
}

实现HandlerMethodArgumentResolver接口,指定遇到什么参数的时候进行解析,每解析controller方法参数的每一项时都会调用HandlerMethodArgumentResolver的supportsParameter和resolveArgument方法进行解析

public class GetQueryJsonParamResolver implements HandlerMethodArgumentResolver {@Overridepublic boolean supportsParameter(MethodParameter parameter) {Annotation[] annotations = parameter.getParameterAnnotations();for (int i = 0; i < annotations.length; i++) {Annotation item = annotations[i];if (item.annotationType().equals(JsonParam.class)){return true;}}return false;}@Overridepublic Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);String parameterName = parameter.getParameterName();Annotation[] annotations = parameter.getParameterAnnotations();String params = request.getParameter(parameterName);if (StringUtils.isBlank(params)){for (Annotation item : annotations) {if (item instanceof JsonParam) {JsonParam param = (JsonParam) item;params = request.getParameter(param.value());if (StringUtils.isBlank(params)) {params = param.defaultValue();}if (StringUtils.isBlank(params) && param.required() || params.equals(ValueConstants.DEFAULT_NONE)) {throw new RuntimeException(parameterName + ":不能为空");}}}}Class parameterType = parameter.getParameterType();Object bean = JSONUtil.toBean(params, parameterType);return bean;}
}

最后我们在配置类中添加参数解析器 添加完毕后,参数解析器从原来的31个就会变成32个,到解析参数的时候就会走到我们自己写的参数解析器哪里,解析完毕后把对应的参数返回去。

@Configuration
public class StaticConfig implements WebMvcConfigurer {@Overridepublic void addArgumentResolvers(List resolvers) {resolvers.add(new GetQueryJsonParamResolver());}
}

4测试

最后我们在controller上写一个方法进行测试即可,可以看到我们传递的参数被成功的解析到

image-20221204201452924

    @GetMapping("/requestParam")public void requestParam(@JsonParam UserInfo userInfo, HttpServletResponse response){AjaxResult ajaxResult = new AjaxResult<>(200,"操作成功",0,"请求成功",userInfo);ResponseUtil.response(response,ajaxResult);}

esult ajaxResult = new AjaxResult<>(200,“操作成功”,0,“请求成功”,userInfo);
ResponseUtil.response(response,ajaxResult);

}

相关内容

热门资讯

汽车油箱结构是什么(汽车油箱结... 本篇文章极速百科给大家谈谈汽车油箱结构是什么,以及汽车油箱结构原理图解对应的知识点,希望对各位有所帮...
美国2年期国债收益率上涨15个... 原标题:美国2年期国债收益率上涨15个基点 美国2年期国债收益率上涨15个基...
嵌入式 ADC使用手册完整版 ... 嵌入式 ADC使用手册完整版 (188977万字)💜&#...
重大消息战皇大厅开挂是真的吗... 您好:战皇大厅这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游戏...
盘点十款牵手跑胡子为什么一直... 您好:牵手跑胡子这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游...
senator香烟多少一盒(s... 今天给各位分享senator香烟多少一盒的知识,其中也会对sevebstars香烟进行解释,如果能碰...
终于懂了新荣耀斗牛真的有挂吗... 您好:新荣耀斗牛这款游戏可以开挂,确实是有挂的,需要了解加客服微信8435338】很多玩家在这款游戏...
盘点十款明星麻将到底有没有挂... 您好:明星麻将这款游戏可以开挂,确实是有挂的,需要了解加客服微信【5848499】很多玩家在这款游戏...
总结文章“新道游棋牌有透视挂吗... 您好:新道游棋牌这款游戏可以开挂,确实是有挂的,需要了解加客服微信【7682267】很多玩家在这款游...
终于懂了手机麻将到底有没有挂... 您好:手机麻将这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游戏...