<mvc:annotation-driven>
在spring mvc 3.1增加了此标签的一些新的内置标签,个人能力有限,下面对这个标签进行简要的说明:
以下为可选配置:
<mvc:annotation-driven ignoreDefaultModelOnRedirect="true" conversion-service="" validator="" message-codes-resolver="">
<mvc:argument-resolvers>
<bean class="com.lay.user.util.CustomerArgumentResolver"/>
</mvc:argument-resolvers>
<mvc:message-converters>
<bean class=""/>
</mvc:message-converters>
<mvc:return-value-handlers>
<bean class=""/>
</mvc:return-value-handlers>
</mvc:annotation-driven>
那么mvc:annotation-driven做了哪些事呢?
参考官方文档:
16.14.1 Enabling MVC Java Config or the MVC XML Namespace
1.先说mvc:annotation-driven属性
- ignoreDefaultModelOnRedirect:请求重定向时的参数(重定向是忽略model参数)
- conversion-service:数据绑定时类型转换,如果不设置则默认注册FormattingConversionService,支持joda time,篇幅有限,就不介绍joda time了,有空再说。
- validator:参数验证,可选,如不设置并且加入jsr303.jar的话则会使用jsr303,jsr303的实现框架有hibernate-validator.jar,具体可能以后会详细介绍。
- message-codes-resolver:数据绑定和验证信息解析,可选,不设置默认注册DefaultMessageCodesResolver
基本默认的就够用了,更高级用法可以自己指定。
2.mvc:annotation-driven内置标签
- <mvc:argument-resolvers>:参数解析器,可通过实现HandlerMethodArgumentResolver接口实现,该实现不会覆盖原有spring mvc内置解析对参数的解析,要自定义的内置支持参数解析可以考虑注册RequestMappingHandlerAdapter,以下为参考:
public class CustomerArgumentResolver implements HandlerMethodArgumentResolver {
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return null;
}
public boolean supportsParameter(MethodParameter parameter) {
System.out.println(parameter.getParameterName() + " : " + parameter.getParameterName()
+ " \nParameterType: " + parameter.getParameterType() + " \nMethod: " + parameter.getMethod().getName());
return false;
}
}
代码说明: supportsParameter方法主要判别参数是否为该解析器所支持的,支持:true ,不支持:false
如果返回true的话则调用resolveArgument方法。
那么我们自定义的参数解析会在哪里调用呢?往下看:
我们查看HandlerMethodArgumentResolver的实现类:
没法插入图片。。。。。蛋疼
看代码:
/**
* Resolves method parameters by delegating to a list of registered {@link HandlerMethodArgumentResolver}s.
* Previously resolved method parameters are cached for faster lookups.
*
* @author Rossen Stoyanchev
* @since 3.1
*/
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
/**
* Find a registered {@link HandlerMethodArgumentResolver} that supports the given method parameter.
*/
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver methodArgumentResolver : argumentResolvers) {
if (logger.isTraceEnabled()) {
logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
parameter.getGenericParameterType() + "]");
}
if (methodArgumentResolver.supportsParameter(parameter)) {
result = methodArgumentResolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
}
解析参数的时候会自动找到HandlerMethodArgumentResolverComposite 这个 HandlerMethodArgumentResolver实现类,然后调用他的supportsParameter方法,supportsParameter方法会去判断是否支持该参数的解析,而我们自定义的参数解析器也被注入到for 循环中的argumentResolvers参数中了,不会上传图片,没法截图给大家看了,这里简单说下:
argumentResolvers是一个参数解析器集合,我们自定义的解析器会出现在这里,spring mvc默认把RequestParamMethodArgumentResolver 和 ServletModelAttributeMethodProcessor重复注册到最后,
spring mvc会一次找到supportsParameter方法返回true的解析器,并调用该方法的resolveArgument方法进行解析。
具体大家自己动手实现一下吧,不过多啰嗦了~!
- mvc:return-value-handlers:对返回值的处理。自定义实现类需要实现HandlerMethodReturnValueHandler,这个和上面提到的mvc:argument-resolvers自定义实现类的使用上几乎没差别。同样的,如果想改变内置返回值处理的话请直接注入RequestMappingHandlerAdapter,不累赘了,具体可以查看HandlerMethodReturnValueHandlerComposite源码。
- mvc:message-converters:主要是对 @RequestBody 参数和 @ResponseBody返回值的处理,可选的,在这里注册的HttpMessageConverter默认情况下优先级是高于内置的转换器的,那么怎么自定义转换器呢?
通过实现HttpMessageConverter<T>接口便可以了,当然,你也可以继承AbstractHttpMessageConverter<T>,这样做会更轻松,具体做法参考源码
public interface HttpMessageConverter<T> {
// Indicate whether the given class and media type can be read by this converter.
boolean canRead(Class<?> clazz, MediaType mediaType);
// Indicate whether the given class and media type can be written by this converter.
boolean canWrite(Class<?> clazz, MediaType mediaType);
// Return the list of MediaType objects supported by this converter.
List<MediaType> getSupportedMediaTypes();
// Read an object of the given type from the given input message, and returns it.
T read(Class<T> clazz, HttpInputMessage inputMessage) throws IOException,
HttpMessageNotReadableException;
// Write an given object to the given output message.
void write(T t, HttpOutputMessage outputMessage) throws IOException,
HttpMessageNotWritableException;
}
文章的开头提到mvc:annotation-driven做了哪些事,其实使用mvc:annotation-driven默认情况下就注册了很多转换器了:
- StringHttpMessageConverter
- FormHttpMessageConverter
- ByteArrayHttpMessageConverter
- MarshallingHttpMessageConverter
- MappingJacksonHttpMessageConverter
- SourceHttpMessageConverter
- BufferedImageHttpMessageConverter
由此可以明白我前面的一片关于输出json格式的文章中提及的采用mvc:annotation-driven时只需加入jar包即可完成输出json的原因了,xml又何尝不能通过MarshallingHttpMessageConverter来解决呢?
最后,开发中可以使用mvc:annotation-driven 快速配置,在不注入自己的解析器的情况下基本默认注入的转换器差不多够用了,至于其他的
-
RequestMappingHandlerMapping
-
RequestMappingHandlerAdapter
可配置的属性以后在讨论。