1.SpringMVC的引言

为了使Spring可插入的MVC架构,SpringFrameWork在Spring基础上开发SpringMVC框架,从而在使用Spring进行WEB开发时可以选择使用Spring的SpringMVC框架作为web开发的控制器框架。==注:底层使用的还是servlet==

2.为什么是SpringMVC?

  • 可以和spring框架无缝整合
  • 运行效率高于struts2框架
  • 注解式开发更高效

3.SpringMVC的特点

SpringMVC 轻量级,典型MVC框架,在整个MVC架构中充当控制器框架,相对于之前学习的struts2框架,SpringMVC运行更快,其注解式开发更高效灵活

img

4.SpringMVC与Struts2运行流程对比

img

5.第一个环境搭建

5.1思路

img

5.2代码实现

新建Maven-webapp项目,添加java、resources目录以及test路径下java、resources目录

引入相关依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<!--spring核心及相关依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>

<!--springmvc核心依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>

<!--servlet-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>

<!--jstl-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>

编写springmvc.xml配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?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.study.controller"/>

<!-- &lt;!&ndash;注册处理器映射器&ndash;&gt;-->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>-->
<!-- &lt;!&ndash;注册处理器适配器&ndash;&gt;-->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>-->
<!--【推荐使用】注册处理器映射器、注册处理器适配器,完成参数类型转转、跳转、响应处理...-->
<mvc:annotation-driven/>

<!--注册视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--注入前缀和后缀:前缀和后缀固定写死,制可以根据项目页面目录动态变化-->
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>

注意: 这里还要加载springmvc配置文件位置,通过在servlet写init-­param标签,还是contextConfigLocation属性,value用来加载springmvc配置文件。

创建控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.study.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
* @ClassName HelloController
* @Description TODO
* @Author chabai
* @Date 2022/4/20 16:01
* @Version 1.0
*/
@Controller
@RequestMapping("/hello")
public class HelloController {
/**
* @RequestMapping 修饰范围: 用在 类上 和 方法上
* 1.用在方法上用来给当前方法加入指定的请求路径 相当于之前struts2中action标签的name属性
* 2.用在类上用来给类中所有方法加入一个统一请求路径在方法访问之前需要加入类上@requestMapping的路径
* 相当于之前struts2中package标签的namespace属性
* 注意: 一旦类上和方法上同时加入@requestMapping访问时必须
* /项目名/类上@requestMapping的路径/访问方法上@requestMapping的路径
*/
//访问路径:http://localhost:8888/springmvc01/hello/find
@RequestMapping(value = "/find")
public String find(){
//1.收集数据
//2.调用业务方法
System.out.println("调用了find方法");
//3.处理响应 注意:一个请求只能对应一个唯一的响应
return "index";//页面逻辑名 对应 index.jsp
}

//访问路径:http://localhost:8888/springmvc01/hello/save
@RequestMapping(value = "/save")
public String save(){
//1.收集数据
//2.调用业务方法
System.out.println("调用了save方法");
//3.处理响应
return "index";//页面逻辑名 对应 index.jsp
}
}

@Controller: 该注解用来在类上标识这是一个控制器组件类,并创建这个类实例

@RequestMapping:

​ 修饰范围 : 用在方法或者类上

​ 注解作用: 用来指定类以及类中方法的请求路径

​ 注解详解 :

​ 用在类上相当于struts2中namespace在访问类中方法必须先加入这个路径

​ 用在方法上相当于action标签的name属性用来表示访问这个方法的路径

部署项目在tomcat服务器上进行测试

image-20240324172653946

启动项目进行测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
D:\Software_Development\IDEA_code\apache-tomcat-8.5.78\bin\catalina.bat run
[2022-04-20 04:42:56,645] Artifact springmvc01:war exploded: Waiting for server connection to start artifact deployment...
Using CATALINA_BASE: "C:\Users\cjn\AppData\Local\JetBrains\IntelliJIdea2020.1\tomcat\Unnamed_springmvc01"
Using CATALINA_HOME: "D:\Software_Development\IDEA_code\apache-tomcat-8.5.78"
Using CATALINA_TMPDIR: "D:\Software_Development\IDEA_code\apache-tomcat-8.5.78\temp"
Using JRE_HOME: "D:\Software_Development\JDK"
Using CLASSPATH: "D:\Software_Development\IDEA_code\apache-tomcat-8.5.78\bin\bootstrap.jar;D:\Software_Development\IDEA_code\apache-tomcat-8.5.78\bin\tomcat-juli.jar"
Using CATALINA_OPTS: ""
......
Connected to server
[2022-04-20 04:42:58,218] Artifact springmvc01:war exploded: Artifact is being deployed, please wait...
......
[2022-04-20 04:42:59,430] Artifact springmvc01:war exploded: Artifact is deployed successfully
[2022-04-20 04:42:59,430] Artifact springmvc01:war exploded: Deploy took 1,212 milliseconds
...
调用了find方法
调用了save方法

访问路径 :

http://localhost:8888/springmvc01/hello/find

http://localhost:8888/springmvc01/hello/save

image-20240324172738717

与此同时,控制台输出“调用了xxx方法”

6.SpringMVC中跳转方式

6.0 概述

img

img

6.1 跳转方式

  • 说明 : 跳转方式有两种,一种是forward,一种是redirect
    • forward跳转,一次请求,地址栏不变
    • redirect跳转,多次请求,地址栏改变

image-20240324172933887

6.2 编写代码启动tomcat服务器进行测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package com.study.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
* @ClassName ForwardAndRedirectController
* @Description TODO
* @Author chabai
* @Date 2022/4/21 10:57
* @Version 1.0
*/
@Controller
@RequestMapping("forwardAndRedirect")
public class ForwardAndRedirectController {
/**
* @MethodName test
* @Description 测试forward跳转到页面
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/21 11:03
*/
@RequestMapping("test")
public String test(){
System.out.println("测试forward跳转到页面");
return "index";
/**
* 访问路径:http://localhost:8888/springmvc01/forwardAndRedirect/test
* 输出结果分析:
* 不写时默认forward跳转,即从controller跳转到页面
* 地址栏:不变,仍为 http://localhost:8888/springmvc01/forwardAndRedirect/test
* jsp页面:index.jsp(即原始默认输出Hello World!的页面)
* 控制台输出:测试forward跳转到页面
*/
}

/**
* @MethodName test1
* @Description 测试redirect跳转到页面
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/21 11:04
*/
@RequestMapping("test1")
public String test1(){
System.out.println("测试redirect跳转到页面");
return "redirect:/index.jsp";
/**
* 访问路径:http://localhost:8888/springmvc01/forwardAndRedirect/test1
* 输出结果分析:
* 地址栏:经redirect改变一次,变为 http://localhost:8888/springmvc01/index.jsp
* jsp页面:index.jsp
* 控制台输出:测试redirect跳转到页面
*/
}

/**
* @MethodName test2
* @Description 测试forward跳转到相同controller类中的不同方法
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/21 11:11
*/
@RequestMapping("test2")
public String test2(){
System.out.println("测试forward跳转到相同controller类中的不同方法");
return "forward:/forwardAndRedirect/test";
/**
* 访问路径:http://localhost:8888/springmvc01/forwardAndRedirect/test2
* 输出结果分析:
* 地址栏:不改变,仍为 http://localhost:8888/springmvc01/forwardAndRedirect/test2
* jsp页面:index.jsp
* 控制台输出:测试forward跳转到相同controller类中的不同方法
* 测试forward跳转到页面
*/
}

/**
* @MethodName test3
* @Description 测试redirect跳转到相同controller类中的不同方法
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/21 11:15
*/
@RequestMapping("test3")
public String test3(){
System.out.println("测试redirect跳转到相同controller类中的不同方法");
return "redirect:/forwardAndRedirect/test";
/**
* 访问路径:http://localhost:8888/springmvc01/forwardAndRedirect/test3
* 输出结果分析:
* 地址栏:经redirect改变一次,变为 http://localhost:8888/springmvc01/forwardAndRedirect/test
* jsp页面:index.jsp
* 控制台输出:测试redirect跳转到相同controller类中的不同方法
* 测试forward跳转到页面
*/
}

/**
* @MethodName test4
* @Description 测试forward跳转到不同controller类中的不同方法
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/21 11:18
*/
@RequestMapping("test4")
public String test4(){
System.out.println("测试forward跳转到不同controller类中的不同方法");
return "forward:/hello/find";
/**
* 访问路径:http://localhost:8888/springmvc01/forwardAndRedirect/test4
* 输出结果分析:
* 地址栏:不改变,仍为 http://localhost:8888/springmvc01/forwardAndRedirect/test4
* jsp页面:index.jsp
* 控制台输出:测试forward跳转到不同controller类中的不同方法
* 调用了find方法
*/
}

/**
* @MethodName test5
* @Description 测试redirect跳转到不同controller类中的不同方法
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/21 11:24
*/
@RequestMapping("test5")
public String test5(){
System.out.println("测试redirect跳转到不同controller类中的不同方法");
return "redirect:/hello/find";
/**
* 访问路径:http://localhost:8888/springmvc01/forwardAndRedirect/test5
* 输出结果分析:
* 地址栏:经redirect改变一次,变为 http://localhost:8888/springmvc01/hello/find
* jsp页面:index.jsp
* 控制台输出:测试redirect跳转到不同controller类中的不同方法
* 调用了find方法
*/
}
}

7. SpringMVC中参数接收

image-20240331181615140

接收参数语法说明:springmvc中使用控制器方法参数来收集客户端的请求参数,因此在接收请求参数时直接在需要的控制器方法中声明即可,springmvc可以自动根据指定类型完成类型的转换操作。

7.1 接收零散类型参数

如: 八种基本类型 + String + 日期类型

a.前台传递参数

1
2
3
4
5
6
7
8
9
10
11
12
13
# GET 方式传递参数
http://localhost:8080/springmvc_day1/param/test?name=zhangsan&age=19&sex=true&salary=11.11&bir=2012/12/12

# POST 方式传递参数
<h1>测试参数接收</h1>
<form action="${pageContext.request.contextPath}/param/test" method="post">
用户名: <input type="text" name="name"/> <br>
年龄: <input type="text" name="age"/> <br>
性别: <input type="text" name="sex"> <br>
工资: <input type="text" name="salary"> <br>
生日: <input type="text" name="bir"> <br>
<input type="submit" value="提交"/>
</form>

b.后台控制器接收

1
2
3
4
5
6
7
8
9
10
11
12
13
@Controller
@RequestMapping("/param")
public class ParamController {
@RequestMapping("/test")
public String test(String name, Integer age, Boolean sex,Double salary,Date bir){
System.out.println("姓名: "+name);
System.out.println("年龄: "+age);
System.out.println("性别: "+sex);
System.out.println("工资: "+salary);
System.out.println("生日: "+bir);
return "index";
}
}

注意:springmvc在接收日期类型参数时日期格式必须为yyyy/MM/dd HH:mm:ss

7.2 接收对象类型参数

a.前台传递参数

1
2
3
4
5
6
7
8
9
10
11
12
13
# GET 方式请求参数传递
http://localhost:8080/springmvc_day1/param/test1?name=zhangsan&age=19&sex=true&salary=11.11&bir=2012/12/12

# POST 方式请求参数传递
<h1>测试对象类型参数接收</h1>
<form action="${pageContext.request.contextPath}/param/test1" method="post">
用户名: <input type="text" name="name"/> <br>
年龄: <input type="text" name="age"/> <br>
性别: <input type="text" name="sex"> <br>
工资: <input type="text" name="salary"> <br>
生日: <input type="text" name="bir"> <br>
<input type="submit" value="提交"/>
</form>

注意:在接收对象类型参数时和struts2接收不同,springmvc直接根据传递参数名与对象中属性名一致自动封装对象

b.后台控制器接收

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

// 1.定义对象
public class User {
private String name;
private Integer age;
private Double salary;
private Boolean sex;
private Date bir;
}

// 2.控制器中接收
@RequestMapping("/test1")
public String test1(User user){
System.out.println("接收的对象: "+user);
return "index";
}

// 2.2的特殊情况
@RequestMapping("/test1") //都赋值
public String test1(User user ,String name){
System.out.println("接收的对象: "+user);
return "index";
}

7.3 接收数组类型参数

a.前台传递参数

1
2
3
4
5
6
7
8
9
10
11
12
13
# GET 方式请求参数传递
http://localhost:8080/springmvc_day1/param/test2?names=zhangsan&names=lisi&names=wangwu

# POST 方式请求参数传递
<h1>测试对象类型参数接收</h1>
<form action="${pageContext.request.contextPath}/param/test2" method="post">
爱好: <br>
看书: <input type="checkbox" name="names"/>
看电视:<input type="checkbox" name="names"/>
吃饭: <input type="checkbox" name="names"/>
玩游戏: <input type="checkbox" name="names"/>
<input type="submit" value="提交"/>
</form>

b.后台控制器接收

1
2
3
4
5
6
7
@RequestMapping("/test2")
public String test2(String[] names){
for (String name : names) {
System.out.println(name);
}
return "index";
}

注意:接收数组类型数据时前台传递多个key一致自动放入同一个数组中

7.4 接收集合类型参数

说明:springmvc不支持直接将接收集合声明为控制器方法参数进行接收,如果要接收集合类型参数必须使用对象封装要接收接收类型才可以,推荐放入vo对象中接收集合类型,即新创建vo包,包中自定义集合

7.4.1 list集合

a.前台传递参数

1
2
3
4
5
6
7
8
9
10
11
12
13
# GET 方式请求参数传递
http://localhost:8080/springmvc_day1/param/test3?lists=zhangsan&lists=lisi&lists=wangwu

# POST 方式请求参数传递
<h1>测试对象类型参数接收</h1>
<form action="${pageContext.request.contextPath}/param/test3" method="post">
爱好: <br>
看书: <input type="checkbox" name="lists"/>
看电视:<input type="checkbox" name="lists"/>
吃饭: <input type="checkbox" name="lists"/>
玩游戏: <input type="checkbox" name="lists"/>
<input type="submit" value="提交"/>
</form>

b.后台控制器接收

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 1.封装接收集合类型对象---->在spring mvc中用来接收集合类型参数
public class CollectionVO {
private List<String> lists;

public List<String> getLists() {
return lists;
}

public void setLists(List<String> lists) {
this.lists = lists;
}
}

// 2.控制器中接收集合类型参数
@RequestMapping("/test3")
public String test3(CollectionVO collectionVO){
collectionVO.getLists().forEach(name-> System.out.println(name));
return "index";
}

7.4.2map集合

a.前台传递参数

1
2
访问路径:http://localhost:8888/springmvc01/param/test4?maps['a']=吃饭&maps['b']=睡觉&maps['c']=打豆豆
注意:在url中对参数进行赋值的时候要给CollectionVO中的集合赋值而不是collectionVO赋值

b.后台控制器接收

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
    public class CollectionVO {
private Map<String,String> maps;

public Map<String, String> getMaps() {
return maps;
}

public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
}
/**
* @MethodName test4
* @Description 用来测试map集合类型参数接收
* @param: collectionVO
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/21 16:21
*/
@RequestMapping("test4")
public String test4(CollectionVO collectionVO){
System.out.println("用来测试map集合类型参数接收");
collectionVO.getMaps().forEach((k,v)-> System.out.println("k=" + k+",v="+v));
return "index";
/**
* 访问路径:http://localhost:8888/springmvc01/param/test4?maps['a']=吃饭&maps['b']=睡觉&maps['c']=打豆豆
* 注意:在url中对参数进行赋值的时候要给CollectionVO中的集合赋值而不是collectionVO赋值
* 输出结果:
* 用来测试map集合类型参数接收
* k= a,v= 吃饭
* k= b,v= 睡觉
* k= c,v= 打豆豆
*/
}

7.5 代码实测

User

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package com.study.entity;

import java.util.Date;

/**
* @ClassName User
* @Description TODO
* @Author chabai
* @Date 2022/4/21 15:37
* @Version 1.09
*/
public class User {
private String name;
private Integer age;
private Boolean sex;
private Double salary;
private Date bir;

public User() {
}

public User(String name, Integer age, Boolean sex, Double salary, Date bir) {
this.name = name;
this.age = age;
this.sex = sex;
this.salary = salary;
this.bir = bir;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public Boolean getSex() {
return sex;
}

public void setSex(Boolean sex) {
this.sex = sex;
}

public Double getSalary() {
return salary;
}

public void setSalary(Double salary) {
this.salary = salary;
}

public Date getBir() {
return bir;
}

public void setBir(Date bir) {
this.bir = bir;
}

@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
", salary=" + salary +
", bir=" + bir +
'}';
}
}

CollectionVO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.study.vo;

import com.study.entity.User;

import java.util.List;
import java.util.Map;

/**
* @ClassName CollectionVO
* @Description 自定义VO对象
* @Author chabai
* @Date 2022/4/21 15:38
* @Version 1.0
*/
public class CollectionVO {
private List<String> lists;
private Map<String,String> maps;

public List<String> getLists() {
return lists;
}

public void setLists(List<String> lists) {
this.lists = lists;
}

public Map<String, String> getMaps() {
return maps;
}

public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
}

ParamController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package com.study.controller;

import com.study.entity.User;
import com.study.vo.CollectionVO;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Date;

/**
* @ClassName ParamController
* @Description TODO
* @Author chabai
* @Date 2022/4/21 15:36
* @Version 1.0
*/
@Controller
@RequestMapping("param")
public class ParamController {
/**
* @MethodName test
* @Description 用来测试零散类型参数接收
* @param: name
* @param: age
* @param: sex
* @param: salary
* @param: bir
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/21 15:44
*/
@RequestMapping("test")
public String test(String name, Integer age, Boolean sex, Double salary, Date bir){
System.out.println("用来测试零散类型参数接收");
System.out.println("name = " + name);
System.out.println("age = " + age);
System.out.println("sex = " + sex);
System.out.println("salary = " + salary);
System.out.println("bir = " + bir);
return "index";
/**
* 访问路径:http://localhost:8888/springmvc01/param/test?name=张三&age=20&sex=true&salary=1234.5&bir=2020/12/12 12:34:56
* 输出结果:
* 用来测试零散类型参数接收
* name = 张三
* age = 20
* sex = true
* salary = 1234.5
* bir = Sat Dec 12 12:34:56 CST 2020
*
* 注意:
* 日期默认格式:yyyy/MM/dd HH:mm:ss
*/
}

/**
* @MethodName test1
* @Description 用来测试对象类型的参数接收
* @param: user
* @param: name
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/21 15:50
*/
@RequestMapping("test1")
public String test1(User user,String name){
System.out.println("用来测试对象类型的参数接收");
System.out.println("user = " + user);
System.out.println("name = " + name);
return "index";
/**
* 访问路径:http://localhost:8888/springmvc01/param/test1?name=张三&age=20&sex=true&salary=1234.5&bir=2020/12/12 12:34:56
* 输出结果:
* 用来测试对象类型的参数接收
* user = User{name='张三', age=20, sex=true, salary=1234.5, bir=Sat Dec 12 12:34:56 CST 2020}
* name = 张三
*
* 注意:
* 此处的User中的name属性和变量name都会赋值
*
* 总结:
* 接收对象类型: 也是直接将要接收对象作为控制器方法参数声明
* 注意:springmvc封装对象时直接根据传递参数key与对象中属性名一致自动封装对象
* url提交: http://localhost:8888/springmvc01/param/test1?name=张三&age=20&sex=true&salary=1234.5&bir=2020/12/12 12:34:56
* form表单提交:
* input name="id"
* input name="name"
* input name="age"
* ....
*/
}

/**
* @MethodName test2
* @Description 用来测试数组类型的参数接收
* @param: collectionVO
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/21 15:55
*/
@RequestMapping("test2")
public String test2(String[] arrays){
System.out.println("用来测试数组类型的参数接收");
for (String array : arrays) {
System.out.println("array = " + array);
}
return "index";
/**
* 访问路径:http://localhost:8888/springmvc01/param/test2?arrays=吃饭&arrays=睡觉&arrays=打豆豆
* 输出结果:
* 用来测试数组类型的参数接收
* arrays = 吃饭
* arrays = 睡觉
* arrays = 打豆豆
*
* 总结:
* 接收数组: 将要接收数组类型直接声明为方法的形参即可
* 注意: 保证请求参数多个参数key与声明数组变量名一致,springmvc会自动放入同一个数组中
* url提交: http://localhost:8888/springmvc01/param/test2?arrays=吃饭&arrays=睡觉&arrays=打豆豆
* form表单提交中多用于checkbox
* input type="checkbox" name="arrays" value="卖吃饭"
* input type="checkbox" name="arrays" value="睡觉"
* input type="checkbox" name="qqs" value="打豆豆"
* ....
*/
}

/**
* @MethodName test3
* @Description 用来测试list集合类型参数接收
* @param: collectionVO
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/21 16:08
*/
@RequestMapping("test3")
public String test3(CollectionVO collectionVO){
System.out.println("用来测试list集合类型参数接收");
collectionVO.getLists().forEach(list -> System.out.println("list = " + list));
return "index";
/**
* 访问路径:http://localhost:8888/springmvc01/param/test3?lists=吃饭&lists=睡觉&lists=打豆豆
* 注意:在url中对参数进行赋值的时候要给CollectionVO中的集合赋值而不是collectionVO赋值
* 输出结果:
* 用来测试list集合类型参数接收
* list = 吃饭
* list = 睡觉
* list = 打豆豆
*
* 总结:
* springmvc不能直接通过形参列表方式收集集合类型参数
* 如果要接收集合类型的参数必须将集合放入对象中接收才可以,推荐放入vo对象中接收集合类型,即新创建vo包,包中自定义集合
* vo = value object 值对象
*/
}

/**
* @MethodName test4
* @Description 用来测试map集合类型参数接收
* @param: collectionVO
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/21 16:21
*/
@RequestMapping("test4")
public String test4(CollectionVO collectionVO){
System.out.println("用来测试map集合类型参数接收");
collectionVO.getMaps().forEach((k,v)-> System.out.println("k=" + k+",v="+v));
return "index";
/**
* 访问路径:http://localhost:8888/springmvc01/param/test4?maps[1]=吃饭&maps[2]=睡觉&maps[3]=打豆豆
* 注意:在url中对参数进行赋值的时候要给CollectionVO中的集合赋值而不是collectionVO赋值
* 输出结果:
* 用来测试map集合类型参数接收
* k= 1,v= 吃饭
* k= 2,v= 睡觉
* k= 3,v= 打豆豆
*/
}
}

如果map传递参数时出现400错误,如下所示:

img

解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 如果测试时出现HTTP状态 400-错误的请求,是因为日志显示请求地址中包含了不合法字符.
tomcat高版本严格按照RFC 3986规范解析地址。该规范只允许包含a-z A-Z 0-9 - _ . ~
以及所有保留字符 ! * ’ ( ) ; : @ & = + $ , / ? # [ ]

解决方案:在使用的tomcat文件夹中找到conf,打开后对server.xml进行编辑,在
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"/>
后面加上relaxedPathChars="|{}[],%" relaxedQueryChars="|{}[],%",其余不用修改,即:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" relaxedPathChars="|{}[],%" relaxedQueryChars="|{}[],%"/>
保存后,重启tomcat即可解决。
参考链接:https://blog.51cto.com/u_15196075/2765608

image-20240324175449385

img

7.6 表单传递接收参数中文乱码解决方案

7.6.1概述

img

7.6.2问题

param.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>测试参数接收</title>
</head>
<body>
<h1>测试对象和零散类型参数接收</h1>
<form action="${pageContext.request.contextPath}/param/test1" method="post">
用户姓名:<input type="text" name="name"><br>
用户年龄:<input type="text" name="age"><br>
用户性别:<input type="text" name="sex"><br>
用户收入:<input type="text" name="salary"><br>
用户生日:<input type="text" name="bir"><br>
<input type="submit" value="提交">
</form>
</body>
</html>

测试路径:http://localhost:8888/springmvc01/param.jsp

测试结果:

1
2
3
4
5
6
7
8
9
1.英文状态
用来测试对象类型的参数接收
user = User{name='xiaosan', age=20, sex=false, salary=1000.0, bir=Mon Dec 12 00:00:00 CST 2022}
name = xiaosan

2.中文状态
用来测试对象类型的参数接收
user = User{name='?°?è??', age=22, sex=true, salary=800.0, bir=Thu Mar 15 00:00:00 CST 2018}
name = ?°?è??

注意:在使用springmvc接收客户端的请求参数的过程中有时会出现中文乱码问题,这是因为springmvc并没有对对象请求参数进行编码控制,如果需要控制需要自行指定

7.6.3解决具体实现

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1.针对于GET方式中文乱码解决方案:tomcat8以前会出现,server.xml配置文件加URIEncoding="UTF-8"即可解决,8之后不会出现
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>

# 2.针对POST方式中文乱码解决方案:
web.xml中配置字符Filter
<!--配置post请求方式中文乱码的Filter-->
<filter>
<filter-name>charset</filter-name>
<!--自定义的Filter必须配合自定义的类使用-->
<!-- <filter-class>com.study.filter.CharacterEncodingFilter</filter-class>-->
<!--spring框架提供的Filter ,下边类就不用写了-->
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>charset</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

自定义编码Filter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 
package com.study.filter;

import javax.servlet.*;
import java.io.IOException;

/**
* @ClassName CharacterEncodingFilter
* @Description 自定义编码Filter
* @Author chabai
* @Date 2022/4/22 15:51
* @Version 1.0
*/
public class CharacterEncodingFilter implements Filter {
private String encoding;

@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.encoding = filterConfig.getInitParameter("encoding");
System.out.println(encoding);
}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding(encoding);
servletResponse.setCharacterEncoding(encoding);
filterChain.doFilter(servletRequest,servletResponse);
}

@Override
public void destroy() {

}
}

7.7 参数接收总结

img

8.SpringMVC中数据传递机制

其实数据传递机制学完就可整合了 这里学完收参,传递数据,跳转我们都会了,就剩调用业务,结合mybatis和spring即可完成。

==springmvc是一个控制器,对于一个控制器我们就关注三件事:收集数据,调业务对象,流程跳转,==调用业务对象和流程跳转这两步里其实还隐藏了一步===》数据传递过程

8.0概述

img

8.1 数据传递机制

1
2
3
4
5
6
# 1.数据怎么存
Servlet 作用域 Struts2 作用域 SpringMVC 作用域
# 2.数据怎么取
Servlet EL表达式 Struts2 EL表达式 SpringMVC EL表达式
# 3.数据怎么展示
Servlet JSTL标签 Struts2 JSTl标签 SpringMVC JSTL标签

8.2 使用forward跳转传递数据

1
2
3
4
5
6
# 1.使用servlet中原始的request作用域传递数据
request.setAttribute("key",value);

# 2.使用是springmvc中封装的Model和ModelMap对象(底层对request作用域封装)
model.addAttribute(key,value);
modelMap.addAttribute(key,value);

8.3 使用Redirect跳转传递数据

1
2
3
4
5
6
# 1.使用地址栏进行数据传递
url?name=zhangsan&age=21

# 2.使用session作用域
session.setAttribute(key,value);
session.getAttribute(key);

8.4如何在springmvc控制器方法获取request对象,response对象

直接做为控制器方法参数声明即可

8.5 代码测试

AttributeController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package com.study.controller;

import com.study.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
* @ClassName AttributeController
* @Description 用来测试SpringMVC中的数据传递机制
* @Author chabai
* @Date 2022/4/22 20:40
* @Version 1.0
*/
@Controller
@RequestMapping("attribute")
public class AttributeController {
/**
* 使用forward跳转页面数据传递
* 1.传递零散类型数据
* 2.传递对象类型数据
* 3.传递集合类型数据
*
* 可以使用request对象进行数据传递,也可以使用model对象进行数据传递,其底层封装的也是request对象
*/
@RequestMapping("test")
public String test(Model model,HttpServletRequest request, HttpServletResponse response){
//1.收集参数
//2.调用业务方法

//传递零散类型数据
String name = "茶白";
//request.setAttribute("name",name);
model.addAttribute("name",name);

//传递对象类型数据
User user = new User("光头强",50,true,12.12,new Date());
//request.setAttribute("user",user);
model.addAttribute("user",user);

//传递集合类型数据
User user1 = new User("熊大",30,true,6.06,new Date());
User user2 = new User("熊二",20,true,3.03,new Date());
List<User> users = Arrays.asList(user1, user2);//asList可以快速把一些对象转成集合
//request.setAttribute("users",users);
model.addAttribute("users",users);

//3.流程跳转
return "attribute";
}

/**
* 使用redirect跳转传递数据
* 传递数据的方式有2种:
* 1.地址栏?拼接数据 适用数据比较少情况
* 2.session对象
*/
@RequestMapping("test1")
public String test1(HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException {
//1.收集数据
//2.调用业务
String name = "小猫";

User user = new User("小猪", 3, false, 0.1234, new Date());
User user1 = new User("小狗", 4, false, 1.2345, new Date());
User user2 = new User("小兔", 5, false, 2.3456, new Date());
List<User> users = Arrays.asList(user1, user2);
request.getSession().setAttribute("user",user);
request.getSession().setAttribute("users",users);

//3.流程跳转
return "redirect:/attribute.jsp?name=" + URLEncoder.encode(name,"UTF-8");
}
}

attribute.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>测试数据传递</title>
</head>
<body>
<h1>用来测试request作用域传递数据</h1>
获取request作用域数据:${requestScope.name}<br>
获取request作用域数据:${name}<br>

<hr color="red">
name:${requestScope.user.name}<br>
age:${requestScope.user.age}<br>
sex:${requestScope.user.sex}<br>
salary:${requestScope.user.salary}<br>
<!--bir: ${user.bir}<br> 要格式化的话就要借助c标签 ,别忘了引依赖jstl-->
bir:<fmt:formatDate value="${requestScope.user.bir}" pattern="yyyy-MM-dd"/></h3>

<hr>
<c:forEach items="${requestScope.users}" var="user">
name:${user.name}<br>
age: ${user.age}<br>
sex: ${user.sex}<br>
salary: ${user.salary}<br>
bir: <fmt:formatDate value="${user.bir}"/><br>
<hr>
</c:forEach>

<br>

<h1>测试使用redirect跳转传递数据</h1>
获取地址栏数据:${param.name}<br>

<hr color="red">
name: ${sessionScope.user.name}<br>
age: ${sessionScope.user.age}<br>
sex: ${sessionScope.user.sex}<br>
salary: ${sessionScope.user.salary}<br>
bir: ${sessionScope.user.bir}<br>
<hr>

<c:forEach items="${sessionScope.users}" var="user">
name:${user.name}<br>
age: ${user.age}<br>
sex: ${user.sex}<br>
salary: ${user.salary}<br>
bir: <fmt:formatDate value="${user.bir}"/><br>
<hr>
</c:forEach>
</body>
</html>

测试结果:

(1)http://localhost:8888/springmvc01/attribute/test

img

(2)http://localhost:8888/springmvc01/attribute/test1

img

9.SpringMVC处理静态资源拦截

img

10.Spring+SpringMVC+MyBatis整合编程

整合思路

img

代码实现:

1.新建maven-webapp工程,添加java、resources目录及test目录下的java、resources

2.引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<!--spring核心及相关依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>

<!--springmvc核心依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>

<!--servlet-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>

<!--jstl-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>

<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.3</version>
</dependency>

<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>

<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.17</version>
</dependency>

<!--log4j-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>

<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency

3.Spring+Mybatis整合

3.1 新建表

img

3.2 新建实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
 
package com.study.entity;

import java.util.Date;

/**
* @ClassName User
* @Description TODO
* @Author chabai
* @Date 2022/4/23 10:46
* @Version 1.0
*/
public class User {
private String id;
private String name;
private Integer age;
private Date bir;

@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", bir=" + bir +
'}';
}

public User() {
}

public User(String id, String name, Integer age, Date bir) {
this.id = id;
this.name = name;
this.age = age;
this.bir = bir;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public Date getBir() {
return bir;
}

public void setBir(Date bir) {
this.bir = bir;
}
}

3.3 新建DAO接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.study.dao;

import com.study.entity.User;

import java.util.List;

/**
* @ClassName UserDAO
* @Description TODO
* @Author chabai
* @Date 2022/4/23 10:45
* @Version 1.0
*/
public interface UserDAO {

/**
* @MethodName selectAllUsers
* @Description 查询所有用户
* @return: java.util.List<com.study.entity.User>
* @Author chabai
* @Date 2022/4/23 10:50
*/
List<User> selectAllUsers();

/**
* @MethodName insertUser
* @Description 添加用户
* @param: user
* @Author chabai
* @Date 2022/4/23 10:49
*/
void insertUser(User user);

}

3.4 新建Mapper配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="com.study.dao.UserDAO">
<!--selectAllUsers-->
<select id="selectAllUsers" resultType="User">
select id,name,age,bir from t_user
</select>

<!--insertUser-->
<insert id="insertUser" parameterType="User">
insert into t_user values(#{id},#{name},#{age},#{bir})
</insert>

</mapper>

3.5 新建Service接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.study.service;

import com.study.entity.User;

import java.util.List;

/**
* @ClassName UserService
* @Description TODO
* @Author chabai
* @Date 2022/4/23 10:55
* @Version 1.0
*/
public interface UserService {
/**
* @MethodName selectAllUsers
* @Description 查询所有用户
* @return: java.util.List<com.study.entity.User>
* @Author chabai
* @Date 2022/4/23 10:50
*/
List<User> selectAllUsers();

/**
* @MethodName insertUser
* @Description 添加用户
* @param: user
* @Author chabai
* @Date 2022/4/23 10:49
*/
void insertUser(User user);

}

3.6 新建ServiceImpl实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.study.service;

import com.study.dao.UserDAO;
import com.study.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;

/**
* @ClassName UserServiceImpl
* @Description TODO
* @Author chabai
* @Date 2022/4/23 10:55
* @Version 1.0
*/
@Service("userService")
@Transactional
public class UserServiceImpl implements UserService{
@Autowired
private UserDAO userDAO;

@Override
@Transactional(propagation = Propagation.SUPPORTS)
public List<User> selectAllUsers() {
return userDAO.selectAllUsers();
}

@Override
public void insertUser(User user) {
user.setId(UUID.randomUUID().toString());
userDAO.insertUser(user);
}
}

3.7 引入spring.xml配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?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:tx="http://www.springframework.org/schema/tx"
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/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--开启注解扫描-->
<context:component-scan base-package="com.study"/>

<!--创建数据源对象-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=UTF-8&amp;useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>

<!--创建SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:com/study/mapper/*.xml"/>
<property name="typeAliasesPackage" value="com.study.entity"/>
</bean>

<!--创建DAO-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.study.dao"/>
</bean>

<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<!--开启注解式事务生效-->
<tx:annotation-driven transaction-manager="transactionManager"/>

</beans>

3.8 引入log4j.properties

1
2
3
4
5
6
7
log4j.rootLogger=ERROR,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.conversionPattern=[%p] %d{yyyy-MM-dd} %m%n

log4j.logger.com.study.dao=DEBUG
log4j.logger.org.springframework=ERROR

3.9 测试Service方法是否可以成功调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.study.test;

import com.study.entity.User;
import com.study.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

/**
* @ClassName TestUserService
* @Description TODO
* @Author chabai
* @Date 2022/4/23 11:11
* @Version 1.0
*/
public class TestUserService {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
List<User> users = userService.selectAllUsers();
for (User user : users) {
System.out.println("user = " + user);
}
}
}

测试结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[DEBUG] 2022-04-23 ==>  Preparing: select id,name,age,bir from t_user 
[DEBUG] 2022-04-23 ==> Parameters:
[DEBUG] 2022-04-23 <== Total: 18
user = User{id='1', name='张三', age=10, bir=Fri Apr 01 00:00:00 CST 2022}
user = User{id='2', name='李四', age=20, bir=Sat Apr 02 00:00:00 CST 2022}
user = User{id='2d237778-835d-477b-9721-fe6f575064b9', name='波比', age=18, bir=Sun Feb 02 00:00:00 CST 2020}
user = User{id='2f278828-6422-432d-ab1b-a727b33c23bc', name='小胖墩', age=3, bir=Mon Apr 11 21:43:57 CST 2022}
user = User{id='3', name='王五', age=30, bir=Sun Apr 03 00:00:00 CST 2022}
user = User{id='4', name='灰太狼', age=60, bir=Sun Apr 10 09:56:17 CST 2022}
user = User{id='5', name='小超超', age=36, bir=Sun Apr 10 09:55:41 CST 2022}
user = User{id='586a5f71-836c-4171-a038-4620fe0f9354', name='葫芦娃', age=5, bir=Tue Apr 12 09:45:17 CST 2022}
user = User{id='6', name='小呆呆', age=60, bir=Sun Apr 10 09:55:43 CST 2022}
user = User{id='7', name='小超超', age=36, bir=Sun Apr 10 09:55:44 CST 2022}
user = User{id='7a1a00aa-1507-461a-95c0-50110d6f4333', name='唐三', age=20, bir=Fri Apr 15 00:00:00 CST 2022}
user = User{id='8', name='胖嘟嘟', age=50, bir=Sun Apr 10 09:55:39 CST 2022}
user = User{id='8a3e8ab8-5abc-44e1-9aec-31f3978d97f2', name='小胖墩', age=3, bir=Tue Apr 12 10:23:33 CST 2022}
user = User{id='9', name='茶白', age=25, bir=Sun Apr 10 09:55:52 CST 2022}
user = User{id='985cd035-dedc-4e84-973a-a5fdaa2b8475', name='喜洋洋', age=8, bir=Tue Oct 10 00:00:00 CST 2000}
user = User{id='a6be9263-f05f-415f-855e-33843b22e71d', name='皮卡丘', age=10, bir=Thu Apr 14 00:00:00 CST 2022}
user = User{id='cd280176-68b2-4ceb-b781-ba2f5e1fbeff', name='小胖墩', age=3, bir=Tue Apr 12 10:21:18 CST 2022}
user = User{id='e3863fd3-173c-46f4-a753-c72f7c92ad56', name='小猫咪', age=3, bir=Mon Apr 11 21:36:31 CST 2022}

4.Spring+SpringMVC整合

4.1 配置web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--配置工厂监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!--配置工厂配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</context-param>

<!--配置springmvc核心servlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<!--配置post请求参数的中文乱码问题-->
<filter>
<filter-name>charset</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>charset</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

4.2 引入springmvc.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">

<!--开启注解扫描-->
<context:component-scan base-package="com.study.controller"/>

<!--配置处理映射器和处理适配器-->
<mvc:annotation-driven/>

<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>

<!--解决静态资源拦截的配置-->
<mvc:default-servlet-handler/>
</beans>

4.3 新建Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.study.controller;

import com.study.entity.User;
import com.study.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
* @ClassName UserController
* @Description TODO
* @Author chabai
* @Date 2022/4/23 12:12
* @Version 1.0
*/
@Controller
@RequestMapping("user")
public class UserController {
@Autowired
private UserService userService;

@RequestMapping("selectAllUsers")
public String selectAllUsers(HttpServletRequest request){
//1.收集数据
//2.调用业务对象
List<User> users = userService.selectAllUsers();
request.setAttribute("users",users);
return "selectAllUsers";
}

@RequestMapping("insertUser")
public String insertUser(User user){
//1.收集参数
//2.调用业务方法
try {
userService.insertUser(user);
return "redirect:/user/selectAllUsers";
} catch (Exception e) {
e.printStackTrace();
return "redirect:/insertUser.jsp";
}
}
}

4.4 添加jsp文件

selectAllUsers.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>用来展示所有用户信息</title>
<script src="${pageContext.request.contextPath}/js/jquery-3.5.1.min.js"></script>
<script>
$(function(){
alert();
})
</script>
</head>
<body>
<h1>展示用户列表</h1>
<c:forEach items="${requestScope.users}" var="user">
${user.id} ==== ${user.name} ==== ${user.age} ==== ${user.bir} <br>
</c:forEach>

<a href="${pageContext.request.contextPath}/insertUser.jsp">添加用户信息</a>
</body>
</html>

insertUser.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>添加用户信息</title>
</head>
<body>
<h1>添加用户信息</h1>
<form action="${pageContext.request.contextPath}/user/insertUser" method="post">
姓名:<input type="text" name="name"/> <br>
年龄:<input type="text" name="age"/> <br>
生日:<input type="text" name="bir"/> <br>
<input type="submit" value="保存用户信息">
</form>
</body>
</html>

5.部署tomcat服务器测试

image-20240324181211354

测试结果:

img

6.项目目录结构:

img

11.文件上传

文件上传: 指将用户本地计算机中的文件上传到服务器上。

1.springmvc中文件上传流程:

img

2.代码实现

新建maven-webapp工程,添加java、resources目录

pom.xml引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<!--spring核心及相关依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>

<!--springmvc核心依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!--servlet-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>

<!--jstl-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>

<!--commons-fileupload-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>

<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>

<!--@ResponseBody注解在转换json时使用jackson依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>

配置web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<display-name>Archetype Created Web Application</display-name>

<!--配置post请求方式中文乱码的Filter-->
<filter>
<filter-name>charset</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>charset</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!--配置springmvc核心servlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置springmvc配置文件位置-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

引入springmvc.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--开启注解扫描-->
<context:component-scan base-package="com.study.controller"/>

<!--开启注解驱动-->
<mvc:annotation-driven/>

<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>

<!--配置静态资源拦截-->
<mvc:default-servlet-handler/>

<!--配置文件上传解析器:id必须指定为multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--控制文件上传大小,单位:字节,默认没有大小限制,这里设置为2M-->
<property name="maxUploadSize" value="2097152"/>
</bean>

</beans>

开发上传页面upload.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>测试文件上传</title>
</head>
<body>
<h1>文件上传</h1>
<!--向/file/upload提交请求-->
<form action="${pageContext.request.contextPath}/file/upload" method="post" enctype="multipart/form-data">
<input type="file" name="img"/>
<input type="submit" value="上传文件">
</form>
</body>
</html>

部署到tomcat服务器上进行测试

image-20240324181730799

访问测试页面

image-20240324181743757

开发控制器FileController 处理上传后文件img的接收

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.study.controller;

import org.apache.commons.io.FilenameUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import java.util.UUID;

/**
* @ClassName FileController
* @Description TODO
* @Author chabai
* @Date 2022/4/24 9:24
* @Version 1.0
*/
@Controller
@RequestMapping("file")
public class FileController {

/**
* @MethodName upload
* @Description 测试文件上传
* @param: img
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/24 9:34
*/
@RequestMapping("upload")
public String upload(MultipartFile img, HttpServletRequest request) throws IOException {
//获取上传文件属性
System.out.println("文件原始名称为:" + img.getOriginalFilename());
System.out.println("文件大小:" + img.getSize());
System.out.println("文件类型:" + img.getContentType());

//1.根据upload相对路径获取部署到服务之后的绝对路径
//获取上传路径
String realPath = request.getSession().getServletContext().getRealPath("/upload");
System.out.println("上传路径为:" + realPath);

//2.上传文件到upload对应路径
img.transferTo(new File(realPath,img.getOriginalFilename()));
return "index";//上传完跳转回主页
}
}

访问路径:http://localhost:8888/springmvc02/upload.jsp,选择文件后进行上传

image-20240324181743757

上传成功后跳转到index.jsp页面:

image-20240324181755027

控制台输出文件信息、target目录下出现upload本地上传的文件:

img

3.springmvc中文件上传细节处理:

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package com.study.controller;

import org.apache.commons.io.FilenameUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import java.util.UUID;

/**
* @ClassName FileController
* @Description TODO
* @Author chabai
* @Date 2022/4/24 9:24
* @Version 1.0
*/
@Controller
@RequestMapping("file")
public class FileController {

/**
* @MethodName upload
* @Description 测试文件上传
* @param: img
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/24 9:34
*/
@RequestMapping("upload")
public String upload(MultipartFile img, HttpServletRequest request) throws IOException {
//获取上传文件属性
System.out.println("文件原始名称为:" + img.getOriginalFilename());
System.out.println("文件大小:" + img.getSize());
System.out.println("文件类型:" + img.getContentType());

//1.根据upload相对路径获取部署到服务之后的绝对路径
//获取上传路径
String realPath = request.getSession().getServletContext().getRealPath("/upload");
System.out.println("上传路径为:" + realPath);

//2.修改文件原始名称
//获取原始文件名称
String originalFileName = img.getOriginalFilename();
//获取原始文件后缀 FilenameUtils为工具类,里面提供了一些静态方法
String extension = FilenameUtils.getExtension(originalFileName);
//设置新文件名
String newFileName = UUID.randomUUID().toString().replace("-","") + "." + extension;
System.out.println("文件新名称为: " + newFileName);

//3.生成当天日期目录
LocalDate now = LocalDate.now();
//realPath:父路径,now.toString():子路径
File dateDir = new File(realPath, now.toString());
if(!dateDir.exists())
dateDir.mkdirs();
System.out.println("日期目录为:" + dateDir.getName());

//4.上传文件到服务器中对应日期的目录中
//dateDir:存放文件的日期目录,newFileName:新文件名
img.transferTo(new File(dateDir,newFileName));
return "index";//上传完跳转回主页
}
}

12.文件下载

文件下载:即将服务器上的文件下载到当前用户访问的计算机。

12.1思路

img

12.2代码实现

webapp目录下新建下载down目录并放入可下载文件aa.txt

开发下载页面upload.jsp

1
2
<h1>文件下载</h1>
<a href="">aa.txt</a> <!--href=""里边的链接是向控制器发请求的链接-->

此时已经可以访问页面,即下载页面已经有了

写一个控制器用来处理文件下载

1
2
3
4
5
6
7
8
9
@Controller
@RequestMapping("file")
public class FileController{
//用来处理文件下载,请求对应响应输出流
@RequestMapping("download")
public void download(String fileName){

}
}

完善upload.jsp 向控制器发请求

1
2
<h1>文件下载</h1>
<a href="${pageContext.request.contextPath}/file/download?fileName=aa.txt">aa.txt</a>

完善控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Controller
@RequestMapping("file")
public class FileController{
//用来处理文件下载,请求对用相应输出流
@RequestMapping("download")
public void download(String fileName,HttpServletRequest request,HttpServletResponse response) throws IOException {
System.out.println("下载文件的名称: "+fileName);
//1.根据下载相对目录获取下载目录在服务器部署之后的绝对目录
String realPath = request.getSession().getServletContext().getRealPath("/down");
System.out.println("绝对路径:" + realPath);
//2.通过文件输入流读取文件 文件路径 文件名
FileInputStream is = new FileInputStream(new File(realPath, fileName));

//3.获取响应输出流 读到的文件我们必须响应回去 一个请求对应一个响应
response.setContentType("text/plain;charset=UTF-8"); //解决流乱码问题
ServletOutputStream os = response.getOutputStream();

//文件拷贝:流操作读写 文件输入流拷贝给响应输出流 下载默认在线打开 不是以附件形式下载
int len;
byte[] b = new byte[1024];
while(true){
len = is.read(b);
if(len == -1)//读到末尾
break;
os.write(b,0,len);
}
//释放资源
is.close();
os.close();
}
}

改为以附件形式下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Controller
@RequestMapping("file")
public class FileController{
//用来处理文件下载,请求对用相应输出流
@RequestMapping("download")
public void download(String fileName,HttpServletRequest request,HttpServletResponse response) throws IOException {
System.out.println("下载文件的名称: "+fileName);
//1.根据下载相对目录获取下载目录在服务器部署之后的绝对目录
String realPath = request.getSession().getServletContext().getRealPath("/down");
System.out.println("绝对路径:" + realPath);
//2.通过文件输入流读取文件 文件路径 文件名
FileInputStream is = new FileInputStream(new File(realPath, fileName));

//3.获取响应输出流 读到的文件我们必须响应回去 一个请求对应一个响应
response.setContentType("text/plain;charset=UTF-8"); //解决流乱码问题
ServletOutputStream os = response.getOutputStream();

//4.判断是在线打开还是下载附件 openStyle:attachment 附件下载、inline 在线打开
response.setHeader("content-disposition","attachment;fileName=" +fileName);
//5.处理下载流的复制
//文件拷贝:流操作读写 下载默认在线打开 不是以附件形式下载
int len;
byte[] b = new byte[1024];
while(true){
len = is.read(b);
if(len == -1)//读到末尾
break;
os.write(b,0,len);
}
//释放资源
is.close();
os.close();
}
}

12.3文件下载细节处理

完善upload.jsp页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<h1>文件下载</h1>
<ul>
<li>
a.txt <a href="${pageContext.request.contextPath}/file/download?fileName=a.txt">在线打开</a>
<a href="${pageContext.request.contextPath}/file/download?fileName=a.txt&openStyle=attach">附件下载</a>
</li>
<li>
b.rar <a href="${pageContext.request.contextPath}/file/download?fileName=b.rar">在线打开</a>
<a href="${pageContext.request.contextPath}/file/download?fileName=b.rar&openStyle=attach">附件下载</a>
</li>
<li>
c.png <a href="${pageContext.request.contextPath}/file/download?fileName=c.png">在线打开</a>
<a href="${pageContext.request.contextPath}/file/download?fileName=c.png&openStyle=attach">附件下载</a>
</li>
<li>
自我介绍.txt <a href="${pageContext.request.contextPath}/file/download?fileName=自我介绍.txt">在线打开</a>
<a href="${pageContext.request.contextPath}/file/download?fileName=自我介绍.txt&openStyle=attach">附件下载</a>
</li>
</ul>

添加测试文件:

img

完善控制器FileController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* @MethodName download
* @Description 测试文件下载
* @param: openStyle 文件打开方式
* @param: fileName 文件名
* @param: request
* @param: response
* @Author chabai
* @Date 2022/4/25 16:27
*/
@RequestMapping("download")
public void download(String openStyle, String fileName, HttpServletRequest request, HttpServletResponse response) throws IOException {
//三目表达式 若不设置打开方式,即openStyle为null时,说明文件可以在线打开
// 若设置了文件打开方式,即openStyle不为null,说明文件可以以压缩包进行下载
openStyle = openStyle == null ? "inline":"attachment";
System.out.println("下载文件的名称为:" + fileName);
//1.根据下载相对目录获取下载目录在服务器部署之后的绝对目录
String realPath = request.getSession().getServletContext().getRealPath("/download");
System.out.println("绝对路径:" + realPath);
//2.通过文件输入流读取文件 文件路径 文件名
FileInputStream fis = new FileInputStream(new File(realPath, fileName));
//3.解决流乱码问题
response.setContentType("text/plain;charset=UTF-8");
//4.判断是在线打开还是下载附件 openStyle:attachment 附件下载、默认inline在线打开(浏览器会尝试给你在线打开,若无法在线打开文件会以附件形式下载)
response.setHeader("content-disposition",openStyle + ";fileName=" + URLEncoder.encode(fileName,"UTF-8"));
//5.获取响应输出流
ServletOutputStream sos = response.getOutputStream();

//6.处理下载流赋值
//流操作使用Utils工具类:1.操作io流用IOUtils;2.操作file用FileUtils
IOUtils.copy(fis,sos);
IOUtils.closeQuietly(fis);//优雅关闭,安静关流
IOUtils.closeQuietly(sos);//优雅关闭,安静关流


/*//传统写法:流操作读写
int len;
byte[] b = new byte[1024];
while(true){
len = fis.read(b);
if(len == -1)//读到末尾
break;
sos.write(b,0,len);
}
//释放资源
fis.close();
sos.close();*/
}

注意:下载时必须设置响应的头信息,指定文件以何种方式保存,另外,下载文件的控制器不能存在返回值,代表响应只用来下载文件信息。 一个请求只能对应一个响应。

启动服务器进行测试

访问路径:http://localhost:8888/springmvc02/upload.jsp

image-20240324182407464

若文件可以在线打开,点击“在线打开”后,文件在浏览器页面上进行显示;

文件不能在线打开,则点击“在线打开”后文件会以附件形式下载;

点击“附件下载”后文件均可以以附件形式进行下载

13.springmvc与Ajax的集成(@ResponseBody注解使用)

Ajax:异步处理、局部更新数据、在处理响应的时候只认json格式的字符串

fastjson:阿里巴巴提供的转json格式工具

springmvc提供的@ResponseBody注解:为了进一步方便控制器与ajax集成,springmvc提供了@responseBody注解用在方法的返回值上,代表可以将方法的返回值转换为json格式字符串并响应到前台,省去了通过第三方工具转换json的过程。

1.思路

img

2.代码实现

引入相关依赖

1
2
3
4
5
6
<!--@ResponseBody注解在转换json时使用jackson依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>

开发实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package com.study.entity;

import com.fasterxml.jackson.annotation.JsonFormat;

import java.util.Date;

/**
* @ClassName User
* @Description TODO
* @Author chabai
* @Date 2022/4/26 11:51
* @Version 1.0
*/
public class User {
private String id;
private String name;
private Integer age;
@JsonFormat(pattern = "yyyy-MM-dd") //json日期格式转换(jackson依赖提供)
private Date bir;

@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", bir=" + bir +
'}';
}

public User() {
}

public User(String id, String name, Integer age, Date bir) {
this.id = id;
this.name = name;
this.age = age;
this.bir = bir;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public Date getBir() {
return bir;
}

public void setBir(Date bir) {
this.bir = bir;
}
}

开发控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package com.study.controller;

import com.alibaba.fastjson.JSONObject;
import com.study.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

/**
* @ClassName JSonController
* @Description TODO
* @Author chabai
* @Date 2022/4/26 11:42
* @Version 1.0
*/
@Controller
@RequestMapping("json")
public class JsonController {
/**
* @MethodName test
* @Description 测试@ResponseBody注解
* @return: java.util.Map<java.lang.String,java.lang.String>
* @Author chabai
* @Date 2022/4/26 12:11
*/
@RequestMapping("test")
@ResponseBody//以json形式返回,直接将数据写到输入流,不会再经过视图解析器了
public Map<String,String> test(){
Map<String,String> map = new HashMap<>();
map.put("message","测试成功");
return map;
}

/**
* @MethodName findAll
* @Description 使用阿里fastjson转换json
* @param: response
* @Author chabai
* @Date 2022/4/26 12:05
*/
@RequestMapping("findAll")
public void findAll(HttpServletResponse response) throws IOException {
//1.收集数据
//2.调用业务
List<User> users = new ArrayList<>();
users.add(new User(UUID.randomUUID().toString(),"熊大",20,new Date()));
users.add(new User(UUID.randomUUID().toString(),"熊二",10,new Date()));
users.add(new User(UUID.randomUUID().toString(),"光头强",50,new Date()));
//fastjson
String s = JSONObject.toJSONStringWithDateFormat(users, "yyyy-MM-dd");
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println();
}

/**
* @MethodName showAll
* @Description 使用springmvc提供的注解@ResponseBody,将控制器方法的返回值转为json,并响应给前台
* @return: java.util.List<com.study.entity.User>
* @Author chabai
* @Date 2022/4/26 12:06
*/
@RequestMapping("showAll")
public @ResponseBody List<User> showAll(){
//1.收集数据
//2.调用业务
List<User> users = new ArrayList<>();
users.add(new User(UUID.randomUUID().toString(),"熊大",20,new Date()));
users.add(new User(UUID.randomUUID().toString(),"熊二",10,new Date()));
users.add(new User(UUID.randomUUID().toString(),"光头强",50,new Date()));
return users;
}
}

开发json.jsp页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>测试springmvc与ajax集成</title>
<!--这里引了jquery:简化了JavaScript编写,自己下载复制到webapp/js包下-->
<script src="${pageContext.request.contextPath}/js/jquery-3.5.1.min.js"></script>
<script>
$(function(){
$("#btn").click(function () {
<%--$.get("${pageContext.request.contextPath}/json/showAll",function(res){--%>
<%-- console.log(res)--%>
<%--},"JSON");--%>
$.get("${pageContext.request.contextPath}/json/showAll",function(res){
$.each(res,function(i,user){
var ul= $("<ul/>");
var idLi = $("<li/>").text(user.id);
var nameLi = $("<li/>").text(user.name);
var ageLi = $("<li/>").text(user.age);
var birLi = $("<li/>").text(user.bir);
ul.append(idLi).append(nameLi).append(ageLi).append(birLi);
$("#bd").append(ul);
})
},"JSON");
});
})
</script>
</head>
<body id="bd">
<button id="btn">显示一群人</button>
</body>
</html>

启动服务器进行测试

访问路径:http://localhost:8888/springmvc02/json/test

image-20240324182727287

访问路径:http://localhost:8888/springmvc02/json.jsp

image-20240324182740973

访问路径:http://localhost:8888/springmvc02/json/findAll

image-20240324182755085

访问路径:http://localhost:8888/springmvc02/json/showAll

image-20240324182808605

14.SpringMVC中拦截器

img

1 作用
类似于javaweb中的Filter,用来对控制器请求进行拦截,可以将多个Controller中执行的共同代码放入拦截器中执行,减少Controller类中代码的冗余。

2 特点
拦截器器只能拦截Controller的请求,不能拦截jsp、静态资源等相关请求

拦截器可中断用户的请求轨迹

请求先经过拦截器,之后还会经过拦截器

3 自定义拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.study.interceptors;

import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* @ClassName MyInterceptor
* @Description 自定义拦截器
* @Author chabai
* @Date 2022/4/26 15:37
* @Version 1.0
*/
public class MyInterceptor implements HandlerInterceptor {
//执行顺序:1、2、3、4
//1.请求会最先进入拦截器中的preHandler方法,执行preHandler方法中内容
//return true表示放行请求;false表示中断请求
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println(((HandlerMethod)o).getMethod().getName());
System.out.println("===========1=============");
// //强制用户登录
// Object user = httpServletRequest.getSession().getAttribute("user");
// if(user==null){
// //重定向到登录页面
// httpServletResponse.sendRedirect(httpServletRequest.getContextPath() + "/login.jsp");
// return false;
// }
return true;
}

//3.当控制器方法执行结束以后,会返回拦截器中,执行拦截器中的postHandler方法
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println(modelAndView);
System.out.println("===========3=============");
}

//4.postHandler执行完成之后响应请求,在响应请求完成后,会执行afterCompletion方法
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
if(e!=null){
System.out.println(e.getMessage());
}
System.out.println("===========4=============");
}
}

4.开发控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* @MethodName testInterceptor
* @Description 测试拦截器
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/26 15:47
*/
@RequestMapping("interceptor")
public String testInterceptor(){
System.out.println("===========2=============");
throw new RuntimeException("程序出错啦!");
// return "index";//此处的ModelAndView只有view,即index
}

5.springmvc.xml中配置拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!--注册拦截器-->
<bean id="myInterceptor" class="com.study.interceptors.MyInterceptor"></bean>

<!--配置拦截器-->
<mvc:interceptors>
<!--配置一个具体的拦截器-->
<mvc:interceptor>
<!--配置拦截哪个路径-->
<mvc:mapping path="/json/*"/>
<!--配置不拦截哪个路径-->
<mvc:exclude-mapping path="/json/showAll"/>
<!--使用哪个拦截器-->
<ref bean="myInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>

注意:/*代表拦截所有请求路径

6 启动服务测试拦截器

访问路径:http://localhost:8888/springmvc02/json/interceptor

控制台输出结果:

(1)正常执行时

1
2
3
4
5
6
7

testInterceptor
===========1=============
===========2=============
ModelAndView: reference to view with name 'index'; model is {}
===========3=============
===========4=============

(2)出错时

1
2
3
4
5
6

testInterceptor
===========1=============
===========2=============
程序出错啦!
===========4=============

img

访问路径:http://localhost:8888/springmvc02/json/findAll

image-20240324183305859

控制台输出结果:

1
2
3
4
5
findAll
===========1=============
null
===========3=============
===========4=============

访问路径:http://localhost:8888/springmvc02/json/showAll

image-20240324183316379

控制台无输出结果

15.SpringMVC全局异常处理

img

1.作用

​ 当控制器中某个方法在运行过程中突然发生运行时异常时,为了增加用户体验不能出现500错误代码,应该给用户良好展示错误界面,全局异常处理就能更好解决这个问题。

2 控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* @MethodName testInterceptor
* @Description 测试拦截器
* @return: java.lang.String
* @Author chabai
* @Date 2022/4/26 15:47
*/
@RequestMapping("interceptor")
public String testInterceptor(){
System.out.println("===========2=============");
throw new UserNameNotFoundException("保存失败,请稍后再试......");
//throw new RuntimeException("程序出错啦......");
//return "index";//此处的ModelAndView只有view,即index
}

3 自定义异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
package com.study.exceptions;

/**
* @ClassName UserNameNotFoundException
* @Description 自定义异常
* @Author chabai
* @Date 2022/4/26 19:31
* @Version 1.0
*/
public class UserNameNotFoundException extends RuntimeException{
public UserNameNotFoundException(String message) {
super(message);
}
}

4 全局异常处理开发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.study.handlerexception;

import com.study.exceptions.UserNameNotFoundException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* @ClassName GlobalExceptionResolver
* @Description TODO
* @Author chabai
* @Date 2022/4/26 19:22
* @Version 1.0
*/
public class GlobalExceptionResolver implements HandlerExceptionResolver {
/**
* @MethodName resolveException
* @Description 用来处理发生异常时的方法
* @param: httpServletRequest 当前请求对象
* @param: httpServletResponse 当前请求对应的响应对象
* @param: o 当前请求的方法对象
* @param: e 当前出现异常时的异常对象
* @return: 出现异常展示视图和数据org.springframework.web.servlet.ModelAndView
* @Author chabai
* @Date 2022/4/26 19:24
*/
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
System.out.println("进入全局异常处理器获取的异常信息为:" + e.getMessage());
ModelAndView modelAndView = new ModelAndView();
//基于不同业务异常跳转到不同页面
if(e instanceof UserNameNotFoundException){
//view
//forward和redirect跳转区别
modelAndView.setViewName("redirect:/login.jsp");
}else{
modelAndView.setViewName("redirect:/error.jsp");//相当于 return "error" 跳转到error.jsp
}
//model
//modelAndView中model默认放入request作用域,如果使用redirect跳转,model中数据会自动拼接到跳转url
//redirect跳转就两种传值方式:1.拼地址栏 2.session
modelAndView.addObject("msg",e.getMessage());
return modelAndView;
}
}

5 springmvc.xml配置全局异常处理

1
2
<!--配置全局异常处理类-->
<bean class="com.study.handlerexception.GlobalExceptionResolver"/>

6 jsp页面

login.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
<%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>用户登录</title>
</head>
<body>
<h1>用户登录界面</h1>
<h1>登录失败:${param.msg}!</h1>
</body>
</html>

error.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>全局错误页面</title>
</head>
<body id="bd">
<h1>系统出现错误: ${param.msg}!</h1>
</body>
</html>

7 启动服务进行测试

访问路径:http://localhost:8888/springmvc02/json/interceptor

image-20240324183751722

控制台输出结果:

1
2
3
4
5
6
7
 
testInterceptor
===========1=============
===========2=============
null
进入全局异常处理器获取的异常信息为:保存失败,请稍后重试......
===========4=============