栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot自定义控制层参数解析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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 {
    
    
    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.http.HttpServletRequest;
import java.util.Random;


public class RedisMethodArgumentResolver implements HandlerMethodArgumentResolver {
    
    private static final Logger log = LoggerFactory.getLogger(RedisMethodArgumentResolver.class);
    
    
    @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 {
        // 获取http 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实现
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    
    
    @Override
    public void addArgumentResolvers(List resolvers) {
        resolvers.add(new RedisMethodArgumentResolver());
    }
}

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

2、通过BeanPostProcessor来实现

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

@Component
static 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、编写一个简单的控制层
@RestController
public 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);
    }
}

该控制层比较简单,对外提供来一个简单的apihttp://localhost:8080/redisArgumentResolver?hello=123。该api存在2个参数hello和redisValue,其中hello参数的值是从请求参数中获取,redisValue的值是从我们自己定义的参数
解析器中获取。

五、测试
curl http://localhost:8080/redisArgumentResolver?hello=123

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

六、完整代码

完整代码

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/658050.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号