likes
comments
collection
share

SpringBoot Web开发使用注解+参数解析器实现自定义参数解析

作者站长头像
站长
· 阅读数 46

前言

本篇文章介绍如何实现自定义参数解析,主要使用的是注解+ HandlerMethodArgumentResolver 方法参数处理器来实现这个功能。请观众老爷们多多支持,并在评论区批评指正!

1. 问题

SpringBoot Web开发使用注解+参数解析器实现自定义参数解析

在前一篇文章我们进行 jwt+token 登录校验时,token 中保留的信息是用户 ID。当我们在其他请求中需要当前登录的用户 ID 时,就需要解析 token,我们可以这样做:

SpringBoot Web开发使用注解+参数解析器实现自定义参数解析

但是出现了一个问题,当我们有许多接口都要获取用户 ID,那么都需要写一遍解析 token,获取用户 ID 的代码。难道我们在需要获取 token 的方法中都写一遍重复代码,没有一种像 SpringMVC 提供的形参自动注入功能呢?

比如说我们在方法上标注 String userId,他就会自动帮我们获取响应体中的 userId呢?这样不就避免了繁琐提高了代码的复用性以及更加优雅。

    @RequestMapping(value="/hi")
    @ResponseBody
    public ResponseResult<List> hello(@ResponseBody String userId) throws Exception{
        System.out.println(userId);

        List<String> list = new ArrayList<>();
        list.add("hi");
        return ResponseResult.setCommonStatusAndData(ResultCode.SUCCESS, list);
    }

想要实现以下的效果我们可以自定义参数解析。

2. 如何做

如果我们想实现在方法参数上标注@ResponseBody就能获取请求体中的数据那样的效果,我们可以使用 HandlerMethodArgumentResolver 接口来实现自定义的参数解析。

  1. 首先我们在项目根目录下创建 resolver 包,创建 UserIdArgumentResolver 类实现 HandlerMethodArgumentResolver 接口中的方法。
public class UserIdArgumentResolver implements HandlerMethodArgumentResolver {

    /**
     *    判断请求处理方法参数能否使用当前的参数解析器解析
     *    前端发起请求时,请求方法中的参数会被封装成 MethodParameter,
     *    通过 MethodParameter 来判断参数是否满足我们设立的条件
     */
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return false;
    }

    /**
     * 进行参数解析的方法,可以在方法中获取对应的方法中的参数,
     * 对参数进行处理,处理后的结果作为返回值返回,
     * 方法的返回值就会赋值给对应的方法参数
     */
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

        return null;
    }
}
  1. resolver 包下创建 @CurrentUserId 注解,用于将解析后的 userId,放入到被标记该注解的形参上。
/**
 * 该注解标注在方法参数上,且保留在运行时
 */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentUserId {

}
  1. 重写HandlerMethodArgumentResolver接口的 supportsParameter方法,判断方法中的参数是否标注 @CurrentUserId 注解;如果标注,则可以被当前的参数解析器解析。
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        //方法中的参数:标注有 @CurrentUserId 的注解可以被该参数解析器解析
        return parameter.hasParameterAnnotation(CurrentUserId.class);
    }
  1. 重写HandlerMethodArgumentResolver接口的 resolveArgument方法,对参数解析并返回处理后的值,给标注 @CurrentUserId 注解对应的方法参数。
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        // 1.获取请求头中的 token
        String token = webRequest.getHeader("token");
        // 2. 解析token,获取userId
        if(StringUtils.hasText(token)){
            Claims claims = JwtUtil.parseJWT(token);
            return claims.getSubject();
        }
        return null;
    }
  1. 在我们创建的 UserIdArgumentResolver 参数解析器类上标注 @Component 注解将其注入到容器中。
  2. 创建 MyMvcConfiguration 类实现 WebMvcConfigurer ,配置我们的自定义参数解析器,将其加入到参数解析器链中。
@Configuration
public class MyMvcConfiguration implements WebMvcConfigurer{

    @Autowired
    UserIdArgumentResolver userIdArgumentResolver;

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(userIdArgumentResolver);
    }
}

3. 测试

SpringBoot Web开发使用注解+参数解析器实现自定义参数解析

  1. 修改我们之前获取 userId 的处理方法,使用 @CurrentUserId 注解获取,并返回 userId到响应体中。
    @RequestMapping(value="/hi")
    @ResponseBody
    public ResponseResult hello(@CurrentUserId String userId) throws Exception{
        Map<String, String> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("userId", userId);
        return ResponseResult.setCommonStatusAndData(ResultCode.SUCCESS, objectObjectHashMap);
    }
  1. 重新启动我们的 SpringBoot 项目,重新登录获取 token

SpringBoot Web开发使用注解+参数解析器实现自定义参数解析

  1. 在请求头中携带 token,发起 GET 请求进行测试:

SpringBoot Web开发使用注解+参数解析器实现自定义参数解析

就成功获取我们自定义参数解析器解析的 userId了。

转载自:https://juejin.cn/post/7153567607265132557
评论
请登录