SpringBoot自定义控制层参数解析

网友投稿 257 2022-09-26

SpringBoot自定义控制层参数解析

SpringBoot自定义控制层参数解析

​​一、背景​​​​二、参数是如何解析的​​​​三、需求​​​​四、实现​​

​​1、编写一个Redis注解​​​​2、编写参数解析类​​​​3、配置到Spring的上下文中​​

​​1、通过WebMvcConfigurer实现​​​​2、通过BeanPostProcessor来实现​​

​​4、编写一个简单的控制层​​

​​五、测试​​​​六、完整代码​​

一、背景

在Spring的Controller中,我们通过​​@RequestParam​​​或​​@RequestBody​​就可以将请求中的参数映射到控制层具体的参数中,那么这个是怎么实现的呢?如果我现在控制层中的某个参数的值是从​​Redis​​中来,那么应该如何实现呢?

二、参数是如何解析的

从上图中可以我们的参数最终会通过​​HandlerMethodArgumentResolver​​来解析,那么知道了这个后,我们就可以实现自己的参数解析了。

三、需求

如果我们控制层方法的参数中存在​​@Redis​​标注,那么此参数的值应该从redis中获取,不用从请求参数中获取。

从上图中可知​​@Redis(key = "redisKey") String redisValue​​​这个参数就需要从​​Redis​​中获取。

四、实现

此处我们不会真的从​​Redis​​中获取值,模拟从Redis中获取值即可。

1、编写一个Redis注解

@Target({ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)public @interface Redis { /** * redis中的Key */ String key(); }

在控制层的方法上,被此处注解标注的方法参数,都从Redis中获取,都走我们自己定义的参数解析器。

2、编写参数解析类

package com.huan.study.argument.resolver;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.core.MethodParameter;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.java.util.Random;/** * 从redis中获取值放入到参数中 * */public class RedisMethodArgumentResolver implements HandlerMethodArgumentResolver { private static final Logger log = LoggerFactory.getLogger(RedisMethodArgumentResolver.class); /** * 处理参数上存在@Redis注解的 */ @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(Redis.class); } /** * 解析参数 */ @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { // 获取request HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); log.info("当前请求的路径:[{}]", request.getRequestURI()); // 获取到这个注解 Redis redis = parameter.getParameterAnnotation(Redis.class); // 获取在redis中的key String redisKey = redis.key(); // 模拟从redis中获取值 String redisValue = "从redis中获取的值:" + new Random().nextInt(100); log.info("从redis中获取到的值为:[{}]", redisValue); // 返回值 return redisValue; }}

1、通过​​supportsParameter​​​方法判断我们应该处理哪些参数,此处处理的是参数上存在​​@Redis​​​注解的。 2、通过​​​resolveArgument​​方法,获取到参数的具体的值。比如从Redis中获取,代码中没有真的从Redis中获取,只是模拟从Redis中获取。

3、配置到Spring的上下文中

此处我们最好将我们自己的参数解析器放置在第一位,否则可能会有问题。下方提供了2种方式,第一种方式无法达到我们的需求、我们采用第二种方式来实现

1、通过WebMvcConfigurer实现

@Configurationpublic class WebMvcConfig implements WebMvcConfigurer { /** * 这个地方加载的顺序是在默认的HandlerMethodArgumentResolver之后的 */ @Override public void addArgumentResolvers(List resolvers) { resolvers.add(new RedisMethodArgumentResolver()); }}

从上图可知,我们自己的参数解析器不是在第一位,这样可能达不到我们想要的效果,此处不考虑这种方式。

2、通过BeanPostProcessor来实现

​​BeanPostProcessor​​可以在一个Bean完全初始化之后来执行一些操作,此处我们通过这种方式,将我们自己的参数解析器放置在第一位。

@Componentstatic class CustomHandlerMethodArgumentResolverConfig implements BeanPostProcessor { @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof RequestMappingHandlerAdapter) { final RequestMappingHandlerAdapter adapter = (RequestMappingHandlerAdapter) bean; final List argumentResolvers = Optional.ofNullable(adapter.getArgumentResolvers()) .orElseGet(ArrayList::new); final ArrayList handlerMethodArgumentResolvers = new ArrayList<>(argumentResolvers); // 将我们自己的参数解析器放置到第一位 handlerMethodArgumentResolvers.add(0, new RedisMethodArgumentResolver()); adapter.setArgumentResolvers(Collections.unmodifiableList(handlerMethodArgumentResolvers)); return adapter; } return bean; }}

从上图可知,我们自己的参数解析器在第一位,这样就达到我们想要的效果,此处使用这种方式。

4、编写一个简单的控制层

/** * @author huan.fu 2021/12/7 - 下午3:36 */@RestControllerpublic class RedisArgumentController { private static final Logger log = LoggerFactory.getLogger(RedisArgumentController.class); @GetMapping("redisArgumentResolver") public void redisArgumentResolver(@RequestParam("hello") String hello, @Redis(key = "redisKey") String redisValue) { log.info("控制层获取到的参数值: hello:[{}],redisValue:[{}]", hello, redisValue); }}

该控制层比较简单,对外提供来一个简单的api​​解析器中获取。

五、测试

curl http://localhost:8080/redisArgumentResolver?hello=123

由上图可知我们自己定义的参数解析器工作了。

六、完整代码

​​完整代码​​

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:美国批准英特尔供货华为,特朗普放行主要考虑美企利益!
下一篇:在SpringBoot中使用logback优化异常堆栈的输出
相关文章

 发表评论

暂时没有评论,来抢沙发吧~