Franz`s blog

Spring MVC 中自定义参数解析器

前段时间看开源项目看到一段奇怪的代码

1
2
3
4
@PostMapping("clearhistory")
public Object clearhistory(@LoginUser UserVo loginUser) {
xxxx
}

可以发现 loginUser直接就通过函数的参数传递了。

Spring MVC解析参数是通过 org.springframework.web.method.support.InvocableHandlerMethod#getMethodArgumentValues实现的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
MethodParameter[] parameters = this.getMethodParameters();
Object[] args = new Object[parameters.length];

for(int i = 0; i < parameters.length; ++i) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = this.resolveProvidedArgument(parameter, providedArgs);
if (args[i] == null) {
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
// 使用argumentResolvers解析参数
args[i] = this.argumentResolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
} catch (Exception var9) {
if (this.logger.isDebugEnabled()) {
this.logger.debug(this.getArgumentResolutionErrorMessage("Failed to resolve", i), var9);
}

throw var9;
}
} else if (args[i] == null) {
throw new IllegalStateException("Could not resolve method parameter at index " + parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() + ": " + this.getArgumentResolutionErrorMessage("No suitable resolver for", i));
}
}
}

return args;
}

org.springframework.web.method.support.InvocableHandlerMethod#getMethodArgumentValues将具体的解析交给了 argumentResolvers,argumentResolvers是一个实现了 HandlerMethodArgumentResolver接口的对象。

1
2
3
4
5
6
7
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
xxxx
private final List<HandlerMethodArgumentResolver> argumentResolvers = new LinkedList();
xxxx
}


org.springframework.web.method.support.HandlerMethodArgumentResolverComposite#argumentResolvers 中存在一些我们熟悉的argumentResolver。

image_3

我们可以通过实现自己的解析器来实现文中最先提到的效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class LoginUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
private ApiUserService userService;

public void setUserService(ApiUserService userService) {
this.userService = userService;
}

@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().isAssignableFrom(UserVo.class) && parameter.hasParameterAnnotation(LoginUser.class);
}

@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer container,
NativeWebRequest request, WebDataBinderFactory factory) {
//获取用户ID
Object object = request.getAttribute(AuthorizationInterceptor.LOGIN_USER_KEY, RequestAttributes.SCOPE_REQUEST);
if (object == null) {
return null;
}
//获取用户信息
return userService.queryObject((Long) object);
}
}

注意:这里要先在interceptor中设置 LOGIN_USER_KEY属性