本篇是《Spring3.X企業應用開發實戰》,陳雄華 林開雄著,電子工業出版社,2012.2出版”的學習筆記的第三篇,關于SpringMVC。
Spring MVC 3.0和早期版本相比擁有了一個質的飛躍,全面支持REST風格的WEB編程、完全注解驅動、處理方法簽名非常靈活、處理方法不依賴于Servlet API等。
由于Spring MVC框架在后頭做了非常多的隱性工作,所以想深入掌握Spring MVC 3.0并非易事,本章我們在學習Spring MVC的各項功能時,還深入其內部了解其后臺的運作機理,只有了解這些機理后,才能更好地使用這個當前最先進的MVC框架。
服務器啟動時加載配置文件的順序:web.xml ?applicationContext.xml ?springmvc-servlet.xml。
# Spring MVC概述
Spring MVC通過一套MVC注解,讓POJO成為處理請求的控制器,無須實現任何接口,同時,Spring MVC還支持REST風格的URL請求:注解驅動及REST風格的Spring MVC是Spring 3.0最出彩的功能之一。
此外,Spring MVC在數據綁定、視圖解析、本地化處理及靜態資源處理上都有不俗的表現。
# DispatcherServlet
Spring MVC框架圍繞DispatcherServlet這個核心展開,DispatcherServlet是Spring MVC的總導演、總策劃,它負責截獲請求并將其分派給相應的處理器處理。
在web.xml中配置DispatcherServlet,截獲特定的URL請求:
~~~
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
~~~
**Spring如何將上下文中的SpringMVC組件裝配到DispatcherServlet中?**
WebApplicationContext初始化后,此時Spring上下文中的Bean已經初始化完畢,開始執行DispatcherServlet的initStrategies()方法,代碼如下:
~~~
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(); //1.初始化上傳文件解析器
initLocalResolver();//2.初始化本地化解析器
initThemeResolver();//3.初始化主題解析器
initHandlerMappings();//4.初始化處理器映射器
initHandlerAdapters();//5.初始化處理器適配器
initHandlerExceptionResolver();//6.初始化處理器異常解析器
initRequestToViewNameTranslator();//7.初始化請求道試圖名解析器
initViewResolvers();//8.初始化試圖解析器
}
~~~
該方法的工作是通過反射機制查找并裝配Spring容器中顯式自定義的組件Bean,如果找不到,則裝配默認的組件實例,默認的組件實例在spring-webmvc-版本.RELEASE.jar包中,org/springframework/web/servlet路徑下的DispatcherServlet.properties中間中定義。
其中文件上傳沒有默認的解析器,如果需要,自行配置,比如:
~~~
<!-- 配置對文件上傳的支持 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />
~~~
# 注解驅動的控制器
在POJO類定義處標注@Controller,再通過<context:component-scan/>掃描相應的類包,即可使POJO成為一個能處理HTTP請求的控制器。
@RequestMapping:不但支持標注的URL,還支持Ant風格(即?、*和**的字符)和帶有{xxx}占位符的URL。帶占位符的URL是Spring 3.0新增的功能,該功能在Spring MVC向REST目標挺進的發展過程中具有里程碑的意義。
通過@PathVariable可以將URL中的占位符參數綁定到控制器處理方法的入參中。
# 如何設置方法入參以綁定請求信息
其他參考:[http://blog.csdn.net/kobejayandy/article/details/12690161](http://blog.csdn.net/kobejayandy/article/details/12690161)
使用命令/表單對象綁定請求參數值:
這是最常用的,即入參就是一個POJO。Spring MVC會按照請求參數名和對象屬性名進行匹配,自動為對象填充屬性值,支持級聯的屬性名,例如:
@RequestMapping("/handleInsert)
public String handleInsert(User user,String operator)…
使用@RequestParam、@CookieValue、@RequestHeader,分別獲取請求、Cookie、請求報文頭的傳入值,他們都有3個參數:
value:參數名;
required:是否必需,默認為true,表示請求中必須包含對應的參數名,如果不存在將拋出異常;
defaultValue:默認參數名,設置該參數時,自動將required設為false。極少情況需要使用該參數,也不推薦使用該參數
使用Servlet API對象作為入參:
public String handleInsert(HttpServletRequest request,HttpServletResponse response)...
另外Spring MVC在 org.springframework.web.context.request包中定義了若干個可代理Servlet原生API類的接口,如WebRequest和NativeWebRequest,他們也允許作為代理類的入參,通過這些代理類可訪問請求對象的任何信息。
使用IO對象作為入參:
Servlet的ServletRequest擁有getInputStream()和getReader()方法,可以通過他們讀取請求的信息。相應Servlet的ServletResponse擁有getOutputStream()和getWriter()方法,可以通過它們輸出響應信息。
Spring MVC允許控制器的處理方法使用java.io.InputStream/java.io.Reader及java.io.OutputStream/java.io.Writer作為方法的入參,Spring MVC將獲取ServletRequest的InputStream/Reader或ServletResponse的OutputStream/Writer,然后傳遞給控制器的處理方法。
使用其他類型的參數:
比如java.util.Locale、java.security.Principal,可以通過Servlet的HttpServletRequest的getLocale()及getUserPrincipal()得到相應的值。
# HttpMessageConverter<T>進行消息對象轉換
HttpMessageConverter<T>是Spring 3.0新添加的一個重要接口,它負責將請求信息轉換為一個對象(類型為T),將對象(類型為T)輸出為響應信息。
DispatcherServlet默認已經安裝了AnnotationMethodHandlerAdapter作為HandlerAdapter的組件實現類,HttpMessageConverter即由AnnotationMethodHandlerAdapter使用,
將請求信息轉換為對象,或將對象轉換為響應信息。
Spring為HttpMessageConverter<T>提供了眾多的實現類,他們組成了一個功能強大、用途廣泛的HttpMessageConverter<T>家族。
AnnotationMethodHandlerAdapter默認一級裝配了如下的HttpMessageConverter:
StringHttpMessageConverter
ByteArrayHttpMessageConverter
SourceHttpMessageConverter
XmlAwareFormHttpMessageConverter
如果需要裝配其他類型的HttpMessageConverter,可在Spring的Web容器上下文中自行定義一個AnnotationMethodHandlerAdapter,如果在Spring容器中顯式定義了一個
AnnotationMethodHandlerAdapter,則Spring MVC將使用它覆蓋默認的AnnotationMethodHandlerAdapter。
如何使用HttpMessageConverter<T>將請求信息轉換并綁定到處理方法的入參中呢?
Spring MVC提供了兩種途徑:
1.使用@RequestBody/@ResponseBody對處理方法進行標注
2.使用HttpEntity<T>/ResponseEntity<T>作為處理方法的入參或返回值
**關于HttpMessageConverter<T>,得出如下幾條結論:**
1.當控制器處理方法使用到@RequestBody/@ResponseBody 或 HttpEntity<T>/ResponseEntity<T>時,Spring MVC才使用注冊的HttpMessageConverter對請求/響應消息進行處理
2.當控制器處理方法使用到@RequestBody/@ResponseBody 或 HttpEntity<T>/ResponseEntity<T>時,Spring首先根據請求頭或響應頭的Accept屬性選擇匹配的HttpMessageConverter,進而根據參數類型或反向類型的過濾得到匹配的HttpMessageConverter,如果找不到可用的HttpMessageConverter將報錯
3.@RequestBody/@ResponseBody不需要成對出現,如果方法入參使用到@RequestBody,Spring MVC選擇匹配的HttpMessageConverter將請求消息轉換并綁定到該入參中。如果處理方法標注了
4.@ResponseBody,Spring MVC選擇匹配的HttpMessageConverter將方法返回值轉換并輸出相應消息。
5.HttpEntity<T>/ResponseEntity<T>的功用和@RequestBody/@ResponseBody相似
# **RestTemplate**
RestTemplate是Spring 3.0新增的模板類,在客戶端程序中可使用該類調用Web服務端的服務,它支持REST風格的URL。此外,它項AnnotationMethodHandlerAdapter一樣擁有一個httpMessageConverter的注冊表,它默認注冊了5個HttpMessageConverter。
# spring-servlet.xml
spring-servlet.xml配置(WEB-INFO目錄下):?
~~~
<!-- 這是簡單配置,代替bean節點那種顯示加載bean的配置方式,可以自動加載必須得如下兩個bean -->
<!-- <mvc:annotation-driven /> -->
<!-- 這是標準配置,可以解決ResponseBody中文亂碼問題 -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
</list>
</property>
<property name="writeAcceptCharset" value="false"/>
</bean>
</list>
</property>
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<!-- 裝載攔截器 -->
<mvc:interceptors>
<!-- 更改語言環境時,一個'locale'的請求參數發送 -->
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
<!-- 權限攔截 -->
<mvc:interceptor>
<mvc:mapping path="/**/*.do" />
<bean class="com.shopyp.authority.interceptor.AuthorityInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
~~~
# 處理模型數據
對于MVC框架來說模型數據是最重要的,因為控制(C)是為了產生模型數據(M),而視圖(V)則是為了渲染模型數據。
如何將模型數據暴漏給視圖是Spring MVC框架的一項重要工作,Spring MVC提供了多種途徑輸出模型數據,介紹如下:
1、ModelAndView:處理方法返回值為ModelAndView時,方法體即可通過該對象添加模型數據
2、@ModelAttribute:方法入參標注該注解后,入參的對象就會放到數據模型中
3、Map及Model:入參為org.springframework.ui.Model、org.springframework.ui.ModelMap或java.util.Map時,處理方法返回時,Map中的數據會自動添加到模型中
4、@SessionAttribute:將模型中的某個屬性暫存到HttpSession中,以便多個請求之間可以共享這個屬性
# 處理方法的數據綁定
我們知道Spring 會根據請求方法簽名的不同,將請求信息中的信息以一定的方式轉換并綁定到請求方法的入參中。
在請求消息到達真正調用處理方法的這一段時間內,Spring還完成了很多工作,包括數據轉換、數據格式化及數據校驗等。這一節使用較少,臨時不去研究。
# 視圖和視圖解析器
請求處理方法執行完成后,最終返回一個ModelAndView對象。
對于那些返回String、View或ModelMap等類型的處理方法,Spring MVC也會在內部將它們裝配成一個ModelAndView對象,它包含了視圖邏輯名和模型對象的信息。
Spring MVC借助視圖解析器(ViewResolver)得到最終的視圖對象(View),這可能是我們常見的JSP視圖,也可能是一個基于FreeMarker、Velocity模板技術的視圖,還可能是PDF、Excel、XML、JSON等各種形式的視圖。
對于最終究竟采取何種視圖對象對模型對象進行渲染,Controller并不關心,Controller的工作重點聚集在生產模型數據的工作上,從而實現MVC的充分解耦。
**FreeMarker配置:**
~~~
<!-- Freemarker配置,參考: http://www.cnblogs.com/hoojo/archive/2011/04/19/2020551.html-->
<bean id="freemarkerConfig"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<!-- 視圖資源位置 -->
<property name="templateLoaderPath" value="/WEB-INF/ftl/" />
<property name="defaultEncoding" value="UTF-8" />
<property name="freemarkerSettings">
<props>
<prop key="template_update_delay">0</prop><!-- 模板更新延時 -->
<prop key="locale">zh_CN</prop>
<prop key="default_encoding">UTF-8</prop>
<prop key="output_encoding">UTF-8</prop>
<prop key="template_exception_handler">rethrow</prop>
<prop key="number_format">#.##</prop>
<prop key="date_format">yyyy-MM-dd</prop>
<prop key="time_format">HH:mm:ss</prop>
<prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
</props>
</property>
<!-- 全局變量部分 -->
<property name="freemarkerVariables">
<map>
<entry key="BasePath" value="${web.basepath}" />
<entry key="xml_escape" value-ref="fmXmlEscape" />
</map>
</property>
</bean>
<bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape" />
<!-- 配置freeMarker視圖解析器 -->
<bean id="ftlviewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" />
<!-- 如果配置了這個節點,則視圖必須是ftl,redirect等前綴都失效了 -->
<!-- <property name="viewNames" value="*.ftl"/> -->
<property name="contentType" value="text/html;charset=UTF-8" />
<property name="cache" value="true" />
<property name="prefix" value="" />
<property name="suffix" value="" />
</bean>
~~~
針對在實際開發過程中使用到的FreeMarker語法,JSTL標簽等,可以逐漸熟悉和記錄。
FreeMarker和Velocity是除JSP之外被使用最多的頁面模板技術。頁面模板編寫好頁面結構,模板頁面中使用一些特殊的變量標識符綁定Java對象的動態數據。
FreeMarker是一個模板引擎,一個基于模板生產文本輸出的通用工具,FreeMarker可以基于模板產生HTML、XML、JAVA源代碼等多種類型的輸出內容。雖然FreeMarker具有一些編程能力,單通常由Java程序準備數據,FreeMarker僅負責基于模板對模型數據進行渲染的工作。
# 關于Web開發
要想成為一名Web開發高手,不能僅滿足于知道如何做,更要拋開現象探究本質。
筆者認為要成為一名Web開發高手,必須熟練了解如下內容:
1、每次請求和響應的背后究竟發生了哪些步驟,客戶端服務器是如何通過HTTP請求報文進行交互的;
2、深刻掌握MIME類型的知識;
3、深刻掌握HTTP響應狀態碼的知識,如404、303究竟代表什么。
**帖子:**
1、http長連接:[http://www.blogjava.net/xjacker/articles/334709.html](http://www.blogjava.net/xjacker/articles/334709.html)
- 前言
- Java之旅--如何從草根成為技術專家
- 《深入理解Java虛擬機》學習筆記
- 《Spring3.X企業應用開發實戰》學習筆記--IoC和AOP
- 《Tomcat權威指南》第二版學習筆記
- Java之旅--多線程進階
- Java之旅--Web.xml解析
- 《Spring3.X企業應用開發實戰》學習筆記--DAO和事務
- 《Spring3.X企業應用開發實戰》學習筆記--SpringMVC
- Java之旅--定時任務(Timer、Quartz、Spring、LinuxCron)
- Spring實用功能--Profile、WebService、緩存、消息、ORM
- JDK框架簡析--java.lang包中的基礎類庫、基礎數據類型
- JDK框架簡析--java.util包中的工具類庫
- JDK框架簡析--java.io包中的輸入輸出類庫
- Java之旅--通訊
- Java之旅--XML/JSON
- Java之旅--Linux&amp;java進階(看清操作系統層面的事)
- Java之旅--硬件和Java并發(神之本源)
- Java之旅--設計模式
- jetty