天天看點

spring MVC 3.1 <mvc:annotation-driven>快速配置

<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

    可配置的屬性以後在讨論。

繼續閱讀