第一章 Spring的MVC框架
6.1 Spring MVC概要
Spring的web框架是圍繞DispatcherServlet
來進行設計的。DispatcherServlet
的作用是將請求分發到不同的處理器。Spring的web框架包括可配置的處理器(handler)映射、視圖(view)解析、本地化(local)解析、主題(theme)解析以及對上傳文件解析。處理器是對Controller
接口的實現,該接口僅僅定義了ModelAndView handleRequest(request, response)
方法。你可以通過實現這個接口來生成自己的控制器(也可以稱之爲處理器),但是從Spring提供的一系列控制器繼承會更省事,比如AbstractController
、AbstractCommandController
和SimpleFormController
。注意,你需要選擇正確的基類:如果你沒有表單,你就不需要一個FormController。這是和Structs的一個主要區別。Spring的視圖解析相當靈活。一個控制器甚至可以直接向response輸出一個視圖(此時控制器返回ModelAndView的值必須是null)。在一般的情況下,一個ModelAndView實例包含一個視圖名字和一個類型爲Map的model,一個model是一些以bean的名字爲key,以bean對象(可以是命令或form,也可以是其他的JavaBean)爲value的名值對。對視圖名稱的解析處理也是高度可配置的,可以通過bean的名字、屬性文件或者自定義的ViewResolver實現來進行解析。實際上基於Map的model(也就是MVC中的M))是高度抽象的,適用於各種表現層技術。也就是說,任何表現層都可以直接和Spring集成,無論是JSP、Velocity還是其它表現層技術。Map model可以被轉換成合適的格式,比如JSP request attribute或者Velocity template model。
Spring Web MVC框架提供了大量獨特的功能,包括:
1) 清晰的角色劃分:控制器(controller)、驗證器(validator)、命令對象(command object)、表單對象(form object)、模型對象(model object)、Servlet分發器(DispatcherServlet)、處理器映射(handler mapping)、視圖解析器(view resolver)等等。 每一個角色都可以由一個專門的對象來實現。
2)強大而直接的配置方式:將框架類和應用類都作爲JavaBean配置,支持在一個context中引用其他context的中JavaBean,例如,在web控制器中對業務對象和驗證器(validator)的引用。
3) 可適配、非侵入的controller:你可以根據不同的應用場景,選擇合適的控制器子類(simple型、command型、form型、wizard型、multi-action型或者自定義),而不是從單一控制器(比如Action/ActionForm)繼承。
4)可重用的業務代碼:你可以使用現有的業務對象作爲命令或表單對象,而不需要在類似ActionForm的子類中重複它們的定義。
5)可定製的綁定(binding) 和驗證(validation):比如將類型不匹配作爲應用級的驗證錯誤,這可以保存錯誤的值。再比如本地化的日期和數字綁定等等。在其他某些框架中,你只能使用字符串表單對象,需要手動解析它並轉換到業務對象。
6) 可定製的handler mapping和view resolution:Spring提供從最簡單的的URL映射,到複雜的、專用的定製策略。與某些MVC框架強制開發人員使用單一特定技術相比,Spring顯得更加靈活。靈活。
7) 靈活的model轉換: 在Springweb框架中,使用基於Map的名/值對來達到輕易地與各種視圖技術的集成。
8) 可定製的本地化和主題(theme)解析:支持在JSP中可選擇地使用Spring標籤庫、支持JSTL、支持Velocity(不需要額外的中間層)等等。
9)Spring Bean的生命週期可以被限制在當前的HTTP Request或者HTTP Session。準確的說,這並非Spring MVC框架本身特性,而應歸屬於Sping MVC使用的WebApplicationContext容器。
6.2 將請求映射到控制器
和其它web框架一樣,Spring的web框架是一個請求驅動的web框架,其設計圍繞一箇中心的servlet進行,它能將請求分發給控制器,並提供其它功能幫助web應用開發。然而,Spring的DispatcherServlet
所做的不僅僅是這些,它和Spring的IoC容器完全集成在一起,從而允許你使用Spring的其它功能。
代碼清單1
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-config-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
代碼清單1中我們定義了DispatcherServlet取名dispatcher並且將所有以.do結尾的請求都交由dispatcher處理,並且爲他指定了名爲spring-config-mvc.xml 的Spring配置文件。如果我們沒有指定配置文件的名稱Spring會在web應用的WEB-INF
文件夾下尋找名爲[servlet-name]-servlet.xml
的配置文件如dispatcher-servlet.xml
代碼清單2
<bean id="viewResolver" class="org.springframework.web.servlet.view.
InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="simpleUrlHandlerMapping" class="org.springframework.web.servlet.handler.
SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/helloworld.do"> helloworldController</prop>
</props>
</property>
</bean>
<bean id=" helloworldController "
class="com.tony.web.controller.HelloworldController"/>
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class HelloworldController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
//向HttpServletRequest中加入一個名爲message值爲HelloWorld的對象
request.setAttribute("message", "HelloWorld");
//返回一個ModelAndView對象通過viewResolver的處理
//頁面跳轉至/WEB-INF/jsp/helloworld.jsp
return new ModelAndView("helloworld");
}
}
代碼清單1中配置 InternalResourceViewResolver,它是 jsp 渲染模板的處理器。如果你告訴 InternalResourceViewResolver 處理一個名爲 helloworld的模板時,它會渲染 /WEB-INF/jsp/helloworld.jsp 文件。把 jsp 文件放到/WEB-INF/jsp/ 目錄下是被鼓勵的,這樣可以防止用戶不經過 Controller 直接訪問 jsp 文件從而出錯。配置 SimpleUrlHandlerMapping, 在上面的配置文件中,/ helloworld.do 的請求將被 helloworldController處理。 "/ helloworld.do"和"helloworldController" 是變量,你可以更改。但是你注意到了嗎, hello.do 以 .do 作爲後綴名。如果這裏(本文的條件下)你不使用.do 作爲後綴名, 就沒有程序來處理這個請求了。 因爲 DispatcherServlet 將收到的請求轉交給 SimpleUrlHandlerMapping, DispatcherServlet 收不到的請求,SimpleUrlHandlerMapping 當然也收不到了。我們還定義了一個名爲HelloworldController的控制器來處理/helloworld.do的請求。大多數Web應用都會遇到需要填寫表單的頁面,當表單提交成功後,表單的數據被傳送到Web服務器中處理,遇到這種情況Spring爲我們提供了一個簡單的類SimpleFormController。
代碼清單2
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.mvc.SimpleFormController;
public class HelloworldController extends SimpleFormController{
public HelloworldController(){
//設置表單對象類型
this.setCommandClass(User.class);
}
@Override
protected void doSubmitAction(Object command) throws Exception {
User user = (User)command;
//將User對象存入數據庫
}
}
代碼清單2中我們將HelloworldController類繼承SimpleFormController並且實現了doSubmitAction方法,在構造方法中我們設置了表單對象的類型,當表單提交後Spring會自動調用doSubmitAction方法將表單對象裝配好作爲入參傳遞進來,我們將其類型轉後就可以對其操作了。