經過了兩篇的亂碼說明,要重新回到mvc:annotation-driven标簽中,繼續說說HandlerMethodReturnValueHandler的使用,下一篇文章主要說說HttpMessageConverter。
HandlerMethodReturnValueHandler是RequestMappingHandlerAdapter用來處理當含有@RequestMapping的方法排程完成後,後面要進行的事情。
首先是HandlerMethodReturnValueHandler的自定義注冊:
mvc:annotation-driven配置如下:
<a href="http://my.oschina.net/pingpangkuangmo/blog/376341#">?</a>
1
2
3
4
5
<code><mvc:annotation-driven></code>
<code> </code><code><mvc:</code><code>return</code><code>-value-handlers></code>
<code> </code><code><bean</code><code>class</code><code>=</code><code>"org.springframework.web.servlet.mvc.method.annotation.ModelAndViewMethodReturnValueHandler"</code><code>></bean></code>
<code> </code><code></mvc:</code><code>return</code><code>-value-handlers></code>
<code> </code><code></mvc:annotation-driven></code>
在啟動AnnotationDrivenBeanDefinitionParser來解析mvc:annotation-driven标簽的過程中(見本系列第三篇部落格),會注冊我們所配置的HandlerMethodReturnValueHandler,如下:
<code>ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, parserContext);</code>
6
7
<code>private</code> <code>ManagedList<?> getReturnValueHandlers(Element element, ParserContext parserContext) {</code>
<code> </code><code>Element handlersElement = DomUtils.getChildElementByTagName(element,</code><code>"return-value-handlers"</code><code>);</code>
<code> </code><code>if</code> <code>(handlersElement !=</code><code>null</code><code>) {</code>
<code> </code><code>return</code> <code>extractBeanSubElements(handlersElement, parserContext);</code>
<code> </code><code>}</code>
<code> </code><code>return</code> <code>null</code><code>;</code>
<code> </code><code>}</code>
然後将會這些自定義的HandlerMethodReturnValueHandler設定到RequestMappingHandlerAdapter的customReturnValueHandlers屬性中,
RequestMappingHandlerAdapter的兩個重要屬性:
customReturnValueHandlers:存放我們自定義的HandlerMethodReturnValueHandler;
returnValueHandlers:存放最終所有的HandlerMethodReturnValueHandler;
如下所示:
8
9
10
11
12
13
<code>public</code> <code>class</code> <code>RequestMappingHandlerAdapter</code><code>extends</code> <code>AbstractHandlerMethodAdapter</code>
<code> </code><code>implements</code> <code>BeanFactoryAware, InitializingBean {</code>
<code> </code><code>private</code> <code>List<HandlerMethodArgumentResolver> customArgumentResolvers;</code>
<code> </code><code>private</code> <code>HandlerMethodArgumentResolverComposite argumentResolvers;</code>
<code> </code><code>private</code> <code>HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;</code>
<code>//這裡這裡這裡這裡這裡這裡這裡這裡</code>
<code> </code><code>private</code> <code>List<HandlerMethodReturnValueHandler> customReturnValueHandlers;</code>
<code> </code><code>private</code> <code>HandlerMethodReturnValueHandlerComposite returnValueHandlers;</code>
returnValueHandlers的屬性類型為HandlerMethodReturnValueHandlerComposite,裡面也有一個list集合,來存放所有的HandlerMethodReturnValueHandler。
HandlerMethodReturnValueHandlerComposite結構如下:
<code>public</code> <code>class</code> <code>HandlerMethodReturnValueHandlerComposite</code><code>implements</code> <code>HandlerMethodReturnValueHandler {</code>
<code> </code><code>protected</code> <code>final</code> <code>Log logger = LogFactory.getLog(getClass());</code>
<code> </code><code>private</code> <code>final</code> <code>List<HandlerMethodReturnValueHandler> returnValueHandlers =</code>
<code> </code><code>new</code> <code>ArrayList<HandlerMethodReturnValueHandler>();</code>
<code> </code><code>/**</code>
在RequestMappingHandlerAdapter建立出來後,會執行afterPropertiesSet()方法,在該方法中會設定所有的HandlerMethodReturnValueHandler到RequestMappingHandlerAdapter的returnValueHandlers屬性中如下:
14
15
16
17
<code>@Override</code>
<code> </code><code>public</code> <code>void</code> <code>afterPropertiesSet() {</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.argumentResolvers ==</code><code>null</code><code>) {</code>
<code> </code><code>List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();</code>
<code> </code><code>this</code><code>.argumentResolvers =</code><code>new</code> <code>HandlerMethodArgumentResolverComposite().addResolvers(resolvers);</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.initBinderArgumentResolvers ==</code><code>null</code><code>) {</code>
<code> </code><code>List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();</code>
<code> </code><code>this</code><code>.initBinderArgumentResolvers =</code><code>new</code> <code>HandlerMethodArgumentResolverComposite().addResolvers(resolvers);</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.returnValueHandlers ==</code><code>null</code><code>) {</code>
<code>//擷取所有的HandlerMethodReturnValueHandler</code>
<code> </code><code>List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();</code>
<code> </code><code>this</code><code>.returnValueHandlers =</code><code>new</code> <code>HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);</code>
<code> </code><code>initControllerAdviceCache();</code>
getDefaultReturnValueHandlers()方法會擷取預設要注冊的和我們自定義的HandlerMethodReturnValueHandler,如下:
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<code>private</code> <code>List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {</code>
<code> </code><code>List<HandlerMethodReturnValueHandler> handlers =</code><code>new</code> <code>ArrayList<HandlerMethodReturnValueHandler>();</code>
<code> </code><code>// Single-purpose return value types</code>
<code> </code><code>handlers.add(</code><code>new</code> <code>ModelAndViewMethodReturnValueHandler());</code>
<code> </code><code>handlers.add(</code><code>new</code> <code>ModelMethodProcessor());</code>
<code> </code><code>handlers.add(</code><code>new</code> <code>ViewMethodReturnValueHandler());</code>
<code> </code><code>handlers.add(</code><code>new</code> <code>HttpEntityMethodProcessor(getMessageConverters(),</code><code>this</code><code>.contentNegotiationManager));</code>
<code> </code><code>handlers.add(</code><code>new</code> <code>HttpHeadersReturnValueHandler());</code>
<code> </code><code>handlers.add(</code><code>new</code> <code>CallableMethodReturnValueHandler());</code>
<code> </code><code>handlers.add(</code><code>new</code> <code>DeferredResultMethodReturnValueHandler());</code>
<code> </code><code>handlers.add(</code><code>new</code> <code>AsyncTaskMethodReturnValueHandler(</code><code>this</code><code>.beanFactory));</code>
<code> </code><code>// Annotation-based return value types</code>
<code> </code><code>handlers.add(</code><code>new</code> <code>ModelAttributeMethodProcessor(</code><code>false</code><code>));</code>
<code> </code><code>handlers.add(</code><code>new</code> <code>RequestResponseBodyMethodProcessor(getMessageConverters(),</code><code>this</code><code>.contentNegotiationManager));</code>
<code> </code><code>// Multi-purpose return value types</code>
<code> </code><code>handlers.add(</code><code>new</code> <code>ViewNameMethodReturnValueHandler());</code>
<code> </code><code>handlers.add(</code><code>new</code> <code>MapMethodProcessor());</code>
<code> </code><code>// Custom return value types</code>
<code>//這裡這裡會從customReturnValueHandlers屬性中擷取我們自定的HandlerMethodReturnValueHandler</code>
<code> </code><code>if</code> <code>(getCustomReturnValueHandlers() !=</code><code>null</code><code>) {</code>
<code> </code><code>handlers.addAll(getCustomReturnValueHandlers());</code>
<code> </code><code>// Catch-all</code>
<code> </code><code>if</code> <code>(!CollectionUtils.isEmpty(getModelAndViewResolvers())) {</code>
<code> </code><code>handlers.add(</code><code>new</code> <code>ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));</code>
<code> </code><code>else</code> <code>{</code>
<code> </code><code>handlers.add(</code><code>new</code> <code>ModelAttributeMethodProcessor(</code><code>true</code><code>));</code>
<code> </code><code>return</code> <code>handlers;</code>
至此,所有的HandlerMethodReturnValueHandler的注冊已經完成。我們可以再回顧下,在該系列的第三篇部落格中介紹HandlerMethodReturnValueHandler的使用。
第一步:擷取合适的HandlerAdapter,當方法含有@RequestMaiing注釋的時候,便選擇RequestMappingHandlerAdapter來進行方法的排程處理
第二步:方法的排程處理過程為:首先執行方法體,然後根據傳回值來選擇一個合适的HandlerMethodReturnValueHandler,如下代碼:
<code>public</code> <code>final</code> <code>void</code> <code>invokeAndHandle(ServletWebRequest webRequest,</code>
<code> </code><code>ModelAndViewContainer mavContainer, Object... providedArgs)</code><code>throws</code> <code>Exception {</code>
<code> </code><code>Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);</code>
<code> </code><code>setResponseStatus(webRequest);</code>
<code> </code><code>if</code> <code>(returnValue ==</code><code>null</code><code>) {</code>
<code> </code><code>if</code> <code>(isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {</code>
<code> </code><code>mavContainer.setRequestHandled(</code><code>true</code><code>);</code>
<code> </code><code>return</code><code>;</code>
<code> </code><code>}</code>
<code> </code><code>else</code> <code>if</code> <code>(StringUtils.hasText(</code><code>this</code><code>.responseReason)) {</code>
<code> </code><code>mavContainer.setRequestHandled(</code><code>true</code><code>);</code>
<code> </code><code>return</code><code>;</code>
<code> </code><code>mavContainer.setRequestHandled(</code><code>false</code><code>);</code>
<code>//重點重點重點重點重點重點重點重點重點重點</code>
<code> </code><code>try</code> <code>{</code>
<code> </code><code>this</code><code>.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);</code>
<code> </code><code>catch</code> <code>(Exception ex) {</code>
<code> </code><code>if</code> <code>(logger.isTraceEnabled()) {</code>
<code> </code><code>logger.trace(getReturnValueHandlingErrorMessage(</code><code>"Error handling return value"</code><code>, returnValue), ex);</code>
<code> </code><code>throw</code> <code>ex;</code>
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest)會周遊所有的已注冊的HandlerMethodReturnValueHandler判斷他們支不支援returnValue的傳回類型。如下:
<code>public</code> <code>void</code> <code>handleReturnValue(</code>
<code> </code><code>Object returnValue, MethodParameter returnType,</code>
<code> </code><code>ModelAndViewContainer mavContainer, NativeWebRequest webRequest)</code>
<code> </code><code>throws</code> <code>Exception {</code>
<code> </code><code>HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);</code>
<code> </code><code>Assert.notNull(handler,</code><code>"Unknown return value type ["</code> <code>+ returnType.getParameterType().getName() +</code><code>"]"</code><code>);</code>
<code> </code><code>handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);</code>
<code> </code><code>* Find a registered {@link HandlerMethodReturnValueHandler} that supports the given return type.</code>
<code> </code><code>*/</code>
<code> </code><code>private</code> <code>HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {</code>
<code> </code><code>for</code> <code>(HandlerMethodReturnValueHandler returnValueHandler : returnValueHandlers) {</code>
<code> </code><code>logger.trace(</code><code>"Testing if return value handler ["</code> <code>+ returnValueHandler +</code><code>"] supports ["</code> <code>+</code>
<code> </code><code>returnType.getGenericParameterType() +</code><code>"]"</code><code>);</code>
<code> </code><code>if</code> <code>(returnValueHandler.supportsReturnType(returnType)) {</code>
<code> </code><code>return</code> <code>returnValueHandler;</code>
找到支援的HandlerMethodReturnValueHandler後,就要執行它的handleReturnValue方法。
下面就具體介紹下下常用的這幾個HandlerMethodReturnValueHandler;
HttpEntityMethodProcessor:用來處理傳回值類型是HttpEntity的方法,簡單用法如下
<code>@RequestMapping</code><code>(value=</code><code>"/test/httpEntity"</code><code>,method=RequestMethod.GET)</code>
<code> </code><code>public</code> <code>HttpEntity<String> testHttpEntity()</code><code>throws</code> <code>UnsupportedEncodingException{</code>
<code> </code><code>String body=</code><code>"中國"</code><code>;</code>
<code> </code><code>HttpHeaders headers=</code><code>new</code> <code>HttpHeaders();</code>
<code> </code><code>headers.add(</code><code>"Content-type"</code><code>,</code><code>"text/html;charset=GBK"</code><code>);</code>
<code> </code><code>HttpEntity<String> ret=</code><code>new</code> <code>HttpEntity<String>(body,headers);</code>
<code> </code><code>return</code> <code>ret;</code>
就是在建構http協定的傳回體和傳回頭。
使用案例如,檔案下載下傳。
經常有人直接用HttpServletRequest和HttpServletResponse來做檔案下載下傳,這種方式便與web容器産生的對象耦合在一起,不推薦使用,而是直接使用spring為我們提供的HttpEntityMethodProcessor這一傳回值處理器,雖然springmvc最終還是用HttpServletResponse來實作,但是這種方式便斷開我們直接與web容器之間的耦合。
這一過程分析:
當這個方法執行完成之後,會調用HttpEntityMethodProcessor的handleReturnValue方法,
該方法内容就是為response設定響應頭,然後将響應體的内容寫入response的body中,此時又會涉及到HttpMessageConverter,當HttpEntity中的body類型為String,又會讓StringHttpMessageConverter來進行轉換。這和@ResponseBody的處理過程是一樣的。
ViewNameMethodReturnValueHandler:主要用來處理傳回值是String類型(前提不含@ResponseBody标簽),它會将傳回的字元串作為view視圖的名字,如下所示。
另一種用法,當傳回的字元串以redirect:開始,不再作為view視圖名而是作為重定向的位址,如下:
<code>@RequestMapping</code><code>(value=</code><code>"/test/string"</code><code>,method=RequestMethod.GET)</code>
<code> </code><code>public</code> <code>String testString(){</code>
<code> </code><code>return</code> <code>"redirect:/string"</code><code>;</code>
有了重定向,也有轉發。以forward:開頭便是轉發。
如下:
<code> </code><code>return</code> <code>"forward:/string"</code><code>;</code>
ModelMethodProcessor:用來處理傳回類型為Model的,它預設采用請求路徑作為視圖名稱,如下:
<code>@RequestMapping</code><code>(value=</code><code>"/test/model"</code><code>,method=RequestMethod.GET)</code>
<code> </code><code>public</code> <code>Model handleModel(String name)</code><code>throws</code> <code>Exception {</code>
<code> </code><code>Model model=</code><code>new</code> <code>ExtendedModelMap();</code>
<code> </code><code>model.addAttribute(</code><code>"name"</code><code>,name);</code>
<code> </code><code>return</code> <code>model;</code>
ModelAndViewMethodReturnValueHandler:用來處理傳回值類型為ModelAndView,如下:
<code>@RequestMapping</code><code>(value=</code><code>"/test/modelandview"</code><code>,method=RequestMethod.GET)</code>
<code> </code><code>public</code> <code>ModelAndView testModelAndView()</code><code>throws</code> <code>Exception {</code>
<code> </code><code>return</code> <code>new</code> <code>ModelAndView(</code><code>"hello"</code><code>);</code>
RequestResponseBodyMethodProcessor:則是用于處理方法中含有@ResponseBody注解,或類上含有@ResponseBody注解。這一處理過程在本系列的第三篇部落格中有介紹,這裡不再叙述。
還有其他的HandlerMethodReturnValueHandler,這裡僅僅是作為引路,對HandlerMethodReturnValueHandler有個整體的認識,具體的内容,需要讀者去具體研究。