我 | 在这里
🕵️ 读书 | 长沙 ⭐软件工程 ⭐ 本科
🏠 工作 | 广州 ⭐ Java 全栈开发(软件工程师)
🎃 爱好 | 研究技术、旅游、阅读、运动、喜欢流行歌曲
✈️已经旅游的地点 | 新疆-乌鲁木齐、新疆-吐鲁番、广东-广州、广东-佛山、湖南-长沙、湖南-张家界、山西、上海、郑州等。老家河南嘞
🏷️ 标签 | 男 自律狂人 目标明确 责任心强
✈️公众号 | 热爱技术的小郑 。文章底部有个人公众号二维码。回复 Java全套视频教程 或 前端全套视频教程 即可获取 300G+ 教程资料及项目实战案例
🚀 邮箱 | 2977429967@qq.com
✈️ GitHub传送门 开源项目 + 实战Demo
为何而写?
🍍 好记性不如烂笔头,记录学习的相关知识 、项目 BUG 解决
🍇 复盘总结,加深记忆,方便自己查看
🍑 分享知识,咱就是这么乐于助人、专注填坑20年、哈哈哈哈
目标描述
🏆 没有伞的孩子、只能用力奔跑。向着架构师的方向努力、做一个有始有终的人。
案例代码:Github 传送门
可参考相关源码
1、SpringMVC简介
1.1、什么是MVC
MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分
M:Model,模型层,指工程中的JavaBean,作用是处理数据
JavaBean分为两类:
● 一类称为实体类Bean:专门存储业务数据的,如 Student、User 等
● 一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。
V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据
C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器。
MVC的工作流程: 用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller,调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器
1.2、什么是SpringMVC
SpringMVC是Spring的一个后续产品,是Spring的一个子项目
SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 Strust、WebWork、Strust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 Java EE 项目表述层开发的首选方案。
注:三层架构分为表述层(或表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台servlet
1.3、SpringMVC的特点
● 1、Spring 家族原生产品,与 IOC 容器等基础设施无缝对接
● 2、基于原生的Servlet,通过了功能强大的前端控制器DispatcherServlet,对请求和响应进行统一处理
● 3、表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案
● 4、代码清新简洁,大幅度提升开发效率
● 5、内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
● 6、性能卓著,尤其适合现代大型、超大型互联网项目要求
2、SpringMVC创建实例Hello SpringMVC(maven+tomcat)
2.1、开发环境
● IDE:idea 2020
● 构建工具:maven3.3.9
● 服务器:tomcat 8
● Spring版本:5.3.1
2.2、创建maven工程(加入pom依赖)
如何在idea中集成maven、之前写过。这里不在赘述
2022最新版超详细的Maven下载配置教程、IDEA中集成maven(包含图解过程)、以及导入项目时jar包下载不成功的问题解决
● 添加web模块
● 打包方式:war
● 引入依赖
<dependencies>
<!-- SpringMVC -->
<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>compile</scope>
</dependency>
<!-- Spring5和Thymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
</dependencies>
注:由于 Maven 的传递性,我们不必将所有需要的包全部配置依赖,而是配置最顶端的依赖,其他靠传递性导入。
2.3、配置web.xml
2.3.1 生成web.xml
过程:创建webapp包、然后点击项目结构、找到对应的模块、添加web.xml。(对应的web.xml路径要写对)。然后自动在项目中完成创建
注册SpringMVC的前端控制器DispatcherServlet
2.3.2 默认配置方式
此配置作用下,SpringMVC的配置文件默认位于WEB-INF下,默认名称为-servlet.xml,例如,以下配置所对应SpringMVC的配置文件位于WEB-INF下,文件名为springMVC-servlet.xml
springMVC org.springframework.web.servlet.DispatcherServlet springMVC /2.3.3 扩展配置方式
可通过init-param标签设置SpringMVC配置文件的位置和名称,通过load-on-startup标签设置SpringMVC前端控制器DispatcherServlet的初始化时间
注意:这个是WEB-INF下的web.xml
<!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 -->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 通过初始化参数指定SpringMVC配置文件的位置和名称 -->
<init-param>
<!-- contextConfigLocation为固定值 -->
<param-name>contextConfigLocation</param-name>
<!-- 使用classpath:表示从类路径查找配置文件,例如maven工程中的
src/main/resources -->
<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>
<!--
设置springMVC的核心控制器所能处理的请求的请求路径
/所匹配的请求可以是/login或.html或.js或.css方式的请求路径
但是/不能匹配.jsp请求路径的请求
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
提示、默认扩展,就是将外部的MVC文件引入,所以需要创建外部的xml文件
通过以下方式进行创建xml文件
注:标签中使用/和/*的区别:
/所匹配的请求可以是/login或.html或.js或.css方式的请求路径,但是/不能匹配.jsp请求路径的请求,因此就可以避免在访问jsp页面时,该请求被DispatcherServlet处理,从而找不到相应的页面
/则能够匹配所有请求,例如在使用过滤器时,若需要对所有请求进行过滤,就需要使用/的写 法
2.4、创建请求控制器
由于前端控制器对浏览器发送的请求进行了统一的处理,但是具体的请求有不同的处理过程,因此需要创建处理具体请求的类,即请求控制器
请求控制器中每一个处理请求的方法成为控制器方法
因为SpringMVC的控制器由一个POJO(普通的Java类)担任,因此需要通过@Controller注解将其标识
为一个控制层组件,交给Spring的IoC容器管理,此时SpringMVC才能够识别控制器的存在
/**
* @author Lenovo
* @version 1.0
* @data 2022/10/30 16:41
*/
@Controller
public class HelloSpringMVC {
}
2.5、创建springMVC的配置文件
<?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">
<!--扫描组件-->
<context:component-scan base-package="com.zyz.mvc.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>
</beans>
2.6、配置tomcat
具体过程,请参考:2022年最新最详细在IDEA中配置Tomcat(含有详细图解过程)、建立使用IEDA建立一个Web项目的案例
2.7、测试HelloSpringMVC
2.7.1 HelloSpringMVC.java
/**
* @author Lenovo
* @version 1.0
* @data 2022/10/30 16:41
*/
@Controller
public class HelloSpringMVC {
/**
* @RequestMapping注解:处理请求和控制器方法之间的映射关系
* @RequestMapping注解的value属性可以通过请求地址匹配请求,/表示的当前工程的上下文路径
* localhost:8080/springMVC/
*/
@RequestMapping(value = "/")
public String index(){
//返回视图名称
return "index";
}
}
2.7.2 index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>HELLO SpringMVC</h1>
<a th:href="@{/target}">访问目标页面target.html</a>
</body>
</html>
2.7.3 测试结果
2.8、过超链接跳转到指定页面
2.8.1 index.html
同7.2 index.html
注意:要首先引入http://www.thymeleaf.org
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>HELLO SpringMVC</h1>
<a th:href="@{/target}">访问目标页面target.html</a>
</body>
</html>
2.8.2 target.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>目标页面</title>
</head>
<body>
<p style="font-size: 48px;color: red">这里是TARGET页面</p>
</body>
</html>
2.8.3 控制类
/**
* @author Lenovo
* @version 1.0
* @data 2022/10/30 16:41
*/
@Controller
public class HelloSpringMVC {
@RequestMapping(value = "/target")
public String toTarget(){
//返回目标页面
return "target";
}
}
2.8.4 测试结果
2.9、项目结构
2.9.1 HelloSpringMVC.java
package com.zyz.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author Lenovo
* @version 1.0
* @data 2022/10/30 16:41
*/
@Controller
public class HelloSpringMVC {
/**
* @RequestMapping注解:处理请求和控制器方法之间的映射关系
* @RequestMapping注解的value属性可以通过请求地址匹配请求,/表示的当前工程的上下文路径
* localhost:8080/springMVC/
*/
@RequestMapping(value = "/")
public String index(){
//返回视图名称
return "index";
}
@RequestMapping(value = "/target")
public String toTarget(){
//返回目标页面
return "target";
}
}
2.9.2 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">
<!--扫描组件-->
<context:component-scan base-package="com.zyz.mvc.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>
</beans>
2.9.3 index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>HELLO SpringMVC</h1>
<a th:href="@{/target}">访问目标页面target.html</a>
</body>
</html>
2.9.4 target.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>目标页面</title>
</head>
<body>
<p style="font-size: 48px;color: red">这里是TARGET页面</p>
</body>
</html>
2.9.5 web.xml
<?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">
<!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 -->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 通过初始化参数指定SpringMVC配置文件的位置和名称 -->
<init-param>
<!-- contextConfigLocation为固定值 -->
<param-name>contextConfigLocation</param-name>
<!-- 使用classpath:表示从类路径查找配置文件,例如maven工程中的
src/main/resources -->
<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>
<!--
设置springMVC的核心控制器所能处理的请求的请求路径
/所匹配的请求可以是/login或.html或.js或.css方式的请求路径
但是/不能匹配.jsp请求路径的请求
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2.10 、如何让创建的模板包含xmlns:th=“http://www.thymeleaf.org”
3、@RequestMapping注解
3.1、@RequestMapping注解的功能
从注解名称上我们可以看到,@RequestMapping注解的作用就是将请求和处理请求的控制器方法关联起来,建立映射关系。
SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的控制器方法来处理这个请求。
3.2、@RequestMapping注解的位置
● @RequestMapping标识一个类:设置映射请求的请求路径的初始信息
● @RequestMapping标识一个方法:设置映射请求请求路径的具体信息
3.2.1 作用在类上实例
比如A类和B类中都有一个list。为了区分是:在类上加上注解、那么访问的地址就变成/A/list。/B/list。很实用的一个功能
@Controller
@RequestMapping("/hello")
public class TestController {
/**
* 此时请求的路径是/hello/test
* @return
*/
@RequestMapping("/test")
public String success(){
return "success";
}
}
访问方式
<a th:href="@{/hello/test}">访问目标页面target.html</a>
测试结果
3.2.2 仅作用在方法上
直接通过方法上的路径就可以访问到,
@Controller
public class TestController {
/**
* 此时请求的路径是test
* @return
*/
@RequestMapping("/test")
public String success(){
return "success";
}
}
访问方式
<a th:href="@{/test}">访问目标页面target.html</a>
测试结果
3.3、@RequestMapping注解的value属性
● @RequestMapping注解的value属性通过请求的请求地址匹配请求映射
● @RequestMapping注解的value属性是一个字符串类型的数组,表示该请求映射能够匹配多个请求地址所对应的请求
● @RequestMapping注解的value属性必须设置,至少通过请求地址匹配请求映射
注:value一般写一个匹配路径就行
3.3.1 测试
@Controller
public class TestController {
@RequestMapping(value = {"/test","/myTest"})
public String success(){
return "success";
}
}
<a th:href="@{/test}">访问目标页面target.html</a>
<a th:href="@{/myTest}">访问目标页面target.html</a>
3.4、@RequestMapping注解的method属性
● @RequestMapping注解的method属性通过请求的请求方式(get或post)匹配请求映射
● @RequestMapping注解的method属性是一个RequestMethod类型的数组,表示该请求映射能够匹配多种请求方式的请求
● 若当前请求的请求地址满足请求映射的value属性,但是请求方式不满足method属性,则浏览器报错405:Request method ‘POST’ not supported
注:restful风格经常使用method和value联合使用
3.4.1、同时满足value和method
<form th:action="@{/test}" method="post">
<input type="submit">
</form>
@Controller
public class TestController {
@RequestMapping(
value = {"/test", "/myTest"},
method = {RequestMethod.GET, RequestMethod.POST}
)
public String success() {
return "success";
}
}
3.4.2 满足value、不满足method的情况
<form th:action="@{/test}" method="post">
<input type="submit">
</form>
@Controller
public class TestController {
@RequestMapping(value = {"/test","/myTest"},method = RequestMethod.GET)
public String success(){
return "success";
}
}
1、对于处理指定请求方式的控制器方法,SpringMVC中提供@RequestMapping的派生注解
处理get请求的映射–>@GetMapping
处理post请求的映射–>@PostMapping
处理put请求的映射–>@PutMapping
处理delete请求的映射–>@DeleteMapping
2、常用的请求方式有get,post,put,delete
但是目前浏览器只支持get和post,若在form表单提交时,为method设置了其他请求方式的字符
串(put或delete),则按照默认的请求方式get处理
还是建议使用restful风格
3.5、@RequestMapping注解的params属性
● @RequestMapping注解的params属性通过请求的请求参数匹配请求映射
● @RequestMapping注解的params属性是一个字符串类型的数组,可以通过四种表达式设置请求参数和请求映射的匹配关系
1、“param”:要求请求映射所匹配的请求必须携带param请求参数 “2、!param”:要求请求映射所匹配的请求必须不能携带param请求参数
3、 “param=value”:要求请求映射所匹配的请求必须携带param请求参数且param=value
4、“param!=value”:要求请求映射所匹配的请求必须携带param请求参数但是param!=value
注:用的较多也是携带参数
3.5.1 使用数组的形式
<form th:action="@{/test(username='张三',password='1234')}" method="post">
<input type="submit">
</form>
@Controller
public class TestController {
@RequestMapping(
value = {"/test", "/myTest"},
method = {RequestMethod.GET, RequestMethod.POST},
params = {"username","password"}
)
public String success() {
return "success";
}
}
3.5.2 不适用数组的形式
<form th:action="@{/test(username='张三')}" method="post">
<input type="submit">
</form>
@Controller
public class TestController {
@RequestMapping(
value = {"/test", "/myTest"},
method = {RequestMethod.GET, RequestMethod.POST},
params = "username"
)
public String success() {
return "success";
}
}
3.5.3 参数不等于某个数的情况
<form th:action="@{/test(username='张三',password='1234')}" method="post">
<input type="submit">
</form>
@Controller
public class TestController {
@RequestMapping(
value = {"/test", "/myTest"},
method = {RequestMethod.GET, RequestMethod.POST},
params = {"username","password!=1234"}
)
public String success() {
return "success";
}
}
若当前请求满足@RequestMapping注解的value和method属性,但是不满足params属性,此时页面回报错400
提示:这种情况目前我是没遇到过这样的写法
3.6、@RequestMapping注解的headers属性
● @RequestMapping注解的headers属性通过请求的请求头信息匹配请求映射
● @RequestMapping注解的headers属性是一个字符串类型的数组,可以通过四种表达式设置请求头信息和请求映射的匹配关系
●
“header”:要求请求映射所匹配的请求必须携带header请求头信息
“!header”:要求请求映射所匹配的请求必须不能携带header请求头信息
“header=value”:要求请求映射所匹配的请求必须携带header请求头信息且header=value
“header!=value”:要求请求映射所匹配的请求必须携带header请求头信息且header!=value
若当前请求满足@RequestMapping注解的value和method属性,但是不满足headers属性,此时页面显示404错误,即资源未找到
了解就行
3.6.1 测试
请求头中需要携带的信息
<form th:action="@{/test(username='张三',password='12345')}" method="post">
<input type="submit">
</form>
@Controller
public class TestController {
@RequestMapping(
value = {"/test", "/myTest"},
method = {RequestMethod.GET, RequestMethod.POST},
params = {"username","password!=1234"},
headers = {"Host=localhost:8088"}
)
public String success() {
return "success";
}
}
3.7、SpringMVC支持ant风格的路径
?:表示任意的单个字符
*:表示任意的0个或多个字符
:表示任意的一层或多层目录
注意:在使用时,只能使用/**/xxx的方式
3.7.1 测试单个字符
<a th:href="@{/fgf/mytest}">访问目标页面target.html</a>
@Controller
public class TestController {
@RequestMapping("/f?f/mytest")
public String myTest() {
return "success";
}
}
3.7.2测试多个字符
<a th:href="@{/fg54edrf/mytest}">访问目标页面target.html</a>
@Controller
public class TestController {
@RequestMapping("/f*f/mytest")
public String myTest() {
return "success";
}
}
3.7.3 测试目录结构
多级目录都可以访问到、一般也不这样用吧
<a th:href="@{/fg54edrf/mytest}">访问目标页面target.html</a>
@Controller
public class TestController {
@RequestMapping("/**/mytest")
public String myTest() {
return "success";
}
}
3.8、SpringMVC支持路径中的占位符(重点)
SpringMVC路径中的占位符常用于RESTful风格中、我就喜欢这样使用
原始方式:/deleteUser?id=1
rest方式:/deleteUser/1
SpringMVC路径中的占位符常用于RESTful风格中,当请求路径中将某些数据通过路径的方式传输到服务器中,就可以在相应的@RequestMapping注解的value属性中通过占位符{xxx}表示传输的数据,在通过@PathVariable注解,将占位符所表示的数据赋值给控制器方法的形参
3.8.1 测试
<a th:href="@{/mytest/4/张三}">访问目标页面target.html</a>
@Controller
public class TestController {
@RequestMapping("/mytest/{id}/{username}")
public String myTest(@PathVariable("id") String id,@PathVariable("username") String username) {
System.out.println("id:"+ id+",username:"+username);
return "success";
}
3.8.2 项目中的实际引用
后端接口设计
4、SpringMVC获取请求参数(六种方式详细说明)
4.1、通过ServletAPI获取
将HttpServletRequest作为控制器方法的形参,此时HttpServletRequest类型的参数表示封装了当前请求的请求报文的对象
4.1.1 测试
<a th:href="@{/testServletAPI(username='张三',password='123456')}">测试</a>
@Controller
public class paramController {
@RequestMapping("/testServletAPI")
public String testParam(HttpServletRequest request){
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("username:"+username+",password:"+password);
return "param_test";
}
}
4.2、通过控制器方法的形参获取请求参数
在控制器方法的形参位置,设置和请求参数同名的形参,当浏览器发送请求,匹配到请求映射时,在DispatcherServlet中就会将请求参数赋值给相应的形参
4.2.1 测试
<a th:href="@{/testServletAPI(username='张三',password='123456')}">测试</a>
@Controller
public class paramController {
@RequestMapping("/testServletAPI")
public String testParam(String username,String password){
System.out.println("username:"+username+",password:"+password);
return "param_test";
}
}
4.2.2 测试
<form th:action="@{/testParam}" method="post">
姓名:<input type="text" name="username">
密码:<input type="password" name="password">
爱好:<input type="checkbox" name="hobby" value="a">a
<input type="checkbox" name="hobby" value="b">b
<input type="checkbox" name="hobby" value="c">c<br>
<button type="submit" >提交</button>
</form>
@Controller
public class paramController {
@RequestMapping("/testParam")
public String testParam(String username,String password,String hobby){
System.out.println("username:"+username+",password:"+password+",hobby:"+hobby);
return "param_test";
}
}
4.2.3 测试
@Controller
public class paramController {
@RequestMapping("/testParam")
public String testParam(String username,String password,String[] hobby){
System.out.println("username:"+username+",password:"+password+",hobby:"+ Arrays.toString(hobby));
return "param_test";
}
}
注: 若请求所传输的请求参数中有多个同名的请求参数,此时可以在控制器方法的形参中设置字符串 数组或者字符串类型的形参接收此请求参数
若使用字符串数组类型的形参,此参数的数组中包含了每一个数据 若使用字符串类型的形参,此参数的值为每个数据中间使用逗号拼接的结果
4.3、@RequestParam
● @RequestParam是将请求参数和控制器方法的形参创建映射关系
● @RequestParam注解一共有三个属性:
value:指定为形参赋值的请求参数的参数名
required:设置是否必须传输此请求参数,默认值为true
若设置为true时,则当前请求必须传输value所指定的请求参数,若没有传输该请求参数,且没有设置
defaultValue属性,则页面报错400:Required String parameter ‘xxx’ is not present;若设置为
false,则当前请求不是必须传输value所指定的请求参数,若没有传输,则注解所标识的形参的值为
null
defaultValue:不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值
为""时,则使用默认值为形参赋值
4.3.1 测试1、形参不匹配
4.3.2 测试二、解决方法
@RequestParam("user_name") String username。添加一个注解
<form th:action="@{/testParam}" method="get">
姓名:<input type="text" name="user_name">
密码:<input type="password" name="password">
爱好:<input type="checkbox" name="hobby" value="a">a
<input type="checkbox" name="hobby" value="b">b
<input type="checkbox" name="hobby" value="c">c<br>
<button type="submit" >提交</button>
</form>
@Controller
public class paramController {
@RequestMapping("/testParam")
public String testParam(@RequestParam("user_name") String username, String password, String[] hobby){
System.out.println("username:"+username+",password:"+password+",hobby:"+ Arrays.toString(hobby));
return "param_test";
}
}
4.3.3 测试三、参数是否必须传值
默认是必须传值
设置这个参数非必须
@RequestMapping("/testParam")
public String testParam(@RequestParam(value = "user_name",required = false) String username, String password, String[] hobby){
System.out.println("username:"+username+",password:"+password+",hobby:"+ Arrays.toString(hobby));
return "param_test";
}
默认是必须传值
@RequestMapping("/testParam")
public String testParam(@RequestParam("user_name") String username, String password, String[] hobby){
System.out.println("username:"+username+",password:"+password+",hobby:"+ Arrays.toString(hobby));
return "param_test";
}
4.3.4 测试四、默认值
@Controller
public class paramController {
@RequestMapping("/testParam")
public String testParam(@RequestParam(value = "user_name", required = false,defaultValue = "hello") String username, String password, String[] hobby) {
System.out.println("username:" + username + ",password:" + password + ",hobby:" + Arrays.toString(hobby));
return "param_test";
}
}
4.4、@RequestHeader
● @RequestHeader是将请求头信息和控制器方法的形参创建映射关系
● @RequestHeader注解一共有三个属性:value、required、defaultValue,用法同@RequestParam
4.4.1 测试
@Controller
public class paramController {
@RequestMapping("/testParam")
public String testParam(@RequestParam(value = "user_name", required = false,defaultValue = "hello") String username, String password, String[] hobby,
@RequestHeader(value = "ShowHost" ,required = true,defaultValue = "MyHost") String host) {
System.out.println("username:" + username + ",password:" + password + ",hobby:" + Arrays.toString(hobby)+",Host:"+host);
return "param_test";
}
}
4.5、@CookieValue
● @CookieValue是将cookie数据和控制器方法的形参创建映射关系
● @CookieValue注解一共有三个属性:value、required、defaultValue,用法同@RequestParam
4.6、通过POJO获取请求参数
可以在控制器方法的形参位置设置一个实体类类型的形参,此时若浏览器传输的请求参数的参数名和实体类中的属性名一致,那么请求参数就会为此属性赋值
4.6.1 测试
<form th:action="@{/myTestParam}" method="get">
姓名:<input type="text" name="username">
密码:<input type="password" name="password">
性别:<input type="text" name="sex">
<button type="submit" >提交</button>
</form>
@Controller
public class paramController {
@RequestMapping("/myTestParam")
public String myTest(User user){
System.out.println(user);
return "param_test";
}
}
4.7、解决获取请求参数的乱码问题
解决获取请求参数的乱码问题,可以使用SpringMVC提供的编码过滤器CharacterEncodingFilter,但是必须在web.xml中进行注册
<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>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
环境搭建:改系列文章开始有介绍。这部分代码所在磁盘位置:F:\workspace\SpringMVC代码\springMVC-demo4
从源码角度分析控制器:https://blog.csdn.net/weixin_43304253/article/details/128071577
5、域对象共享数据
5.1、使用ServletAPI向request域对象共享数据
设置:request.setAttribute(“testRequestScope”,“Hello,ServletAPI”);。取值:通过key
5.1.1 核心部分代码
设置值
/**
* 使用servletAPI向request域对象共享数据
* @param request
* @return
*/
@RequestMapping("/testRequestScope")
public String toSuccess(HttpServletRequest request){
request.setAttribute("testRequestScope","Hello,ServletAPI");
return "success";
}
跳转后页面获取数据
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>success</title>
</head>
<body>
<h1>这里是成功页面</h1>
<p th:text="${testRequestScope}"></p>
</body>
</html>
5.1.2 测试结果
5.2、使用ModelAndView向request域对象共享数据
5.1.1 核心代码
/**
* @return
*/
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView() {
/**
* ModelAndView有Model和View的功能
* Model主要用于向请求域共享数据
* View主要用于设置视图,实现页面跳转
*/
ModelAndView mav = new ModelAndView();
//用来处理模型数据,向请求域request共享数据
mav.addObject("testRequestScope", "Hello,ModelAndView");
//设置视图名称
mav.setViewName("success");
return mav;
}
取值同1.1
5.1.2 测试结果
5.3、使用Model向request域对象共享数据
5.3.1 核心代码
/**
* 测试Model
* @param model
* @return
*/
@RequestMapping("/testModel")
public String testModel(Model model){
model.addAttribute("testRequestScope","Hello,Model");
return "success";
}
取值同1.1
5.3.2 测试结果
5.4、使用map向request域对象共享数据
5.4.1 核心代码
/**
* 测试MaP
* @param map
* @return
*/
@RequestMapping("/testMap")
public String testMap(Map<String,Object> map){
map.put("testRequestScope","Hello,Map");
return "success";
}
取值方法同1.1
5.4.2 测试结果
5.5、使用ModelMap向request域对象共享数据
5.5.1 核心代码
/**
* 测试 ModelMap
* @param modelMap
* @return
*/
@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap){
modelMap.addAttribute("testRequestScope","Hello,ModelMap");
return "success";
}
取值同1.1
5.5.2 测试结果
5.6、Model、ModelMap、Map的关系
CTRL+H 查看实现接口类。通过反射查看调用的对应方法
Model、ModelMap、Map类型的参数其实本质上都是 BindingAwareModelMap 类型的
public interface Model{}
public class ModelMap extends LinkedHashMap<String, Object> {}
public class ExtendedModelMap extends ModelMap implements Model {}
public class BindingAwareModelMap extends ExtendedModelMap {}
通过反射查看调用的方法
System.out.println(model.getClass().getName());
System.out.println(map.getClass().getName());
System.out.println(modelMap.getClass().getName());
5.7、向session域共享数据
5.7.1 核心代码
/**
* 测试Session
* @param session
* @return
*/
@RequestMapping("/testSession")
public String testSession(HttpSession session){
session.setAttribute("testSession","Hello Session");
return "success";
}
取值方法
<p th:text="${session.testSession}"></p>
5.7.2 测试结果
5.8、向application域共享数据
5.8.1 核心代码
/**
* 测试Application
* @param session
* @return
*/
@RequestMapping("/testApplication")
public String testApplication(HttpSession session){
ServletContext application = session.getServletContext();
application.setAttribute("testApplication","Hello Application");
return "success";
}
获取数据
<p th:text="${application.testApplication}"></p>
5.8.2 测试结果
5.9、项目结构
5.9.1 结构
5.9.2 首页跳转链接
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<a th:href="@{/testRequestScope}">测试requestAPI</a>
<hr>
<a th:href="@{/testModelAndView}">测试ModelAndView</a>
<hr>
<a th:href="@{/testModel}">测试Model</a>
<hr>
<a th:href="@{/testMap}">测试Map</a>
<hr>
<a th:href="@{/testModelMap}">测试ModelMap</a>
<hr>
<a th:href="@{/testSession}">测试Session</a>
<hr>
<a th:href="@{/testApplication}">测试Application</a>
</body>
</html>
5.9.3 数据展示页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>success</title>
</head>
<body>
<h1>这里是成功页面</h1>
<p th:text="${testRequestScope}"></p>
<p th:text="${session.testSession}"></p>
<p th:text="${application.testApplication}"></p>
</body>
</html>
5.9.4 跳转控制器
package com.zyz.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionContext;
import java.util.Map;
/**
* @author zyz
* @version 1.0
* @data 2022/11/27 20:58
* @Description:
*/
@Controller
public class TestController {
@RequestMapping("/")
public String toIndex() {
return "index";
}
/**
* 使用servletAPI向request域对象共享数据
*
* @param request
* @return
*/
@RequestMapping("/testRequestScope")
public String toSuccess(HttpServletRequest request) {
request.setAttribute("testRequestScope", "Hello,ServletAPI");
return "success";
}
/**
* 测试ModelAndView
* @return
*/
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView() {
/**
* ModelAndView有Model和View的功能
* Model主要用于向请求域共享数据
* View主要用于设置视图,实现页面跳转
*/
ModelAndView mav = new ModelAndView();
//用来处理模型数据,向请求域request共享数据
mav.addObject("testRequestScope", "Hello,ModelAndView");
//设置视图名称
mav.setViewName("success");
return mav;
}
/**
* 测试Model
* @param model
* @return
*/
@RequestMapping("/testModel")
public String testModel(Model model){
model.addAttribute("testRequestScope","Hello,Model");
System.out.println(model.getClass().getName());
return "success";
}
/**
* 测试MaP
* @param map
* @return
*/
@RequestMapping("/testMap")
public String testMap(Map<String,Object> map){
map.put("testRequestScope","Hello,Map");
System.out.println(map.getClass().getName());
return "success";
}
/**
* 测试 ModelMap
* @param modelMap
* @return
*/
@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap){
modelMap.addAttribute("testRequestScope","Hello,ModelMap");
System.out.println(modelMap.getClass().getName());
return "success";
}
/**
* 测试Session
* @param session
* @return
*/
@RequestMapping("/testSession")
public String testSession(HttpSession session){
session.setAttribute("testSession","Hello Session");
return "success";
}
/**
* 测试Application
* @param session
* @return
*/
@RequestMapping("/testApplication")
public String testApplication(HttpSession session){
ServletContext application = session.getServletContext();
application.setAttribute("testApplication","Hello Application");
return "success";
}
}
5.10 SpringMVC种通过追踪源码查看是哪种类型的视图渲染器(一般流程方法)
1、返回视图打断点
2、刷新页面进入断点
在这个位置打两个断点、进入视图跳转控制器
3、进入processDispatchResult方法
4、进入render方法
5、查看使用的哪种视图
SpringMVC中的视图是View接口,视图的作用渲染数据,将模型Model中的数据展示给用户
SpringMVC视图的种类很多,默认有转发视图和重定向视图
当工程引入jstl的依赖,转发视图会自动转换为JstlView
若使用的视图技术为Thymeleaf,在SpringMVC的配置文件中配置了Thymeleaf的视图解析器,由此视
图解析器解析之后所得到的是ThymeleafView
通过Debug模式查看:通过追踪源码查看是哪种类型的视图渲染器(一般流程方法)
6、SpringMVC的视图
6.1、ThymeleafView
当控制器方法中所设置的视图名称没有任何前缀时,此时的视图名称会被SpringMVC配置文件中所配置
的视图解析器解析,视图名称拼接视图前缀和视图后缀所得到的最终路径,会通过转发的方式实现跳转
6.1.1 核心代码
/**
* 测试testThymeleafView
* @return
*/
@RequestMapping("/testThymeleafView")
public String testView(){
return "success";
}
6.1.2 测试结果
6.1.3 通过源码查看
6.2、转发视图
SpringMVC中默认的转发视图是InternalResourceView
SpringMVC中创建转发视图的情况:
当控制器方法中所设置的视图名称以"forward:"为前缀时,创建InternalResourceView视图,此时的视
图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"forward:“去掉,剩余部分作为最终路径通过转发的方式实现跳转
例如"forward:/”,“forward:/employee”
6.2.1 核心代码
@RequestMapping(“/testThymeleafView”)
public String testView(){
return “success”;
}
/**
- 测试forward
- @return
*/
@RequestMapping(“/testForward”)
public String testForward(){
return “forward:/testThymeleafView”;
}
6.2.2 测试结果
6.2.3 源码查看
6.3、重定向视图
SpringMVC中默认的重定向视图是RedirectView
当控制器方法中所设置的视图名称以"redirect:"为前缀时,创建RedirectView视图,此时的视图名称不
会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"redirect:“去掉,剩余部分作为最
终路径通过重定向的方式实现跳转
例如"redirect:/”,“redirect:/employee”
6.3.1 核心代码
@RequestMapping("/testThymeleafView")
public String testView(){
return "success";
}
/**
* 测试redirect 重定向
* @return
*/
@RequestMapping("/testRedirect")
public String testRedirect(){
return "redirect:/testThymeleafView";
}
6.3.2 测试结果
6.3.3 源码查看
6.4、视图控制器view-controller
当控制器方法中,仅仅用来实现页面跳转,即只需要设置视图名称时,可以将处理器方法使用viewcontroller标签进行表示
<!--
path:设置处理的请求地址
view-name:设置请求地址所对应的视图名称
-->
<mvc:view-controller path="/testView" view-name="success"></mvc:view-controller>
注:
当SpringMVC中设置任何一个view-controller时,其他控制器中的请求映射将全部失效,此时需
要在SpringMVC的核心配置文件中设置开启mvc注解驱动的标签:
<mvc:annotation-driven />
6.4.1 核心代码
<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
代替
@RequestMapping("/")
public String toIndex() {
return "index";
}
需要添加注解驱动、否则跳转连接无效
<!--开启mvc的注解驱动-->
<mvc:annotation-driven/>
6.4.2 开启后、正常跳转
6.4.3 如果不开启、跳转失败
7、RESTful的详细介绍和使用 具体代码案例分析
7.1、RESTful简介
REST:Representational State Transfer,表现层资源状态转移。
● a>资源
资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成。每个资源是服务器上一个可命名的抽象概念。因为资源是一个抽象的概念,所以它不仅仅能代表服务器文件系统中的一个文件、数据库中的一张表等等具体的东西,可以将资源设计的要多抽象有多抽象,只要想象力允许而且客户端应用开发者能够理解。与面向对象设计类似,资源是以名词为核心来组织的,首先关注的是名词。一个资源可以由一个或多个URI来标识。URI既是资源的名称,也是资源在Web上的地址。对某个资源感兴趣的客户端应用,可以通过资源的URI与其进行交互。
● b>资源的表述
资源的表述是一段对于资源在某个特定时刻的状态的描述。可以在客户端-服务器端之间转移(换)。资源的表述可以有多种格式,例如HTML/XML/JSON/纯文本/图片/视频/音频等等。资源的表述格式可以通过协商机制来确定。请求-响应方向的表述通常使用不同的格式。
● c>状态转移
状态转移说的是:在客户端和服务器端之间转移(transfer)代表资源状态的表述。通过转移和操作资源的表述,来间接实现操作资源的目的。
7.2、RESTful的实现
具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。
它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE用来删除资源。REST 风格提倡 URL 地址使用统一的风格设计,从前到后各个单词使用斜杠分开,不使用问号键值对方式携带请求参数,而是将要发送给服务器的数据作为 URL 地址的一部分,以保证整体风格的一致性。
7.3、HiddenHttpMethodFilter
由于浏览器只支持发送get和post方式的请求,那么该如何发送put和delete请求呢?
SpringMVC 提供了 HiddenHttpMethodFilter 帮助我们将 POST 请求转换为 DELETE 或 PUT 请求HiddenHttpMethodFilter 处理put和delete请求的条件:
● 当前请求的请求方式必须为post
● 当前请求必须传输请求参数_method
满足以上条件,HiddenHttpMethodFilter 过滤器就会将当前请求的请求方式转换为请求参数
method的值,因此请求参数method的值才是最终的请求方式
在web.xml中注册HiddenHttpMethodFilter
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
目前为止,SpringMVC中提供了两个过滤器:CharacterEncodingFilter和
HiddenHttpMethodFilter
在web.xml中注册时,必须先注册CharacterEncodingFilter,再注册HiddenHttpMethodFilter
原因:
在 CharacterEncodingFilter 中通过 request.setCharacterEncoding(encoding) 方法设置字
符集的
request.setCharacterEncoding(encoding) 方法要求前面不能有任何获取请求参数的操作
而 HiddenHttpMethodFilter 恰恰有一个获取请求方式的操作:String paramValue = request.getParameter(this.methodParam);
7.4、实际代码案例
7.4.1 控制层
package com.zyz.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* @author zyz
* @version 1.0
* @data 2022/11/28 15:17
* @Description:
*/
@Controller
public class ResultController {
/**
* 使用RESULT模拟用户资源的增删改查
*
/**
*查询所有用户信息
* @return
*/
@RequestMapping(value = "/user",method = RequestMethod.GET)
public String getAllUser(){
System.out.println("查询所有用户信息");
return "success";
}
/**
* 根据ID查询用户信息
* @return
*/
@RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
public String getUserById(){
System.out.println("根据ID查询用户信息");
return "success";
}
/**
* 添加用户
* @param username
* @param password
* @return
*/
@RequestMapping(value = "/user",method = RequestMethod.POST)
public String addUser(String username,String password){
System.out.println("添加用户信息:"+username+","+password);
return "success";
}
/**
* 修改用户
* @param username
* @param password
* @return
*/
@RequestMapping(value = "/user",method = RequestMethod.PUT)
public String updateUser(String username,String password){
System.out.println("修改用户信息:"+username+","+password);
return "success";
}
}
7.4.2 页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a th:href="@{/user}">查询所有用户</a>
<br>
<a th:href="@{/user/1}">根据ID查询用户信息</a>
<br>
<form th:action="@{/user}" method="post" >
用户名:<input type="text" name="username">
<br>
密码:<input type="password" name="password">
<br>
<input type="submit" value="添加">
</form>
<hr>
<form th:action="@{/user}" method="post" >
<input type="hidden" name="_method" value="PUT">
用户名:<input type="text" name="username">
<br>
密码:<input type="password" name="password">
<br>
<input type="submit" value="添加">
</form>
</body>
</html>
7.4.3 测试结果
8、SpringMVC创建JSP页面的详细过程+配置模板+实现页面跳转+配置Tomcat
8.1、创建Maven项目
8.2、填写项目基本信息、完成创建
8.3、导入POM依赖
打包方式设置为War包
<packaging>war</packaging>
依赖、可自行添加需要jar包依赖
<dependencies>
<!-- SpringMVC -->
<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>compile</scope>
</dependency>
<!-- Spring5和Thymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
8.4、选择项目结构
8.5、创建web.xml
如果创建的项目无法展开目录、请重启IDEA、或者清缓存
8.6、点击应用apply、查看项目是否创建成功
8.7、配置web.xml
<?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">
<!--配置过滤器编码-->
<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>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 -->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 通过初始化参数指定SpringMVC配置文件的位置和名称 -->
<init-param>
<!-- contextConfigLocation为固定值 -->
<param-name>contextConfigLocation</param-name>
<!-- 使用classpath:表示从类路径查找配置文件,例如maven工程中的
src/main/resources -->
<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>
<!--
设置springMVC的核心控制器所能处理的请求的请求路径
/所匹配的请求可以是/login或.html或.js或.css方式的请求路径
但是/不能匹配.jsp请求路径的请求
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
8.8、配置模板解析器
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">
<!--扫描组件-->
<context:component-scan base-package="com.zyz.mvc.controller"></context:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/templates/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
8.9、配置包templates
8.10、创建index.jsp
创建的index.jsp页面是和WEB-INFP平级
index.jsp
<%--
Created by IntelliJ IDEA.
User: Lenovo
Date: 2022/11/29
Time: 10:11
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
</head>
<body>
这是我的首页
</body>
</html>
8.11、 基本的目录结构
8.12、配置Tomcat
8.12.1 点击Run、选择Edit Configurations…
8.12.2 基本信息配置
8.12.3 点击apply
8.13 启动tomcat
8.14 启动成功进入首页
8.15、如何实现请求转发页面跳转
8.15.1 创建controller 控制请求跳转
TestJsp.java
package com.zyz.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author zyz
* @version 1.0
* @data 2022/11/29 10:13
* @Description:
*/
@Controller
public class TestJsp {
@RequestMapping("/success")
public String success(){
return "success";
}
}
8.15.2 创建跳转后页面
改页面要创建在templates下、否则模板解析器解释不到
<%--
Created by IntelliJ IDEA.
User: Lenovo
Date: 2022/11/29
Time: 10:27
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>success</title>
</head>
<body>
<h1>这里是成功页面</h1>
</body>
</html>
8.15.3 跳转连接
index.jsp
<%--
Created by IntelliJ IDEA.
User: Lenovo
Date: 2022/11/29
Time: 10:11
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
</head>
<body>
这是我的首页
<a href="${pageContext.request.contextPath}/success">success.jsp</a>
</body>
</html>
8.15.4 页面效果
8.15.5 点击跳转
8.16、最终完整的项目结构介绍
目录结构、请确保目录结构正确、否则也会导致运行项目失败
8.17、JSP模板解析和HTML模板解析对比
HTML模板解析
<!-- 配置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>
这篇的主要目的是锻炼使用Result风格的接口开发。数据是假数据(并未真正连接到数据库)、页面使用BootStrap大致构建一下(不至于那么丑)
项目地址:F:\workspace\SpringMVC代码\SpringMVC-rest
项目的搭建过程、如何配置Tomcat过程略、改专栏系列之前有些。此处不做赘述
9、RESTful案例。SpringMVC+thymeleaf+BootStrap+RestFul实现员工信息的增删改查
9.1、项目结构
9.2、源码
9.2.1 web.xml文件
<?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">
<!--配置过滤器编码-->
<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>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 -->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 通过初始化参数指定SpringMVC配置文件的位置和名称 -->
<init-param>
<!-- contextConfigLocation为固定值 -->
<param-name>contextConfigLocation</param-name>
<!-- 使用classpath:表示从类路径查找配置文件,例如maven工程中的
src/main/resources -->
<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>
<!--
设置springMVC的核心控制器所能处理的请求的请求路径
/所匹配的请求可以是/login或.html或.js或.css方式的请求路径
但是/不能匹配.jsp请求路径的请求
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
9.2.2 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 http://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.zyz.mvc"></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>
<!--配置视图控制器-->
<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
<mvc:view-controller path="/addEmployee" view-name="employee_add"></mvc:view-controller>
<!--开放对静态资源的访问-->
<mvc:default-servlet-handler/>
<!--开启mvc的注解驱动-->
<mvc:annotation-driven/>
</beans>
9.2.3 EmployeeController.java
package com.zyz.mvc.controller;
import com.zyz.mvc.dao.EmployeeDao;
import com.zyz.mvc.pojo.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.Collection;
/**
* @author zyz
* @version 1.0
* @data 2022/11/28 22:00
* @Description:
*/
@Controller
public class EmployeeController {
@Autowired
private EmployeeDao employeeDao;
/**
* 查询所有员工信息
* @param model
* @return
*/
@RequestMapping(value = "/employee",method = RequestMethod.GET)
public String getAllEmployee(Model model){
Collection<Employee> employeeList = employeeDao.getAll();
model.addAttribute("employeeList",employeeList);
return "employee_list";
}
/**
* 删除员工信息
* @param id
* @return
*/
@RequestMapping(value = "/employee/{id}",method = RequestMethod.DELETE)
public String deleteEmployee(@PathVariable("id") Integer id ){
employeeDao.delete(id);
return "redirect:/employee";
}
/**
* 添加用户信息
* @param employee
* @return
*/
@RequestMapping(value = "/employee",method = RequestMethod.POST)
public String addEmployee(Employee employee){
employeeDao.save(employee);
return "redirect:/employee";
}
/**
* 跳转修改员工信息
* @param id
* @param model
* @return
*/
@RequestMapping(value = "/employee/{id}",method = RequestMethod.GET)
public String toUpdateEmployee(@PathVariable("id") Integer id,Model model){
Employee employee = employeeDao.get(id);
model.addAttribute("employee",employee);
return "employee_update";
}
/**
* 修改用户信息
* @param employee
* @return
*/
@RequestMapping(value = "/employee",method = RequestMethod.PUT)
public String upDateEmployee(Employee employee){
employeeDao.save(employee);
return "redirect:/employee";
}
}
9.2.4 EmployeeDao.java
假数据模拟
package com.zyz.mvc.dao;
import com.zyz.mvc.pojo.Employee;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* @author zyz
* @version 1.0
* @data 2022/11/28 21:56
* @Description:
*/
@Repository
public class EmployeeDao {
private static Map<Integer, Employee> employees = null;
static {
employees = new HashMap<Integer, Employee>();
employees.put(1001, new Employee(1001, "E-AA", "aa@163.com", 1));
employees.put(1002, new Employee(1002, "E-BB", "bb@163.com", 1));
employees.put(1003, new Employee(1003, "E-CC", "cc@163.com", 0));
employees.put(1004, new Employee(1004, "E-DD", "dd@163.com", 0));
employees.put(1005, new Employee(1005, "E-EE", "ee@163.com", 1));
}
private static Integer initId = 1006;
public void save(Employee employee) {
if (employee.getId() == null) {
employee.setId(initId++);
}
employees.put(employee.getId(), employee);
}
public Collection<Employee> getAll() {
return employees.values();
}
public Employee get(Integer id) {
return employees.get(id);
}
public void delete(Integer id) {
employees.remove(id);
}
}
9.2.5 Employee.java
实体类 使用Lombok
package com.zyz.mvc.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* @author zyz
* @version 1.0
* @data 2022/11/28 21:54
* @Description:
*/
@Data
@AllArgsConstructor
public class Employee {
private Integer id;
private String lastName;
private String email;
private Integer gender;
}
9.2.6 employee_list.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>员工信息</title>
<style type="text/css">
a {
text-decoration: none;
}
</style>
<!-- 新 Bootstrap 核心 CSS 文件 -->
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row clearfix">
<div class="col-md-12 column">
<div class="page-header">
<h1>
<small>员工信息----------显示所有员工信息</small>
</h1>
</div>
</div>
</div>
<div class="row ">
<div class="col-md-4 column">
<a class="btn btn-primary btn-sm" th:href="@{/addEmployee}">添加员工</a>
</div>
<div class="col-md-4 column">
</div>
</div>
<div class="row clearfix">
<div class="col-md-12 column">
<table id="mydataTable" class="table table-hover table-striped">
<thead>
<tr>
<th>编号</th>
<th>姓名</th>
<th>邮箱</th>
<th>性别</th>
<th colspan="2">操作</th>
</tr>
</thead>
<!--查询用户处理-->
<tbody>
<tr th:each="employee : ${employeeList}">
<td th:text="${employee.id}"></td>
<td th:text="${employee.lastName}"></td>
<td th:text="${employee.email}"></td>
<td>
<div th:switch="${employee.gender}">
<span th:case="1">男</span>
<span th:case="0">女</span>
</div>
</td>
<td>
<a class="btn btn-danger btn-xs" @click="deleteEmployee"
th:href="@{'/employee/'+${employee.id}}">删除</a>
<a class="btn btn-primary btn-xs" th:href="@{'/employee/'+${employee.id}}">修改</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<form id="deleteForm" method="post">
<input type="hidden" name="_method" value="DELETE">
</form>
<script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
<script type="text/javascript">
var vue = new Vue({
el: "#mydataTable",
methods: {
deleteEmployee: function (event) {
var deleteForm = document.getElementById("deleteForm");
deleteForm.action = event.target.href;
deleteForm.submit();
event.preventDefault();
}
}
})
</script>
</body>
</html>
9.2.7 employee_add.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>添加</title>
<!-- 新 Bootstrap 核心 CSS 文件 -->
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row clearfix">
<div class="col-md-12 column">
<div class="page-header">
<h1>
<small>添加员工</small>
</h1>
</div>
</div>
</div>
<form th:action="@{/employee}" method="post">
<div class="form-group">
<label>姓名</label>
<input type="text" class="form-control" name="lastName">
</div>
<div class="form-group">
<label>邮箱</label>
<input type="text" class="form-control" name="email">
</div>
<div class="form-group">
<label>性别 </label>
<input type="radio" name="gender" value="1" checked>男
<input type="radio" name="gender" value="0">女
</div>
<input type="submit" class="btn btn-default" value="添加">
</form>
</div>
</div>
</body>
</html>
9.2.8 employee_update.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>修改</title>
<!-- 新 Bootstrap 核心 CSS 文件 -->
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row clearfix">
<div class="col-md-12 column">
<div class="page-header">
<h1>
<small>修改信息</small>
</h1>
</div>
</div>
</div>
<form th:action="@{/employee}" method="post">
<input type="hidden" name="_method" value="put">
<input type="hidden" name="id" th:value="${employee.id}">
<div class="form-group">
<label>姓名</label>
<input type="text" class="form-control" name="lastName" th:value="${employee.lastName}">
</div>
<div class="form-group">
<label>邮箱</label>
<input type="text" class="form-control" name="email" th:value="${employee.email}">
</div>
<div class="form-group">
<label >性别 </label>
<input type="radio" name="gender" value="1" th:field="${employee.gender}">男
<input type="radio" name="gender" value="0" th:field="${employee.gender}">女
</div>
<input type="submit" class="btn btn-default" value="保存">
</form>
</div>
</div>
</body>
</html>
9.2.9 index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
<style type="text/css">
a{
text-decoration: none;
color: black;
font-size: 18px;
}
h3{
width: 180px;
height: 38px;
margin:100px auto;
text-align: center;
line-height: 38px;
background: deepskyblue;
border-radius: 5px;
}
</style>
</head>
<body>
<h3>
<a th:href="@{/employee}">查看所有员工信息</a><br>
</h3>
<h3>
<a th:href="@{/addEmployee}">添加员工</a>
</h3>
</body>
</html>
9.3、实现的效果
9.3.1 首页
9.3.2 全部员工信息
9.3.3 添加员工
9.3.4 删除员工
9.3.5 修改信息
HttpMessageConverter,报文信息转换器,将请求报文转换为Java对象,或将Java对象转换为响应报文
HttpMessageConverter提供了两个注解和两个类型:@RequestBody,@ResponseBody,RequestEntity, ResponseEntity
10、HttpMessageConverter @RequestBody 、@ResponseBody 、RequestEntity、ResponseEntity
10.1、@RequestBody
@RequestBody可以获取请求体,需要在控制器方法设置一个形参,使用@RequestBody进行标识,当前请求的请求体就会为当前注解所标识的形参赋值
<form th:action="@{/testRequestBody}" method="post">
姓名:<input type="text" name="username">
密码:<input type="password" name="password">
性别:<input type="text" name="sex">
<button type="submit" >提交</button>
</form>
/**
* 测试requestBody
* @param requestBody
* @return
*/
@RequestMapping(value = "/testRequestBody", method = RequestMethod.POST)
public String testRequestBody(@RequestBody String requestBody) {
System.out.println(requestBody);
return "success";
}
测试结果
10.2、RequestEntity
RequestEntity封装请求报文的一种类型,需要在控制器方法的形参中设置该类型的形参,当前请求的请求报文就会赋值给该形参,可以通过getHeaders()获取请求头信息,通过getBody()获取请求体信息
<form th:action="@{/testRequestEntity}" method="post">
姓名:<input type="text" name="username">
密码:<input type="password" name="password">
<button type="submit" >提交</button>
</form>
/**
* 测试requestEntity
* @param requestEntity
* @return
*/
@RequestMapping(value = "/testRequestEntity", method = RequestMethod.POST)
public String testRequestEntity(RequestEntity<String> requestEntity) {
System.out.println("请求头:" + requestEntity.getHeaders());
System.out.println("请求体:" + requestEntity.getBody());
return "success";
}
测试结果
10.3、@ResponseBody
@ResponseBody用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器
<a th:href="@{/testResponse}">测试response</a>
/**
* 测试response
* @param response
* @throws IOException
*/
@RequestMapping("/testResponse")
public void testResponse(HttpServletResponse response) throws IOException {
response.getWriter().print("hello,Resopnse");
}
测试结果
10.4、SpringMVC处理json
@ResponseBody处理json的步骤:
● 导入jackson的依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</version>
</dependency>
● 在SpringMVC的核心配置文件中开启mvc的注解驱动,此时在HandlerAdaptor中会自动装配一个消息转换器:MappingJackson2HttpMessageConverter,可以将响应到浏览器的Java对象转换为Json格式的字符串
<mvc:annotation-driven />
● 在处理器方法上使用@ResponseBody注解进行标识
● 将Java对象直接作为控制器方法的返回值返回,就会自动转换为Json格式的字符串
/**
* 如果返回数组对象 返回一个对象
* @return
*/
@RequestMapping("/testResponseUser")
@ResponseBody
public List<User> testResponseUser() {
User user1 = new User("张三", "男");
User user2 = new User("李四", "男");
ArrayList<User> list = new ArrayList<>();
list.add(user1);
list.add(user2);
return list;
}
测试结果
提示:可以是对象数组、也可以是对象
10.5、SpringMVC处理ajax
使用到了vue、axios。需要下载对应的文件
请求链接:
<div id="app">
<a @click="testAxios" th:href="@{/testAxios}">SpringMVC处理axios</a>
</div>
<script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
<script type="text/javascript" th:src="@{/static/js/axios.min.js}"></script>
<script type="text/javascript">
new Vue({
el:"#app",
methods:{
testAxios:function (event){
axios({
method:'post',
url:event.target.href,
params:{
username:"张三",
password:"123456"
}
}).then(function (res){
alert(res.data)
})
event.preventDefault();
}
}
})
</script>
控制器方法
/**
* 测试axios
* @param username
* @param password
* @return
*/
@RequestMapping("/testAxios")
@ResponseBody
public String testAxios(String username,String password){
System.out.println("姓名:"+username+",密码:"+password);
return "hello,axios";
}
测试结果
10.6、@RestController注解
我终于深刻理解RestController和Controller两者的使用场景
@RestController注解是springMVC提供的一个复合注解,标识在控制器的类上,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody注解
10.7、ResponseEntity
ResponseEntity用于控制器方法的返回值类型,该控制器方法的返回值就是响应到浏览器的响应报文
该文对纯小白不友好
11、文件上传和下载
11.1、文件下载
<a th:href="@{/testDown}">下载</a>
/**
* 测试下载
* @param session
* @return
* @throws IOException
*/
@RequestMapping("/testDown")
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
//获取ServletContext对象
ServletContext servletContext = session.getServletContext();
//获取服务器中文件的真实路径
String realPath = servletContext.getRealPath("/static/img/1.jpg");
//创建输入流
InputStream is = new FileInputStream(realPath);
//创建字节数组
byte[] bytes = new byte[is.available()];
//将流读到字节数组中
is.read(bytes);
//创建HttpHeaders对象设置响应头信息
MultiValueMap<String, String> headers = new HttpHeaders();
//设置要下载方式以及下载文件的名字
headers.add("Content-Disposition", "attachment;filename=1.jpg");
//设置响应状态码
HttpStatus statusCode = HttpStatus.OK;
//创建ResponseEntity对象
ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode);
//关闭输入流
is.close();
return responseEntity;
}
测试结果
11.2、文件上传
文件上传要求form表单的请求方式必须为post,并且添加属性enctype=“multipart/form-data”
SpringMVC中将上传的文件封装到MultipartFile对象中,通过此对象可以获取文件相关信息
● 添加依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
● 在SpringMVC的配置文件中添加配置:
<!--必须通过文件解析器的解析才能将文件转换为MultipartFile对象-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
● 控制器方法:
这里对存储的文件名进行了处理、存储地址可以自定义
/**
* 测试上传
* @param photo
* @param session
* @return
* @throws IOException
*/
@RequestMapping("/testUp")
public String testUp(MultipartFile photo, HttpSession session) throws IOException {
//获取上传的文件的文件名
String fileName = photo.getOriginalFilename();
//处理文件重名问题
String hzName = fileName.substring(fileName.lastIndexOf("."));
fileName = UUID.randomUUID().toString() + hzName;
//获取服务器中photo目录的路径
ServletContext servletContext = session.getServletContext();
String photoPath = servletContext.getRealPath("photo");
System.out.println(photoPath);
File file = new File(photoPath);
if(!file.exists()){
file.mkdir();
}
String finalPath = photoPath + File.separator + fileName;
//实现上传功能
photo.transferTo(new File(finalPath));
return "success";
}
测试效果
12、拦截器的使用
12.1、拦截器的配置
● 拦截器用于拦截控制器方法的执行
● 拦截器需要实现HandlerInterceptor
● 拦截器必须在SpringMVC的配置文件中进行配置
1.1 和1.2 是对所有的请求进行拦截;1.3 对排出的请求不在拦截
12.1.1 不使用注解的情况
创建拦截器类
/**
* 拦截器
* @author zyz
* @version 1.0
* @data 2022/12/18 14:15
* @Description:
*/
public class FirstInterceptor implements HandlerInterceptor {
/**
* 方法执行前
* CTRL+O 重写的快捷键
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("FirstInterceptor--->:preHandle");
/**
* 如果返回false、视图页面不出效果,由源码得知、走到一般返回了。没有到视图解析那一步
*/
return true;
}
/**
* 方法执行后
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("FirstInterceptor--->:postHandle");
}
/**
* 视图渲染后执行
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("FirstInterceptor--->:afterCompletion");
}
}
在SpringMVC中进行配置
mvc:interceptors
</mvc:interceptors>
12.1.2 使用注解的方式
只需要在拦截器类上添加注解@Component。
@Component
public class FirstInterceptor implements HandlerInterceptor {
在配置文件中使用
mvc:interceptors
</mvc:interceptors>
12.1.3 自定义拦截
/*拦截当前目录下的请求。/**拦截所有的请求。这里的exclude-mapping表示排除拦截
<!--
以上配置方式可以通过ref或bean标签设置拦截器,通过mvc:mapping设置需要拦截的请求,
通过mvc:exclude-mapping设置需要排除的请求,即不需要拦截的请求
-->
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/*"/>
<mvc:exclude-mapping path="/"/>
<ref bean="firstInterceptor"></ref>
</mvc:interceptor>
</mvc:interceptors>
12.2、拦截器的三个抽象方法
SpringMVC中的拦截器有三个抽象方法:
● preHandle:控制器方法执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返回true为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法
● postHandle:控制器方法执行之后执行postHandle()
● afterComplation:处理完视图和模型数据,渲染视图完毕之后执行afterComplation()
12.3、多个拦截器的执行顺序
● 若每个拦截器的preHandle()都返回true,此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关:preHandle()会按照配置的顺序执行,而postHandle()和afterComplation()会按照配置的反序执行
● 若某个拦截器的preHandle()返回了false,preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false的拦截器之前的拦截器的afterComplation()会执行
至于为啥是反序执行、根据源码可知是通过i-- 的形式
配置文件中配置拦截器、可以通过普通的bean也可以通过注解形式
mvc:interceptors
</mvc:interceptors>
preHandle()都返回true的时候
preHandle()都返回有一个为false的时候
13、异常处理器
13.1、基于配置的异常处理
SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口:HandlerExceptionResolver
HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolver和SimpleMappingExceptionResolver
SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResolver,使用方式:
1、编写一个方法,里边运算异常。2、调用该异常方法,会自动抛出异常信息到指定页面
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<!--
properties的键表示处理器方法执行过程中出现的异常
properties的值表示若出现指定异常时,设置一个新的视图名称,跳转到指定页面
-->
<prop key="java.lang.ArithmeticException">error</prop>
</props>
</property>
<!--
exceptionAttribute属性设置一个属性名,将出现的异常信息在请求域中进行共享
-->
<property name="exceptionAttribute" value="ex"></property>
</bean>
13.2、基于注解的异常处理
//@ControllerAdvice将当前类标识为异常处理的组件
@ControllerAdvice
public class ExceptionController {
//@ExceptionHandler用于设置所标识方法处理的异常
@ExceptionHandler(ArithmeticException.class)
//ex表示当前请求处理中出现的异常对象
public String handleArithmeticException(Exception ex, Model model){
model.addAttribute("ex", ex);
return "error";
}
}