【萬字長文】Spring MVC 層層遞進輕鬆入門 !

SpringMVC 開篇絮叨

(一) 談一談 Web 項目開發

Html是「名詞」,CSS是「形容詞」,JavaScript是「動詞」,這三個兄弟湊在一塊兒,就構成了 「靜態」 頁面,那麼如何讓他 「動態」 起來呢?這就須要後端相關技術的支持,這也是咱們今天想要說的。php

那麼又怎麼去理解 「靜態」「動態」 這兩個詞呢?css

這兩個詞最大的不一樣就是在於其交互性,靜態頁面不是指頁面不能進行變化,而是指不能與後端進行交互,實現數據的傳輸與處理,也就是說,靜態頁面一旦作好後,基本就是這個樣子了,更像一個單純的展現,而動態頁面卻能夠實現根據用戶的要求和選擇而動態的去改變和響應,瀏覽器客戶端,成爲了先後端動態交互的一個橋樑。html

而隨着如今用戶需求的增長,以及數據量的增長,在Web開發中,可以及時、正確地響應用戶的請求幾乎已經能夠說是必須的了前端

  • ① 用戶在前端的頁面上,進行一個提交或者說點擊 URL,就會向後端服務器發送一個請求
  • ② 後端通過一系列處理後(例如,從數據庫中查到須要的數據)把數據響應給前端頁面
  • ③ 前端頁面獲取到響應內容後,對其進行解析以及進行一些處理(例如:回顯內容到頁面)

今天重點要學習的就是也就是——如何在獲取請求後對其解析,而後執行相關的邏輯處理,最終跳轉到頁面,將數據回饋java

(二) 三層架構

上面我提到了,在先後端動態交互中,瀏覽器客戶端,成爲了先後端溝通的橋樑,這也就是常見的 B/S 架構方式,也就是 瀏覽器/服務器,在其中最爲經常使用的就是三層架構的開發模式jquery

你們在 JavaWeb 的學習過程當中,基本上已經在用三層架構的模式來進行編程,哪三層呢?web

注:以JavaWeb中爲例ajax

① 表現層(Web層)spring

  • 做用:接收客戶端請求(通常是HTTP請求),同時向其響應結果
  • 分類:表現層分爲,展現層和控制層,控制層 (Servlet) 負責接收請求,展現層 (HTML JSP) 負責結果的展現
  • 在表現層會依賴於業務層,進行業務處理,也就是比如在 Servlet 中調用某個Service
  • 通常使用 MVC 模型開發(僅限此層,詳情下面會說)

② 業務層(Service層)數據庫

  • 做用:根據項目需求,進行業務邏輯處理
  • 在業務層可能會依賴於持久層,也就是比如在 Service 中調用某個 Dao

③ 持久層 (Dao)

  • 做用:數據持久化
  • 說白了,就是實現和數據庫之間的交互,本質都是增刪改查,只不過不一樣的項目複雜程度會有所不一樣

有兩點須要強調一下:

什麼是,某某層依賴於某某層?

例如表現層依賴業務層,在 JavaWeb 階段實際上就是在 Servlet 中 new 了一個 Service ,固然,在Spring的 IOC 下咱們只須要在控制層中添加Service的引用就能夠了,並不須要再new了,耦合大大下降,咱們上面說的依賴主要指兩個層之間存在必定的關係

什麼是業務邏輯?

針對,一些簡單的操做,例如單表數據的增刪,實際上幾乎沒有任何業務,最多例如參數不合法一類的,能加個返回的錯誤碼,但若是面對一些比較複雜的項目,就存在一些業務邏輯須要編寫

例如:查詢時須要的結果,並非簡單的一張表中,而查詢條件也比較複雜,咱們就能夠經過對查詢條件進行拆分,再組合,就能夠查詢到不一樣需求的數據。

再例如:之前文章中我常說的轉帳案例,爲了不在轉帳的整個過程當中發生異常,致使資金髮生問題,就須要保證事務的一致性,而這些事務咱們就能夠放在業務層來作,固然 Spring 的AOP 能夠幫助咱們更好的處理事務問題

(三) MVC 模型

MVC 也就是 model-view-controller,咱們來看看它的每一部分

Model(模型)

  • Model 能夠叫作數據模型層,也就是用來封裝數據的
  • 例如請求的過程當中,用戶信息被封裝在 User 實體類中,這個實體類就屬於 Model 層中

View(視圖)

  • 視圖層中會選擇一個恰當的視圖來顯示最終的執行結果
  • 例如常見的 HTML JSP 就是用來展現數據的

Controller(控制)

  • 這就是比較直觀的用來處理交互的部分,接收用戶請求,而後執行業務等流程,以及一些數據的校驗,最終反饋結果

作了一張 MVC 模式下的工程結構圖,方便你們理解

初識 Spring MVC

實際上,若是是初次接觸 Spring MVC 實際上,看個基本概念也就好了,好比下面我提到的,Spring MVC 的優勢,Spring MVC 與 Struts 的區別,若是在沒有進行過一些基本的使用,以及簡單一些流程的簡單分析,實際上沒啥卵用,這些東西簡單看看就好了,通過必定的學習之後,回過頭來再看,會有感受的多

(一) Spring MVC 基礎

Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name, 「Spring Web MVC,」 comes from the name of its source module (spring-webmvc), but it is more commonly known as 「Spring MVC」.

—— Spring官網

Spring MVC屬於SpringFrameWork的後續產品,已經融合在Spring Web Flow裏面。Spring 框架提供了構建 Web 應用程序的全功能 MVC 模塊。使用 Spring 可插入的 MVC 架構,從而在使用Spring進行WEB開發時,能夠選擇使用Spring的Spring MVC框架或集成其餘MVC開發框架,如Struts1(如今通常不用),Struts 2(通常老項目使用)等。

—— 百度百科

MVC 在上面咱們已經進行了基本的介紹,而Spring MVC 就是一款基於 MVC架構模式的輕量級Web框架,咱們所說的 Spring MVC 與 Spring Web MVC 是等價的,只不過人們更習慣前者的叫法,這一款框架,本質上也是基於 Servlet 的,若是你有 Servlet 以及 Spring 的基礎,簡單的上手這個Web框架是很是快的

(二) Spring MVC 的優勢

  • ① Spring MVC 具備 Spring 的優勢,例如依賴注入 (IOC) 和切面編程 (AOP)

  • ② 清晰的模塊化職能劃分,各模塊各司其職,清晰明瞭

    • 控制器 (controller)
    • 驗證器 (validator)
    • 命令對象 (command obect)
    • 表單對象 (form object)
    • 模型對象 (model object)
    • Servlet分發器 (DispatcherServlet)
    • 處理器映射 (handler mapping)
    • 試圖解析器 (view resoler)
  • ③ 能夠很是方便的與其餘視圖技術 (FreeMarker) 整合,因爲Spring MVC 的模型數據每每放在 Map 數據結構中,所以能夠很方便的被其餘框架引用

  • ④ 能夠靈活的實現綁定 (binding) 、驗證 (validation)

  • ⑤ 簡介的異常處理機制

  • ⑥ 比較強大的 JSP 標籤庫,簡化了JSP的開發

  • ⑦ 支持 RESTful 風格

  • ⑧ 提供了強大的約定大於配置的契約式編程支持,也就是提供一種軟件設計範式,減小軟件開發人員作決定的次數,開發人員僅須要規定應用中不符合約定的部分

(三) Spring MVC 與 Struts 的區別

Struts 也是一款基於 MVC 這種在開發模式的 JavaEE框架,近些年來,實際上開發者更多的選擇使用 SpringMVC 這個框架,那麼二者的區別是什麼呢?Spring MVC 的過人之處又在哪裏呢?

① Spring MVC 基於方法開發,Struts 基於類開發

  • 使用 Spring MVC 開發的時候,會將 URL 請求的路徑與 Controller 的某個方法進行綁定,請求參數做爲該參數方法的形參
  • 使用 Struts 開始的時候,Action 類中全部方法使用的請求參數都是 Action 類中的成員變量,一旦方法變多,很容易混淆成員變量對應使用的方法

② Spring MVC 支持單例開發模式,而 Struts 不支持

③ Spring MVC 的速度比 Struts 的速度稍微快一些

  • 一是因爲 Struts 每次都會建立一個動做類
  • 二是因爲 Struts 的標籤設計問題

④ Spring MVC 使用更加簡潔,同時還支持 JSR303,可以比較方便的處理 ajax

  • JSR 303 – Bean Validation (後臺通用參數校驗)

⑤ Struts2 的 OGNL 表達式使頁面的開發效率相比 Spring MVC 更高一點,可是執行效率對於 JSTL 也沒有很明顯的提高

淺嘗 Spring MVC

(一) 搭建開發環境

(1) 建立項目

① 建立Maven項目 --> ② 選擇JDK版本 --> ③ 勾選 create from archetype 即便用骨架建立項目 --> ④ 選擇 maven-archetype-webapp 建立出一個web項目

而後指定基本信息,點擊下一步

可是,因爲建立 maven archetype 的緣由,在建立時,會執行 mvn archetype:generate這個命令,這樣就須要指定一個 archetype-catalog.xml 文件,命令中參數 -DarchetypeCatalog 的值有三種

  • remote:從Maven遠程中央倉庫獲取 archetypeCatalog(默認的)
  • internal:從 maven-archetype-plugin 內置的 archetypeCatalog 文件獲取
  • local:本地的 archetypeCatalog 文件

咱們須要作的就是添加這樣一組鍵值對,就能夠加快建立項目的速度

  • DarchetypeCatalog
  • internal

這裏沒什麼好說的,基本不須要更改,繼續下一步

(2) 修改pom文件

將版本從1.7改成1.8,接着又在 dependencies 中引入咱們須要的一些 jar 包

定義 <spring.version>5.0.2.RELEASE</spring.version> 這樣一個標籤對,在下面就能夠引用,這樣相比於直接將版本信息寫到每個 dependencie 中,更利於後期的維護,方便更換版本,這種方式叫作鎖定版本

<?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>cn.ideal</groupId>
  <artifactId>spring_mvc_01_basic</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>spring_mvc_01_basic Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <spring.version>5.0.2.RELEASE</spring.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.0</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

  </dependencies>


  <build>
    <finalName>spring_mvc_01_basic</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>
複製代碼

(3) 目錄結構

剛建立好的項目中,main文件夾下是空的,咱們須要建立出 java 以及 resources 兩個文件夾,而且分別設置爲,源代碼根目錄 以及 資源根目錄,設置方式以下圖

(二) 編寫入門程序

(1) 配置核心控制器

在之前 JavaWeb 階段中,咱們都很清楚,前端發出的請求,都會被映射到 Web.xml 中,而後匹配到對應的 Servlet 中,而後調用對應的 Servlet 類 來處理這個請求

因爲如今咱們使用了 Spring MVC,因此這些請求,咱們就交給 Spring MVC 進行管理,因此須要在工程 webapp-WEB-INF 中找到 web.xml 進,在其中配置核心控制器,也就是 DispatcherServelt

<servlet ></servlet >標籤中指定了一個實現類爲 DispatcherServelt ,名稱爲 dispatcherServlet 的 servlet 配置

<servlet-mapping></servlet-mapping>標籤中則指定了 dispatcherServlet 攔截請求的範圍,使用 / 即表明全部請求都須要通過這裏

<init-param></init-param>標籤對中放置 DispatcherServelt 所須要的初始化參數,配置的是 contextConfigLocation 上下文參數變量,其加載的配置文件爲編譯目錄下的 springmvc.xml (下面建立)

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--配置Servlet初始化參數,讀取springmvc的配置文件,建立spring容器-->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <!-- 配置servlet啓動時加載對象-->
    <load-on-startup>1</load-on-startup>

  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

複製代碼

(2) 建立核心配置文件

在這裏,一個是開啓掃描,以及開啓註解,還有就是配置視圖解析器,它的做用就是執行方法後,根據返回的信息,來加載相應的界面,而且綁定反饋數據

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 配置spring建立容器時要掃描的包-->
    <context:component-scan base-package="cn.ideal"></context:component-scan>

    <!-- 配置視圖解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!-- 配置spring開啓註解mvc的支持 -->
    <mvc:annotation-driven></mvc:annotation-driven>
</beans>

複製代碼

特別說明:通常開發咱們都須要寫上這個標籤,即便或許如今還沒怎麼體現出來

(3) 編寫控制類

package cn.ideal.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class ControllerDemo {
    @RequestMapping(path = "/test")
    public String methodTest(){
        System.out.println("這是Controller測試方法");
        return "testSuccess";
    }
}
複製代碼

(4) 編寫頁面

index.jsp

寫一個超連接,去請求test這個路徑,也就是指向到了 Controller 下的 methodTest() 方法

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>這是主頁面</h3>
    <a href="test">訪問test試試</a>
</body>
</html>
複製代碼

WEB-INF -> pages

testSuccess.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>跳轉成功哈</h3>
</body>
</html>
複製代碼

(5) 配置 Tomcat

我這裏,配置了本地的tomcat,以及項目名稱

(三) Spring MVC 請求流程

前端控制器(DispatcherServlet)

  • 接收用戶請求,以及作出響應
  • 它負責調用其餘組件處理用戶的請求,控制整個流程的執行,想當於一箇中央處理器
  • 它下降了組件之間的耦合行,利於組件之間的擴展

處理器映射器(HandlerMapping)

  • 根據用戶請求的 URL 路徑,經過註解或者 XML 配置,尋找匹配的 Handler 即處理器

處理器適配器(HandlerAdapter)

  • 根據映射器找到的處理器(Handler)信息,按照特定規則執行相關的 Handler (常稱爲 Controller)

處理器(Hander)

  • 這就是開發中要編寫的具體業務邏輯控制器,執行相關的請求處理邏輯,而且返回相應的數據和視圖信息,而後封裝到 ModeAndView 對象中

視圖解析器(View resolver)

  • 經過ModelAndView 對象中的 View 信息將邏輯視圖名解析成物理視圖名,即具體的頁面地址,而後再生成 View 視圖對象,最後對 View 進行渲染處理結果經過頁面展現給用戶

視圖(View)

  • 自己是一個接口,實現類支持不一樣 View 類型 (JSP、FreeMarker、Excel 等)

注:咱們開發人員真正須要進行開發的是處理器(Handler)和視圖(View)

也就是,處理用戶請求的具體邏輯代碼,以及展現給用戶的界面

(四) 請求映射與參數綁定

(1) RequestMapping

@RequestMaspping 註解是指定控制器能夠處理哪些URL請求,這個註解能夠放在類或者方法上。

  • 類上:一級訪問目錄
  • 方法上:二級訪問目錄
  • ${ pageContext.request.contextPath }能夠省略不寫,但路徑上不能寫/

屬性:

  • path:指定請求路徑的url
  1. value:value屬性和path屬性是同樣的
  2. mthod:指定該方法的請求方式
  3. params:指定限制請求參數的條件
  4. headers:發送的請求中必須包含的請求頭

而通常不在 @RequestMaspping 中配置其餘屬性的時候,能夠省去 value 參數名,直接寫一個表明 URL 映射信息的字符串就能夠了

例如:@RequestMaspping(/test)

(2) 請求參數的綁定

在用戶在頁面中出發請求的時候,提交表單的數據通常都是 key/value 格式的數據

在傳統JavaWeb 中咱們所使用的通常是 request.getParameter() 等方法將請求參數獲取到

而Spring MVC中能夠經過參數綁定,將客戶端請求的這個 key/value 格式的數據綁定到 Controller 處理器方法的形參上,支持的數據類型咱們能夠分爲三類

A:基本數據類型和字符串類型

index.jsp

注:只截取了部分

<h3>這是主頁面</h3>
<a href="user/testA?username=admin&password=admin888">測試一下</a>
複製代碼

pages --> testSuccess.jsp

<h3>跳轉成功哈</h3>
複製代碼

UserController

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/testA")
    public String testA(String username, String password) {
        System.out.println("獲取到的username: " + username);
        System.out.println("獲取到的password: " + password);
        return "testSuccess";
    }

}
複製代碼

經過構建一個超連接的方式傳遞參數,例如 ?username=admin 而在後端中若是方法形參與這個username是一致的,這個提交的數據就會被綁定到參數username中

B:JavaBean 實體類型

參數中使用 JavaBean 類型接收時,在提交表單的時候,就須要將其中的 name 屬性中的值與實體類中的成員變量的值是同樣的

若是一個JavaBean類中包含其餘的引用類型,那麼表單的name屬性須要編寫成:對象.屬性例如:account.username

index.jsp

<form action="user/testB" method="post">
	暱稱: <input type="text" name="nickname"><br/>
	年齡: <input type="text" name="age"><br/>
    住址: <input type="text" name="address"><br/>
    用戶名: <input type="text" name="account.username"><br/>
    密碼: <input type="text" name="account.password"><br/>
    <input type="submit" value="提交">
</form>
複製代碼

UserController

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/testB")
    public String testB(User user) {
        System.out.println(user);
        return "testSuccess";
    }
    
}
複製代碼

實體類 User 和 Account

public class User implements Serializable {
    private String nickname;
    private int age;
    private String address;
    private Account account;
    ......省略 get set toString方法
}
複製代碼
public class Account implements Serializable {
    private String username;
    private String password;
    ......省略 get set toString方法
}
複製代碼

C:集合數據類型

對於集合類型,仍然使用一個表達式的寫法

index.jsp

<form action="user/testB" method="post">
    暱稱: <input type="text" name="nickname"><br/>
    年齡: <input type="text" name="age"><br/>
    住址: <input type="text" name="address"><br/>
    用戶名1: <input type="text" name="list[0].username"><br/>
    密碼1: <input type="text" name="list[0].password"><br/>
    用戶名2: <input type="text" name="map['First'].username"><br/>
    密碼2: <input type="text" name="map['First'].password"><br/>
    <input type="submit" value="提交">
</form>
複製代碼

UserController

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/testB")
    public String testB(User user) {
        System.out.println(user);
        return "testSuccess";
    }
    
}
複製代碼

實體類 User 和 Account

public class User implements Serializable {
    private String nickname;
    private int age;
    private String address;

    private List<Account> list;
    private Map<String, Account> map;
    ......省略 get set toString方法
}
複製代碼
public class Account implements Serializable {
    private String username;
    private String password;
    ......省略 get set toString方法
}
複製代碼

解決請求參數中文亂碼的問題

在 web.xml 中的 <web-app></web-app>標籤內配置過濾器類,達到解決請求參數中文亂碼的問題

<!--配置解決中文亂碼的過濾器-->
<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>
複製代碼

(五) 經常使用註解

(1) RequestParam 註解

  • 做用:把請求中的指定名稱的參數傳遞給控制器中的形參

  • 屬性

    • value:請求參數中的名稱

    • name:name是value的別名,一個帳戶

    • required:是否必需,默認爲 true,即 請求中必須包含該參數,若是沒有包含,將會拋出異常(可選)

@RequestMapping(path="/hello")
public String sayHello(@RequestParam(value="nick",required=false)String nickname) {
	System.out.println(nickname);
	return "success";
}
複製代碼

(2) RequestBody 註解

  • 做用:用於獲取請求體的內容(注:get方法不能夠)
@RequestMapping("/testC")
public String testC(@RequestBody String body) {
    System.out.println(body);
    return "testSuccess";
}
複製代碼

例如接收到這樣的語句

nickname=BWH_Steven&age=666&address=beijing
複製代碼

(3) PathVariable 註解

  • 做用:用於綁定url中的佔位符,例如:url中有/test/{id},{id}就是佔位符
  • 屬性:
    • value:用於指定url中佔位符名稱

UserController

@RequestMapping(path="/test/{uid}")
public String testD(@PathVariable(value="uid") String id) {
    System.out.println(id);
    return "testSuccess";
}
複製代碼

index.jsp

<a href="user/test/66">訪問test試試</a>
複製代碼

(4) RequestHeader 註解 (不經常使用)

  • 做用:獲取指定請求頭的值
  • 屬性:
    • value:請求頭的名稱

UserController

@RequestMapping("/testD")
public String testD(@RequestHeader(value="Accept") String header) {
    System.out.println(header);
    return "testSuccess";
}
複製代碼

index.jsp

<a href="user/testD">訪問test試試</a>
複製代碼

打印結果:

text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3
複製代碼

(5) CookieValue註解

  • 做用:用於獲取指定cookie的名稱的值

屬性:

  • value:cookie的名稱

UserController

@RequestMapping("/testF")
    public String testF(@CookieValue(value="JSESSIONID") String cookieValue) {
        System.out.println(cookieValue);
        return "testSuccess";
    }
複製代碼

index.jsp

<a href="user/testF">訪問test試試</a>
複製代碼

打印結果:

FCFDD389AC473F837266FC890E9E6F36
複製代碼

(6) ModelAttribute 註解

做用:

  • 在方法上:表示當前方法會在控制器方法執行前執行

  • 在參數上:獲取指定的數據給參數賦值

應用場景:

  • 提交表單的數據不是完整的數據,而沒提交的字段,就是用數據庫中原來的
  • 例如:用戶修改我的信息,可是暱稱則不容許修改,只提供修改例如年齡、地址等的表單,若是不進行任何的處理,就會致使,接收到的數據中 nickname 這個值是 null,再存到數據庫就會對原來的數據形成損失影響
  • 還有一些狀況就例如:帳號註冊日期這種信息固然也是不能被修改的

index.jsp

只提供修改年齡和地址的表單,同時傳一個隱藏域中的id,方便去數據庫查詢(固然咱們這裏是模擬的)

<form action="user/testG" method="post">
    <input type="hidden" name="uid" value="1">
    年齡: <input type="text" name="age"><br/>
    住址: <input type="text" name="address"><br/>
    <input type="submit" value="提交">
</form>
複製代碼

UserController

實體類就不給出了,就是三個成員,nickname age address

若是沒有下面這個增長了 @ModelAttribute 註解的 findUserByUid方法,當執行 testG 方法後,會獲取到一個 nickname = null 的值

而咱們下面的作法,在執行 testG 以前會先執行 findUserByUid,而後能夠去數據庫中根據uid查詢,固然咱們這裏是模擬的,而後將這個user返回

接着執行 testG 方法的時候,就能將用戶提交的 age 和 address 獲取到,同時將用戶沒有提交的 nickname 使用數據庫中的值

@RequestMapping("/testG")
public String testG(User user) {
    System.out.println("這是testG方法");
    System.out.println("用戶修改後的: " + user);
    return "testSuccess";
}

@ModelAttribute
public User findUserByUid(Integer uid) {
    System.out.println("這是findUserByUid方法");
    //模擬查詢數據庫
    User user = new User();
    user.setNickname("BWH_Steven");
    user.setAge(66);
    user.setAddress("北京");

    System.out.println("數據庫中查詢到: " + user);

    return user;
}
複製代碼

另外一種方式

若是沒有返回值的方式就能夠這樣改寫,增長一個 map ,而後存進去

@RequestMapping("/testG")
public String testG(@ModelAttribute("first") User user) {
    System.out.println("這是testG方法");
    System.out.println("用戶修改後的: " + user);
    return "testSuccess";
}

@ModelAttribute
public void findUserByUid(Integer uid, Map<String,User> map) {
    System.out.println("這是findUserByUid方法");
    //模擬查詢數據庫
    User user = new User();
    user.setNickname("BWH_Steven");
    user.setAge(66);
    user.setAddress("北京");

    System.out.println("數據庫中查詢到: " + user);

    map.put("first",user);

}
複製代碼

(7) SessionAttributes 註解

  • 做用:用於屢次執行控制器方法間的參數共享

屬性

  • value:指定存入屬性的名稱

UserController

在存入方法跳轉以前,會將數據保存到 nickname age address 中,由於註解@SessionAttribute中有這幾個參數

@Controller
@RequestMapping("/user")
@SessionAttributes(value = {"nickname","age","address"})
public class UserController {
	/** * 向session中存入值 * @param model * @return */
    @RequestMapping("/addUser")
    public String addUser(Model model) {
        model.addAttribute("nickname", "BWH_Steven");
        model.addAttribute("age", 20);
        model.addAttribute("address", "北京");
        return "testSuccess";
    }

    /** * 從session中獲取值 * @param modelMap * @return */
    @RequestMapping("/findUser")
    public String findUser(ModelMap modelMap) {
        String nickname = (String) modelMap.get("nickname");
        Integer age = (Integer)modelMap.get("age");
        String address= (String) modelMap.get("address");
        System.out.println(nickname + " " + age + " " + address);
        return "testSuccess";
    }

    /** * 清除值 * @return */
    @RequestMapping("/delete")
    public String delete(SessionStatus status) {
        status.setComplete();
        return "testSuccess";
    }
}
複製代碼

index.jsp

<a href="user/addUser">訪問addUser試試</a>
<a href="user/findUser">訪問findUser試試</a>
<a href="user/delete">訪問delete試試</a>
複製代碼

testSuccess.jsp

注意設置 isELIgnored="false"

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>跳轉成功哈</h3>
    ${nickname}
    ${age}
    ${address}
    ${sessionScope}
</body>
</html>
複製代碼

(六) 響應數據以及結果視圖

講完了請求與參數綁定,以及一些經常使用的註解,接着就能夠說一下響應的一些知識,也就是咱們接受到用戶的請求,而且進行必定的處理之後,如何進行正確的響應

(1) 返回字符串

其實在前面的講解中,咱們一直用的就是返回字符串的形式,而結果也是很直觀的,也就是,進行了同名頁面的跳轉,例如返回 success 則跳轉到 success.jsp 的頁面中

這也就是說,Controller 方法返回字符串能夠指定邏輯視圖的名稱,視圖解析器會將其解析成物理視圖的地址

演示一種常見的使用場景

index.jsp

<a href="user/testString">修改用戶信息頁面</a>
複製代碼

UserController

注:實體類就不談了,只有 username 和 password 兩個成員

模擬一個數據庫查詢到數據信息,而後將數據存到 request 域中

@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/testString")
    public String testString(Model model) {
        //模擬從數據庫中查詢
        User user = new User();
        user.setUsername("張三");
        user.setPassword("888666");
        model.addAttribute("user", user);
        return "success";
    }
}
複製代碼

success.jsp

注意配置:isELIgnored="false"

當用戶點擊主頁面中進行頁面修改,就會跳轉到這個用戶名以及密碼的修改界面,同時將數據進行回顯,優化體驗

<%@ page contentType="text/html;charset=UTF-8" language="java"  isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>修改</h3>
    <form action="" method="post">
        用戶名:<input type="text" name="username" value="${ user.username }"><br>
        密碼:<input type="text" name="password" value="${ user.password }"><br>
        <input type="submit" value="提交">
    </form>
</body>
</html>
複製代碼

A:響應轉發或者重定向

<a href="user/testForward">測試一下</a>
複製代碼
@RequestMapping("/testForward")
    public String testForward() throws Exception{
        System.out.println("testForward 被執行了");
          //轉發
// return "forward:/WEB-INF/pages/success.jsp";
        //重定向
        return "redirect:/index.jsp";
    }
複製代碼

(2) 返回 void

若是說直接去掉返回值,以及修改返回類型爲void,會報出一個404異常,能夠看到地址欄中,去指向了一個 http://localhost:8080/springmvc-response/user/testVoid.jsp 的地址,也就是說它默認去查找了一個jsp頁面(也就是 @RequestMapping("/testVoid") 值同名的 jsp),不過沒有找到

若是想要在這種狀況下,跳轉頁面可使用請求轉發,或者重定向跳轉

@RequestMapping("/testVoid")
public void testVoid(HttpServletRequest request,HttpServletResponse response) throws Exception {
System.out.println("請求轉發或者重定向被執行了");
// 1. 請求轉發
// request.getRequestDispatcher("/WEB-INF/pages/test1.jsp").forward(request,
response);
    
// 2. 重定向
// response.sendRedirect(request.getContextPath()+"/test2.jsp");
    
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 3. 直接響應數據
response.getWriter().print("測試被執行了哈");
return;
}

複製代碼

(3) 返回值是ModelAndView對象

這種方式其實和String達到的效果基本是一致的

index.jsp

<a href="user/findAll">測試一下</a>
複製代碼

UserController

@RequestMapping("/findUser")
public ModelAndView findUser() throws Exception{
    ModelAndView modelAndView = new ModelAndView();
    //跳轉到jsp
    modelAndView.setViewName("success");

    //模擬從數據庫中查詢用戶信息
    User user = new User();
    user.setUsername("李四");
    user.setPassword("888888");
    
    modelAndView.addObject("user",user);
    return modelAndView;
}
複製代碼

success.jsp

${user.username}
${user.password}
複製代碼

(4) 過濾靜態資源(必備)

在 web.xml 中配置的 DispatcherServle(前端控制器),會攔截到全部的資源,在之後的開發中,一個特別顯著的問題就是,靜態資源 (img、css、js)這樣的文件也被攔截了,也就沒法使用,咱們首先須要瞭解的就是如何不對靜態資源進行攔截

很是簡單,在springmvc.xml中配置就能夠了

mvc:resources 標籤就能夠配置不過濾

  • location 表示webapp目錄下的包下的全部文件
  • mapping 表示以/xxx開頭的全部請求路徑,如/xxx/a 或者/xxx/a/b
<!--前端控制器-->
<mvc:resources mapping="/css/**/" location="/css/"/>
<mvc:resources mapping="/images/**/" location="/images/"/>
<mvc:resources mapping="/js/**/" location="/js/"/>
複製代碼
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>

    <%--引入jquery--%>
    <script src="js/jquery-2.1.0.min.js"></script>
    <script>
        $(function () {
            $("#btn").click(function () {
                alert("Just for test");
            });
        });
    </script>
</head>
<body>
    <%--<a href="user/testString">修改用戶信息頁面</a>--%>
    <%--<a href="user/testForward">測試一下</a>--%>
    <button id="btn">發送ajax請求</button>
</body>
</html>
複製代碼

(5) 發送ajax請求-後臺獲取請求體

index.jsp

在 Javaweb 階段,你們基本都是有了解過 ajax 的,因此我就直接用了,若是有不熟悉的,能夠去查一下api或者找一下教程,格式仍是很是好理解的

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>

    <%--引入jquery--%>
    <script src="js/jquery-2.1.0.min.js"></script>
    <script>
        $(function () {
            $("#btn").click(function () {
                //發送ajax請求
                $.ajax({
                    url:"user/testAjax",
                    contentType:"application/json;charset=UTF-8",
                    data:'{"username":"zhangsan","password":"888888"}',
                    dataType:"json",
                    type:"post",
                    success:function (data) {
                        //解析響應數據
                    }
                })
            });
        });
    </script>
</head>
<body>
    <button id="btn">發送ajax請求</button>
</body>
</html>
複製代碼

參數中使用 @RequestBody 這個註解,就能夠接收到請求體,而後變成這樣一個串的形式

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/testAjax")
    public void testAjax(@RequestBody String body){
        System.out.println("testAjax 被執行了");
        System.out.println(body);
    }
}
複製代碼

打印結果就是這樣的

testAjax 被執行了
{"username":"zhangsan","password":"888888"}
複製代碼

(6) 響應json格式數據

UserControllr

@RequestMapping("/testAjax")
public @ResponseBody User testAjax(@RequestBody User user){
    System.out.println("testAjax 被執行了");
    // 模擬數據庫查詢
    System.out.println(user);
    user.setUsername("admin");
    user.setPassword("admin888");
    return user;
}
複製代碼

使用 @RequestBody String body 接收到的是一個串,而想要直接將 Json 字符串和 JavaBean 對象相互轉換,須要 jackson 的jar包,咱們能夠增長這樣的依賴

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.0</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.9.0</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.9.0</version>
</dependency>
複製代碼

index.jsp

<%--引入jquery--%>
<script src="js/jquery-2.1.0.min.js"></script>
<script>
    $(function () {
        $("#btn").click(function () {
            //發送ajax請求
            $.ajax({
                url:"user/testAjax",
                contentType:"application/json;charset=UTF-8",
                data:'{"username":"zhangsan","password":"888888"}',
                dataType:"json",
                type:"post",
                success:function (data) {
                    //解析響應數據
                    alert(data);
                    alert(data.username);
                    alert(data.password);
                }
            })
        });
     });
</script>
複製代碼

(七) 文件上傳

(1) 普通文件上傳方式

index.jsp

<h3>文件上傳</h3>
<form action="user/fileupload" method="post" enctype="multipart/form-data">
    選擇文件:<input type="file" name="upload"/><br/>
    <input type="submit" value="上傳文件"/>
</form>
複製代碼
  • form表單的enctype的默認值是:application/x-www-form-urlencoded

    • 表單正文內容通常是:key=value&key=value&key=value
  • 若是想要進行文件上傳,就必需要改成 multipart/form-data(),同時method屬性取值必須是Post

    • 每一部分都變成MIME類型描述的正文

注意:當form表單的enctype取值不是application/x-www-form-urlencoded後,request.getParameter()方法就不能再使用

注意:想要實現文件上傳,能夠藉助一些組件,須要導入該組件相應的支撐jar 包:Commons-fileupload 和commons-io

commons-io 不屬於文件上傳組件的開發jar文件,但Commons-fileupload 組件從1.1 版本開始,它使用須要commons-io包的支持

UserController

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/fileupload")
    public String fileupload(HttpServletRequest request) throws Exception {
        System.out.println("文件上傳...");

        // 使用fileupload組件完成文件上傳
        // 上傳位置
        String path = request.getSession().getServletContext().getRealPath("/uploads/");
        // 判斷,該路徑是否存在
        File file = new File(path);
        if (!file.exists()) {
            // 不存在則建立文件夾
            file.mkdirs();
        }

        // 解析request對象,獲取上傳文件項
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        // 解析request
        List<FileItem> items = upload.parseRequest(request);
        // 遍歷
        for (FileItem item : items) {
            // 進行判斷,當前item對象是不是上傳文件項
            if (item.isFormField()) {
                // 普通表單項
            } else {
                // 上傳文件項
                // 上傳文件的名稱
                String filename = item.getName();
                // 把文件的名稱設置惟一值,UUID 防止重複覆蓋問題
                String uuid = UUID.randomUUID().toString().replace("-", "");
                filename = uuid + "_" + filename;
                // 完成文件上傳
                item.write(new File(path, filename));
                // 刪除臨時文件
                item.delete();
            }
        }

        return "success";
    }
}

複製代碼

說明

request.getSession().getServletContext() 獲取的是Servlet容器對象,就比如tomcat容器

getRealPath("/") 表明獲取實際路徑,「/」指代項目根目錄

因此代碼返回的是項目在容器中的實際發佈運行的根路徑

(2) Spring MVC 上傳方式(同服務器)

index.jsp

<h3>文件上傳</h3>
<form action="user/fileupload2" method="post" enctype="multipart/form-data">
    選擇文件:<input type="file" name="upload"/><br/>
    <input type="submit" value="上傳文件"/>
</form>
複製代碼

springmvc.xml

<!--配置文件解析器對象-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="10485760" />
</bean>
複製代碼

注意:10485760 = 10x1024x1024

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/fileupload2")
    public String fileupload2(HttpServletRequest request, MultipartFile upload) throws Exception {
        System.out.println("文件上傳...");

        // 使用fileupload組件完成文件上傳
        // 上傳位置
        String path = request.getSession().getServletContext().getRealPath("/uploads/");
        // 判斷,該路徑是否存在
        File file = new File(path);
        if (!file.exists()) {
            // 不存在則建立文件夾
            file.mkdirs();
        }

        // 獲取上傳文件的名稱
        String filename = upload.getOriginalFilename();
        // 把文件的名稱設置惟一值,uuid
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid+"_"+filename;
        // 完成文件上傳
        upload.transferTo(new File(path,filename));

        return "success";
    }
}

複製代碼

(3) Spring MVC 上傳方式(跨服務器)

不少時候會將整個工程部署到不一樣的服務器,例如:

應用服務器,數據庫服務器,緩存和消息服務器,文件服務器等等,不過入門來講了解一下就能夠了

想要測試下面的代碼,能夠配置兩個 Tomcat 給不一樣端口等配置,模擬一下

index.jsp

<h3>文件上傳</h3>
<form action="user/fileupload3" method="post" enctype="multipart/form-data">
    選擇文件:<input type="file" name="upload"/><br/>
    <input type="submit" value="上傳文件"/>
</form>
複製代碼

增長依賴

<dependency>
  <groupId>com.sun.jersey</groupId>
  <artifactId>jersey-core</artifactId>
  <version>1.18.1</version>
</dependency>
<dependency>
  <groupId>com.sun.jersey</groupId>
  <artifactId>jersey-client</artifactId>
  <version>1.18.1</version>
</dependency>
複製代碼

UserController

@Controller
@RequestMapping("/user")
public class UserController {
    
   @RequestMapping("/fileupload3")
    public String fileupload3(MultipartFile upload) throws Exception {
        System.out.println("SpringMVC跨服務器方式的文件上傳...");
        // 定義圖片服務器的請求路徑
        String path = "http://localhost:9090//springmvc-fileupload/uploads/";
        // 獲取到上傳文件的名稱
        String filename = upload.getOriginalFilename();
        String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
        // 把文件的名稱惟一化
        filename = uuid + "_" + filename;
        // 向圖片服務器上傳文件
        // 建立客戶端對象

        Client client = Client.create();
        // 鏈接圖片服務器
        WebResource webResource = client.resource(path + filename);
        // 上傳文件
        webResource.put(upload.getBytes());
        return "success";
    }
}
複製代碼

(八) 異常處理

異常處理也算一個老生常談的問題,在上線項目或者運行項目的時候,總可能會出現一些沒法預料的異常信息,對於開發者而言,天然須要看到具體的異常信息,而後進行排除,而對於用戶,天然儘量的出現一些簡單,易於理解的語言或者提示

在 Spring MVC 中,提供了一個全局異常處理器,能夠對異常進行統一處理

Dao、Service、Controller出現都經過 throws Exception 向上拋出,最後由Spring MVC前端 控制器交由全局異常處理器進行異常處理

(1) 自定義異常類

對於預期的異常,一般定義一個自定義異常類,用來存儲異常的信息

首先這個類繼承了 Exception 類,用來描述程序能獲取的異常,設置了一個成員message,就是用來存放異常信息的

package cn.ideal.exception;

public class SysException extends Exception {
    private String message;

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public SysException(String message) {
        this.message = message;
    }
}
複製代碼

(2) 全局異常處理器

全局異常處理器實現的是 Spring MVC 的 HandlerExceptionResolver 接口

這是接口的源碼

public interface HandlerExceptionResolver {
    @Nullable
    ModelAndView resolveException(HttpServletRequest var1, HttpServletResponse var2, @Nullable Object var3, Exception var4);
}
複製代碼
  • Exception ex:就是 Controller 或下層拋出的異常
  • Object handler:處理器適配器要執行的 Handler 對象
  • 返回值類型:ModelAndView 這也就是說,能夠經過這個返回值設置異常時顯示的頁面
public class SysExceptionResolver implements HandlerExceptionResolver {
    /** * 跳轉到具體的錯誤頁面的方法 */
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,Exception ex) {
        ex.printStackTrace();
        //解析出異常類型
        SysException sysException = null;
        // 獲取到異常對象
        if (ex instanceof SysException) {
            //若是異常類型是系統自定義異常,直接取出異常信息,在錯誤頁面展現
            sysException = (SysException) ex;
        } else {
            //若是異常類型不是系統自定義異常,則構造一個自定義異常類型
            sysException = new SysException("未知錯誤");
        }
        ModelAndView mv = new ModelAndView();
        // 存入錯誤的提示信息
        mv.addObject("errorMsg", sysException.getMessage());
        // 跳轉的Jsp頁面
        mv.setViewName("error");
        return mv;
    }
}
複製代碼

(3) 配置異常處理器

springmvc.xml 中配置

<bean id="sysExceptionResolver" class="cn.ideal.exception.SysExceptionResolver"/>
複製代碼

(4) 測試代碼

UserController

@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping("testException")
    public String testException() throws SysException {
        System.out.println("testException被執行了");
        try {
            int a = 100 / 0;
        } catch (Exception e) {
            e.printStackTrace();
            throw new SysException("測試這個方法出錯了");
        }
        return "success";
    }
}
複製代碼

index.jsp

<h3>主頁面</h3>
<a href="user/testException">測試一下</a>
複製代碼

error.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    ${errorMsg}
</body>
</html>
複製代碼

(九) 攔截器

攔截器,用來幹嗎呢,就好比你須要檢測用戶的權限,或者把請求信息記錄到日誌等等,也就是說須要在用戶請求先後執行的一些行爲

首先在 Spring MVC 中是有兩種機制,第一種就是實現 HandlerInterceptor接口,還有一種就是實現 Spring 的 WebRequestInterceptor 接口,不過咱們就簡單說一下第一種

自定義一個類簡單看一下,實現三個方法

public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle方法執行了");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle方法執行了");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion方法執行了");
    }
}
複製代碼

① preHandle方法:controller 方法執行前攔截的方法

  • 可使用 request 或者 response 跳轉到指定的頁面

  • return true放行,執行下一個攔截器,若是沒有攔截器,執行 controller 中的方法

  • return false不放行,不會執行 controller 中的方法

② postHandle:controller 方法執行後執行的方法,在 JSP 視圖執行前

  • 可使用 request 或者 response 跳轉到指定的頁面

  • 若是指定了跳轉的頁面,那麼 controller 方法跳轉的頁面將不會顯示。

③ postHandle方法:在JSP執行後執行

  • request 或者 response 不能再跳轉頁面了

配置攔截器

注:不要攔截用這個標籤<mvc:exclude-mapping path=""/>

注:/user/* 表明全部訪問帶有 /user/的路徑都會被攔截,例如 /user/test

<!--配置攔截器-->
<mvc:interceptors>
    <!--配置攔截器-->
    <mvc:interceptor>
        <!--要攔截的具體的方法-->
        <mvc:mapping path="/user/*"/>
        <!--配置攔截器對象-->
        <bean class="cn.ideal.interceptor.MyInterceptor" />
    </mvc:interceptor>
</mvc:interceptors>
複製代碼

隨便寫一個方法測試一下

@RequestMapping("/testInterceptor")
public String testInterceptor() {
    System.out.println("testInterceptor被執行了");
    return "success";
}
複製代碼

執行結果

preHandle方法執行了
testInterceptor被執行了
postHandle方法執行了
afterCompletion方法執行了
複製代碼

總結

寫着寫着又是1w字了,以前就想着寫這篇文章,也一直沒什麼空,對於這一篇文章,我認爲對於入門來講仍是比較有好的,前面給了幾個大點的基本知識講解,而後從開發環境以及一個入門程序開始,再到請求以及如何響應,以及一些經常使用的註解,再到其餘的,文件上傳,異常處理,攔截器等知識,基原本說,達到了一個 工具書 + 入門講解的效果,不過要說的點太多了,即便1w字的文章,實際上也只夠簡單說起,再加個小案例,就例如攔截器,或者文件上傳的講解,只能說講了最基本的,對於已經有必定基礎的朋友,天然沒什麼進階的幫助,不過個人初心,也是想鞏固一下本身的知識,而後能將文章帶給剛接觸 Spring MVC 的朋友,我也不是什麼大牛,不過但願能給你們一點幫助,咱們能夠一塊兒交流,一塊兒進步哈!

感謝你們的支持!!!

結尾

若是文章中有什麼不足,歡迎你們留言交流,感謝朋友們的支持!

若是能幫到你的話,那就來關注我吧!若是您更喜歡微信文章的閱讀方式,能夠關注個人公衆號

在這裏的咱們素不相識,卻都在爲了本身的夢而努力 ❤

一個堅持推送原創開發技術文章的公衆號:理想二旬不止

相關文章
相關標籤/搜索