(一) Spring MVC

2.1、Spring Web MVC是什么

Spring Web MVC是一種基于Java的實(shí)現(xiàn)了Web MVC設(shè)計(jì)模式的請(qǐng)求驅(qū)動(dòng)類型的輕量級(jí)Web框架,即使用了MVC架構(gòu)模式的思想,將web層進(jìn)行職責(zé)解耦,基于請(qǐng)求驅(qū)動(dòng)指的就是使用請(qǐng)求-響應(yīng)模型,框架的目的就是幫助我們簡(jiǎn)化開發(fā),Spring Web MVC也是要簡(jiǎn)化我們?nèi)粘eb開發(fā)的。

另外還有一種基于組件的、事件驅(qū)動(dòng)的Web框架在此就不介紹了,如Tapestry、JSF等。

Spring Web MVC也是服務(wù)到工作者模式的實(shí)現(xiàn),但進(jìn)行可優(yōu)化。前端控制器是DispatcherServlet;應(yīng)用控制器其實(shí)拆為處理器映射器(Handler Mapping)進(jìn)行處理器管理和視圖解析器(View Resolver)進(jìn)行視圖管理;頁(yè)面控制器/動(dòng)作/處理器為Controller接口(僅包含ModelAndView handleRequest(request, response) 方法)的實(shí)現(xiàn)(也可以是任何的POJO類);支持本地化(Locale)解析、主題(Theme)解析及文件上傳等;提供了非常靈活的數(shù)據(jù)驗(yàn)證、格式化和數(shù)據(jù)綁定機(jī)制;提供了強(qiáng)大的約定大于配置(慣例優(yōu)先原則)的契約式編程支持。

2.2、Spring Web MVC能幫我們做什么

√讓我們能非常簡(jiǎn)單的設(shè)計(jì)出干凈的Web層和薄薄的Web層;

√進(jìn)行更簡(jiǎn)潔的Web層的開發(fā);

√天生與Spring框架集成(如IoC容器、AOP等);

√提供強(qiáng)大的約定大于配置的契約式編程支持;

√能簡(jiǎn)單的進(jìn)行Web層的單元測(cè)試;

√支持靈活的URL到頁(yè)面控制器的映射;

√非常容易與其他視圖技術(shù)集成,如Velocity、FreeMarker等等,因?yàn)槟P蛿?shù)據(jù)不放在特定的API里,而是放在一個(gè)Model里(Map數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn),因此很容易被其他框架使用);

√非常靈活的數(shù)據(jù)驗(yàn)證、格式化和數(shù)據(jù)綁定機(jī)制,能使用任何對(duì)象進(jìn)行數(shù)據(jù)綁定,不必實(shí)現(xiàn)特定框架的API;

√提供一套強(qiáng)大的JSP標(biāo)簽庫(kù),簡(jiǎn)化JSP開發(fā);

√支持靈活的本地化、主題等解析;

√更加簡(jiǎn)單的異常處理;

√對(duì)靜態(tài)資源的支持;

√支持Restful風(fēng)格。

2.3、Spring Web MVC架構(gòu)

Spring Web MVC框架也是一個(gè)基于請(qǐng)求驅(qū)動(dòng)的Web框架,并且也使用了前端控制器模式來進(jìn)行設(shè)計(jì),再根據(jù)請(qǐng)求映射規(guī)則分發(fā)給相應(yīng)的頁(yè)面控制器(動(dòng)作/處理器)進(jìn)行處理。首先讓我們整體看一下Spring Web MVC處理請(qǐng)求的流程:

2.3.1、Spring Web MVC處理請(qǐng)求的流程

如圖2-1

image

圖2-1

具體執(zhí)行步驟如下:

1、 首先用戶發(fā)送請(qǐng)求————>前端控制器,前端控制器根據(jù)請(qǐng)求信息(如URL)來決定選擇哪一個(gè)頁(yè)面控制器進(jìn)行處理并把請(qǐng)求委托給它,即以前的控制器的控制邏輯部分;圖2-1中的1、2步驟;

2、 頁(yè)面控制器接收到請(qǐng)求后,進(jìn)行功能處理,首先需要收集和綁定請(qǐng)求參數(shù)到一個(gè)對(duì)象,這個(gè)對(duì)象在Spring Web MVC中叫命令對(duì)象,并進(jìn)行驗(yàn)證,然后將命令對(duì)象委托給業(yè)務(wù)對(duì)象進(jìn)行處理;處理完畢后返回一個(gè)ModelAndView(模型數(shù)據(jù)和邏輯視圖名);圖2-1中的3、4、5步驟;

3、 前端控制器收回控制權(quán),然后根據(jù)返回的邏輯視圖名,選擇相應(yīng)的視圖進(jìn)行渲染,并把模型數(shù)據(jù)傳入以便視圖渲染;圖2-1中的步驟6、7;

4、 前端控制器再次收回控制權(quán),將響應(yīng)返回給用戶,圖2-1中的步驟8;至此整個(gè)結(jié)束。

問題:

1、 請(qǐng)求如何給前端控制器?

2、 前端控制器如何根據(jù)請(qǐng)求信息選擇頁(yè)面控制器進(jìn)行功能處理?

3、 如何支持多種頁(yè)面控制器呢?

4、 如何頁(yè)面控制器如何使用業(yè)務(wù)對(duì)象?

5、 頁(yè)面控制器如何返回模型數(shù)據(jù)?

6、 前端控制器如何根據(jù)頁(yè)面控制器返回的邏輯視圖名選擇具體的視圖進(jìn)行渲染?

7、 不同的視圖技術(shù)如何使用相應(yīng)的模型數(shù)據(jù)?

首先我們知道有如上問題,那這些問題如何解決呢?請(qǐng)讓我們先繼續(xù),在后邊依次回答。

2.3.2、Spring Web MVC架構(gòu)

1、Spring Web MVC核心架構(gòu)圖,如圖2-2

image

圖2-2

架構(gòu)圖對(duì)應(yīng)的DispatcherServlet核心代碼如下:

java代碼:

1.  //前端控制器分派方法  
2.  protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  
3.  HttpServletRequest processedRequest = request;  
4.  HandlerExecutionChain mappedHandler = null;  
5.  int interceptorIndex = -1;  

7.  try {  
8.  ModelAndView mv;  
9.  boolean errorView = false;  

11.  try {  
12.  //檢查是否是請(qǐng)求是否是multipart(如文件上傳),如果是將通過MultipartResolver解析  
13.  processedRequest = checkMultipart(request);  
14.  //步驟2、請(qǐng)求到處理器(頁(yè)面控制器)的映射,通過HandlerMapping進(jìn)行映射  
15.  mappedHandler = getHandler(processedRequest, false);  
16.  if (mappedHandler == null || mappedHandler.getHandler() == null) {  
17.  noHandlerFound(processedRequest, response);  
18.  return;  
19.  }  
20.  //步驟3、處理器適配,即將我們的處理器包裝成相應(yīng)的適配器(從而支持多種類型的處理器)  
21.  HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  

23.  // 304 Not Modified緩存支持  
24.  //此處省略具體代碼  

26.  // 執(zhí)行處理器相關(guān)的攔截器的預(yù)處理(HandlerInterceptor.preHandle)  
27.  //此處省略具體代碼  

29.  // 步驟4、由適配器執(zhí)行處理器(調(diào)用處理器相應(yīng)功能處理方法)  
30.  mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  

32.  // Do we need view name translation?  
33.  if (mv != null && !mv.hasView()) {  
34.  mv.setViewName(getDefaultViewName(request));  
35.  }  

37.  // 執(zhí)行處理器相關(guān)的攔截器的后處理(HandlerInterceptor.postHandle)  
38.  //此處省略具體代碼  
39.  }  
40.  catch (ModelAndViewDefiningException ex) {  
41.  logger.debug("ModelAndViewDefiningException encountered", ex);  
42.  mv = ex.getModelAndView();  
43.  }  
44.  catch (Exception ex) {  
45.  Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);  
46.  mv = processHandlerException(processedRequest, response, handler, ex);  
47.  errorView = (mv != null);  
48.  }  

50.  //步驟5 步驟6、解析視圖并進(jìn)行視圖的渲染  
51.  //步驟5 由ViewResolver解析View(viewResolver.resolveViewName(viewName, locale))  
52.  //步驟6 視圖在渲染時(shí)會(huì)把Model傳入(view.render(mv.getModelInternal(), request, response);)  
53.  if (mv != null && !mv.wasCleared()) {  
54.  render(mv, processedRequest, response);  
55.  if (errorView) {  
56.  WebUtils.clearErrorRequestAttributes(request);  
57.  }  
58.  }  
59.  else {  
60.  if (logger.isDebugEnabled()) {  
61.  logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +  
62.  "': assuming HandlerAdapter completed request handling");  
63.  }  
64.  }  

66.  // 執(zhí)行處理器相關(guān)的攔截器的完成后處理(HandlerInterceptor.afterCompletion)  
67.  //此處省略具體代碼  

70.  catch (Exception ex) {  
71.  // Trigger after-completion for thrown exception.  
72.  triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);  
73.  throw ex;  
74.  }  
75.  catch (Error err) {  
76.  ServletException ex = new NestedServletException("Handler processing failed", err);  
77.  // Trigger after-completion for thrown exception.  
78.  triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);  
79.  throw ex;  
80.  }  

82.  finally {  
83.  // Clean up any resources used by a multipart request.  
84.  if (processedRequest != request) {  
85.  cleanupMultipart(processedRequest);  
86.  }  
87.  }  
88.  }  

核心架構(gòu)的具體流程步驟如下:

1、 首先用戶發(fā)送請(qǐng)求——>DispatcherServlet,前端控制器收到請(qǐng)求后自己不進(jìn)行處理,而是委托給其他的解析器進(jìn)行處理,作為統(tǒng)一訪問點(diǎn),進(jìn)行全局的流程控制;

2、 DispatcherServlet——>HandlerMapping, HandlerMapping將會(huì)把請(qǐng)求映射為HandlerExecutionChain對(duì)象(包含一個(gè)Handler處理器(頁(yè)面控制器)對(duì)象、多個(gè)HandlerInterceptor攔截器)對(duì)象,通過這種策略模式,很容易添加新的映射策略;

3、 DispatcherServlet——>HandlerAdapter,HandlerAdapter將會(huì)把處理器包裝為適配器,從而支持多種類型的處理器,即適配器設(shè)計(jì)模式的應(yīng)用,從而很容易支持很多類型的處理器;

4、 HandlerAdapter——>處理器功能處理方法的調(diào)用,HandlerAdapter將會(huì)根據(jù)適配的結(jié)果調(diào)用真正的處理器的功能處理方法,完成功能處理;并返回一個(gè)ModelAndView對(duì)象(包含模型數(shù)據(jù)、邏輯視圖名);

5、 ModelAndView的邏輯視圖名——> ViewResolver, ViewResolver將把邏輯視圖名解析為具體的View,通過這種策略模式,很容易更換其他視圖技術(shù);

6、 View——>渲染,View會(huì)根據(jù)傳進(jìn)來的Model模型數(shù)據(jù)進(jìn)行渲染,此處的Model實(shí)際是一個(gè)Map數(shù)據(jù)結(jié)構(gòu),因此很容易支持其他視圖技術(shù);

7、返回控制權(quán)給DispatcherServlet,由DispatcherServlet返回響應(yīng)給用戶,到此一個(gè)流程結(jié)束。

此處我們只是講了核心流程,沒有考慮攔截器、本地解析、文件上傳解析等,后邊再細(xì)述。

到此,再來看我們前邊提出的問題:

1、 請(qǐng)求如何給前端控制器?這個(gè)應(yīng)該在web.xml中進(jìn)行部署描述,在HelloWorld中詳細(xì)講解。

2、 前端控制器如何根據(jù)請(qǐng)求信息選擇頁(yè)面控制器進(jìn)行功能處理? 我們需要配置HandlerMapping進(jìn)行映射

3、 如何支持多種頁(yè)面控制器呢?配置HandlerAdapter從而支持多種類型的頁(yè)面控制器

4、 如何頁(yè)面控制器如何使用業(yè)務(wù)對(duì)象?可以預(yù)料到,肯定利用Spring IoC容器的依賴注入功能

5、 頁(yè)面控制器如何返回模型數(shù)據(jù)?使用ModelAndView返回

6、 前端控制器如何根據(jù)頁(yè)面控制器返回的邏輯視圖名選擇具體的視圖進(jìn)行渲染? 使用ViewResolver進(jìn)行解析

7、 不同的視圖技術(shù)如何使用相應(yīng)的模型數(shù)據(jù)? 因?yàn)镸odel是一個(gè)Map數(shù)據(jù)結(jié)構(gòu),很容易支持其他視圖技術(shù)

在此我們可以看出具體的核心開發(fā)步驟:

1、 DispatcherServlet在web.xml中的部署描述,從而攔截請(qǐng)求到Spring Web MVC

2、 HandlerMapping的配置,從而將請(qǐng)求映射到處理器

3、 HandlerAdapter的配置,從而支持多種類型的處理器

4、 ViewResolver的配置,從而將邏輯視圖名解析為具體視圖技術(shù)

5、處理器(頁(yè)面控制器)的配置,從而進(jìn)行功能處理

上邊的開發(fā)步驟我們會(huì)在Hello World中詳細(xì)驗(yàn)證。

2.4、Spring Web MVC優(yōu)勢(shì)

1、清晰的角色劃分:前端控制器(DispatcherServlet)、請(qǐng)求到處理器映射(HandlerMapping)、處理器適配器(HandlerAdapter)、視圖解析器(ViewResolver)、處理器或頁(yè)面控制器(Controller)、驗(yàn)證器( Validator)、命令對(duì)象(Command 請(qǐng)求參數(shù)綁定到的對(duì)象就叫命令對(duì)象)、表單對(duì)象(Form Object 提供給表單展示和提交到的對(duì)象就叫表單對(duì)象)。

2、分工明確,而且擴(kuò)展點(diǎn)相當(dāng)靈活,可以很容易擴(kuò)展,雖然幾乎不需要;

3、由于命令對(duì)象就是一個(gè)POJO,無需繼承框架特定API,可以使用命令對(duì)象直接作為業(yè)務(wù)對(duì)象;

4、和Spring 其他框架無縫集成,是其它Web框架所不具備的;

5、可適配,通過HandlerAdapter可以支持任意的類作為處理器;

6、可定制性,HandlerMapping、ViewResolver等能夠非常簡(jiǎn)單的定制;

7、功能強(qiáng)大的數(shù)據(jù)驗(yàn)證、格式化、綁定機(jī)制;

8、利用Spring提供的Mock對(duì)象能夠非常簡(jiǎn)單的進(jìn)行Web層單元測(cè)試;

9、本地化、主題的解析的支持,使我們更容易進(jìn)行國(guó)際化和主題的切換。

10、強(qiáng)大的JSP標(biāo)簽庫(kù),使JSP編寫更容易。

………………還有比如RESTful風(fēng)格的支持、簡(jiǎn)單的文件上傳、約定大于配置的契約式編程支持、基于注解的零配置支持等等。

到此我們已經(jīng)簡(jiǎn)單的了解了Spring Web MVC,接下來讓我們來個(gè)實(shí)例來具體使用下這個(gè)框架。

2.5、Hello World入門

2.5.1、準(zhǔn)備開發(fā)環(huán)境和運(yùn)行環(huán)境:

☆開發(fā)工具:eclipse

☆運(yùn)行環(huán)境:tomcat6.0.20

☆工程:動(dòng)態(tài)web****工程(springmvc-chapter2****)

☆spring****框架下載:

spring-framework-3.1.1.RELEASE-with-docs.zip

☆依賴jar****包:

1、 Spring框架jar包:

為了簡(jiǎn)單,將spring-framework-3.1.1.RELEASE-with-docs.zip/dist/下的所有jar包拷貝到項(xiàng)目的WEB-INF/lib目錄下;

2、 Spring框架依賴的jar包:

需要添加Apache commons logging日志,此處使用的是commons.logging-1.1.1.jar;

需要添加jstl標(biāo)簽庫(kù)支持,此處使用的是jstl-1.1.2.jar和standard-1.1.2.jar;

2.5.2、前端控制器的配置

在我們的web.xml中添加如下配置:

java代碼:

1.  <servlet>  
2.  <servlet-name>chapter2</servlet-name>  
3.  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
4.  <load-on-startup>1</load-on-startup>  
5.  </servlet>  
6.  <servlet-mapping>  
7.  <servlet-name>chapter2</servlet-name>  
8.  <url-pattern>/</url-pattern>  
9.  </servlet-mapping>  

load-on-startup****:表示啟動(dòng)容器時(shí)初始化該Servlet;

url-pattern****:表示哪些請(qǐng)求交給Spring Web MVC處理, “/” 是用來定義默認(rèn)servlet映射的。也可以如“*.html”表示攔截所有以html為擴(kuò)展名的請(qǐng)求。

自此請(qǐng)求已交給Spring Web MVC框架處理,因此我們需要配置Spring的配置文件,默認(rèn)DispatcherServlet會(huì)加載WEB-INF/[DispatcherServlet的Servlet名字]-servlet.xml配置文件。本示例為WEB-INF/ chapter2-servlet.xml。

2.5.3、在Spring配置文件中配置HandlerMapping、HandlerAdapter

具體配置在WEB-INF/ chapter2-servlet.xml文件中:
java代碼:

1.  <!-- HandlerMapping -->  
2.  <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>  
4.  <!-- HandlerAdapter -->  
5. 
 <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

BeanNameUrlHandlerMapping:表示將請(qǐng)求的URL和Bean名字映射,如URL為 “上下文/hello”,則Spring配置文件必須有一個(gè)名字為“/hello”的Bean,上下文默認(rèn)忽略。
SimpleControllerHandlerAdapter:表示所有實(shí)現(xiàn)了org.springframework.web.servlet.mvc.Controller接口的Bean可以作為Spring Web MVC中的處理器。如果需要其他類型的處理器可以通過實(shí)現(xiàn)HadlerAdapter來解決。

2.5.4、在Spring配置文件中配置ViewResolver

具體配置在WEB-INF/ chapter2-servlet.xml文件中:

java代碼:

1.  <!-- ViewResolver -->  
2.  <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
3.  <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>  
4.  <property name="prefix" value="/WEB-INF/jsp/"/>  
5.  <property name="suffix" value=".jsp"/>  
6.  </bean>  

InternalResourceViewResolver:用于支持Servlet、JSP視圖解析;

viewClass:JstlView表示JSP模板頁(yè)面需要使用JSTL標(biāo)簽庫(kù),classpath中必須包含jstl的相關(guān)jar包;

prefix和suffix:查找視圖頁(yè)面的前綴和后綴(前綴[邏輯視圖名]后綴),比如傳進(jìn)來的邏輯視圖名為hello,則該該jsp視圖頁(yè)面應(yīng)該存放在“WEB-INF/jsp/hello.jsp”;

2.5.5、開發(fā)處理器/頁(yè)面控制器

java代碼:

1.  package cn.javass.chapter2.web.controller;  
2.  import javax.servlet.http.HttpServletRequest;  
3.  import javax.servlet.http.HttpServletResponse;  
4.  import org.springframework.web.servlet.ModelAndView;  
5.  import org.springframework.web.servlet.mvc.Controller;  
6.  public class HelloWorldController implements Controller {  
7.  @Override  
8.  public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception {  
9.  //1、收集參數(shù)、驗(yàn)證參數(shù)  
10.  //2、綁定參數(shù)到命令對(duì)象  
11.  //3、將命令對(duì)象傳入業(yè)務(wù)對(duì)象進(jìn)行業(yè)務(wù)處理  
12.  //4、選擇下一個(gè)頁(yè)面  
13.  ModelAndView mv = new ModelAndView();  
14.  //添加模型數(shù)據(jù) 可以是任意的POJO對(duì)象  
15.  mv.addObject("message", "Hello World!");  
16.  //設(shè)置邏輯視圖名,視圖解析器會(huì)根據(jù)該名字解析到具體的視圖頁(yè)面  
17.  mv.setViewName("hello");  
18.  return mv;  
19.  }  
20.  }  

org.springframework.web.servlet.mvc.Controller:頁(yè)面控制器/處理器必須實(shí)現(xiàn)Controller接口,注意別選錯(cuò)了;后邊我們會(huì)學(xué)習(xí)其他的處理器實(shí)現(xiàn)方式;

public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) :功能處理方法,實(shí)現(xiàn)相應(yīng)的功能處理,比如收集參數(shù)、驗(yàn)證參數(shù)、綁定參數(shù)到命令對(duì)象、將命令對(duì)象傳入業(yè)務(wù)對(duì)象進(jìn)行業(yè)務(wù)處理、最后返回ModelAndView對(duì)象;

ModelAndView:包含了視圖要實(shí)現(xiàn)的模型數(shù)據(jù)和邏輯視圖名;“mv.addObject("message", "Hello World!");

”表示添加模型數(shù)據(jù),此處可以是任意POJO對(duì)象;“mv.setViewName("hello");”表示設(shè)置邏輯視圖名為“hello”,視圖解析器會(huì)將其解析為具體的視圖,如前邊的視圖解析器InternalResourceVi。wResolver會(huì)將其解析為“WEB-INF/jsp/hello.jsp”。

我們需要將其添加到Spring配置文件(WEB-INF/chapter2-servlet.xml),讓其接受Spring IoC容器管理:

java代碼:

1.  <!-- 處理器 -->  
2.  <bean name="/hello" class="cn.javass.chapter2.web.controller.HelloWorldController"/>  

name="/hello":前邊配置的BeanNameUrlHandlerMapping,表示如過請(qǐng)求的URL為 “上下文/hello”,則將會(huì)交給該Bean進(jìn)行處理。 

2.5.6、開發(fā)視圖頁(yè)面

創(chuàng)建 /WEB-INF/jsp/hello.jsp視圖頁(yè)面:

java代碼:

1.  <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
2.  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
3.  <html>  
4.  <head>  
5.  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
6.  <title>Hello World</title>  
7.  </head>  
8.  <body>  
9.  ${message}  
10.  </body>  
11.  </html>  

${message}:表示顯示由HelloWorldController處理器傳過來的模型數(shù)據(jù)。

2.5.6、啟動(dòng)服務(wù)器運(yùn)行測(cè)試

通過請(qǐng)求:http://localhost:9080/springmvc-chapter2/hello,如果頁(yè)面輸出“Hello World! ”就表明我們成功了!

2.5.7、運(yùn)行流程分析

如圖2-3

image

圖2-3

運(yùn)行步驟:

1、 首先用戶發(fā)送請(qǐng)求http://localhost:9080/springmvc-chapter2/hello——>web容器,web容器根據(jù)“/hello”路徑映射到DispatcherServlet(url-pattern為/)進(jìn)行處理;

2、 DispatcherServlet——>BeanNameUrlHandlerMapping進(jìn)行請(qǐng)求到處理的映射,BeanNameUrlHandlerMapping將“/hello”路徑直接映射到名字為“/hello”的Bean進(jìn)行處理,即HelloWorldController,BeanNameUrlHandlerMapping將其包裝為HandlerExecutionChain(只包括HelloWorldController處理器,沒有攔截器);

3、 DispatcherServlet——> SimpleControllerHandlerAdapter,SimpleControllerHandlerAdapter將HandlerExecutionChain中的處理器(HelloWorldController)適配為SimpleControllerHandlerAdapter;

4、 SimpleControllerHandlerAdapter——> HelloWorldController處理器功能處理方法的調(diào)用,SimpleControllerHandlerAdapter將會(huì)調(diào)用處理器的handleRequest方法進(jìn)行功能處理,該處理方法返回一個(gè)ModelAndView給DispatcherServlet;

5、 hello(ModelAndView的邏輯視圖名)——>InternalResourceViewResolver, InternalResourceViewResolver使用JstlView,具體視圖頁(yè)面在/WEB-INF/jsp/hello.jsp;

6、 JstlView(/WEB-INF/jsp/hello.jsp)——>渲染,將在處理器傳入的模型數(shù)據(jù)(message=HelloWorld!)在視圖中展示出來;

7、 返回控制權(quán)給DispatcherServlet,由DispatcherServlet返回響應(yīng)給用戶,到此一個(gè)流程結(jié)束。

到此HelloWorld就完成了,步驟是不是有點(diǎn)多?而且回憶下我們主要進(jìn)行了如下配置:

1、 前端控制器DispatcherServlet;

2、 HandlerMapping

3、 HandlerAdapter

4、 ViewResolver

5、 處理器/頁(yè)面控制器

6、 視圖

因此,接下來幾章讓我們?cè)敿?xì)看看這些配置,先從DispatcherServlet開始吧。

2.6、POST中文亂碼解決方案

spring Web MVC框架提供了org.springframework.web.filter.CharacterEncodingFilter用于解決POST方式造成的中文亂碼問題,具體配置如下:

java代碼:

1.  <filter>  
2.  <filter-name>CharacterEncodingFilter</filter-name>  
3.  <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>  
4.  <init-param>  
5.  <param-name>encoding</param-name>  
6.  <param-value>utf-8</param-value>  
7.  </init-param>  
8.  </filter>  
9.  <filter-mapping>  
10.  <filter-name>CharacterEncodingFilter</filter-name>  
11.  <url-pattern>/*</url-pattern>  
12.  </filter-mapping>  

以后我們項(xiàng)目及所有頁(yè)面的編碼均為UTF-8。

2.7、Spring3.1新特性

一、Spring2.5之前,我們都是通過實(shí)現(xiàn)Controller接口或其實(shí)現(xiàn)來定義我們的處理器類。

二、Spring2.5引入注解式處理器支持,通過@Controller 和 @RequestMapping注解定義我們的處理器類。并且提供了一組強(qiáng)大的注解:

需要通過處理器映射DefaultAnnotationHandlerMapping和處理器適配器AnnotationMethodHandlerAdapter來開啟支持@Controller 和 @RequestMapping注解的處理器。

@Controller:``用于標(biāo)識(shí)是處理器類;

@RequestMapping:``請(qǐng)求到處理器功能方法的映射規(guī)則;

@RequestParam:``請(qǐng)求參數(shù)到處理器功能處理方法的方法參數(shù)上的綁定;

@ModelAttribute:``請(qǐng)求參數(shù)到命令對(duì)象的綁定;

@SessionAttributes:``用于聲明session級(jí)別存儲(chǔ)的屬性,放置在處理器類上,通常列出模型屬性(如@ModelAttribute)對(duì)應(yīng)的名稱,則這些屬性會(huì)透明的保存到session中;

@InitBinder:``自定義數(shù)據(jù)綁定注冊(cè)支持,用于將請(qǐng)求參數(shù)轉(zhuǎn)換到命令對(duì)象屬性的對(duì)應(yīng)類型;

三、Spring3.0引入RESTful架構(gòu)風(fēng)格支持(通過@PathVariable注解和一些其他特性支持),且又引入了更多的注解支持:

@CookieValue:``cookie數(shù)據(jù)到處理器功能處理方法的方法參數(shù)上的綁定;

@RequestHeader:``請(qǐng)求頭(header)數(shù)據(jù)到處理器功能處理方法的方法參數(shù)上的綁定;

@RequestBody:``請(qǐng)求的body體的綁定(通過HttpMessageConverter進(jìn)行類型轉(zhuǎn)換);

@ResponseBody:``處理器功能處理方法的返回值作為響應(yīng)體(通過HttpMessageConverter進(jìn)行類型轉(zhuǎn)換);

@ResponseStatus:``定義處理器功能處理方法/異常處理器返回的狀態(tài)碼和原因;

@ExceptionHandler:``注解式聲明異常處理器;

@PathVariable:``請(qǐng)求URI中的模板變量部分到處理器功能處理方法的方法參數(shù)上的綁定,從而支持RESTful架構(gòu)風(fēng)格的URI;

四、還有比如:

JSR-303驗(yàn)證框架的無縫支持(通過@Valid注解定義驗(yàn)證元數(shù)據(jù));

使用Spring 3開始的ConversionService進(jìn)行類型轉(zhuǎn)換(PropertyEditor依然有效),支持使用@NumberFormat 和 @DateTimeFormat來進(jìn)行數(shù)字和日期的格式化;

HttpMessageConverter``(Http輸入/輸出轉(zhuǎn)換器,比如JSON、XML等的數(shù)據(jù)輸出轉(zhuǎn)換器);

ContentNegotiatingViewResolver``,內(nèi)容協(xié)商視圖解析器,它還是視圖解析器,只是它支持根據(jù)請(qǐng)求信息將同一模型數(shù)據(jù)以不同的視圖方式展示(如json、xml、html等),RESTful架構(gòu)風(fēng)格中很重要的概念(同一資源,多種表現(xiàn)形式);

Spring 3 引入 一個(gè) mvc XML的命名空間用于支持mvc配置,包括如:

<mvc:annotation-driven>:

自動(dòng)注冊(cè)基于注解風(fēng)格的處理器需要的DefaultAnnotationHandlerMapping、AnnotationMethodHandlerAdapter

支持Spring3的ConversionService自動(dòng)注冊(cè)

支持JSR-303驗(yàn)證框架的自動(dòng)探測(cè)并注冊(cè)(只需把JSR-303實(shí)現(xiàn)放置到classpath)

自動(dòng)注冊(cè)相應(yīng)的HttpMessageConverter(用于支持@RequestBody 和 @ResponseBody)(如XML輸入輸出轉(zhuǎn)換器(只需將JAXP實(shí)現(xiàn)放置到classpath)、JSON輸入輸出轉(zhuǎn)換器(只需將Jackson實(shí)現(xiàn)放置到classpath))等。

<mvc:interceptors>:注冊(cè)自定義的處理器攔截器;

<mvc:view-controller>:和ParameterizableViewController類似,收到相應(yīng)請(qǐng)求后直接選擇相應(yīng)的視圖;

<mvc:resources>:邏輯靜態(tài)資源路徑到物理靜態(tài)資源路徑的支持;

<mvc:default-servlet-handler>:當(dāng)在web.xml 中DispatcherServlet使用<url-pattern>/</url-pattern> 映射時(shí),能映射靜態(tài)資源(當(dāng)Spring Web MVC框架沒有處理請(qǐng)求對(duì)應(yīng)的控制器時(shí)(如一些靜態(tài)資源),轉(zhuǎn)交給默認(rèn)的Servlet來響應(yīng)靜態(tài)文件,否則報(bào)404找不到資源錯(cuò)誤,)。

……等等。

五、Spring3.1新特性:

對(duì)Servlet 3.0的全面支持。

@EnableWebMvc:``用于在基于Java類定義Bean配置中開啟MVC支持,和XML中的<mvc:annotation-driven>功能一樣;

新的@Contoller和@RequestMapping注解支持類:處理器映射RequestMappingHandlerMapping 和 處理器適配器RequestMappingHandlerAdapter組合來代替Spring2.5開始的處理器映射DefaultAnnotationHandlerMapping和處理器適配器AnnotationMethodHandlerAdapter,提供更多的擴(kuò)展點(diǎn),它們之間的區(qū)別我們?cè)谔幚砥饔成湟徽陆榻B。

新的@ExceptionHandler 注解支持類:ExceptionHandlerExceptionResolver來代替Spring3.0的AnnotationMethodHandlerExceptionResolver,在異常處理器一章我們?cè)僭敿?xì)講解它們的區(qū)別。

@RequestMapping的"consumes" 和 "produces" 條件支持:``用于支持@RequestBody 和 @ResponseBody,

1``consumes``指定請(qǐng)求的內(nèi)容是什么類型的內(nèi)容,即本處理方法消費(fèi)什么類型的數(shù)據(jù),如consumes="application/json"表示JSON類型的內(nèi)容,Spring會(huì)根據(jù)相應(yīng)的HttpMessageConverter進(jìn)行請(qǐng)求內(nèi)容區(qū)數(shù)據(jù)到@RequestBody注解的命令對(duì)象的轉(zhuǎn)換;

2``produces``指定生產(chǎn)什么類型的內(nèi)容,如produces="application/json"表示JSON類型的內(nèi)容,Spring的根據(jù)相應(yīng)的HttpMessageConverter進(jìn)行請(qǐng)求內(nèi)容區(qū)數(shù)據(jù)到@RequestBody注解的命令對(duì)象的轉(zhuǎn)換,Spring會(huì)根據(jù)相應(yīng)的HttpMessageConverter進(jìn)行模型數(shù)據(jù)(返回值)到JSON響應(yīng)內(nèi)容的轉(zhuǎn)換

3``以上內(nèi)容,本章第×××節(jié)詳述。

URI模板變量增強(qiáng):``URI模板變量可以直接綁定到@ModelAttribute指定的命令對(duì)象、@PathVariable方法參數(shù)在視圖渲染之前被合并到模型數(shù)據(jù)中(除JSON序列化、XML混搭場(chǎng)景下)。

@Validated:``JSR-303的javax.validation.Valid一種變體(非JSR-303規(guī)范定義的,而是Spring自定義的),用于提供對(duì)Spring的驗(yàn)證器(org.springframework.validation.Validator)支持,需要Hibernate Validator 4.2及更高版本支持;

@RequestPart:``提供對(duì)“multipart/form-data”請(qǐng)求的全面支持,支持Servlet 3.0文件上傳(javax.servlet.http.Part)、支持內(nèi)容的HttpMessageConverter(即根據(jù)請(qǐng)求頭的Content-Type,來判斷內(nèi)容區(qū)數(shù)據(jù)是什么類型,如JSON、XML,能自動(dòng)轉(zhuǎn)換為命令對(duì)象),比@RequestParam更強(qiáng)大(只能對(duì)請(qǐng)求參數(shù)數(shù)據(jù)綁定,key-alue格式),而@RequestPart支持如JSON、XML內(nèi)容區(qū)數(shù)據(jù)的綁定;詳見本章的第×××節(jié);

Flash 屬性 和 RedirectAttribute:``通過FlashMap存儲(chǔ)一個(gè)請(qǐng)求的輸出,當(dāng)進(jìn)入另一個(gè)請(qǐng)求時(shí)作為該請(qǐng)求的輸入,典型場(chǎng)景如重定向(POST-REDIRECT-GET模式,1、POST時(shí)將下一次需要的數(shù)據(jù)放在FlashMap;2、重定向;3、通過GET訪問重定向的地址,此時(shí)FlashMap會(huì)把1放到FlashMap的數(shù)據(jù)取出放到請(qǐng)求中,并從FlashMap中刪除;從而支持在兩次請(qǐng)求之間保存數(shù)據(jù)并防止了重復(fù)表單提交)。

Spring Web MVC提供FlashMapManager用于管理FlashMap,默認(rèn)使用SessionFlashMapManager,即數(shù)據(jù)默認(rèn)存儲(chǔ)在session中

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容