1、Spring Web MVC是什麼
Spring Web MVC是一種基於Java的實現了Web MVC設計模式的請求驅動類型的輕量級Web框架,即使用了MVC架構模式的思想,將web層進行職責解耦,基於請求驅動指的就是使用請求-響應模型,框架的目的就是幫助我們簡化開發,Spring Web MVC也是要簡化我們日常Web開發的。
另外還有一種基於組件的、事件驅動的Web框架在此就不介紹了,如Tapestry、JSF等。
Spring Web MVC也是服務到工作者模式的實現,但進行可優化。前端控制器是DispatcherServlet;
應用控制器其實拆爲處理器映射器(Handler Mapping)進行處理器管理和視圖解析器(View Resolver)進行視圖管理;頁面控制器/動作/處理器爲Controller接口(僅包含ModelAndView handleRequest(request,
response)
方法)的實現(也可以是任何的POJO類);支持本地化(Locale)解析、主題(Theme)解析及文件上傳等;提供了非常靈活的數據驗證、格式化和數據綁定機制;提供了強大的約定大於配置(慣例優先原則)的契約式編程支持。
在Spring的Web MVC框架提供了模型 - 視圖 - 控制器架構以及可用於開發靈活,鬆散耦合的Web應用程序準備的組件。 MVC模式會導致分離的應用程序(輸入邏輯,業務邏輯和UI邏輯)的不同方面,同時提供這些元素之間的鬆耦合。
-
模型(Model )封裝了應用程序的數據和一般他們會組成的POJO。
-
視圖(View)是負責呈現模型數據和一般它生成的HTML輸出,客戶端的瀏覽器能夠解釋。
-
控制器(Controller )負責處理用戶的請求,並建立適當的模型,並把它傳遞給視圖渲染。
2、Spring Web MVC能幫我們做什麼
√讓我們能非常簡單的設計出乾淨的Web層和薄薄的Web層;
√進行更簡潔的Web層的開發;
√天生與Spring框架集成(如IoC容器、AOP等);
√提供強大的約定大於配置的契約式編程支持;
√能簡單的進行Web層的單元測試;
√支持靈活的URL到頁面控制器的映射;
√非常容易與其他視圖技術集成,如Velocity、FreeMarker等等,因爲模型數據不放在特定的API裏,而是放在一個Model裏(Map
數據結構實現,因此很容易被其他框架使用);
√非常靈活的數據驗證、格式化和數據綁定機制,能使用任何對象進行數據綁定,不必實現特定框架的API;
√提供一套強大的JSP標籤庫,簡化JSP開發;
√支持靈活的本地化、主題等解析;
√更加簡單的異常處理;
√對靜態資源的支持;
√支持Restful風格。
3、Spring Web MVC架構
Spring Web MVC框架也是一個基於請求驅動的Web框架,並且也使用了前端控制器模式來進行設計,再根據請求映射規則分發給相應的頁面控制器(動作/處理器)進行處理。首先讓我們整體看一下Spring Web MVC處理請求的流程:
3.1、Spring Web MVC處理請求的流程
如圖2-1
圖2-1
具體執行步驟如下:
1、 首先用戶發送請求————>前端控制器,前端控制器根據請求信息(如URL)來決定選擇哪一個頁面控制器進行處理並把請求委託給它,即以前的控制器的控制邏輯部分;圖2-1中的1、2步驟;
2、 頁面控制器接收到請求後,進行功能處理,首先需要收集和綁定請求參數到一個對象,這個對象在Spring Web MVC中叫命令對象,並進行驗證,然後將命令對象委託給業務對象進行處理;處理完畢後返回一個ModelAndView(模型數據和邏輯視圖名);圖2-1中的3、4、5步驟;
3、 前端控制器收回控制權,然後根據返回的邏輯視圖名,選擇相應的視圖進行渲染,並把模型數據傳入以便視圖渲染;圖2-1中的步驟6、7;
4、 前端控制器再次收回控制權,將響應返回給用戶,圖2-1中的步驟8;至此整個結束。
問題:
1、 請求如何給前端控制器?
2、 前端控制器如何根據請求信息選擇頁面控制器進行功能處理?
3、 如何支持多種頁面控制器呢?
4、 如何頁面控制器如何使用業務對象?
5、 頁面控制器如何返回模型數據?
6、 前端控制器如何根據頁面控制器返回的邏輯視圖名選擇具體的視圖進行渲染?
7、 不同的視圖技術如何使用相應的模型數據?
首先我們知道有如上問題,那這些問題如何解決呢?請讓我們先繼續,在後邊依次回答。
3.2、Spring Web MVC架構
1、Spring Web MVC核心架構圖,如圖2-2
圖2-2
核心架構的具體流程步驟如下:
1、 首先用戶發送請求——>DispatcherServlet,前端控制器收到請求後自己不進行處理,而是委託給其他的解析器進行處理,作爲統一訪問點,進行全局的流程控制;
2、 DispatcherServlet——>HandlerMapping, HandlerMapping將會把請求映射爲HandlerExecutionChain對象(包含一個Handler處理器(頁面控制器)對象、多個HandlerInterceptor攔截器)對象,通過這種策略模式,很容易添加新的映射策略;
3、 DispatcherServlet——>HandlerAdapter,HandlerAdapter將會把處理器包裝爲適配器,從而支持多種類型的處理器,即適配器設計模式的應用,從而很容易支持很多類型的處理器;
4、 HandlerAdapter——>處理器功能處理方法的調用,HandlerAdapter將會根據適配的結果調用真正的處理器的功能處理方法,完成功能處理;並返回一個ModelAndView對象(包含模型數據、邏輯視圖名);
5、 ModelAndView的邏輯視圖名——> ViewResolver, ViewResolver將把邏輯視圖名解析爲具體的View,通過這種策略模式,很容易更換其他視圖技術;
6、 View——>渲染,View會根據傳進來的Model模型數據進行渲染,此處的Model實際是一個Map數據結構,因此很容易支持其他視圖技術;
7、返回控制權給DispatcherServlet,由DispatcherServlet返回響應給用戶,到此一個流程結束。
此處我們只是講了核心流程,沒有考慮攔截器、本地解析、文件上傳解析等,後邊再細述。
到此,再來看我們前邊提出的問題:
1、 請求如何給前端控制器?這個應該在web.xml中進行部署描述,在HelloWorld中詳細講解。
2、 前端控制器如何根據請求信息選擇頁面控制器進行功能處理? 我們需要配置HandlerMapping進行映射
3、 如何支持多種頁面控制器呢?配置HandlerAdapter從而支持多種類型的頁面控制器
4、 如何頁面控制器如何使用業務對象?可以預料到,肯定利用Spring IoC容器的依賴注入功能
5、 頁面控制器如何返回模型數據?使用ModelAndView返回
6、 前端控制器如何根據頁面控制器返回的邏輯視圖名選擇具體的視圖進行渲染? 使用ViewResolver進行解析
7、 不同的視圖技術如何使用相應的模型數據? 因爲Model是一個Map數據結構,很容易支持其他視圖技術
在此我們可以看出具體的核心開發步驟:
1、 DispatcherServlet在web.xml中的部署描述,從而攔截請求到Spring Web MVC
2、 HandlerMapping的配置,從而將請求映射到處理器
3、 HandlerAdapter的配置,從而支持多種類型的處理器
4、 ViewResolver的配置,從而將邏輯視圖名解析爲具體視圖技術
5、處理器(頁面控制器)的配置,從而進行功能處理
你需要映射所需的DispatcherServlet處理,通過在web.xml文件中使用URL映射請求。下面是一個例子,說明聲明和映射 HelloWeb DispatcherServlet 的例子:
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
- id="WebApp_ID" version="3.0">
- <!-- SpringMVC的前端控制器 -->
- <servlet>
- <servlet-name>Hello</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <!-- Spring MVC配置文件結束 -->
- <!-- 攔截設置 -->
- <servlet-mapping>
- <servlet-name>Hello</servlet-name>
- <!-- 由SpringMVC攔截所有請求 -->
- <url-pattern>/</url-pattern>
- </servlet-mapping>
- </web-app>
web.xml 文件將被保存在您的Web應用程序的 WebContent/ WEB-INF 目錄。 在 DispatcherServlet 的 HelloWeb 初始化,該框架將嘗試從一個名爲 [servlet-name]-servlet.xml位於應用程序 WebContent/WEB-INF 目錄文件加載應用程序上下文。在這種情況下我們的文件將是HelloWeb-servlet.xml。
接下來,<servlet-mapping>標記指示URL會被DispatcherServlet處理。這裏全部用。jsp結束HTTP請求將由DispatcherServlet的HelloWeb處理。如果不想用默認文件名爲[servlet-name]-servlet.xml和默認位置的WebContent/WEB-INF。 在 web.xml 文件中定義該文件的名稱和位置如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
- id="WebApp_ID" version="3.0">
- <!-- SpringMVC的前端控制器 -->
- <servlet>
- <servlet-name>Hello</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <!-- 設置自己定義的控制器xml文件 -->
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>/WEB-INF/Hello-servlet.xml</param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <!-- Spring MVC配置文件結束 -->
- <!-- 攔截設置 -->
- <servlet-mapping>
- <servlet-name>Hello</servlet-name>
- <!-- 由SpringMVC攔截所有請求 -->
- <url-pattern>/</url-pattern>
- </servlet-mapping>
- </web-app>
現在,讓我們檢查所需配置的HelloWeb-servlet.xml文件,放置在 Web應用程序的WebContent/WEB-INF目錄:
下面是有關 Hello-servlet.xml 文件的要點:
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
- xsi:schemaLocation="
- http://www.springframework.org/schema/mvc
- http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <!-- 把標記了@Controller註解的類轉換爲bean -->
- <context:component-scan base-package="com.mucfc" />
- <!-- 啓動Spring MVC的註解功能,完成請求和註解POJO的映射 -->
- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
- <!-- 對模型視圖名稱的解析,即在模型視圖名稱添加前後綴 -->
- <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
- p:prefix="/WEB-INF/views/" p:suffix=".jsp"/>
- </beans>
-
[servlet-name]-servlet.xml 文件將被用於創建定義的Bean,會覆蓋在全局範圍里名字相同的Bean的定義。
-
<context:component-scan...>標籤將使用啓動Spring MVC的註解掃描功能,允許做出像 @Controller和使用@RequestMapping註解等使用。
-
使用InternalResourceViewResolver將有定義來解析視圖名的規則。按照上述定義的規則,命名爲你好的邏輯視圖被委託給一個視圖實現位於/WEB-INF/jsp/hello.jsp。
3.3、定義控制器
DispatcherServlet 委託請求發送到控制器,以執行特定於它的功能。註解@Controller表示一個特定的類提供一個控制器的角色。註解@RequestMapping 用於將URL映射到任何一個類或者一個特定的處理方法。
- package com.mucfc;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.ModelMap;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- @Controller
- public class HelloWorldController {
- @RequestMapping(value="/hello")
- public String printWelcome(ModelMap model) {
- model.addAttribute("message", "Spring 3 MVC Hello World");
- return "hello";
- }
- }
註解@Controller類定義爲一個Spring MVC控制器。在這裏,使用@RequestMapping第一次使用表明,該控制器上的所有處理方法是相對於/hello 路徑。下一步標註使用@RequestMapping(方法= RequestMethod.GET)用於聲明printHello() 方法作爲控制器的默認服務方法來處理HTTP GET請求。可以定義另一種方法來處理同一URL的POST請求。
可以寫在上面的另一種形式,可以使用@RequestMapping添加額外的屬性如下控制:
- package com.mucfc;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.ModelMap;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- @Controller
- public class HelloWorldController {
- @RequestMapping(value="/hello",method=RequestMethod.GET,params="userid")
- public String printWelcome(ModelMap model,String userid) {
- model.addAttribute("message", "Spring 3 MVC Hello World");
- return "hello";
- }
- }
value屬性指示該處理方法所映射到的URL和method屬性定義了服務的方法來處理HTTP GET請求。有以下重要點要注意關於上述定義的控制器:
-
將定義所需的業務邏輯內部的服務方法。可以調用此方法在另一個方法按要求。
-
基於定義的業務邏輯,將在此方法中創建一個模型。您可以設定器不同的模型的屬性和這些屬性將被視圖訪問提出的最終結果。此示例創建一個具有自己的屬性“message”的模型。
-
定義的服務方法可以返回一個字符串,其中包含要用於渲染模型視圖的名稱。這個例子返回“hello”作爲邏輯視圖名。
3.4、創建JSP視圖
Spring MVC支持多種類型的視圖不同的演示技術。這些措施包括:JSP,HTML,PDF,Excel,XML,Velocity,XSLT,JSON,Atom和RSS訂閱,JasperReports等,但最常用JSTL JSP模板。因此,我們編寫一個/WEB-INF/hello/hello.jsp簡單的hello 視圖:
在這裏, ${message}是我們已經建立了控制器內部的屬性。你可以在視圖中顯示多個屬性。- <%@ page language="java" contentType="text/html; charset=gb2312"
- pageEncoding="gb2312"%>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
- <title>Insert title here</title>
- </head>
- <body>
- Message:${message}
- </body>
- </html>
4、Spring Web MVC優勢
1、清晰的角色劃分:前端控制器(DispatcherServlet
)、請求到處理器映射(HandlerMapping)、處理器適配器(HandlerAdapter)、視圖解析器(ViewResolver)、處理器或頁面控制器(Controller)、驗證器( Validator)、命令對象(Command 請求參數綁定到的對象就叫命令對象)、表單對象(Form Object 提供給表單展示和提交到的對象就叫表單對象)。
2、分工明確,而且擴展點相當靈活,可以很容易擴展,雖然幾乎不需要;
3、由於命令對象就是一個POJO,無需繼承框架特定API,可以使用命令對象直接作爲業務對象;
4、和Spring 其他框架無縫集成,是其它Web框架所不具備的;
5、可適配,通過HandlerAdapter可以支持任意的類作爲處理器;
6、可定製性,HandlerMapping、ViewResolver等能夠非常簡單的定製;
7、功能強大的數據驗證、格式化、綁定機制;
8、利用Spring提供的Mock對象能夠非常簡單的進行Web層單元測試;
9、本地化、主題的解析的支持,使我們更容易進行國際化和主題的切換。
10、強大的JSP標籤庫,使JSP編寫更容易。
………………還有比如RESTful風格的支持、簡單的文件上傳、約定大於配置的契約式編程支持、基於註解的零配置支持等等。
到此我們已經簡單的瞭解了Spring Web MVC,接下來讓我們來個實例HelloWorld來具體使用下這個框架。