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伺服器,啟動,執行,成功。
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";
}
}
- @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。
關於引數繫結,在形參列表中通過新增 @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頁面。
- 轉發
@RequestMapping("/forward")
public String forward() {
return "forward:/index.jsp";
//return "index";
}
- 重定向
@RequestMapping("/redirect")
public String redirect() {
return "redirect:/index.jsp";
}
總結
另外我這裡為大家準備了一線大廠面試資料和我原創的超硬核PDF技術文件,以及我為大家精心準備的多套大廠面試題(不斷更新中),歡迎關注公眾號:前程有光領取!希望大家都能找到心儀的工作!