SpringMVC學習筆記

1、SpringMVC概述

  • Spring爲展示層提供的基於MVC設計理念的優秀的Web框架,是目前最主流的MVC框架之一
  • Spring3.0以後全面超越Struts2,成爲最優秀的MVC框架
  • SpringMVC經過一套MVC註解,讓POJO成爲處理請求的控制器,而無須實現任何接口
  • 支持REST風格的URL請求
  • 採用了鬆散耦合可挺拔組件結構,比其餘MVC框架更具擴展性和靈活性

2、HelloWorld

步驟:html

  1. maven依賴java

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.meituan.spring</groupId>
        <artifactId>mvc</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>4.3.14.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>4.3.14.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>4.3.14.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>4.3.14.RELEASE</version>
            </dependency>
    
        </dependencies>
    
        <build>
            <plugins>
                <!--  添加編譯插件 -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.5.1</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-war-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>

    在Module Settings->Project Settings->Artifacts->output layout中,找到WEB-INF目錄,確認在其下存在lib目錄,不存在則建立,將library files添加進去程序員

  2. web.xmlweb

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/applicationContext.xml</param-value>
        </context-param>
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        <servlet>
            <servlet-name>dispatcher</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>dispatcher</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    </web-app>
  3. dispatcher-servlet.xmlspring

    • 能夠經過contextConfigLocation來指定SpringMVC配置文件的位置
    • 使用默認規則:/WEB-INF/<servlet-name>-servlet.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
               http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
               http://www.springframework.org/schema/mvc
               http://www.springframework.org/schema/mvc/spring-mvc.xsd
    ">
    
        <context:component-scan base-package="com.meituan.springmvc"/>
    
        <mvc:annotation-driven/>
    
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="prefix" value="/WEB-INF/views/"/>
            <property name="suffix" value=".jsp"/>
        </bean>
    </beans>

    注意:先後綴必定不要出錯數據庫

  4. Controller類apache

    import org.springframework.stereotype.Controller;
       import org.springframework.web.bind.annotation.RequestMapping;
       import org.springframework.web.bind.annotation.ResponseBody;
    
       @Controller
       public class HelloWorld {
       
           @RequestMapping("/helloworld")
           public String hello() {
               System.out.println("hello world, hello springmvc !");
               return "success";
           }
       }
  5. index.jsp文件瀏覽器

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
     <html>
      <head>
        <title>$Title$</title>
      </head>
      <body>
        <a href="/helloworld">hello world!</a>
      </body>
     </html>
  6. 視圖jsp文件spring-mvc

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
     <html>
      <head>
        <title>$Title$</title>
      </head>
      <body>
        <h4>success page!</h4>
      </body>
     </html>
  7. 配置好Tomcat

    值得注意的是,在deployment->Deploy at the server startup中添加artifact安全

  8. 啓動Tomcat便可

3、使用@RequestMapping映射請求

源碼

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping

3.1 使用@RequestMapping映射請求

  • 能夠用來修飾方法,還能夠用來修飾類

    • 類定義處:提供初步的請求映射信息,相對於WEB應用的根目錄
    • 方法處:提供進一步的細分映射信息,相對於類定義處的URL,若類定義處未標@RequestMapping,則方法處標記的URL相對於WEB應用的根目錄
  • DispatcherServlet截獲請求後,就經過控制器上@RequestMapping提供的映射信息肯定請求所對應的處理方法

3.2 映射請求參數、請求方法或請求頭

  • @RequestMapping除了可使用請求URL映射請求外,還可使用請求方法、請求參數及請求頭映射請求
  • @RequestMapping的value、method、params及heads分別表示請求URL、請求方法、請求參數及請求頭的映射條件,它們之間是與的關係,聯合使用多個條件可以讓請求映射更加精確化
  • params和headers支持簡單的表達式

    • param1:表示請求必須包含名爲param1的請求參數
    • !param1:表示請求不能包含名爲param1的請求參數
    • param1!=value1表示請求包含名爲param1的請求參數,但其值不能爲value1
    • {"param1=value1", "param2"}:請求必須包含名爲param1和param2的兩個請求參數,且param1參數的值必須爲value1
  • Ant風格資源地址支持3種匹配符:

    • ?:匹配文件名中的一個字符
    • * :匹配文件名中的任意字符
    • **:匹配多層路徑

3.3 支持Ant風格(瞭解便可)

  • @RequestMapping 還支持 Ant 風格的 URL :

    • /user/*/createUser:匹配 /user/aaa/createUser、/user/bbb/createUser 等 URL
    • /user/**/createUser:匹配 /user/createllser、/user/aaa/bbb/createUser 等 URL
    • /user/createllser??:匹配 /user/createllseraa、/user/createllserbb 等 URL

3.4 @PathVariable映射URL綁定的佔位符

  • 帶 佔 位 符 的 URL是Spring3.0新增的功能,該功能在SpringMVC向REST目標挺進發展過程當中具備里程碑的意義
  • 經過@PathVariable能夠將URL中佔位符參數綁定到控制器處理方法的入參中:URL中的{xxx丨佔位符能夠經過 @PathVariable("xxx")綁定到操做方法的入參中。
@RequestMapping("/delete/{id}")
    public String delete(@PathVariable("id") Integer id) {
        System.out.println(id);
        return "redirect:/user/list.action";
    }

3.5 REST

REST 即Representational State Transfer。 (資源)表現層狀態轉化。是目前最流行的一種互聯網軟件架構。它結構清晰、符合標準、易於理解、擴展方便, 因此正獲得愈來愈多網站的採用

  • 資 源 ( Resources):網絡上的一個實體,或者說是網絡上的一個具體信息。它 能夠是一段文本、 一 張圖片、一首歌曲、一種服務,總之就是一個具體的存在。 能夠用一個URI (統一資源定位符)指向它,每種資源對應一個特定的URU要 獲取這個資源,訪問它的URI就能夠,所以<u>URI即爲每個資源的獨一無二的識別符</u>。
  • 表現層 ( Representation):把資源具體呈現出來的形式,叫作它的表現層 (Representation) ^好比,文本能夠用txt格式表現,也能夠用HTML格式、XML格式、JSON格式表現,甚至能夠採用二進制格式
  • 狀態轉化 ( StateTransfer):每發出一個請求,就表明了客戶端和服務器的一 次交互過程。HTTP協議,是一個無狀態協議,即全部的狀態都保存在服務器端。所以,若是客戶端想要操做服務器,必須經過某種手段,讓服務器端發生「狀態轉化」( State Transfer)。而這種轉化是創建在表現層之上的,因此就是「 表現層狀態轉化」。具體說,就是<u>HTTP協議裏面,四個表示操做方式的動詞:GET、POST、PUT、DELETE。它們分別對應四種基本操做:GET用來獲取資源,POST用來新建資源,PUT用來更新資源,DELETE用來刪除資源。</u>
  • HiddenHttpMethodFilter: 瀏覽器 form 表單只支持 GET 與 POST請求,而 DELETE、PUT等method並不支持,Spring3.0添加了一個過濾器,能夠將這些請求轉換爲標準的http方法,使得支持GET、POST、PUT與DELETE請求

    • web.xml

      <!--配置org.springframework.web.filter.HiddenHttpMethodFilter:能夠把POST請求轉換爲DELETE或PUT請求-->
          <filter>
              <filter-name>HiddenHttpMethodFilter</filter-name>
              <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
          </filter>
          
          <filter-mapping>
              <filter-name>HiddenHttpMethodFilter</filter-name>
              <url-pattern>/*</url-pattern>
          </filter-mapping>
    • jsp

      添加一個form,增長一個隱藏域name="_method",指明請求的類型,值取PUT或DELETE

      <form action="/testRest" method="post">
            <input type="hidden" name="_method" value="DELETE">
            <input type="submit" value="TestRest DELETE">
          </form>
    • java

      @RequestMapping("/delete/{id}")
          public String delete(@PathVariable("id") Integer id) {
              userDao.deleteUserById(id);
              return "success";
          }

在Tomcat8以上版本,會出現問題,須要在jsp文件中添加

<%@ page contentType="text/html;charset=UTF-8" language="java"  isErrorPage="true"%>

指定屬性isErrorPage="true"

4、映射請求參數 & 請求參數

4.1 請求處理方法簽名

  • Spring MVC經過分析處理方法的簽名,將HTTP請求信息綁定處處理方法的相應入參中。
  • Spring MVC對控制器處理方法簽名的限制是很寬鬆的, 幾乎能夠按喜歡的任何方式對方法進行簽名。
  • 必要時能夠對方法及方法入參標註相應的註解(@PathVariable、@RequestParam、 @RequestHeader等)、Spring MVC框架會將HTTP請求的信息綁定到相應的方法入參中,並根據方法的返回值類型作出相應的後續處理。

4.2 使用@RequestParam綁定請求參數值

在處理方法入參處使用@RequestParam能夠把請求參數傳遞給請求方法

  • value:參數名
  • required:是否必須。默認爲true,表示請求參數中必須包含對應 的參數,若不存在,將拋出異常
  • defaultValue:請求參數的默認值

4.3 使用@RequestHeader綁定請求報頭的屬性值(瞭解便可)

請求頭包含了若干個屬性,服務器可據此獲知客戶端的信息,經過@RequestHeader便可將請求頭中的屬性值綁定處處理方法的入參中

image

4.4 使用CookieValue綁定請求中的cookie值(瞭解便可)

@CookieValue可以讓處理方法入參綁定某個cookie值

image

4.5 使用POJO對象綁定請求參數值

SpringMVC會按請求參數名和POJO屬性名進行自動匹配,自動爲該對象填充屬性值,支持級聯屬性

如:dept.deptId、dept.address.tel等

image

4.6 使用Servlet API做爲入參

MVC的handler訪求能夠接受如下Servlet API類型的參數

  • HttpServletRequest
  • HttpServletResponse
  • HttpSession
  • java.security.Principal
  • Locale
  • InputStream
  • OutputStream
  • Reader
  • Writer

5、處理模式數據

Spring MVC提供瞭如下幾種途徑輸出模型數據:

  • ModelAndView:處理方法返回值類型爲ModelAndView 時,方法體便可經過該對象添加模型數據
  • Map及Model: 入參爲org.springframework.ui.Model、 org.springframework.ui.ModelMap或 java.util.Map時,處理 方法返回時,Map中的數據會自動添加到模型中。
  • @SessionAttributes:將模型中的某個屬性暫存到 HttpSession中,以便多個請求之間能夠共享這個屬性
  • @ModelAttribute:方法入參標註該註解後,入參的對象就會放到數據模型中

5.1 ModelAndView

SpringMVC會把 ModelAndView 裏model 中的數據放入到request域對象( requestScope )中

  • 控制器處理方法的返回值若是爲ModelAndView,則其既包含視圖信息,也包含模型數據信息。
  • 添加模型數據:

    • MoelAndView addObject(String attributeName, Object attributeValue)
    • ModelAndView addAIIObject(Map<String, ?> modelMap)
  • 設置視圖:

    • void setView(View view)
    • void setViewName(String viewName)

5.2 Map及Model

  • Spring MVC在內部使用了一個 org.springframework.ui.Model 接口存儲模型數據
  • 具體步驟

    • Spring MVC在調用方法前會建立一個隱 含的模型對象做爲模型數據的存儲容器。
    • 若是方法的入參爲Map或Model類型,Spring MVC會將隱含模型的引用傳遞給這些入參。在方法體內,開發者能夠經過這個入參對象訪問到模型中的全部數 據,也能夠向模型中添加新的屬性數據。

image

5.3 將模型數據存入Session中

  • 若但願在多個請求之間共用某個模型屬性數據,則能夠在控制器<u>類</u>上標註一個 @SessionAttributes,Spring MVC 將在模型中對應的屬性暫存到HttpSession中。
  • @SessionAttributes除了能夠經過<u>屬性名</u>指定須要放到會話中的屬性外,還能夠經過模型屬性的<u>對象類型</u>指定哪些模型屬性須要放到session會話中

    • @SessionAttributes(types=User.class)會將隱含模型中全部類型 爲User.class的屬添加到會話中。
    • @SessionAttributes(value={「user1」, 「user2」})
    • @SessionAttributes(types={User.class, Dept.class})
    • @SessionAttributes(value={「user1」, 「user2」 } , types={Dept.class})

5.4 @ModelAttribute

  • 在方法定義上使用@ModelAttribute註解: Spring MVC 在調用目標處理方法前,會先逐個調用在方法級上標註了@ModelAttribute 的方法,所以對於一個controller映射多個URL的用法來講,要謹慎使用。
  • 在方法的入參前使用@ModelAttribute註解:

    • 能夠從隱含對象中獲取隱含的模型數據中獲取對象,再將請求參數綁定到對象中,再傳入入參
    • 將方法入參對象添加到模型中
  • @ModelAttribute 註解也能夠來修飾目標方法POJO類型的入參,其 value 屬性值有以下的做用:

    • SpringMVC會使用 value 屬性值在implicitModel中查找對應的對象,若存在則會直接傳入到目標方法的入參中
    • SpringMVC會以value爲key,POJO類型的對象爲value,存入到request中

5.4.1 @ModelAttribute運行原理

@ModelAttribute
public void getUser(@RequestParam(value="id", required=false) Integer id, Map<String, Object> map) {
    System.out.println("modelAttribute method");
    
    if (id != null) {
        //模擬從數據庫中獲取對象
        User user = new User(1, "Tom", "123456", "Tom@meituan.com", 12);
        System.out.println("從數據庫中獲取一個對象: " + user);
        map.put("user", user);
    }
}

運行流程:

一、 執行@ModelAttribute註解修飾的方法;從數據庫中取出對象,把對象放入到Map中,鍵爲user

二、SpringMVC從Map中取出User對象,並把表單的請求參數賦值給該User對象對應的屬性

三、SpringMVC把上述對象傳入目標方法的參數

注意:在@ModelAttribute修飾的方法中,放入到Map時的鍵須要和目標方法入參類型的第一個字母小寫的字符串一致!

5.4.2 源碼分析的流程

  1. 調用@ModelAttribute註解修飾的方法,實際上把@ModelAttribute方法中Map中的數據放在了implicitModel中
  2. 解析請求處理器的目標參數,實際上該目標參數來自於WebDataBinder對象的target屬性,

    1. 建立WebDataBinder對象:

      • 肯定objectName屬性:若傳入的attrName屬性值爲"",則objectName爲類名第一個字母小寫

        注意:attrName,若目標方法的POJO屬性使用了@ModelAttribute來修飾,則attrName值即爲@ModelAttribute的value屬性

      • 肯定target的值

        在implicitModel中查找attrName對應的屬性值。若存在,ok;若不存在,則驗證當前handler是否使用了@SessionAttributes進行修飾,若使用了,則嘗試從Session中獲取attrName所對應的屬性值,若session中沒有對應的屬性值,則拋出異常;若handler沒有使用@SessionAttribute進行修飾,或@SessionAttributes中沒有使用value值指定的key和attrName相匹配,則經過反射建立POJO對象

    2. SpringMVC把表單的請求參數賦給了WebDataBinder的target對應的屬性
    3. SpringMVC會把WebDataBinder的attrName和target賦值給implicitModel
  3. 把WebDataBinder的target做爲參數傳遞給目標參數的入參

5.4.3 如何肯定目標方法POJO類型的入參

  1. 肯定一個key

    1. 若目標方法的POJO類型的參數沒有使用@ModelAttribute做爲修飾,則key爲POJO類名第一個字母的小寫
    2. 若使用了@ModelAttribute來修飾,則key爲@ModelAttribute註解的value屬性值
  2. 在implicitModel中查找key對應的對象,若存在,則做爲入參傳入

    若@ModelAttribute標記的方法在Map中保存過,且key和1肯定的key一致,則會獲取到

  3. 若implicitModel中不存在key對應的對象,則檢查當前的handler是否使用@SessionAttributes註解修飾,若使用了該註解,且@SessionAttributes註解的value屬性值中包含了key,則會從HttpSession中來獲取key所對應的value值,若存在則直接傳入目標方法的入參中;若不存在則將拋出異常
  4. 若handler沒有標識@SessionAttributes註解的value值中不包含key,則會經過反射來建立POJO類型的參數,傳入爲目標方法的參數
  5. SpringMVC會把key和POJO類型的對象保存到implicitModel,進而保存到request中

5.5 @SessionAttributes 註解引起的異常

org.springframework.web.HttpSessionRequiredException: Session attribute 'user' required - not found in session

若是在處理類定義處標註了@SessionAttributes(「xxx」), 則嘗試從session會話中獲取該屬性,並將其賦給該入參,而後再用請求消息填充該入參對象。若是在會話中找不到對應的屬性,則拋出HttpSessionRequiredException 異常

5.6 視圖和視圖解析器

5.6.1 視圖解析流程分析

image

  • 請求處理方法執行完成後,最終返回一個ModelAndView 對象。對於那些返回String, View或ModeMap等類型的處理方法,Spring MVC也會在內部將它們裝配成一個 ModelAndView對象,它包含了邏輯名和模型對象的視圖
  • SpringMVC藉助視圖解析器(ViewResolver)獲得最終的視圖對象(View),最終的視圖能夠是JSP,也多是 Excel、JFreeChart等各類表現形式的視圖
  • 對於最終究竟採起何種視圖對象對模型數據進行渲染,處理器並不關心,處理器工做重點聚焦在生產模型數據的工做上,從而實現MVC的充分解耦

5.6.2 視圖

  • 視圖的做用是渲染模型數據,將模型裏的數據以某種形式呈現給客 戶。
  • 爲了實現視圖模型和具體實現技術的解耦,Spring在org.springframework.web.servlet 包中定義了一個高度抽象的 View接口
  • 視圖對象由視圖解析器負責實例化。因爲視圖是無狀態的,因此他們 不會有線程安全的問題

經常使用的視圖實現類: 

image

5.6.3 視圖解析器(ViewResolver)

  • 視圖解析器的做用是將邏輯視圖轉爲物理視圖,全部的視圖解析器都必須實現ViewResolver接口。
  • 視圖解析器的做用比較單一:將邏輯視圖解析爲一個具體的視圖對象
  • SpringMVC爲邏輯視圖名的解析提供了不一樣的策略,能夠在Spring WEB上下文中配置一種或多種解析策略,並指定他們之間的前後順序。每一種映射策略對應一個具體的視圖解析器實現類。
  • 程序員能夠選擇一種視圖解析器或混用多種視圖解析器。能夠經過order屬性指定解析器的優先順序,order越小優先級越高
  • SpringMVC會按視圖解析器順序的優先順序對邏輯視圖名進行解析,直到解析成功並返回視圖對象,不然拋出ServletException異常。

image

5.6.4 使用mvc:view-controller不經控制器直接跳轉到頁面

若但願直接響應經過SpringMVC渲染的頁面,可使用mvc:view-controller標籤實現:

 <!-- 配置直接轉發的頁面 -->      
<!-- 能夠直接相應轉發的頁面, 而無需再通過 Handler 的方法.  -->  
    <mvc:view-controller path="/success" view-name="success"/>

那麼如今能夠直接在某一頁面中經過請求路徑」success」訪問到/WEB-INF/views/success.jsp頁面(由於咱們上面配置了視圖解析器將邏輯視圖解析爲前綴爲/WEB-INF/views/,後綴爲.jsp的物理視圖)。可是,這種狀況下經過控制器就沒法映射到請求了,須要再進行以下配置:

<!-- 在實際開發中一般都需配置 mvc:annotation-driven 標籤,  以前的頁面纔不會由於配置了直接轉發頁面而受到影響 -->  
    <mvc:annotation-driven></mvc:annotation-driven>

5.6.5 關於重定向

通常狀況下,控制器方法返回字符串類型的值會被當成邏輯視圖名處理,但若是返回的字符串中帶forward:或redirect:前綴時,SpringMVC會對它們進行特殊處理:將forward: 和redirect: 當成指示符,其後的字符串做爲URL 來處理。示例以下: 

index.jsp:

<a href="${pageContext.request.contextPath }/springmvc/testRedirect">Test Redirect</a>

controller:

@Controller
@RequestMapping("/springmvc")
public class SpringMVCTest {

    @RequestMapping("/testRedirect")
    public String testRedirect() {
        System.out.println("testRedirect");
        return "redirect:/index.jsp";
    }
}

便可重定向到index.jsp。也可在redirect:/後添加控制器方法的映射路徑,重定向到該目標方法。

6、SpringMVC表單標籤&處理靜態資源

經過SpringMVC的表單標籤能夠實現將模型數據 中的屬性和HTML表單元素相綁定,以實現表單

數據更便捷編輯和表單值的回顯

6.1 表單標籤

form:input、 form:passwordN form:hidden、 form:textarea :對應 HTML 表車的 text、password、hidden、 textarea 標籤

  • form:radiobutton :單選框組件標籤,當表單bean對應的屬性值和value值相等時,單選框破選中
  • form:radiobuttons :單選框組標籤,用於構造多個單選

    • items :能夠是一個 List、String[]或 Map
    • item Value :指定radio 的value值。能夠是集合中bean的一個屬性值
    • itemLabel :指定 radio 的 label 值
    • delimiter :多個單選框能夠經過delimiter指定分隔符
  • form:checkbox :複選框組件。用於構造單個複選框
  • form:checkboxs :用於構造多個複選框。使用方式同form:radiobuttons 標籤
  • form:select :用於@造下拉框組件。使用方式同form:radiobuttons 標籤
  • form:option :下拉框選項組件標籤。使用方式同 form:radiobuttons 標籤
  • form:errors :顯示錶單組件或數據校驗所對應的錯誤

6.2 處理靜態資源

  • 優雅的REST風格的資源URL不但願帶.html或.do等後綴
  • 若將DispatcherServlet請求映射配置爲/,則Spring MVC將捕獲 WEB容器的全部請求,包括靜態資源的請求,SpringMVC會將他 們當成一個普通請求處理,因找不到對應處理器將致使錯誤。
  • 能夠在SpringMVC的配置文件中配置的方式解決靜態資源的問題:

    • 將在 SpringMVC 上下文中定義一個DefaultServletHttpRequestHandler,它會對進入DispatcherServlet 的請求進行篩查,若是發現是沒有通過映射的請求,就將該請求交由WEB 應用服務器默認的Servlet處理,若是不是靜態資源的請求,才由DispatcherServlet 繼續處理
    • 通常WEB應用服務器默認的Servlet的名稱都是default。若所使用的 WEB服務器的默認Servlet名稱不是default,則須要經過default-servlet-name 屬性顯式指定

7、數據轉換 & 數據格式化 & 數據校驗

7.1 數據轉換

7.1.1 數據綁定流程

  1. Spring MVC主框架將ServletRequest對象及目標方法的入參實例傳遞給WebDataBinderFactory實例,以建立DataBinder實例對象
  2. DataBinder調用裝配在Spring MVC上下文中的
    ConversionService組件進行數據類型轉換、數據格式化工做。將Servlet中的請求信息填充到入參對象中
  3. 調用Validator組件對已經綁定了請求消息的入參對象進行數據合法性校驗,並最終生成數據綁定結果BindingData 對象
  4. Spring MVC抽取BindingResult中的入參對象和校驗錯誤對象,將它們賦給處理方法的響應入參

SpringMVC經過反射機制對目標處理方法進行解析,將請求消息綁定處處理方法的入參中。數據綁定的核心部件是DataBinder,運行機制以下:

image

7.1.2 關於mvc:annotation-driven

  • <mvc:annotation-driven /> 會自動註冊RequestMappingHandlerMapping、RequestMappingHandlerAdapter 與ExceptionHandlerExceptionResolver 三個bean。
  • 還將提供如下支持:

    • 支持使用ConversionService實例對錶單參數進行類型轉換
    • 支持使用 @NumberFormat annotation、@DateTimeFormat註解完成數據類型的格式化
    • 支持使用@Valid註解對JavaBean實例進行JSR 303驗證
    • 支持使用 @RequestBody和 @ResponseBody 註解

7.1.3 @InitBinder註解

由@lnitBinder標識的方法,能夠對WebDataBinder對

象進行初始化。WebDataBinder是DataBinder的子類,用
於完成由表單字段到JavaBean屬性的綁定

@lnitBinder方法不能有返回值,它必須聲明爲void。

@lnitBinder方法的參數一般是是WebDataBinder

7.2 數據格式化

  • 對屬性對象的輸入/輸出進行格式化,從其本質上講依然屬於「類型轉換」的範疇。
  • Spring在格式化模塊,定義了一個實現ConversionService接口的FormattingConversionService 實現類,該實現類擴展了 GenericConversionService,所以它既具備類型轉換的功能,又具備格式化的功能
  • FormattingConversionService 擁有一個FormattingConversionServiceFactroyBean 工廠類,後者用於在 Spring上下文中構造前者
  • FormattingConversionServiceFactroyBean 內部已經註冊了:

    • NumberFormatAnnotationFormatterFactroy :支持對數字類型的屬性,使用 @NumberFormat 註解
    • JodaDateTimeFormatAnnotationFormatterFactroy :支持對日期類型的屬性使用@DateTimeFormat註解
  • 裝配了 FormattingConversionServiceFactroyBean 後,就可

    以在Spring MVC入參綁定及模型數據輸出時使用註解驅動
    了。<mvc:annotation-driven/> 默認建立的ConversionService 實例即爲FormattingConversionServiceFactroyBean

7.2.1 日期格式化

@DateTimeFormat 註解可對java.util.Date、java.util.Calendar、java.long.Long 時間類型進行標註:

  • pattern屬性:類型爲字符串。指定解析/格式化字段數據的模式,如:」yyyy-MM-dd hh:mm:ss」
  • iso屬性:類型爲DateTimeFormat.lSO。指定解析/格式化字段數據的ISO模式,包括四種MSO.NONE (不使用)默認、ISO.DATE(yyyy-MM-dd)、IS〇.TIME(hh:mm:ss.SSSZ)、ISO.DATE_TIME(yyyy-MM-dd hh:mm:ss.SSSZ)
  • style屬性:字符串類型。經過樣式指定日期時間的格式,由兩位字符組成,第一位表示日期的格式,第二位表示時間的格式:S :短日期/時間格式、M :中日期/時間格式、L :長日期/時間格式、F :完整日期/時間格式、忽略日期或時間格式

7.2.2

@NumberFormat可對相似數字類型的屬性進行標註,它擁有兩個互斥的屬性:

  • style :類型爲NumberFormat.Style。用於指定樣式類型,包括三種:Style.NUMBER (正常數字類型)、Style.CURRENCY (貨幣類型)、Style.PERCENT (百分數類型)
  • pattern :類型爲String,自定義樣式,如patter="#,###";

7.3 數據校驗

7.3.1 JSR 303

  • JSR 303是Java爲Bean數據合法性校驗提供的標準框架,它已經包含在JavaEE 6.0中
  • JSR 303經過在Bean屬性上標註相似於@NotNull、@Max等標準的註解指定校驗規則,並經過標準的驗證接口對Bean進行驗證

wx20180721-183913 2x

7.3.2 SpringMVC數據校驗

  • Spring 4.0擁有本身獨立的數據校驗框架,同時支持JSR 303標準的校驗框架。
  • Spring在進行數據綁定時,可同時調用校驗框架完成數據校驗工做。在Spring MVC中,可直接經過註解驅動的方式進行數據校驗
  • Spring 的 LocalValidatorFactroyBean 既實現了 Spring 的Validator 接口,也實現了 JSR 303 的 Validator 接口。只要在Spring容器中定義了一個LocalValidatorFactoryBean,便可將其注入到須要數據校驗的Bean中。
  • Spring自己並無提供JSR303的實現,因此必須將JSR303的實現者的jar包放到類路徑下。
  • <mvc:annotation-driven/>會默認裝配好一個 LocalValidatorFactoryBean ,經過在處理方法的入參上標註@valid 註解便可讓 Spring MVC 在完成數據綁定後執行數據校驗的工做
  • 在已經標註了 JSR303 註解的表單/命令對象前標註一個 @Valid , Spring MVC 框架在將請求參數綁定到該入參對象後,就會調用校驗框架根據註解聲明的校驗規則實施校驗
  • Spring MVC 是經過對處理方法簽名的規約來保存校驗結果的:前一個表單/命令對象的校驗結果保存到隨後的入參中,這個保存校驗結果的入參必須是 BindingResult 或 Errors 類型,這兩個類都位於 org.springframework.validation 包中
  • 需校驗的Bean對象和其綁定結果對象或錯誤對象時成對出現的,它們之間不容許聲明其餘的入參
  • Errors接口提供了獲取錯誤信息的方法,如getErrorCount()或getFieldErrors(String field)
  • BindingResult擴展了Errors接口

7.3.3 在目標方法中獲取校驗結果

  • 在表單/命令對象類的屬性中標校驗註解,在處理方法對應的入參前添加@Valid,SpringMVC就會實施校驗並將校驗結果保存在被校驗入參對象以後的BindingResult或Errors入參中

7.3.4 在頁面上顯示錯誤

  • Spring MVC 除了會將表單/命令對象的校驗結果保存到對 應的 BindingResu|t或 Errors對象中外,還會將全部校驗結果保存到「隱含模型」
  • 即便處理方法的簽名中沒有對應於表單/命合對象的結果入參,校驗結果也會保存在「隱含對象」中。
  • 隱含模型中的全部數據最終將經過 Http Servletrequest的屬性列表暴露給 JSP 視圖對象,所以在 JSP 中能夠獲取錯誤信息
  • 在JSP頁面上可經過<form:errors path="userName">顯示錯誤消息

8、文件上傳

  • Spring MVC爲文件上傳提供了直接的支持,這種支持是經過即插即用的MultipartResolver實現的。 Spring用 Jakarta Commons FileUpload 技術實現了一個 MultipartResolver 實現類:CommonsMultipartResovler
  • Spring MVC上下文中默認沒有裝配MultipartResovler,所以默認狀況下不能處理文件的上傳工做,若是想使用Spring 的文件上傳功能,需如今上下文中配置MultipartResolver

配置MultipartResolver

  • defaultEncoding:必須和用戶 JSP 的 pageEncoding 屬性 一致,以便正確解析表單的內容
  • 爲了讓 CommonsMultipartResovler正確工做,必須先將 Jakarta Commons FileUpload & Jakarta Commons io 的類包添加到類路徑下。

9、攔截器

  • Spring MVC也可使用攔截器對請求進行攔截處理,用戶 能夠自定義攔截器來實現特定的功能,自定義的攔截器必須實現 Handlerlnterceptor 接口

    • preHandle():這個方法在業務處理器處理請求以前被調用,在該 方法中對用戶請求request進行處理。若是程序員決定該攔截器對 請求進行攔截處理後還要調用其餘的攔截器,或者是業務處理器去 進行處理,則返回true ;若是程序員決定不須要再調用其餘的組件 去處理請求,則返回false
    • postHandle():這個方法在業務處理器處理完請求後,可是DispatcherServlet向客戶端返回響應前被調用,在該方法中對用戶請求request進行處理。
    • afterCompletion():這個方法在 DispatcherServlet 徹底處理完請求後被調用,能夠在該方法中進行一些資源清理的操做。
  • 攔截器方法執行順序

image

  • 攔截器配置

    image

  • 多個攔截器的執行順序

    image
    image

10、 異常處理

  • Spring MVC經過 HandlerExceptionResolver 處理程序的異常,包括Handler映射、數據綁定以及目標方法執行時發生的異常
  • Spring MVC提供的 HandlerExceptionResolver 的實現類

10.1 HandlerExceptionResolver

  • DispatcherServlet 默認裝配的HandlerExceptionResolver

    • 沒有使用<mvc:annotation-driven/>配置

      image

    • 使用<mvc:annotation-driven/>配置

      image

10.2 ExceptionHandlerExceptionResolver

  • 主要處理Handler中用@ExceptionHandler註解定義的方法。
  • @ExceptionHandler註解定義的方法優先級問題:例如發生的是NullPointerException,可是聲明的異常有 RuntimeException和Exception,此時會根據異常的最近繼承關係找到繼承深度最淺的那個@ExceptionHandler 註解方法,即標記了 RuntimeException的方法
  • ExceptionHandlerMethodResolver 內部若找不到@ExceptionHandler註解的話,會找 @ControllerAdvice 中的@ExceptionHandler 註解方法

10.3 ResponseStatusExceptionResolver

  • 在異常及異常父類中找到@ResponseStatus註解,而後使用這個註解的屬性進行處理。
  • 定義一個@ResponseStatus註解修飾的異常類
  • 若在處理器方法中拋出了上述異常: 若 ExceptionHandlerExceptionResolver 不解析上述異常。因爲觸發的異常 UnauthorizedException 帶有@ResponseStatus 註解。所以會被 ResponseStatusExceptionResolver 解析到。最後響應HttpStatus_UNAUTH〇RIZED代碼給客戶端。HttpStatus_UNAUTH〇RIZED表明響應碼401,無權限。 關於其餘的響應碼請參考HttpStatus枚舉類型源碼。

10.4 DefaultHandlerExceptionResolver

對一些特殊的異常進行處理,好比NoSuchRequestHandlingMethodException、 HttpReques tMethodNotSupportedException、 HttpMediaTypeNotSuppo rtedException、 HttpMediaTypeNotAcceptableException 等

10.5 SimpleMappingExceptionResolver

若是但願對全部異常進行統一處理,可使用SimpleMappingExceptionResolver,它將異常類名映射爲視圖名,即發生異常時使用對應的視圖報告異常

image

11、SpringMVC運行流程

image

12、在Spring環境下使用SpringMVC

須要進行Spring 整合SpringMVC嗎

仍是否須要再加入Spring的IOC容器?

是否須要在web.xml文件中配置啓動Spring IOC容器的ContextLoaderListener?

  1. 須要:一般狀況下,相似於數據源、事務、整合其餘框架都是放在Spring 的配置文件中(而不是放在SpringMVC的配置文件中),實際上放入Spring配置文件對應的IOC容器中的還有Service和Dao(推薦)
  2. 不須要:都放在SpringMVC的配置文件中,也能夠分多個Spring的配置文件,而後使用import節點導入其餘的配置文件(不推薦)

12.1 Bean的重複建立

若Spring的IOC容器和SpringMVC的IOC容器掃描的包有重合的部分,就會致使有的bean會被建立2次

解決:

  1. 使Spring的IOC容器掃描的包和SpringMVC的IOC容器掃描的包沒有重合的部分
  2. 使用 exclude-filter 和 include-filter 子節點來規定只能掃描的註解

    image

12.2 SpringMVC與Spring容器的關係

  • 多個Spring l〇C容器之間能夠設置爲父子關係,以實現良好的解耦。
  • Spring MVC WEB層容器可做爲「業務層」 Spring 容器的子容器:即WEB層容器能夠引用業務層容器的Bean,而業務層容器卻訪問不到WEB層容器的Bean

image

相關文章
相關標籤/搜索