MVC模式
MVC指的是模型(model)-視圖(view)-控制器(controller)模型,是一種用于設(shè)計創(chuàng)建Web應(yīng)用程序表現(xiàn)層的模式。可以將業(yè)務(wù)邏輯、數(shù)據(jù)、界面顯示代碼分離開來。

-
三層架構(gòu)-mvc
image.png
SpringMVC
SpringMVC是Spring產(chǎn)品對MVC模式的一種具體實現(xiàn),屬于輕量級的WEB框架,可以通過一套注解,讓一個簡單的Java類稱為控制器。而無須實現(xiàn)任何接口,同時還支持restful風(fēng)格

SpringMVC主要工作的組件有:
- 前端控制器
- 處理器映射器
- 處理器適配器
SpringMVC入門案例
- 加入坐標(biāo)
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
- SpringMVC配置文件 spring-mvc.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.itheima.controller"/>
<!-- 配置組件-->
<!-- 配置處理器映射器和處理器適配器-->
<mvc:annotation-driven/>
<!-- 配置視圖解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean>
</beans>
- web.xml
<?xml version="1.0" encoding="utf-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置參數(shù)-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!-- 除了jsp不攔截-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 后端controller
@Controller
public class HelloController {
@RequestMapping("/helloServlet/demo1")
public String demo1() {
System.out.println("hello1");
return "/success.jsp";
}
}
- 請求頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/helloServlet/demo1">入門案例</a>
</body>
</html>
- 響應(yīng)頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
Success
</body>
</html>
SpringMVC原理

- 當(dāng)用戶通過瀏覽器發(fā)送一個請求會被前端控制器DispatcherServlet接收
- DispathcerServlet接收請求后會調(diào)用處理器映射器HandlerMapper
- HandlerMapper會找到具體的處理器鏈返回給DispatcherServlet
- DispatcherServlet會根據(jù)收到返回的處理器鏈調(diào)用處理器適配器HandlerAdapter
- HandlerAdapter經(jīng)過適配后會調(diào)用具體的Controller
- Controller執(zhí)行完成后會返回一個執(zhí)行結(jié)果
- HandlerAdapter將Handler的結(jié)果ModelAndView對象返還給DispatcherServlet
- DispatcherServlet將ModelAndView對象傳給視圖解析器ViewReslover
- ViewReslover解析后得到具體的View,并返回給DispatcherServlet
- DispatcherServlet根據(jù)ViewReslover返回的View進(jìn)行視圖渲染。將模型數(shù)據(jù)填充到視圖中
- DispathcerServlet會將渲染后的視圖響應(yīng)給瀏覽器
SpringMVC三大組件
- 處理器映射器 HandlerMapper
根據(jù)請求中的URL尋找對應(yīng)的處理方法
- 處理器適配器
真正的去調(diào)用處理方法
- 視圖解析器
將邏輯視圖轉(zhuǎn)化成物理視圖
配置視圖解析器
<!-- 配置視圖解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置前綴-->
<property name="prefix" value="/"/>
<!-- 配置后綴-->
<property name="suffix" value=".jsp"/>
</bean>
RequestMapping
RequestMapping用于建立請求URL和處理方法之間的對應(yīng)關(guān)系,可以通過它的屬性對請求做出各種限制
- value:用于限制請求URL(和path作用一樣),可以傳遞多個url @RequestMapping(value={url1,url2})
- method:用于限制請求類型 get post 支持多個,如果不寫表示不做限制
- Params:用于限制請求參數(shù)的條件 用于限制必傳參數(shù),支持?jǐn)?shù)組
@RequestMapping("/helloServlet/demo1")
public String demo1() {
System.out.println("hello1");
return "success";
}
此注解可以標(biāo)注在方法上,也可以標(biāo)注在類上,標(biāo)注在類上代表類中的所有方法都可以共用一段URL
限制請求路徑(value path)
- 前臺頁面
<a href="${pageContext.request.contextPath}/helloServlet/demo2">指定請求路徑</a>
- 后臺
@RequestMapping("/helloServlet/demo2")
public String demo2() {
System.out.println("指定請求路徑為:/helloServlet/demo2");
return "success";
}
限制請求類型(method)
限制只能是post方式請求,如果不是指定的請求方式 將會拋出405異常
- 頁面
<form action="helloServlet/demo3" method="post">
<input type="submit" value="限制請求方式">
</form>
- 后臺
@RequestMapping(value = "/helloServlet/demo3",method = RequestMethod.POST)
public String demo3() {
System.out.println("限制請求類型");
return "success";
}
限制請求參數(shù)(params)
- 頁面
<a href="${pageContext.request.contextPath}/helloServlet/demo4?name=zs">指定請求的參數(shù)</a>
- 后臺
表示必須傳遞name參數(shù)
@RequestMapping(value = "/helloServlet/demo4", params = "name")
public String demo4() {
return "success";
}
接收請求參數(shù)
在SpringMVC中可以使用多種類型來接收前端傳入的參數(shù)
簡單類型
基本類型、基本類型的包裝類、字符串類型
只需要保證前端傳遞的參數(shù)名稱跟方法的形參名稱一致就好
- 頁面
<a href="${pageContext.request.contextPath}/helloServlet/demo5?name=zs&age=18">接收簡單類型參數(shù)</a>
- 后臺
@RequestMapping(value = "/helloServlet/demo5")
public String demo5(String name, Integer age) {
System.out.println("name = " + name);
System.out.println("age = " + age);
return "success";
}
對象類型
只要保證前端傳遞的參數(shù)名稱和pojo的屬性名稱(set方法)一致
- 前臺
<a href="${pageContext.request.contextPath}/helloServlet/demo6?name=ss&age=20">接收對象類型</a>
- 后臺
@RequestMapping("/helloServlet/demo6")
public String demo6(User user) {
System.out.println("user = " + user);
return "success";
}
數(shù)組類型
需要保證前端傳遞的參數(shù)名稱和方法中的數(shù)組形參名稱一致
- 頁面
<a href="${pageContext.request.contextPath}/helloServlet/demo7?username=zz&username=zz2&username=zz3">傳遞數(shù)組類型</a>
- 后臺
@RequestMapping("/helloServlet/demo7")
public String demo7(String[] username) {
for (String s : username) {
System.out.println(s);
}
return "success";
}
集合類型
獲取集合類型的參數(shù)時,需要提供一個pojo對象,SpringMVC會將集合包裝到pojo對象中
- 頁面
<form action="${pageContext.request.contextPath}/helloServlet/demo8" method="post">
第一個user.name <input type="text" name="users[0].name"/><br/>
第一個user.age <input type="text" name="users[0].age"/><br/>
第二個user.name <input type="text" name="users[1].name"/><br/>
第二個user.age <input type="text" name="users[1].age"/><br/>
第三個user.name <input type="text" name="users[2].name"/><br/>
第三個user.age <input type="text" name="users[2].age"/><br/>
<input type="submit" value="傳遞集合"/>
</form>
- 封裝vo對象
public class Vo {
private List<User> users;
private Map<String, String> map;
@Override
public String toString() {
return "Vo{" +
"users=" + users +
", map=" + map +
'}';
}
public void setUsers(List<User> users) {
this.users = users;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
}
- 后臺controller
@RequestMapping("/helloServlet/demo8")
public String demo8(Vo vo) {
List<User> users = vo.getUsers();
users.stream().forEach(user -> System.out.println(user));
return "success";
}
日期類型
對于一些常見的類型,SpringMVC是內(nèi)置了類型轉(zhuǎn)換器,也就是說在內(nèi)置中存在一個類型轉(zhuǎn)換器,可以自動轉(zhuǎn)換基本類型,但是對于一些類型的參數(shù),無法完成類型轉(zhuǎn)換。這時候就必須自定義類型轉(zhuǎn)換器了
- 頁面
-
自定義時間類型轉(zhuǎn)換器
自定義類型轉(zhuǎn)換器需要實現(xiàn)Converter<S,D>接口
- S:代表需要轉(zhuǎn)換的源Source類型
- D:代表轉(zhuǎn)換后的目標(biāo)類型
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String s) {
return new SimpleDateFormat("yyyy-MM-dd").parse(s);
}
}
- 配置類型轉(zhuǎn)換器 spring-mvc.xml
將自定義的類型轉(zhuǎn)換器注冊SpringMVC的轉(zhuǎn)換服務(wù),并且將服務(wù)注冊到注解驅(qū)動上
<mvc:annotation-driven conversion-service="conversionService2"/>
<!-- 配置視圖解析器-->
<!-- 配置自定義類型轉(zhuǎn)換器-->
<bean id="conversionService2" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<!-- 指定自定義類型轉(zhuǎn)換器-->
<bean class="com.itheima.converters.DateConverter"/>
</set>
</property>
</bean>
- 后臺
@RequestMapping("/helloServlet/demo9")
public String demo9(Date date) {
System.out.println(date);
return "success";
}
文件類型(文件上傳)
- 配置文件上傳用的坐標(biāo)
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
-
配置文件上傳解析器
<!-- 配置文件解析器--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="5242880"/> </bean> -
頁面
- post提交
- 多部分表單 part-form
- type=file
<%--文件上傳--%>
<form action="${pageContext.request.contextPath}/helloServlet/demo10" method="post"
enctype="multipart/form-data"
>
<input type="file" name="upFile"/><br/>
<input type="submit" value="上傳">
</form>
- 后臺
@RequestMapping("/helloServlet/demo10")
public String demo10(MultipartFile upFile) throws IOException {
//獲取名字 重新命名
String newFileName = UUID.randomUUID() + upFile.getOriginalFilename();
String saveFilePath = "/Users/wangxin/Documents/temp";
File uploadFile = new File(saveFilePath, newFileName);
//接收上傳文件
upFile.transferTo(uploadFile);
return "success";
}
多文件上傳
- 頁面
多文件上傳 需要在<input type="file">標(biāo)簽中添加multiple屬性
多文件上傳:
<form method="post" action="${pageContext.request.contextPath}/helloServlet/demo11" enctype="multipart/form-data">
<input type="file" multiple/>
<input type="submit" value="提交">
</form>
- 后臺 多文件上傳 后臺需要接收MultiPartFile數(shù)組
@RequestMapping("helloServlet/demo11")
public String demo11(MultipartFile[] upFiles) throws IOException {
String saveFilePath = "/Users/wangxin/Documents/temp";
for (MultipartFile file : upFiles) {
String newFileName = UUID.randomUUID() + file.getOriginalFilename();
File uploadFile = new File(saveFilePath, newFileName);
//文件上傳
file.transferTo(uploadFile);
}
System.out.println("文件上傳完畢");
return "success";
}
文件上傳原理
在前端控制器(DispatcherServlet)有一個屬性叫做multipartResolver,它對應(yīng)著一個文件上傳解析器
當(dāng)SpringMVC啟動的時候,它就會在容器中尋找是否有一個id位multipartResolver的bean,如果有那么會將文件上傳的文件交給指定的文件解析器來做。
當(dāng)DispathcerServlet調(diào)用controller方法的時候就可以將MultipartFile作為參數(shù)傳進(jìn)去了
在Controller中就可以操作MultiPartFIle對象進(jìn)行文件的操作
接收參數(shù)的處理
中文亂碼
SpringMVC在使用POST提交請求時,對于中文參數(shù)會存在亂碼問題,我們可以使用SpringMVC提供的中文亂碼過濾器
- 前端
通過form表單的post請求提交中文
<%--提交中文亂碼--%>
<br/>
<form action="${pageContext.request.contextPath}/helloServlet/demo12" method="post">
姓名:<input type="text" name="username"/>
</form>
- 配置 編碼過濾器
<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>
后臺
@RequestMapping("/helloServlet/demo12") public String demo12(String username) { System.out.println("接收到的參數(shù):" + username); return "success"; }
@RequestParam
@RequestParam標(biāo)注在方法參數(shù)之前,用于對傳入的參數(shù)做一些限制,支持三個屬性:
- Value:用于指定前端傳入的參數(shù)名稱
- required:用于指定此參數(shù)是否必傳,默認(rèn)是true
- defaultValue:當(dāng)參數(shù)為非必傳參數(shù)設(shè)置一個默認(rèn)值
- 前臺
<a href="${pageContext.request.contextPath}/helloServlet/demo13?username=達(dá)到">前端參數(shù)對應(yīng)</a>
- 后臺
@RequestMapping("/helloServlet/demo13")
public String demo13(@RequestParam("username") String name) {
System.out.println(name);
return "success";
}
接收請求頭信息
接收請求頭,使用
- @RequestHeader 前端控制器會將所有的請求頭封裝成一個Map結(jié)構(gòu)傳遞過來
- @RequestHeader("key") 接收指定的請求頭
- @CookieValue("key") 接收一個Cookie中的值
@RequestMapping("/helloServlet/demo14")
public String demo14(
@RequestHeader Map<String, String> headMap,
@RequestHeader("cookie") String cookieKey,
@CookieValue("JSESSIONID") String jSessionId
) {
System.out.println(headMap);
System.out.println(cookieKey);
System.out.println(jSessionId);
return "success";
}
