自定义参数解析

2020-09-10 49 ℃

说明

我们都知道,在SpringMVC中,如果想要获取request,直接在方法上添加HttpServletRequest参数就可以获取到,有时候,我们也希望能将一些参数通过类似的方式很便捷的获取到。

例如获取当前登录用户的信息时,我们以前常用的做法是在每个Controller里调用获取用户信息的方法来手动获取(如从session中获取或通过token获取),这种方式不够优雅。

通过实现HandlerMethodArgumentResolver接口就可以做到直接在方法中注入参数。

方法参数解析器

HandlerMethodArgumentResolver是用来处理方法参数的解析器,包含以下2个方法:

  • supportsParameter:用于判定是否需要处理该参数分解,返回true为需要,并会去调用下面的方法resolveArgument。
  • resolveArgument:真正用于处理参数分解的方法,返回的Object就是controller方法上的形参对象。

SpringMVC自带了一些实现,如有需要,我们可以根据业务进行接口重写

  • ServletRequestMethodArgumentResolver和ServletResponseMethodArgumentResolver处理了自动绑定HttpServletRequest和HttpServletResponse
  • RequestParamMapMethodArgumentResolver处理了@RequestParam
  • RequestHeaderMapMethodArgumentResolver处理了@RequestHeader
  • PathVariableMapMethodArgumentResolver处理了@PathVariable
  • ModelAttributeMethodProcessor处理了@ModelAttribute
  • RequestResponseBodyMethodProcessor处理了@RequestBody

注入当前登录用户

1.实现HandlerMethodArgumentResolver接口

这里是从session中获取用户信息,需确保session中已存在登录信息注入才有效。若想从request中获取,可通过在SpringMVC拦截器中的preHandle方法中将数据存在request对象中。

public class CustomAugmentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.getParameterType().equals(User.class) } @Override public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) { if (methodParameter.getParameterType().equals(User.class)) { return nativeWebRequest.getAttribute(Const.USER_SESSION_KEY, RequestAttributes.SCOPE_SESSION); } return null; } }

2.配置MVC

定义MVC配置类,需继承WebMvcConfigurationSupport或实现WebMvcConfigurer。在addArgumentResolvers方法中,添加自定义的参数解析器

@Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { argumentResolvers.add(new CustomAugmentResolver()); }

3.Controller中使用

通过上面的简单配置,就可以直接在controller中注入参数了,非常方便。

@GetMapping("userInfo") public User userInfo(User user) { return user; }

4.存在的问题

如果有这样一种情况,我们接收前端传递的参数用的刚好也是User对象,那么,就会导致参数无法传递进来,会被注入成session中的user对象。

解决方案大概有两种:

  • 注入时过滤掉这个方法。如利用注解区分
  • 不适用同一对象。如User对象用于注入,另外新建一个类叫UserParam用于接收参数

我们可以自定义一个注解,用于绑定当前登录用户信息。

/** * 绑定当前登录的用户 */ @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CurrentUser { /** * 当前用户在session中的名字 * * @return */ String value() default Const.USER_SESSION_KEY; }

然后修改CustomAugmentResolver中的supportsParameter方法,加上一个注解判断的条件。

public class CustomAugmentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.getParameterType().equals(User.class) && parameter.hasParameterAnnotation(CurrentUser.class); } @Override public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) { if (methodParameter.getParameterType().equals(User.class)) { return nativeWebRequest.getAttribute(Const.USER_SESSION_KEY, RequestAttributes.SCOPE_SESSION); } return null; } }

在需要注入的地方加上这个注解,就像@RequestBody一样,就能进行区分了。

@GetMapping("userList") public void userList(User user, @CurrentUser User currentUser) { //略 }
版权声明:周华个人博客原创文章,转载请注明出处。

文章链接:http://www.iszhouhua.com/custom-augment-resolver.html

发表时间:2020-09-10 11:32

最后更新时间:2020-09-10 12:54