自定义SpringMVC参数解析器

问题

在维护公司开发的一个项目中,发现很多地方都要获取当前登录用户对象,而且是根据请求头中的token值去redis中获取用户信息,于是就很多地方出现了如下类似的代码

public Object commentAdd(TravelComment comment, HttpServletRequest request){
    //根据token获取用户信息
    String token = request.getHeader("token");
    UserInfo user = userInfoRedisService.getUserByToken(token);

    //...其他代码
    return JsonResult.success();
}
复制代码

每次都要写HttpServletRequest request,然后根据请求头中的token去获取当前登录对象,这样就导致了很多地方代码都重复了,要如何解决这种问题呢?

解决方案

在请求映射方法列表声明即可,就可以获取当前登录用户对象,代码如下

public Object commentAdd(TravelComment comment, UserInfo userInfo){
    UserInfo user = userInfo;

    //...其他代码
    return JsonResult.success();
}
复制代码

要如何实现上述操作呢? 那就是自定义SpringMVC的参数解析器来完成这项工作,因为通过现有的SpringMVC自带的参数解析器无法完成我们的需求

创建参数解析器

/**
 * 将请求映射方法列表中UserInfo类型参数进行解析
 * 解析成当前登录用户对象
 */
public class UserInfoArgumentResolver implements HandlerMethodArgumentResolver {
    @Autowired
    private IUserInfoRedisService userInfoRedisService;
    //判断当前解析器支持解析的参数类型,返回true表示支持意思
    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        return methodParameter.getParameterType() == UserInfo.class;
    }
    //解析器解析规则:
    //此处将UserInfo类型参数, 解析成当前登录用户对象。
    //当supportsParameter方法返回true时候才执行
    @Override
    public Object resolveArgument(MethodParameter methodParameter,
                                  ModelAndViewContainer modelAndViewContainer,
                                  NativeWebRequest nativeWebRequest,
                                  WebDataBinderFactory webDataBinderFactory) throws Exception {
        HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
        String token = request.getHeader("token");
        return userInfoRedisService.getUserByToken(token);
    }
}
复制代码

将自定义参数解析器添加到Spring容器中

@Configuration
public class WebConfig implements WebMvcConfigurer{

    //自定义的用户解析器
    @Bean
    public UserInfoArgumentResolver userInfoArgumentResolver(){
        return new UserInfoArgumentResolver();
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(userInfoArgumentResolver());
    }
}
复制代码

上述的所有操作,确实可以达到我们想要的结果,但是还是存在一些问题,并不是所有的请求映射方法列表中有UserInfo userInfo都要走自定义的参数解析器,那要如何来区分是用框架自带的解析器还是自定义的呢?

使用自定义的注解来区分

在需要使用自定义解析器的请求映射方法列表中添加自定义注解

/**
 * 用户参数注入注解
 * 贴有该注解用户参数使用自定义的参数解析器
 */
@Target({ElementType.PARAMETER})  //表示贴在参数上
@Retention(RetentionPolicy.RUNTIME)
public @interface UserParam {
}
复制代码

接口代码改进

public Object commentAdd(TravelComment comment, @UserParam UserInfo userInfo){
    UserInfo user = userInfo;

    //...其他代码
    return JsonResult.success();
}
复制代码

以上就是最终的解决方法!