SpringMVC基本概念和入門案例
SpringMVC的基本概念
關於三層架構和MVC
三層架構
我們的開發架構一般都是基於兩種形式,一種是 C/S 架構,也就是客戶端/伺服器,另一種是 B/S 架構,也就是瀏覽器伺服器。在 JavaEE 開發中,幾乎全都是基於 B/S 架構的開發。
那麼在 B/S 架構中,系統標準的三層架構包括:表現層、業務層、持久層。三層架構在我們的實際開發中使用的非常多,所以我們課程中的案例也都是基於三層架構設計的。
三層架構中,每一層各司其職,接下來我們就說說每層都負責哪些方面:
- 表現層:
也就是我們常說的 web 層。它負責接收客戶端請求,向客戶端響應結果,通常客戶端使用http協議請求web層,web 需要接收 http 請求,完成 http 響應。表現層包括展示層和控制層:控制層負責接收請求,展示層負責結果的展示。表現層依賴業務層,接收到客戶端請求一般會呼叫業務層進行業務處理,並將處理結果響應給客戶端。表現層的設計一般都使用 MVC 模型。(MVC 是表現層的設計模型,和其他層沒有關係)。
- 業務層:
也就是我們常說的 service 層。它負責業務邏輯處理,和我們開發專案的需求息息相關。web 層依賴業務層,但是業務層不依賴 web 層。業務層在業務處理時可能會依賴持久層,如果要對資料持久化需要保證事務一致性。(也就是我們說的,事務應該放到業務層來控制)。
- 持久層:
也就是我們是常說的 dao 層。負責資料持久化,包括資料層即資料庫和資料訪問層,資料庫是對資料進行持久化的載體,資料訪問層是業務層和持久層互動的介面,業務層需要通過資料訪問層將資料持久化到資料庫中。通俗的講,持久層就是和資料庫互動,對資料庫表進行曾刪改查的。
MVC模型
MVC全名是 Model View Controller,是模型(model)-檢視(view)-控制器(controller)的縮寫,是一種用於設計建立 Web 應用程式表現層的模式。MVC 中每個部分各司其職:
Model(模型):通常指的就是我們的資料模型。作用一般情況下用於封裝資料。
View(檢視):通常指的就是我們的 jsp 或者 html。作用一般就是展示資料的。通常檢視是依據模型資料建立的。
Controller(控制器):是應用程式中處理使用者互動的部分,作用一般就是處理程式邏輯的。
SpringMVC概述
SpringMVC是什麼
SpringMVC 是一個基於 Java 的實現 MVC 設計模型的請求驅動型別的輕量級 Web 框架,屬於SpringFrameWork 的後續產品,已經融合在 Spring Web Flow 裡面,已經成為目前最主流的 MVC 框架之一。
SpringMVC 框架可以通過一套註解,讓一個簡單的 Java 類成為處理請求的控制器,而無須實現任何介面。同時它還支援 RESTful 程式設計風格的請求。
SpringMVC的優勢
(1)清晰的角色劃分:
- 前端控制器(DispatcherServlet)
- 請求到處理器對映(HandlerMapping)
- 處理器介面卡(HandlerAdapter)
- 檢視解析器(ViewResolver)
- 處理器或頁面控制器(Controller)
- 驗證器( Validator)
- 命令物件(Command 請求引數繫結到的物件就叫命令物件)
- 表單物件(Form Object 提供給表單展示和提交到的物件就叫表單物件)。
(2)分工明確,而且擴充套件點相當靈活,可以很容易擴充套件,雖然幾乎不需要。
(3)由於命令物件就是一個 POJO,無需繼承框架特定 API,可以使用命令物件直接作為業務物件。
(4)和 Spring 其他框架無縫整合,是其它 Web 框架所不具備的。
(5)可適配,通過 HandlerAdapter 可以支援任意的類作為處理器。
(6)可定製性,HandlerMapping、ViewResolver 等能夠非常簡單的定製。
(7)功能強大的資料驗證、格式化、繫結機制。
(8)RESTful風格的支援、簡單的檔案上傳、約定大於配置的契約式程式設計支援、基於註解的零配
置支援等等。
SpringMVC的入門
環境搭建
新建 maven web 專案,引入相關的依賴
<modelVersion>4.0.0</modelVersion>
<artifactId>SpringMVC_Learn</artifactId>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.1</version>
</dependency>
<!-- 日誌 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- ServletAPI -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- Spring5和Thymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
</dependencies>
入門案例
(1)配置核心的控制器(配置DispatcherServlet),在 webapp/WEB-INF 下的 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>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置SpringMVC配置檔案的位置和名稱 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 將前端控制器DispatcherServlet的初始化時間提前到伺服器啟動時 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
(2)resources 目錄下新建 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"
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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 開啟註解掃描 -->
<context:component-scan base-package="com.lalala.controller"></context:component-scan>
<!-- 配置Thymeleaf檢視解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!-- 檢視字首 -->
<property name="prefix" value="/WEB-INF/templates/"/>
<!-- 檢視字尾 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
</property>
</bean>
</property>
</bean>
<!--
處理靜態資源,例如html、js、css、jpg
若只設置該標籤,則只能訪問靜態資源,其他請求則無法訪問
此時必須設定<mvc:annotation-driven/>解決問題
-->
<mvc:default-servlet-handler/>
<!-- 開啟mvc註解驅動 -->
<mvc:annotation-driven>
<mvc:message-converters>
<!-- 處理響應中文內容亂碼 -->
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="defaultCharset" value="UTF-8"/>
<property name="supportedMediaTypes">
<list>
<value>text/html</value>
<value>application/json</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
</beans>
(3)webapp/WEB-INF/templates 下的 index.html 如下
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首頁</title>
</head>
<body>
<h1>首頁</h1>
</body>
</html>
(4)建立請求控制器,控制器由不同的JAVA類擔任,請求控制器中每一個處理請求的方法稱為控制器方法。在 controller 包下新建 HelloController
package com.lalala.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
//控制器類
@Controller
public class HelloController {
@RequestMapping("/")
public String index() {
System.out.println("Hello SpringMVC");
//返回檢視名稱
return "index";
}
}
(5)設定tomcat
(6)啟動tomcat
入門案例的執行過程分析
入門案例的執行流程:
- 當啟動Tomcat伺服器的時候,因為配置了load-on-startup標籤,所以會建立DispatcherServlet物件,
就會載入springmvc.xml配置檔案。 - 開啟了註解掃描,那麼HelloController物件就會被建立。
- 傳送請求,請求會先到達DispatcherServlet核心控制器,根據配置@RequestMapping註解,找到執行的具體方法。
- 根據執行方法的返回值,再根據配置的檢視解析器,去指定的目錄下查詢指定名稱的html檔案。
- Tomcat伺服器渲染頁面,做出響應。
springmvc執行流程原理
RequestMapping註解
使用說明
原始碼:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
}
作用:用於建立請求 URL 和處理請求方法之間的對應關係。
出現位置
-
@RequestMapping標識在類上:
設定請求 URL 的第一級訪問目錄,對映請求路徑的初始資訊。此處不寫的話,就相當於應用的根目錄。寫的話需要以 / 開頭。它出現的目的是為了使我們的 URL 可以按照模組化管理。
例如:
賬戶模組
/account/add
/account/update
/account/delete
...
訂單模組
/order/add
/order/update
/order/delete
可以把 account 和 order 寫在類上使我們的 URL 更加精細。
- @RequestMapping標識在方法上:設定請求 URL 的第二級訪問目錄,對映請求路徑的具體資訊。
屬性:
- value:用於指定請求的 URL。可以是一個字串型別的陣列,表示該請求對映能夠匹配多個請求地址所對應的請求,它和 path 屬性的作用是一樣的。
- method:用於指定請求的方式。可以是一個RequestMethod型別的陣列,表示能夠匹配多種請求方式,當請求方式不滿足要求時就會報錯。
- params:用於指定限制請求引數的條件,它支援簡單的表示式。要求請求引數的key和value必須和配置的一模一樣。
例如:
params = {"accountName"},表示請求引數必須有 accountName
params = {"moeny!100"},表示請求引數中 money 不能是 100
- headers:用於指定限制請求訊息頭的條件。
使用示例
出現位置示例
新建控制器:在類上新增 @RequestMapping
註解
package com.lalala.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
//控制器類
@Controller
@RequestMapping("/hello")
public class HelloController {
@RequestMapping("/testRequestMapping")
public String testRequestMapping(){
System.out.println("測試requestMapping註解...");
return "success";
}
}
index.html中的程式碼:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首頁</title>
</head>
<body>
<h1>首頁</h1>
<a th:href="@{/hello/testRequestMapping}">測試requestMapping註解</a>
</body>
</html>
success.html頁面內容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
success
</body>
</html>
value屬性的示例
新建控制器類:
package com.lalala.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
//控制器類
@Controller
public class HelloController {
@RequestMapping(value = {"/testRequestMapping", "/test"})
public String testRequestMapping() {
return "success";
}
}
index.html中的程式碼如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首頁</title>
</head>
<body>
<h1>首頁</h1>
<a th:href="@{/testRequestMapping}">測試RequestMapping的value屬性 /testRequestMapping</a><br/>
<a th:href="@{/test}">測試RequestMapping的value屬性 test</a>
</body>
</html>
可以發現通過/testRequestMapping
和/test
都能夠跳轉到我們的success.html頁面
method屬性的示例
控制器程式碼
package com.lalala.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
//控制器類
@Controller
public class HelloController {
//指定請求方式為GET請求
@RequestMapping(value = "/test", method = RequestMethod.GET)
public String testRequestMapping() {
return "success";
}
}
index.html如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首頁</title>
</head>
<body>
<h1>首頁</h1>
<!-- 使用post請求-->
<form th:action="@{/test}" method="post">
<input type="submit">
</form>
</body>
</html>
我們在控制器中設定了method = RequestMethod.POST
,當使用GET方式的請求就會報HTTP Status 405 – Method Not Allowed
的錯誤。
可以設定接收多種型別的請求方式:
@RequestMapping(value = "/test", method = {RequestMethod.GET, RequestMethod.POST})
params屬性的示例
控制器中的程式碼
package com.lalala.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
//控制器類
@Controller
public class HelloController {
@RequestMapping(value = "/testParams", params = {"username"})
public String testParams() {
return "success";
}
}
index.html中如下
<a th:href="@{/testParams?username=admin}">測試RequestMapping註解的params屬性</a>
headers屬性的示例
控制器中的程式碼
package com.lalala.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
//控制器類
@Controller
public class HelloController {
@RequestMapping(
value = "/testParamsAndHeaders",
params = {"username", "password!=123456"},
headers = {"Host=localhost:8000"})
public String testParamsAndHeaders() {
return "success";
}
}
index.html如下
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首頁</title>
</head>
<body>
<h1>首頁</h1>
<a th:href="@{/testParamsAndHeaders?username=admin,password=123}">測試RequestMapping註解的headers屬性</a>
</body>
</html>
由於不滿足headers屬性,所以此時頁面顯示404錯誤。
RequestMapping註解的派生註解
對於處理請求方式的控制器方法,SpringMVC提供了@RequestMapping的派生註解。
- 處理get請求的對映:@GetMapping,即相當於@RequestMapping(method = RequestMethod.GET)的縮寫。
- 處理post請求的對映:@PostMapping
- 處理put請求的對映:@PutMapping
- 處理delete請求的對映:@DeleteMapping
- 處理Patch請求的對映:@PatchMapping
@GetMapping(value = "/testGetMapping")
public String testGetMapping() {
return "success";
}
入門案例中涉及的元件
DispatcherServlet:前端控制器
對有使用者的請求和響應進行統一的處理,使用者請求到達前端控制器,它就相當於 MVC 模式中的 C,DispatcherServlet 是整個流程控制的中心,由它呼叫其它元件處理使用者的請求,dispatcherServlet 的存在降低了元件之間的耦合性。
HandlerMapping:處理器對映器
HandlerMapping 負責根據使用者請求找到 Handler 即處理器,SpringMVC 提供了不同的對映器實現不同的對映方式,例如:配置檔案方式,實現介面方式,註解方式等。
Handler:處理器
它就是我們開發中要編寫的具體業務控制器。由 DispatcherServlet 把使用者請求轉發到 Handler。由 Handler 對具體的使用者請求進行處理。
HandlAdapter:處理器介面卡
通過 HandlerAdapter 對處理器進行執行,這是介面卡模式的應用,通過擴充套件介面卡可以對更多型別的處理器進行執行。
View Resolver:檢視解析器
View Resolver 負責將處理結果生成 View 檢視,View Resolver 首先根據邏輯檢視名解析成物理檢視名即具體的頁面地址,再生成 View 檢視物件,最後對 View 進行渲染將處理結果通過頁面展示給使用者。
View:檢視
SpringMVC 框架提供了很多的 View 檢視型別的支援,包括:jstlView、freemarkerView、pdfView等。我們最常用的檢視就是 jsp。
一般情況下需要通過頁面標籤或頁面模版技術將模型資料通過頁面展示給使用者,需要由程式設計師根據業務需求開發具體的頁面。
mvc:annotation-driven標籤的作用
在 SpringMVC 的各個元件中,處理器對映器、處理器介面卡、檢視解析器稱為 SpringMVC 的三大元件。
使用<mvc:annotation-driven>
自動載入 RequestMappingHandlerMapping(處理對映器)和
RequestMappingHandlerAdapter(處理介面卡), 可用在springmvc.xml配置檔案中使用
<mvc:annotation-driven>
替代註解處理器和介面卡的配置。它就相當於在 xml 中配置了:
<!-- 上面的標籤相當於如下配置 -->
<!-- HandlerMapping -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerM
apping"></bean>
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- HandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerA
dapter"></bean>
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!-- HadnlerExceptionResolvers -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExcept
ionResolver"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"></bean>
<bean class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver"></bean>
注意:
- 一般開發中,我們都需要寫上此標籤(雖然從入門案例中看,我們不寫也行,但該標籤還有具體的使用場景)。
明確:
- 我們只需要編寫處理具體業務的控制器以及檢視。