SpringMVC入門

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)解析及文件上傳等;提供了非常靈活的數據驗證、格式化和數據綁定機制;提供了強大的約定大於配置(慣例優先原則)的契約式編程支持。

2.SpringWebMVC能做什麼?

  • 讓我們能非常簡單的設計出乾淨的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處理請求的流程:

① Spring Web MVC處理請求的流程

這裏寫圖片描述
具體執行步驟如下:
1、 首先用戶發送請求————>前端控制器,前端控制器根據請求信息(如URL)來決定選擇哪一個頁面控制器進行處理並把請求委託給它,即以前的控制器的控制邏輯部分;圖中的1、2步驟;
2、 頁面控制器接收到請求後,進行功能處理,首先需要收集和綁定請求參數到一個對象,這個對象在Spring Web MVC中叫命令對象,並進行驗證,然後將命令對象委託給業務對象進行處理;處理完畢後返回一個ModelAndView(模型數據和邏輯視圖名);圖中的3、4、5步驟;
3、 前端控制器收回控制權,然後根據返回的邏輯視圖名,選擇相應的視圖進行渲染,並把模型數據傳入以便視圖渲染;圖中的步驟6、7;
4、 前端控制器再次收回控制權,將響應返回給用戶,圖中的步驟8;至此整個結束。

② Spring Web MVC架構

Spring Web MVC核心架構圖:
這裏寫圖片描述
架構圖對應的DispatcherServlet核心代碼如下:

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

        try {  
            ModelAndView mv;  
            boolean errorView = false;  

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

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

                // 執行處理器相關的攔截器的預處理(HandlerInterceptor.preHandle)  
                //此處省略具體代碼  

                // 步驟4、由適配器執行處理器(調用處理器相應功能處理方法)  
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  

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

                // 執行處理器相關的攔截器的後處理(HandlerInterceptor.postHandle)  
                //此處省略具體代碼  
            }  
            catch (ModelAndViewDefiningException ex) {  
                logger.debug("ModelAndViewDefiningException encountered", ex);  
                mv = ex.getModelAndView();  
            }  
            catch (Exception ex) {  
                Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);  
                mv = processHandlerException(processedRequest, response, handler, ex);  
                errorView = (mv != null);  
            }  

            //步驟5 步驟6、解析視圖並進行視圖的渲染  
//步驟5 由ViewResolver解析View(viewResolver.resolveViewName(viewName, locale))  
//步驟6 視圖在渲染時會把Model傳入(view.render(mv.getModelInternal(), request, response);)  
            if (mv != null && !mv.wasCleared()) {  
                render(mv, processedRequest, response);  
                if (errorView) {  
                    WebUtils.clearErrorRequestAttributes(request);  
                }  
            }  
            else {  
                if (logger.isDebugEnabled()) {  
                    logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +  
                            "': assuming HandlerAdapter completed request handling");  
                }  
            }  

            // 執行處理器相關的攔截器的完成後處理(HandlerInterceptor.afterCompletion)  
            //此處省略具體代碼  


        catch (Exception ex) {  
            // Trigger after-completion for thrown exception.  
            triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);  
            throw ex;  
        }  
        catch (Error err) {  
            ServletException ex = new NestedServletException("Handler processing failed", err);  
            // Trigger after-completion for thrown exception.  
            triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);  
            throw ex;  
        }  

        finally {  
            // Clean up any resources used by a multipart request.  
            if (processedRequest != request) {  
                cleanupMultipart(processedRequest);  
            }  
        }  
    }  

核心架構的具體流程步驟如下:
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、 DispatcherServlet在web.xml中的部署描述,從而攔截請求到Spring Web MVC
2、 HandlerMapping的配置,從而將請求映射到處理器
3、 HandlerAdapter的配置,從而支持多種類型的處理器
4、 ViewResolver的配置,從而將邏輯視圖名解析爲具體視圖技術
5、處理器(頁面控制器)的配置,從而進行功能處理

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風格的支持、簡單的文件上傳、約定大於配置的契約式編程支持、基於註解的零配置支持等等。

5.Hello World入門

Ⅰ.準備開發環境和運行環境:

開發工具:eclipse
運行環境:tomcat7
Spirng jar包spring-framework-3.1.1.RELEASE-with-docs.zip
依賴jar包
1. Spring框架jar包:
爲了簡單,將spring-framework-3.1.1.RELEASE-with-docs.zip/dist/下的所有jar包拷貝到項目的WEB-INF/lib目錄下;
2、 Spring框架依賴的jar包:
需要添加Apache commons logging日誌,此處使用的是commons.logging-1.1.1.jar;
需要添加jstl標籤庫支持,此處使用的是jstl-1.1.2.jar和standard-1.1.2.jar;

Ⅱ.前端控制器的配置

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

<servlet>  
    <servlet-name>chapter2</servlet-name>  
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
    <load-on-startup>1</load-on-startup>  
</servlet>  
<servlet-mapping>  
    <servlet-name>chapter2</servlet-name>  
    <url-pattern>/</url-pattern>  
</servlet-mapping>  

load-on-startup:表示啓動容器時初始化該Servlet;

url-pattern:表示哪些請求交給Spring Web MVC處理, “/” 是用來定義默認servlet映射的。也可以如“*.html”表示攔截所有以html爲擴展名的請求。

Ⅲ.在Spring配置文件中配置HandlerMapping、HandlerAdapter

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

<!-- HandlerMapping -->  
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>  

<!-- HandlerAdapter -->  
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>  

BeanNameUrlHandlerMapping:表示將請求的URL和Bean名字映射,如URL爲 “上下文/hello”,則Spring配置文件必須有一個名字爲“/hello”的Bean,上下文默認忽略。

SimpleControllerHandlerAdapter:表示所有實現了org.springframework.web.servlet.mvc.Controller接口的Bean可以作爲Spring Web MVC中的處理器。如果需要其他類型的處理器可以通過實現HadlerAdapter來解決。

Ⅳ.在Spring配置文件中配置ViewResolver

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

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

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

viewClass: JstlView表示JSP模板頁面需要使用JSTL標籤庫,classpath中必須包含jstl的相關jar包;

prefix和suffix:查找視圖頁面的前綴和後綴(前綴[邏輯視圖名]後綴),比如傳進來的邏輯視圖名爲hello,則該該jsp視圖頁面應該存放在“WEB-INF/jsp/hello.jsp”;

Ⅴ.開發處理器/頁面控制器

package cn.javass.chapter2.web.controller;  
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 req, HttpServletResponse resp) throws Exception {  
       //1、收集參數、驗證參數  
       //2、綁定參數到命令對象  
       //3、將命令對象傳入業務對象進行業務處理  
       //4、選擇下一個頁面  
       ModelAndView mv = new ModelAndView();  
       //添加模型數據 可以是任意的POJO對象  
       mv.addObject("message", "Hello World!");  
       //設置邏輯視圖名,視圖解析器會根據該名字解析到具體的視圖頁面  
       mv.setViewName("hello");  
       return mv;  
    }  
}  

org.springframework.web.servlet.mvc.Controller:頁面控制器/處理器必須實現Controller接口,注意別選錯了;後邊我們會學習其他的處理器實現方式;

public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) :功能處理方法,實現相應的功能處理,比如收集參數、驗證參數、綁定參數到命令對象、將命令對象傳入業務對象進行業務處理、最後返回ModelAndView對象;

ModelAndView:包含了視圖要實現的模型數據和邏輯視圖名;

“mv.addObject(“message”, “Hello World!”);”表示添加模型數據,此處可以是任意POJO對象;“mv.setViewName(“hello”);”表示設置邏輯視圖名爲“hello”,視圖解析器會將其解析爲具體的視圖,如前邊的視圖解析器InternalResourceVi。wResolver會將其解析爲“WEB-INF/jsp/hello.jsp”。

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

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

name=”/hello”:前邊配置的BeanNameUrlHandlerMapping,表示如過請求的URL爲 “上下文/hello”,則將會交給該Bean進行處理。

Ⅵ.開發視圖頁面

創建 /WEB-INF/jsp/hello.jsp視圖頁面:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
<!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=UTF-8">  
<title>Hello World</title>  
</head>  
<body>  
${message}  
</body>  
</html>  

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

Ⅶ.啓動服務器運行測試

通過請求:http://localhost:8080/springmvc-chapter2/hello,如果頁面輸出“Hello World! ”就表明我們成功了!

Ⅷ.運行流程分析

運行步驟:

1、 首先用戶發送請求http://localhost:8080/springmvc-chapter2/hello——>web容器,web容器根據“/hello”路徑映射到DispatcherServlet(url-pattern爲/)進行處理;
2、 DispatcherServlet——>BeanNameUrlHandlerMapping進行請求到處理的映射,BeanNameUrlHandlerMapping將“/hello”路徑直接映射到名字爲“/hello”的Bean進行處理,即HelloWorldController,BeanNameUrlHandlerMapping將其包裝爲HandlerExecutionChain(只包括HelloWorldController處理器,沒有攔截器);
3、 DispatcherServlet——> SimpleControllerHandlerAdapter,SimpleControllerHandlerAdapter將HandlerExecutionChain中的處理器(HelloWorldController)適配爲SimpleControllerHandlerAdapter;
4、 SimpleControllerHandlerAdapter——> HelloWorldController處理器功能處理方法的調用,SimpleControllerHandlerAdapter將會調用處理器的handleRequest方法進行功能處理,該處理方法返回一個ModelAndView給DispatcherServlet;
5、 hello(ModelAndView的邏輯視圖名)——>InternalResourceViewResolver, InternalResourceViewResolver使用JstlView,具體視圖頁面在/WEB-INF/jsp/hello.jsp;
6、 JstlView(/WEB-INF/jsp/hello.jsp)——>渲染,將在處理器傳入的模型數據(message=HelloWorld!)在視圖中展示出來;
7、 返回控制權給DispatcherServlet,由DispatcherServlet返回響應給用戶,到此一個流程結束。

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

1、 前端控制器DispatcherServlet;
2、 HandlerMapping
3、 HandlerAdapter
4、 ViewResolver
5、 處理器/頁面控制器
6、 視圖

Ⅸ.POST中文亂碼解決方案

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

<filter>  
    <filter-name>CharacterEncodingFilter</filter-name>  
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>  
    <init-param>  
        <param-name>encoding</param-name>  
        <param-value>utf-8</param-value>  
    </init-param>  
</filter>  
<filter-mapping>  
    <filter-name>CharacterEncodingFilter</filter-name>  
    <url-pattern>/*</url-pattern>  
</filter-mapping>  

以後我們項目及所有頁面的編碼均爲UTF-8。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章