谈及Spring MVC ,一定会记得spring mvc为应用程序提供的强大的参数绑定机制,那么我们今天来分析spring MVC如何为我们提供的参数解析器,以及这些参数解析器支持分别支持哪些参数类型.
一.当我们没有指定特别的HandlerAdapter的时候,spring-mvc会采用默认策略模式,使用RequestMappingHandlerAdapter类充当Adapter角色,
RequestMappingHandlerAdapter中有两个属性customArgumentResolvers,argumentResolvers,自定义参数解析器和默认的参数解析器。
默认参数解析器初始化如下代码所示:
public void afterPropertiesSet() {
List handlers;
if(this.argumentResolvers == null) {
handlers = this.getDefaultArgumentResolvers();
this.argumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers);
}
if(this.initBinderArgumentResolvers == null) {
handlers = this.getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers);
}
if(this.returnValueHandlers == null) {
handlers = this.getDefaultReturnValueHandlers();
this.returnValueHandlers = (new HandlerMethodReturnValueHandlerComposite()).addHandlers(handlers);
}
this.initControllerAdviceCache();
}
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
ArrayList resolvers = new ArrayList();
resolvers.add(new RequestParamMethodArgumentResolver(this.getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
resolvers.add(new RequestResponseBodyMethodProcessor(this.getMessageConverters()));
resolvers.add(new RequestPartMethodArgumentResolver(this.getMessageConverters()));
resolvers.add(new RequestHeaderMethodArgumentResolver(this.getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(this.getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(this.getBeanFactory()));
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(this.getMessageConverters()));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
if(this.getCustomArgumentResolvers() != null) {
resolvers.addAll(this.getCustomArgumentResolvers());
}
resolvers.add(new RequestParamMethodArgumentResolver(this.getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
自定义参数解析器,需要定义一个类并且实现HandlerMethodArgumentResolover类,然后在配置文件中添加该类的bean
二.默认参数解析器阐述
1>.RequestParamMethodArgumentResolver 这个解析器能够为参数上加了RequestParam注解的参数提供支持,请看如下代码
@Override
public boolean supportsParameter(MethodParameter parameter) {
Class<?> paramType = parameter.getParameterType();
if (parameter.hasParameterAnnotation(RequestParam.class)) {
if (Map.class.isAssignableFrom(paramType)) {
String paramName = parameter.getParameterAnnotation(RequestParam.class).value();
return StringUtils.hasText(paramName);
}
else {
return true;
}
}
else {
if (parameter.hasParameterAnnotation(RequestPart.class)) {
return false;
}
else if (MultipartFile.class.equals(paramType) || "javax.servlet.http.Part".equals(paramType.getName())) {
return true;
}
else if (this.useDefaultResolution) {
return BeanUtils.isSimpleProperty(paramType);
}
else {
return false;
}
}
}
2>.RequestParamMapMethodArgumentResolver,支持参数上加了RequestParam注解并且是Map类型的参数.
3>.PathVariableMethodArgumentResolver,支持参数上加了PathVariable注解并且不是Map类型的参数,
4>.PathVariableMapMethodArgumentResolver,支持参数上加了PathVariable注解并且参数类型为Map的参数,
5>.MatrixVariableMethodArgumentResolver.支持参数上加了MatrixVariable注解并且不是Map类型
6>.MatrixVariableMapMethodArgumentResolver,支持参数上加了MatrixVariable注解并且类型是Map的参数.
7>.ServletModelAttributeMethodProcessor.支持参数加了ModelAttribute注解的参数,
8>.RequestResponseBodyMethodProcessor支持参数上加了RequestBody注解的参数,
9>.RequestPartMethodArgumentResolver支持参数上了RequestPart注解的参数,代码如下:
@Override
public boolean supportsParameter(MethodParameter parameter) {
if (parameter.hasParameterAnnotation(RequestPart.class)) {
return true;
}
else {
if (parameter.hasParameterAnnotation(RequestParam.class)){
return false;
}
else if (MultipartFile.class.equals(parameter.getParameterType())) {
return true;
}
else if ("javax.servlet.http.Part".equals(parameter.getParameterType().getName())) {
return true;
}
else {
return false;
}
}
}
10>.RequestHeaderMethodArgumentResolver支持参数加了RequestHeader注解的并且不是Map类型的参数,
11>.RequestHeaderMapMethodArgumentResolver支持参数加了RequestHeader注解并且是Map类型的参数,
12>.ServletCookieValueMethodArgumentResolver支持参数上加了CookieValue注解的参数.
13>.ExpressionValueMethodArgumentResolver支持参数上加了Value注解的参数.
14>.ServletRequestMethodArgumentResolver支持代码如下:
@Override
public boolean supportsParameter(MethodParameter parameter) {
Class<?> paramType = parameter.getParameterType();
return (WebRequest.class.isAssignableFrom(paramType) ||
ServletRequest.class.isAssignableFrom(paramType) ||
MultipartRequest.class.isAssignableFrom(paramType) ||
HttpSession.class.isAssignableFrom(paramType) ||
Principal.class.isAssignableFrom(paramType) ||
Locale.class.equals(paramType) ||
TimeZone.class.equals(paramType) ||
"java.time.ZoneId".equals(paramType.getName()) ||
InputStream.class.isAssignableFrom(paramType) ||
Reader.class.isAssignableFrom(paramType) ||
HttpMethod.class.equals(paramType));
}
15>.ServletResponseMethodArgumentResolver支持代码如下:
Class<?> paramType = parameter.getParameterType();
return (ServletResponse.class.isAssignableFrom(paramType) ||
OutputStream.class.isAssignableFrom(paramType) ||
Writer.class.isAssignableFrom(paramType));
16>.HttpEntityMethodProcessor支持参数类型为HttpEntity或者RequestEntity类型的参数
17>.RedirectAttributesMethodArgumentResolver支持参数类型为RedirectAttributes的参数.
18>.ModelMethodProcessor支持参数是Model类型的参数
19>.MapMethodProcessor支持参数是Map类型的参数.
20>.ErrorsMethodArgumentResolver支持类型是Errors类型的参数
21>.SessionStatusMethodArgumentResolver支持参数类型是SessionStatus的参数.
22>.UriComponentsBuilderMethodArgumentResolver支持参数类型是UriComponentBuilder的参数.
以上是系统提供的默认的参数解析器。
下面是自定义参数解析器的例子。
public class UserArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
//判断参数是否是loginInfo的子类
return LoginInfo.class.isAssignableFrom(methodParameter.getParameterType());
}
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
return UserUtils.getUser();
}
}
最主要的就是resolveArgument方法,supportsParmeter只是判断是否支持,因为spring会将所有的参数解析器在程序启动的时候加载到dispatcherServlet中,然后一个个的遍历判断。