SpringMVC基础01
# SpringMVC
是一个基于 Java 实现的 MVC模型
的轻量级 Web 框架
# 快速开始
启动服务器初始化过程
- 服务器启动时,会自动执行
ServletContainersInitConfig
一个实现类,初始化 web 容器 - 执行
createServletApplicationContext
方法,创建对象,注册配置类 - 加载
SpringConfig
配置类,执行@ComponentScan
加载对应类,此处扫描的是SpringMVC
的Bean
- 加载
controller
包下的所有控制类,每个@RequestMapping
都有一个具体的方法 - 执行
getServletMappings
方法,定义所有的请求都通过SpringMVC
- 当有请求发送时,web容器会将请求交给
SpringMVC
处理
示例代码
环境装备
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>80</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
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
- 注意版本的匹配
编写控制层代码
//定义表现层控制器bean
@Controller
public class UserController {
//设置映射路径为/save,即外部访问路径
@RequestMapping("/save")
//设置当前操作返回结果为指定json数据(本质上是一个字符串信息)
@ResponseBody
public String save(){
System.out.println("user save ...");
return "{'info':'springmvc'}";
}
}
2
3
4
5
6
7
8
9
10
11
12
@ResponseBody
:返回值默认是表示要跳转的页面,没有对应的页面就是报错。需要返回响应数据,就需要在方法中加此注释
配置类 : Spring 扫描包,这里专门扫描 SpringMVC 的 Bean
//springmvc配置类,本质上还是一个spring配置类
@Configuration
@ComponentScan("com.itheima.controller")
public class SpringMvcConfig {
}
2
3
4
5
配置类:AbstractDispatcherServletInitializer
的继承实现类,会在容器中自动执行,创建 WEB
容器
//web容器配置类
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
//加载springmvc配置类,产生springmvc容器(本质还是spring容器)
protected WebApplicationContext createServletApplicationContext() {
//初始化WebApplicationContext对象
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
//加载指定配置类
ctx.register(SpringMvcConfig.class);
return ctx;
}
//设置由springmvc控制器处理的请求映射路径
protected String[] getServletMappings() {
return new String[]{"/"};
}
//加载spring配置类
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
开启 tomcat
服务器,访问 localhost/save
可以获取到相关数据
注解解释扩展
@Controller
@RequestMapping
作用:设置当前控制器方法请求访问路径
@ResponseBody
作用:设置当前控制器方法响应内容为当前返回值,无需解析
AbstractDispatcherServletInitializer
类是
SpringMVC
提供的快速初始化 Web 容器的的抽象类提供了三个接口方法供用户实现
createServletApplicationContext()
创建Servlet容器时,加载SpringMVC对应的bean并放入WebApplicationContext对象范围中,而WebApplicationContext的作用范围为ServletContext范围,即整个web容器范围
//加载springmvc配置类,产生springmvc容器(本质还是spring容器) protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(SpringMvcConfig.class); return ctx; }
1
2
3
4
5
6getServletMappings()
设定SpringMVC对应的请求映射路径,设置为/表示拦截所有请求,任意请求都将转入到SpringMVC进行处理
//设置由springmvc控制器处理的请求映射路径 protected String[] getServletMappings() { return new String[]{"/"}; }
1
2
3
4createRootApplicationContext()
如果创建Servlet容器时需要加载非SpringMVC对应的bean,使用当前方法进行,使用方式同createServletApplicationContext()
//加载spring配置类 protected WebApplicationContext createRootApplicationContext() { return null; }
1
2
3
4
# 避免Bean加载
避免 Spring
错误的加载到 SpringMVC
的 bean
Spring
加载的Bean
扫描范围为con.yuadh
, 排除掉controller
包@Configuration @ComponentScan(value = "com.itheima", excludeFilters = @ComponentScan.Filter( type = FilterType.ANNOTATION, classes = Controller.class ) ) public class SpringConfig { }
1
2
3
4
5
6
7
8
9excludeFilters
:排除扫描路径中加载的bean,需要指定类别(type)与具体项(classes)includeFilters
:加载指定的bean,需要指定类别(type)与具体项(classes)Spring
加载的Bnea
设定扫描范围为精准范围不区分
Spring
和SpringMVC
的环境,加载到同一个环境中public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer { protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(SpringMvcConfig.class); return ctx; } protected WebApplicationContext createRootApplicationContext() { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(SpringConfig.class); return ctx; } protected String[] getServletMappings() { return new String[]{"/"}; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15简化
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer{ protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class} }; protected String[] getServletMappings() { return new String[]{"/"}; } protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } }
1
2
3
4
5
6
7
8
9
10
11
# 请求处理
快速开始
@Controller
//类上方配置的请求映射与方法上面配置的请求映射连接在一起,形成完整的请求映射路径
@RequestMapping("/user")
public class UserController {
//请求路径映射
@RequestMapping("/save") //此时save方法的访问路径是:/user/save
@ResponseBody
public String save(){
System.out.println("user save ...");
return "{'module':'user save'}";
}
}
2
3
4
5
6
7
8
9
10
11
12
@RequestMapping
: 设置当前控制器方法请求访问路径,如果设置在类上统一设置当前控制器方法请求访问路径前缀
可以设置在类的上方统一访问前缀
# 请求普通参数
//普通参数:请求参数与形参名称对应即可完成参数传递
@RequestMapping("/commonParam")
@ResponseBody
public String commonParam(String name ,int age){
System.out.println("普通参数传递 name ==> "+name);
System.out.println("普通参数传递 age ==> "+age);
return "{'module':'common param'}";
}
2
3
4
5
6
7
8
在没有任何处理的清空下可能会出现中文乱码问题
解决:在tomcat7
的插件中设置,UTF8
字符集
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>80</port><!--tomcat端口号-->
<path>/</path> <!--虚拟目录-->
<uriEncoding>UTF-8</uriEncoding><!--访问路径编解码字符集-->
</configuration>
</plugin>
</plugins>
</build>
2
3
4
5
6
7
8
9
10
11
12
13
14
解决post
请求中文乱码的问题,在SpringMVC配置类中设置
//乱码处理
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[]{filter};
}
2
3
4
5
6
7
在出现参数名和方法参数不对应的清空,可以使用 @RequestParam("name")
注解设置别名
//普通参数:请求参数名与形参名不同时,使用@RequestParam注解关联请求参数名称与形参名称之间的关系
@RequestMapping("/commonParamDifferentName")
@ResponseBody
public String commonParamDifferentName(@RequestParam("name") String userName , int age){
System.out.println("普通参数传递 userName ==> "+userName);
System.out.println("普通参数传递 age ==> "+age);
return "{'module':'common param different name'}";
}
2
3
4
5
6
7
8
@RequestParam()
:绑定请求参数与处理器方法形参间的关系
可用参数
required
:是否为必传参数defaultValue
:参数默认值
public String commonParamDifferentName(@RequestParam(value = "name" required=true,defaultValue="yuadh") String userName , int age)
# 多种类型参数
1.普通参数
2.对象参数
请求参数名与形参对象属性名相同,定义POJO类型形参即可接收参数
public class User {
private String name;
private int age;
//同学们自己添加getter/setter/toString()方法
}
2
3
4
5
//POJO参数:请求参数与形参对象中的属性对应即可完成参数传递
@RequestMapping("/pojoParam")
@ResponseBody
public String pojoParam(User user){
System.out.println("pojo参数传递 user ==> "+user);
return "{'module':'pojo param'}";
}
2
3
4
5
6
7
3.对象嵌套的参数
public class User {
private String name;
private int age;
private Address address;
//同学们自己添加getter/setter/toString()方法
}
public class Address {
private String province;
private String city;
private Address address;
}
2
3
4
5
6
7
8
9
10
11
参数请求的发送,只要有嵌套关系即可接收到
4.数组类型的参数
//数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中
@RequestMapping("/arrayParam")
@ResponseBody
public String arrayParam(String[] likes){
System.out.println("数组参数传递 likes ==> "+ Arrays.toString(likes));
return "{'module':'array param'}";
}
2
3
4
5
6
7
5.集合类型的参数
//集合参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据
@RequestMapping("/listParam")
@ResponseBody
public String listParam(@RequestParam List<String> likes){
System.out.println("集合参数传递 likes ==> "+ likes);
return "{'module':'list param'}";
}
2
3
4
5
6
7
参数的请求和数组一样,注意集合需要 @RequestParam
来映射同名集合类型
# Jsoin数据参数
json数据类型
- 普通数组
- json对象
- json对象数组
Json数据的响应识别需要相关的数据包
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
2
3
4
5
配置相关设置
@Configuration
@ComponentScan("com.itheima.controller")
//开启json数据类型自动转换
@EnableWebMvc
public class SpringMvcConfig {
}
2
3
4
5
6
@EnableWebMvc
开启自动转换 json
全局配置
接收示例
//集合参数:json格式
//1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc
//2.使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据
@RequestMapping("/listParamForJson")
@ResponseBody
public String listParamForJson(@RequestBody List<String> likes){
System.out.println("list common(json)参数传递 list ==> "+likes);
return "{'module':'list common for json param'}";
}
2
3
4
5
6
7
8
9
@RequestBody
:将请求中请求体所包含的数据传递给请求参数,此注解一个处理器方法只能使用一次@EnableWebMvc
:开启SpringMVC多项辅助功能
# 日期类型参数
DataTimeFormat
注解,处理日期数据
日期类型数据基于不同的系统会有不同的格式,为了限制参数的接收可以使用此注解,对形参的日期数据进行限制
//日期参数 http://localhost:80/dataParam?date=2088/08/08&date1=2088-08-18&date2=2088/08/28 8:08:08
//使用@DateTimeFormat注解设置日期类型数据格式,默认格式yyyy/MM/dd
@RequestMapping("/dataParam")
@ResponseBody
public String dataParam(Date date,
@DateTimeFormat(pattern="yyyy-MM-dd") Date date1,
@DateTimeFormat(pattern="yyyy/MM/dd HH:mm:ss") Date date2){
System.out.println("参数传递 date ==> "+date);
System.out.println("参数传递 date1(yyyy-MM-dd) ==> "+date1);
System.out.println("参数传递 date2(yyyy/MM/dd HH:mm:ss) ==> "+date2);
return "{'module':'data param'}";
}
2
3
4
5
6
7
8
9
10
11
12
@DateTimeFormat
:设定日期时间型数据格式,pattern
:指定日期时间格式字符串
# 扩展参数
@RequestBody
和 @RequestParam
区别
@RequestParam
用于接收url地址传参,表单传参application/x-www-form-urlencoded
@RequestBody
用于接收json数据application/json
# 响应处理
json数据的响应为主要方式
# 页面响应
@Controller
public class UserController {
//响应页面/跳转页面
//返回值为String类型,设置返回值为页面名称,即可实现页面跳转
@RequestMapping("/toJumpPage")
public String toJumpPage(){
System.out.println("跳转页面");
return "page.jsp";
}
}
2
3
4
5
6
7
8
9
10
11
# 文本数据响应
//响应文本数据
//返回值为String类型,设置返回值为任意字符串信息,即可实现返回指定字符串信息,需要依赖@ResponseBody注解
@RequestMapping("/toText")
@ResponseBody
public String toText(){
System.out.println("返回纯文本数据");
return "response text";
}
2
3
4
5
6
7
8
# Json数据响应
//响应POJO对象
//返回值为实体类对象,设置返回值为实体类类型,即可实现返回对应对象的json数据,需要依赖@ResponseBody注解和@EnableWebMvc注解
@RequestMapping("/toJsonPOJO")
@ResponseBody
public Object toJsonPOJO(){
System.out.println("返回json对象数据");
User user = new User();
user.setName("itcast");
user.setAge(15);
return user;
}
2
3
4
5
6
7
8
9
10
11
注意 Json 格式的返回依赖于 @EnableWebMvc
# REST风格接口
Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
# 风格介绍
表现形式状态转换
传统资源请求形式
http//localhost/user/getById?id=1
http//localhost/user/saveUser
REST
风格描述形式
http://localhost/user/1
http://localhost/user
隐藏资源的访问方式,无法通过地址得知对资源的操作
在 RESTful
架构中,每个网址代表一种资源,所以网址中不能有动词,只能有名词,而且名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的集合,所以 API
中的名词也应该使用复数
# 动词
请求方式 | 作用 |
---|---|
GET | 读取 |
POST | 新建 |
PUT | 更新全部 |
PATCH | 更新部分 |
DELETE | 删除 |
示例
GET /zoos:列出所有动物园
POST /zoos:新建一个动物园
GET /zoos/ID:获取某个指定动物园的信息
PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
DELETE /zoos/ID:删除某个动物园
GET /zoos/ID/animals:列出某个指定动物园的所有动物
DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物
2
3
4
5
6
7
8
过滤信息
?limit=10:指定返回记录的数量
?offset=10:指定返回记录的开始位置。
?page=2&per_page=100:指定第几页,以及每页的记录数。
?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
?animal_type_id=1:指定筛选条件
2
3
4
5
# 状态码
200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
204 NO CONTENT - [DELETE]:用户删除数据成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
2
3
4
5
6
7
8
9
10
11
12
1xx:相关信息
2xx:操作成功
3xx:重定向
4xx:客户端错误
5xx:服务器错误
2
3
4
5
# 返回结果
GET /collection:返回资源对象的列表(数组)
GET /collection/resource:返回单个资源对象
POST /collection:返回新生成的资源对象
PUT /collection/resource:返回完整的资源对象
PATCH /collection/resource:返回完整的资源对象
DELETE /collection/resource:返回一个空文档
2
3
4
5
6
# 快速入门
@Controller
public class UserController {
//设置当前请求方法为POST,表示REST风格中的添加操作
@RequestMapping(value = "/users",method = RequestMethod.POST)
@ResponseBody
public String save(){
System.out.println("user save...");
return "{'module':'user save'}";
}
//设置当前请求方法为DELETE,表示REST风格中的删除操作
//@PathVariable注解用于设置路径变量(路径参数),要求路径上设置对应的占位符,并且占位符名称与方法形参名称相同
@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
@ResponseBody
public String delete(@PathVariable Integer id){
System.out.println("user delete..." + id);
return "{'module':'user delete'}";
}
//设置当前请求方法为PUT,表示REST风格中的修改操作
@RequestMapping(value = "/users",method = RequestMethod.PUT)
@ResponseBody
public String update(@RequestBody User user){
System.out.println("user update..."+user);
return "{'module':'user update'}";
}
//设置当前请求方法为GET,表示REST风格中的查询操作
//@PathVariable注解用于设置路径变量(路径参数),要求路径上设置对应的占位符,并且占位符名称与方法形参名称相同
@RequestMapping(value = "/users/{id}" ,method = RequestMethod.GET)
@ResponseBody
public String getById(@PathVariable Integer id){
System.out.println("user getById..."+id);
return "{'module':'user getById'}";
}
//设置当前请求方法为GET,表示REST风格中的查询操作
@RequestMapping(value = "/users",method = RequestMethod.GET)
@ResponseBody
public String getAll(){
System.out.println("user getAll...");
return "{'module':'user getAll'}";
}
}
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
@PathVariable
:绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应
# 开发简化的注解
解决:重复定义路径
、重复使用method=RequestMethod
、ResponseBody
使用重复性太高的问题
- 在类上使用
@RequestMapping
注解,统一路由 - 使用
@GetMapping
、@PostMapping
、@PutMapping
、DeleteMapping
、替代RequestMapping(method=RequestMethod.XXX)
- 使用
@RestController
注解,等同于@Controller
和ResponseBody
注解,返回json
数据类型
# 代码示例
环境准备
//POJO实体类
public class Book {
private Integer id;
private String type;
private String name;
private String description;
//同学们自己重写getter、setter、toString()方法...
}
//SpringMVC容器初始化类
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
//乱码处理
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[]{filter};
}
}
//SpringMVC配置类
@Configuration
@ComponentScan({"com.itheima.controller","com.itheima.config"})
@EnableWebMvc
public class SpringMvcConfig {
}
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
controller
@RestController
@RequestMapping("/books")
public class BookController {
@PostMapping
public String save(@RequestBody Book book){
System.out.println("book save ==> "+ book);
return "{'module':'book save success'}";
}
@GetMapping
public List<Book> getAll(){
System.out.println("book getAll is running ...");
List<Book> bookList = new ArrayList<Book>();
Book book1 = new Book();
book1.setType("计算机");
book1.setName("SpringMVC入门教程");
book1.setDescription("小试牛刀");
bookList.add(book1);
Book book2 = new Book();
book2.setType("计算机");
book2.setName("SpringMVC实战教程");
book2.setDescription("一代宗师");
bookList.add(book2);
Book book3 = new Book();
book3.setType("计算机丛书");
book3.setName("SpringMVC实战教程进阶");
book3.setDescription("一代宗师呕心创作");
bookList.add(book3);
return bookList;
}
}
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