一文讲明SpringMVC 【爆肝整理一万五千字】
我 | 在这里
🕵️ 读书 | 长沙 ⭐软件工程 ⭐ 本科
🏠 工作 | 广州 ⭐ 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.xsdhttp://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.xsdhttp://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.xsdhttp://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: LenovoDate: 2022/11/29Time: 10:11To 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.javapackage 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: LenovoDate: 2022/11/29Time: 10:27To 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: LenovoDate: 2022/11/29Time: 10:11To 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.xsdhttp://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 {@Autowiredprivate 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*/@Overridepublic 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*/@Overridepublic 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*/@Overridepublic 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";}}
相关文章:
一文讲明SpringMVC 【爆肝整理一万五千字】
我 | 在这里 🕵️ 读书 | 长沙 ⭐软件工程 ⭐ 本科 🏠 工作 | 广州 ⭐ Java 全栈开发(软件工程师) 🎃 爱好 | 研究技术、旅游、阅读、运动、喜欢流行歌曲 ✈️已经旅游的地点 | 新疆-乌鲁木齐、新疆-吐鲁番、广东-广州…...
【Python爬虫实战项目】ip代理池项目原理及代码解析
视频讲解链接:https://www.bilibili.com/video/BV1e8411r7xX/ 代码链接:https://github.com/w-x-x-w/Spider-Project 大家好,这一季我们来介绍一个Python爬虫实战项目-ip代理池项目,这一集我们会首先介绍ip代理池的工作原理流程&a…...
Ardupilot开源飞控之VTOL之旅:配件规格
Ardupilot开源飞控之VTOL之旅:配件规格 1. 源由2. 飞控板 Aocoda-RC H743Dual3. PDB分电板 Aocoda-RC PDB30604. GPS BN8805. 摄像头 RunCam 1200TVL6. 模拟图传 JHEMCU RuiBet Tran-3016W 5.8GHZ 1.6W7. 打印件7.1 飞控/GPS座子7.2 VTX/天线座子7.3 接收机天线座 8…...
Binlog vs. Redo Log:数据库日志的较劲【基础】
🎏:你只管努力,剩下的交给时间 🏠 :小破站 Binlog vs. Redo Log:数据库日志的较劲 前言第一:Binlog与Redo Log的基础概念Binlog(二进制日志)的基础概念Redo Logÿ…...
代理模式-C语言实现
UML图: 代码实现: #include <stdio.h>// 抽象主题接口 typedef struct {void (*request)(void*); } Subject;// 具体主题类 typedef struct {void (*request)(void*); } RealSubject;void RealSubject_request(void* obj) {printf("RealSubj…...
解密 sqli靶场第一关:一步一步学习 SQL 注入技术
目录 一、判断是否存在注入点 二、构造类似?id1 --的语句 三、判断数据表中的列数 四、使用union联合查询 五、使用group_concat()函数 六、爆出数据库中的表名 七、爆出users表中的列名 八、爆出users表中的数据 🌈嗨!我是Filotimo__🌈。很…...
Flask 使用Jinja2模板引擎
Jinja2,由Flask框架的创作者开发,是一款功能丰富的模板引擎,以其完整的Unicode支持、灵活性、高效性和安全性而备受推崇。最初受Django模板引擎启发,Jinja2为Flask提供了强大的模板支持,后来也成为其他项目的首选。在本…...
C/C++内存管理,malloc,realloc,calloc,new,delete详解!!!
1.初步了解内存中各个区间存储的数据特征 1.栈区:存储一些局部变量、函数参数、返回值等,跟函数栈振有关,出了作用域,生命周期结束。 2.堆区:用于动态开辟空间,如果不主动销毁空间,则程序运行结…...
高级JVM
一、Java内存模型 1. 我们开发人员编写的Java代码是怎么让电脑认识的 首先先了解电脑是二进制的系统,他只认识 01010101比如我们经常要编写 HelloWord.java 电脑是怎么认识运行的HelloWord.java是我们程序员编写的,我们人可以认识,但是电脑不…...
论文阅读——MCAN(cvpr2019)
补充一下MCAN-VQA: 对图片的处理:首先输入图片到Faster R-CNN,会先设定一个判断是否检测到物体的阈值,这样动态的生成m∈[10,100]个目标,然后从检测到的对应的区域通过平均池化提取特征。第i个物体特征表示为ÿ…...
mac电脑文件比较工具 UltraCompare 中文for mac
UltraCompare是一款功能强大的文件和文件夹比较工具,用于比较和合并文本、二进制和文件夹。它提供了丰富的功能和直观的界面,使用户能够轻松地比较和同步文件内容,查找差异并进行合并操作。 以下是UltraCompare软件的一些主要特点和功能&…...
XML Schema 的extension 元素
XML Schema 的extension 元素对complexContent、simpleContent元素进行扩展。 例如,下面通过增加了两个属性,对simpleContent进行了扩展: <xs:element name"condition" maxOccurs"unbounded" minOccurs"0"…...
每日一题2023.11.26——打印沙漏【PTA】
题目要求: 本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印 ************ *****所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;…...
【C++】类和对象——拷贝构造和赋值运算符重载
上一篇我们讲了构造函数,就是对象实例化时会自动调用,那么,我们这里的拷贝构造在形式上是构造函数的一个重载,拷贝构造其实也是一种构造函数,那么我们就可以引出这里的规则 1.拷贝构造函数的函数名必须与类名相同。 2.…...
基于acme免费申请泛域名证书
参考文档:https://github.com/acmesh-official/acme.sh 文章目录 step1: 获取阿里云的ak、skstep2: 安装acmestep3: 安装通配符证书step4: 查看证书step5: 证书的使用step6: 删除证书 step1: 获取阿里云的ak、sk export Ali_Key"LTAI5tG8888888CDoEjLzkE"…...
系列十九、Spring实例化bean的方式
一、概述 所谓实例化bean,大白话讲就是Spring如何把这一个个的普通的Java对象创建为Spring bean的。 二、方式 Spring中实例化bean常用的有以下四种,即: ① 构造器方式; ② 静态工厂方式; ③ 实例工厂方式;…...
WordPress无插件实现css、js加速 实现动静态分离
“Wordpress网站现在普遍较慢”,其实是没有做好优化罢了,像我的网站生成页面的时间才0.06s,而且我这网站还有提速的机会呢,如css、js使用CDN加速,实现动静态分离,我安装过,Memcache和PHP加速脚本就已经让我…...
2017年五一杯数学建模B题自媒体时代的消息传播问题解题全过程文档及程序
2017年五一杯数学建模 B题 自媒体时代的消息传播问题 原题再现 电视剧《人民的名义》中人物侯亮平说:“现在是自媒体时代,任何突发性事件几分钟就传播到全世界。”相对于传统媒体,以互联网技术为基础的自媒体以其信息传播的即时性、交往方式…...
虹科分享 | AR世界揭秘:从二维码的起源到数据识别与位姿技术的奇妙融合!
引言:探索AR的神奇世界,我们将从二维码的诞生谈起。在这个科技的海洋中,二维码是如何帮助AR实现数据获取与位姿识别的呢?让我们一起揭开这层神秘的面纱! 一、二维码的由来 二维码是将数据存储在图形中的技术ÿ…...
基于helm部署并配置StorageClass
此类方法适用于测试环境或者小型的集群环境,因为nfs是网络文件系统,在io性能上并不能有所保证。 前置条件: 已部署k8s集群已安装helm 工具 step1: 安装nfs服务 yum install nfs-utils -ystep2: 配置nfs # 编辑/etc/exports /data/nfs *(r…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
基于鸿蒙(HarmonyOS5)的打车小程序
1. 开发环境准备 安装DevEco Studio (鸿蒙官方IDE)配置HarmonyOS SDK申请开发者账号和必要的API密钥 2. 项目结构设计 ├── entry │ ├── src │ │ ├── main │ │ │ ├── ets │ │ │ │ ├── pages │ │ │ │ │ ├── H…...
Java中HashMap底层原理深度解析:从数据结构到红黑树优化
一、HashMap概述与核心特性 HashMap作为Java集合框架中最常用的数据结构之一,是基于哈希表的Map接口非同步实现。它允许使用null键和null值(但只能有一个null键),并且不保证映射顺序的恒久不变。与Hashtable相比,Hash…...
