趕緊收藏!Spring MVC 萬字長文筆記,我願奉你為王者筆記!

前程有光發表於2020-12-21

Spring MVC

Spring MVC是目前主流的實現MVC設計模式的企業級開發框架,Spring框架的一個子模組,無需整合Spring,開發起來更加便捷。

什麼是MVC設計模式?

將應用程式分為Controller、Model、View三層,Controller 接收客戶端請求,呼叫 Model 生成業務資料,傳遞給View。

Spring MVC 就是對這套流程的封裝,遮蔽了很多底層程式碼,開放出介面,讓開發者可以更加輕鬆、便捷地完成基於MVC設計模式的Web開發。

Spring MVC的核心元件

  • DispatcherServlet:前置控制器,是整個流程控制的核心,控制其他元件的執行,進行統一排程,降低元件之間的耦合性,相當於總指揮;
  • Handler:處理器,完成具體的業務邏輯,相當於 Servlet;
  • HandlerMapping:DispatcherServlet 接收到請求之後,通過 HandlerMapping 將不同的請求對映到不同的Handler;
  • HandlerInterceptor:處理器攔截器,是一個介面,如果需要完成一些攔截處理,可以實現該介面;
  • HandlerExecutionChain:處理器執行鏈,包括兩部分內容:Handler 和 HandlerInterceptor (系統會有一個預設的 HandlerInterceptor,如果需要額外設定攔截,可以新增攔截器);
  • HandlerAdapter:處理器介面卡,Handler 執行業務方法之前,需要進行一系列的操作,包括表單資料的驗證、資料型別的轉換、將表單資料封裝到 JavaBean 等,這些操作都是由 HandlerAdapter 來完成,開發者只需要將注意力集中業務邏輯的處理上(介面卡設計模式),DispatcherServlet 通過 HandlerAdapter 來執行不同的Handler;
  • ModelAndView:裝載了模型資料和檢視資訊,作為 Handler 的處理結果,返回給 DispatcherServlet ;
  • ViewResolver:檢視解析器,DispatcherServlet 通過它將邏輯檢視解析為物理檢視,最終將渲染結果響應給客戶端。

Spring MVC的工作流程

  • 客戶端請求被 DispatcherServlet 接收;
  • 根據 HandlerMapping 對映到Handler;
  • 生成 Handler 和 HandlerInterceptor;
  • Handler 和 HandlerInterceptor 以 HandlerExecutionChain 的形式一併返回給 DispatcherServlet;
  • DispatcherServlet 通過 HandlerAdapter 來呼叫 Handler 的方法來完成業務邏輯處理;
  • Handler 返回一個 ModelAndView 給 DispatcherServlet;
  • DispatcerServlet 將獲取的 ModelAndView 物件傳給 ViewResolver 檢視解析器,將邏輯檢視解析為物理檢視 View;
  • ViewResolver 返回一個View 給 DispatcherServlet;
  • DispatcherServlet 根據 View 進行檢視渲染(將模型資料 Model 填充到檢視 View 中);
  • DispatcherServlet 將渲染後的結果響應給客戶端。

Spring MVC 流程非常複雜,實際開發中很簡單,因為大部分的元件不需要開發者建立、管理,只需要通過配置檔案的方式完成配置即可,真正需要開發者進行處理的只有 Handler、View。

如何使用?

  • 建立 Maven 工程,pom.xml;

(當IDEA工具左側不顯示專案名稱,可以關閉IDEA,刪除.idea資料夾,重新開啟IDEA)

(利用webapp模板建立的Web工程目錄,src/main/webapp,java原始檔目錄和resources資源目錄需要自己建立)

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>
</dependencies>

  • 在web.xml中配置 DispatcherServlet ;
<?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">
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

  • springmvc.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"
       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">
    <!--配置自動掃描,將元件掃描到IoC容器中-->
    <context:component-scan base-package="org.westos"></context:component-scan>

    <!--配置檢視解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"/>
        <!--value="/"代表根目錄-->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

  • 建立 Handler
package org.westos.controller;

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

/**
 * @author lwj
 * @date 2020/12/13 22:29
 */
@Controller
public class HelloHandler {

    @RequestMapping("/index")
    public String index() {
        System.out.println("執行了index...");
        return "index";
    }
}

  • 配置Tomcat伺服器,啟動,執行,成功。

http://localhost:8080/index

Spring MVC 註解

  • @RequestMapping

Spring MVC 通過 @RequestMapping 註解將 URL 請求與業務方法進行對映,在 Handler 的類定義處和方法定義處都可以新增 @RequestMapping ,在類定義處新增,相當於客戶端多了一層訪問路徑;

  • @Controller

@Controller 在類定義處新增,將該類交給 IoC 容器來管理(結合 springmvc.xml 的自動掃描配置使用),同時使其成為一個控制器,可以接收客戶端請求;

package org.westos.controller;

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

/**
 * @author lwj
 * @date 2020/12/13 22:29
 */
@Controller
@RequestMapping("/hello")
public class HelloHandler {

    @RequestMapping("/index")
    public String index() {
        System.out.println("執行了index...");
        return "index";
    }
}

http://localhost:8080/hello/index

  • @RequestMapping 相關引數

1、value:指定URL請求的實際地址,是 @RequestMapping 的預設值。

@RequestMapping("/index")
public String index() {
    System.out.println("執行了index...");
    return "index";
}

等於

@RequestMapping(value = "/index")
public String index() {
    System.out.println("執行了index...");
    return "index";
}

2、method:指定請求的Method型別,GET、POST、PUT、DELETE。

@RequestMapping(value = "/index", method = RequestMethod.GET)
public String index() {
    System.out.println("執行了index...");
    return "index";
}

上述程式碼表示 index 方法只可以接收 GET 請求。

使用Postman工具來模擬一個POST請求訪問index方法。

在這裡插入圖片描述

3、params:指定請求中必須包含某些引數,否則無法呼叫該方法。

@RequestMapping(value = "/index", method = RequestMethod.GET, params = {"name", "id=5"})
public String index() {
    System.out.println("執行了index...");
    return "index";
}

上述程式碼表示請求中必須包含 name 和 id 兩個引數,並且 id 的值必須是5。

http://localhost:8080/hello/index?name=zhangsan&id=5

關於引數繫結,在形參列表中通過新增 @RequestParam 註解完成 HTTP 請求引數與業務方法形參的對映。

(當請求引數名和方法形參名一致時,可以不用新增 @RequestParam 註解)

@RequestMapping(value = "/index", method = RequestMethod.GET, params = {"name", "id=5"})
public String index(@RequestParam("name") String str, @RequestParam("id") int age) {
    System.out.println("執行了index...");
    System.out.println(str);
    System.out.println(age);
    return "index";
}

上述程式碼表示將請求的引數 name 和 id 分別賦給形參 str 和 age,同時自動完成了資料型別轉換,將字串"10"轉換為 int 型別的10,再賦給 age,這些工作都是由 HandlerAdapter 完成。

Spring MVC 同時支援 RESTful 風格的 URL 。

傳統型別:http://localhost:8080/hello/index?name=zhangsan&id=5

RESTful:http://localhost:8080/hello/rest/zhangsan/10

@RequestMapping(value = "/rest/{name}/{id}")
public String rest(@PathVariable("name") String name, @PathVariable("id") int id) {
    System.out.println(name);
    System.out.println(id);
    return "index";
}

通過 @PathVariable 註解完成請求引數與形參的對映。

  • 對映 Cookie

Spring MVC 通過對映可以直接在業務方法中獲取Cookie的值。

@RequestMapping(value = "/cookie")
public String cookie(@CookieValue(value = "JSESSIONID") String sessionId) {
    System.out.println(sessionId);
    return "index";
}

  • 使用 JavaBean 繫結引數

Spring MVC 會根據請求引數名和 JavaBean 屬性名進行自動匹配,自動為物件填充屬性值,同時支援級聯屬性。

package org.westos.entity;

import lombok.Data;

/**
 * @author lwj
 * @date 2020/12/19 15:57
 */
@Data
public class Address {
    private String value;
}

package org.westos.entity;

import lombok.Data;

/**
 * @author lwj
 * @date 2020/12/19 15:58
 */
@Data
public class User {
    private long id;
    private String name;
    private Address address;
}

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%--頁面上的路徑與重定向是需要新增Web專案的上下文路徑的--%>
    <form action="/hello/register" method="post">
        <label for="id">使用者id:</label>
        <input type="text" name="id" id="id"> <br>
        <label for="name">使用者名稱:</label>
        <input type="text" name="name" id="name"> <br>
        <label for="value">使用者地址:</label>
        <input type="text" name="address.value" id="value"> <br>
        <input type="submit" value="註冊">
    </form>
</body>
</html>

@RequestMapping(value = "/register", method = RequestMethod.POST)
public String register(User user) {
    System.out.println(user);
    return "index";
}

上述會出現中文亂碼問題,只需在 web.xml 中新增 Spring MVC 自帶的過濾器即可。

<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>

JSP 頁面的轉發與重定向

Spring MVC 預設是以轉發的形式響應 jsp頁面。

  1. 轉發
@RequestMapping("/forward")
public String forward() {
    return "forward:/index.jsp";
    //return "index";
}

  1. 重定向
@RequestMapping("/redirect")
public String redirect() {
    return "redirect:/index.jsp";
}

總結

另外我這裡為大家準備了一線大廠面試資料和我原創的超硬核PDF技術文件,以及我為大家精心準備的多套大廠面試題(不斷更新中),歡迎關注公眾號:前程有光領取!希望大家都能找到心儀的工作!

相關文章