SpringMvc参数解析器HandlerMethodArgumentResolver

介绍

首先什么是Handler?我的理解是Spring MVC中真正用于处理业务逻辑的类,也就是常说的、标注了@Controller注解的Controller类;Controller类中使用@RequestMapping(或GetMapping等变种注解)标注的方法称为处理器方法;处理器方法的参数指的就是该方法的参数。
处理器方法参数解析器HandlerMethodArgumentResolver用于自动向处理器方法参数注入值(自动赋值)。
从代码角度说HandlerMethodArgumentResolver是一个接口,开发者实现该接口可以实现自定义的Controller方法的参数的自动注入。

/**
 * Strategy interface for resolving method parameters into argument values in
 * the context of a given request.
 *
 * @author Arjen Poutsma
 * @since 3.1
 * @see HandlerMethodReturnValueHandler
 */
public interface HandlerMethodArgumentResolver {

    /**
     * 对应的方法参数是否支持该处理器解析处理
     * @param 要检查的方法参数,MethodParameter Spring MVC中对方法参数的包装类
     * @return 如果支持该参数则返回true,否则返回false
     */
	boolean supportsParameter(MethodParameter parameter);

   /**
    * 从给定的request中解析出方法参数所需要的值,并返回
    * ModelAndViewContainer 提供了request中的model
    * WebDataBinderFactory 提供了创建WebDataBinder实例的方法(当需要绑定数据和类型转换时)
    * @param parameter 要解析的方法参数。
    * @param mavContainer 当前请求的ModelAndViewContainer
    * @param webRequest 当前请求对象request
    * @param binderFactory 创建WebDataBinder实例的工厂
    * @return 返回解析后的参数值,如果不能解析返回null
    * @throws Exception 如果解析参数值出错抛出异常
    */
	@Nullable
	Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;

}

需求

很多Controller方法,需要用户信息,以便做后续的用户相关操作。但是我们token中同样是可以获取到用户信息这里我们通过HandlerMethodArgumentResolver注入

注解定义

/**
 * 请求的方法参数SysUser上添加该注解,则注入当前登录人信息
 * 例1:public void test(@LoginUser SysUser user) //只有username 和 roles
 * 例2:public void test(@LoginUser(isFull = true) SysUser user) //能获取SysUser对象的所有信息
 */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LoginUser {
    /**
     * 是否查询SysUser对象所有信息
     */
    boolean isFull() default false;
}

 HandlerMethodArgumentResolver实现

请求是接口参数中满足supportsParameter条件
进入resolveArgument返回user对象

public class UserArgumentResolver implements HandlerMethodArgumentResolver {
    private final UserService userService;

    public UserArgumentResolver(UserService userService) {
        this.userService = userService;
    }

    /**
     * 入参筛选
     * @param methodParameter 参数集合
     * @return 格式化后的参数
     */
    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        return methodParameter.hasParameterAnnotation(LoginUser.class) && methodParameter.getParameterType().equals(SysUser.class);
    }

    /**
     * @param methodParameter       入参集合
     * @param modelAndViewContainer model 和 view
     * @param nativeWebRequest      web相关
     * @param webDataBinderFactory  入参解析
     * @return 包装对象
     */
    @Override
    public Object resolveArgument(MethodParameter methodParameter,
                                  ModelAndViewContainer modelAndViewContainer,
                                  NativeWebRequest nativeWebRequest,
                                  WebDataBinderFactory webDataBinderFactory) {
        LoginUser loginUser = methodParameter.getParameterAnnotation(LoginUser.class);
        boolean isFull = loginUser.isFull();
        HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
        String username = request.getHeader(SecurityConstants.USER_HEADER);
        if (StrUtil.isBlank(username)) {
            log.warn("resolveArgument error username is empty");
            return null;
        }
        SysUser user;
        if (isFull) {
            user = userService.selectByUsername(username);
        } else {
            user = new SysUser();
            user.setUsername(username);
        }
        return user;
    }
}

配置参数解析器

使用WebMvcConfigurer#addArgumentResolvers注册参数解析器

/**
 * 默认SpringMVC拦截器
 */
public class WebMvcConfig implements WebMvcConfigurer {
    @Lazy
    @Autowired
    private UserService userService;

    /**
     * 参数解析
     *
     * @param argumentResolvers 解析类
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        //注入用户信息
        argumentResolvers.add(new UserArgumentResolver(userService));
    }

}

controller 

结果

@Slf4j
@RestController
@RequestMapping(value = "/sys/user")
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 当前登录用户 user
     * */
    @ApiOperation(value = "根据access_token当前登录用户")
    @GetMapping("/users/current")
    public Result<LoginUser> getLoginUser(@LoginUser(isFull = true) SysUser user) {
        //...
        return loginUser;
    }
}

controller 使用@LoginUser注解修饰 且是SysUser对象 前端无需传入参数请求时,UserArgumentResolver会对我们满足条件的接口进行一个用户信息注入。

@Controller
public class TestController {
	@GetMapping
	@ResponseBody
	public Result<Void> test(HttpServletRequest request, HttpServletResponse response){
        //...
		return Reuslt.ok();
	}
}

在test方法中直接可以用request和response,很方便,无需开发者自己去获取即可使用。同样是使用HandlerMethodArgumentResolver进行注入,感兴趣的可以查看ServletRequestMethodArgumentResolver代码

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值