<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 現象 本章使用的demo基于maven,是根據入門blog的例子繼續寫下去的。 我們先來看一看對應的現象。 我們這里的配置文件 *-dispatcher.xml中的關鍵配置如下(其他常規的配置文件不在講解,可參考本書一開始提到的入門章節): (視圖配置省略) <mvc:resources location="/static/" mapping="/static/**"/> <mvc:annotation-driven/> <context:component-scan base-package="org.format.demo.controller"/> pom中需要有以下依賴(Spring依賴及其他依賴不顯示): <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-core-asl</artifactId> <version>1.9.13</version> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>1.9.13</version> </dependency> 這個依賴是json序列化的依賴。 ok。我們在Controller中添加一個method: @RequestMapping("/xmlOrJson") @ResponseBody public Map<String, Object> xmlOrJson() { Map<String, Object> map = new HashMap<String, Object>(); map.put("list", employeeService.list()); return map; } 直接訪問地址: ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert01.png) 我們看到,短短幾行配置。使用@ResponseBody注解之后,Controller返回的對象 自動被轉換成對應的json數據,在這里不得不感嘆SpringMVC的強大。 我們好像也沒看到具體的配置,唯一看到的就是*-dispatcher.xml中的一句配置:<mvc:annotation-driven/>。其實就是這個配置,導致了java對象自動轉換成json對象的現象。 那么spring到底是如何實現java對象到json對象的自動轉換的呢? 為什么轉換成了json數據,如果想轉換成xml數據,那該怎么辦? # 源碼分析 在講解<mvc:annotation-driven/>這個配置之前,我們先了解下Spring的消息轉換機制。@ResponseBody這個注解就是使用消息轉換機制,最終通過json的轉換器轉換成json數據的。 HttpMessageConverter接口就是Spring提供的http消息轉換接口。有關這方面的知識大家可以參考"參考資料"中的第二條鏈接,里面講的很清楚。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert02.png) 下面開始分析<mvc:annotation-driven/>這句配置: 這句代碼在spring中的解析類是: ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert03.png) 在AnnotationDrivenBeanDefinitionParser源碼的152行parse方法中: 分別實例化了RequestMappingHandlerMapping,ConfigurableWebBindingInitializer,RequestMappingHandlerAdapter等諸多類。 其中**RequestMappingHandlerMapping**和**RequestMappingHandlerAdapter**這兩個類比較重要。 RequestMappingHandlerMapping處理請求映射的,處理@RequestMapping跟請求地址之間的關系。 RequestMappingHandlerAdapter是請求處理的適配器,也就是請求之后處理具體邏輯的執行,關系到哪個類的哪個方法以及轉換器等工作,這個類是我們講的重點,其中它的屬性messageConverters是本章要講的重點。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert04.png) 私有方法:getMessageConverters ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert05.png) 從代碼中我們可以,RequestMappingHandlerAdapter設置messageConverters的邏輯: 1.如果<mvc:annotation-driven>節點有子節點message-converters,那么它的轉換器屬性messageConverters也由這些子節點組成。 message-converters的子節點配置如下: <mvc:annotation-driven> <mvc:message-converters> <bean class="org.example.MyHttpMessageConverter"/> <bean class="org.example.MyOtherHttpMessageConverter"/> </mvc:message-converters> </mvc:annotation-driven> 2.message-converters子節點不存在或它的屬性register-defaults為true的話,加入其他的轉換器:ByteArrayHttpMessageConverter、StringHttpMessageConverter、ResourceHttpMessageConverter等。 我們看到這么一段: ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert06.png) 這些boolean屬性是哪里來的呢,它們是AnnotationDrivenBeanDefinitionParser的靜態變量。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert07.png) 其中ClassUtils中的isPresent方法如下: ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert08.png) 看到這里,讀者應該明白了為什么本章一開始在pom文件中需要加入對應的jackson依賴,為了讓json轉換器jackson成為默認轉換器之一。 mvc:annotation-driven標簽的作用讀者也明白了。 下面我們看如何通過消息轉換器將java對象進行轉換的。 RequestMappingHandlerAdapter在進行handle的時候,會委托給HandlerMethod(具體由子類ServletInvocableHandlerMethod處理)的invokeAndHandle方法進行處理,這個方法又轉接給HandlerMethodReturnValueHandlerComposite處理。 HandlerMethodReturnValueHandlerComposite維護了一個HandlerMethodReturnValueHandler列表。 **HandlerMethodReturnValueHandler是一個對返回值進行處理的策略接口,這個接口非常重要。關于這個接口的細節**請參考[解析SpringMVC中Controller的方法中參數的工作原理](333548)章節。然后找到對應的HandlerMethodReturnValueHandler對結果值進行處理。 最終找到RequestResponseBodyMethodProcessor這個Handler(由于使用了@ResponseBody注解)。 RequestResponseBodyMethodProcessor的supportsReturnType方法: ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert09.png) 然后使用handleReturnValue方法進行處理: ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert10.png) 我們看到,這里使用了轉換器。   具體的轉換方法: ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert11.png) ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert12.png) 至于為何是請求頭部的**Accept**數據,讀者可以進去debug這個**getAcceptableMediaTypes**方法看看。 我就不羅嗦了~~~ ok。至此,我們走遍了所有的流程。 現在,回過頭來看。為什么一開始的demo輸出了json數據? 我們來分析吧。 由于我們只配置了<mvc:annotation-driven>,因此使用spring默認的那些轉換器。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert13.png) 很明顯,我們看到了2個xml和1個json轉換器。 **要看能不能轉換,得看HttpMessageConverter接口的public boolean canWrite(Class<?> clazz, MediaType mediaType)方法是否返回true來決定的。** 我們先分析SourceHttpMessageConverter: 它的canWrite方法被父類AbstractHttpMessageConverter重寫了。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert14.png) ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert15.png) ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert16.png) 發現SUPPORTED_CLASSES中沒有Map類(本章demo返回的是Map類),因此不支持。 下面看Jaxb2RootElementHttpMessageConverter: 這個類直接重寫了canWrite方法。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert17.png) 需要有XmlRootElement注解。 很明顯,Map類當然沒有。 最終MappingJackson2HttpMessageConverter匹配,進行json轉換。(為何匹配,請讀者自行查看源碼) # 實例講解 我們分析了轉換器的轉換過程之后,下面就通過實例來驗證我們的結論吧。 首先,我們先把xml轉換器實現。 之前已經分析,默認的轉換器中是支持xml的。下面我們加上注解試試吧。 由于Map是jdk源碼中的部分,因此我們用Employee來做demo。 因此,Controller加上一個方法: @RequestMapping("/xmlOrJsonSimple") @ResponseBody public Employee xmlOrJsonSimple() { return employeeService.getById(1); } 實體中加上@XmlRootElement注解 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert18.png) 結果如下: ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert19.png) 我們發現,解析成了xml。 這里為什么解析成xml,而不解析成json呢? 之前分析過,消息轉換器是根據class和mediaType決定的。 我們使用firebug看到: ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert20.png) 我們發現Accept有xml,沒有json。因此解析成xml了。 我們再來驗證,同一地址,HTTP頭部不同Accept。看是否正確。 $.ajax({ url: "${request.contextPath}/employee/xmlOrJsonSimple", success: function(res) { console.log(res); }, headers: { "Accept": "application/xml" } }); ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert21.png) $.ajax({ url: "${request.contextPath}/employee/xmlOrJsonSimple", success: function(res) { console.log(res); }, headers: { "Accept": "application/json" } }); ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert22.png) 驗證成功。 # 關于配置 如果不想使用mvc:annotation-driven標簽中默認的RequestMappingHandlerAdapter的話,我們可以在重新定義這個bean,spring會覆蓋掉默認的RequestMappingHandlerAdapter。 為何會覆蓋,請參考[Spring中Ordered接口簡介](spring/Spring-Ordered-interface.md) <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/> <bean class="org.springframework.http.converter.StringHttpMessageConverter"/> <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/> </list> </property> </bean> 或者如果只想換messageConverters的話。 <mvc:annotation-driven> <mvc:message-converters> <bean class="org.example.MyHttpMessageConverter"/> <bean class="org.example.MyOtherHttpMessageConverter"/> </mvc:message-converters> </mvc:annotation-driven> 如果還想用其他converters的話。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert23.png) 以上是spring-mvc jar包中的converters。 這里我們使用轉換xml的MarshallingHttpMessageConverter。 這個converter里面使用了marshaller進行轉換 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert24.png) 我們這里使用XStreamMarshaller。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert25.png) ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-xml-json-convert26.png) json沒有轉換器,返回406. 至于xml格式的問題,大家自行解決吧。 這里用的是XStream~。 使用這種方式,pom別忘記了加入xstream的依賴: <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.4.7</version> </dependency> # 總結 寫了這么多,可能讀者覺得有點羅嗦。 畢竟這也是自己的一些心得,希望都能說出來與讀者共享。 剛接觸SpringMVC的時候,發現這種自動轉換機制很牛逼,但是一直沒有研究它的原理,目前,算是了了一個小小心愿吧,SpringMVC還有很多內容,以后自己研究其他內容的時候還會與大家一起共享的。 # 參考資料 [http://my.oschina.net/HeliosFly/blog/205343](http://my.oschina.net/HeliosFly/blog/205343) [http://my.oschina.net/lichhao/blog/172562](http://my.oschina.net/lichhao/blog/172562) [http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看