REST(Representational State Transfer),表现形式状态转换,它是一种软件架构风格,听不懂很正常。说通俗点就是用URL定位资源,用HTTP动词(GET, POST, DELETE, PUT)描述操作的一种开发方式。

REST简介

当我们想表示一个网络资源的时候,可以使用两种方式:

(1)传统风格资源描述形式

​ ① http://localhost/user/getById?id=1 查询id为1的用户信息

​ ② http://localhost/user/saveUser 保存用户信息

(2)REST风格描述形式

​ ① http://localhost/users/1

​ ② http://localhost/users

传统方式一般是一个请求url对应一种操作,这样做不仅麻烦,也不安全,因为会程序的人读取了你的请求url地址,就大概知道该url实现的是一个什么样的操作。

所以REST的优点有:

  • 隐藏资源的访问行为,无法通过地址得知对资源是何种操作

  • 书写简化

那么对于REST来说,一个相同的url地址即可以是新增也可以是修改或者查询,那么到底我们该如何区分该请求到底是什么操作呢?

按照REST风格访问资源时使用的行为动作(一共有8种,常用的只有以下4种)区分对资源进行了何种操作:

按照不同的请求方式代表不同的操作类型:发送GET请求是用来做查询;发送POST请求是用来做新增;发送PUT请求是用来做修改;发送DELETE请求是用来做删除。

REST提供了对应的架构方式,按照这种架构设计项目可以降低开发的复杂性,提高系统的可伸缩性。

上述行为是约定方式,约定不是规范,可以打破,所以称REST风格,而不是REST规范。REST中规定GET/POST/PUT/DELETE针对的是查询/新增/修改/删除,但是我们如果非要用GET请求做删除,这点在程序上运行是可以实现的,但是如果绝大多数人都遵循这种风格,你写的代码让别人读起来就有点莫名其妙了。

根据REST风格对资源进行访问称为RESTful,所以可以说以后都是基于RESTful来进行开发的。

RESTful入门案例

环境准备

image-20230618093614185

思路分析

将之前的增删改查替换成RESTful开发方式:

  • 之前不同的请求有不同的路径,现在要将其修改成统一的请求路径

    修改前:新增: /save ,修改: /update,删除 /delete …

    修改后:增删改查: /users

  • 根据GET查询、POST新增、PUT修改、DELETE删除对方法的请求方式进行限定

修改RESTful风格

新增

请求路径更改为/users,并且使用method属性限定该方法的访问方式为POST:

1
2
3
4
5
6
7
8
9
/**
* 设置当前请求方法为POST,表示REST风格中的添加操作
* */
@RequestMapping(value = "/users", method = RequestMethod.POST)
@ResponseBody
public String save(User user){
System.out.println("user save..." + user);
return "{'module':'user save'}";
}

删除

对于RESTful开发,如何携带数据参数?

前端发送请求的时候使用:http://localhost/users/1 ,路径中的1就是我们想要传递的参数。

后端获取参数,需要做如下修改:① 修改@RequestMapping的value属性,将其中修改为/users/{id},目的是和路径匹配;② 在方法的形参前添加@PathVariable注解。

1
2
3
4
5
6
7
8
9
10
		/**
* 设置当前请求方法为DELETE,表示REST风格中的删除操作
* */
@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
@ResponseBody
// public String delete(@PathVariable("id") Integer userid){
public String delete(@PathVariable Integer id){
System.out.println("user delete..." + id);
return "{'module':'user delete'}";
}

如果方法形参的名称和路径{}中的值不一致:

image-20230618112603915

如果有多个参数需要传递该如何编写:

1
public String delete(@PathVariable Integer id,@PathVariable String name)

修改

1
2
3
4
5
6
7
8
9
/**
* 设置当前请求方法为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'}";
}

复习一下:只有在请求参数是json格式的时候,才需要在control方法的形参前加@RequestBody注解。

image-20230618113323094

根据ID查询

1
2
3
4
5
6
7
8
9
/**
* 设置当前请求方法为GET,表示REST风格中的查询操作
* */
@RequestMapping(value = "/users/{id}", method = RequestMethod.GET)
@ResponseBody
public String getById(@PathVariable Integer id){
System.out.println("user getById..." + id);
return "{'module':'user getById'}";
}

查询全部

1
2
3
4
5
6
@RequestMapping(value = "/users",method = RequestMethod.GET)
@ResponseBody
public String getAll(){
System.out.println("user getAll...");
return "{'module':'user getAll'}";
}

RESTful入门开发总结

  • 设定Http请求动作(method动词)
1
@RequestMapping(value="",method = RequestMethod.POST|GET|PUT|DELETE)
  • 设定请求参数(路径变量)
1
2
3
4
@RequestMapping(value="/users/{id}",method = RequestMethod.DELETE)
@ReponseBody
public String delete(@PathVariable Integer id){
}

三大接收参数@RequestBody@RequestParam@PathVariable

区别:

(1) @RequestParam用于接收url地址传参或表单传参;

(2) @RequestBody用于接收json数据;

(3) @PathVariable用于接收路径参数,使用参数名称描述路径参数;

应用:

(1) 如果发送非json格式数据,选用@RequestParam接收请求参数;

(2) 后期开发中,发送请求参数超过1个时,以json格式为主,@RequestBody应用较广;

(3) 采用RESTful进行开发,当参数数量较少时,例如1个,可以采用@PathVariable接收请求路径变量,通常用于传递id值;

RESTful快速开发

简化前面RESTful入门开发的繁琐流程:

image-20230618150323271
  • 每个方法的@RequestMapping注解中都定义了访问路径/books,重复性太高:将@RequestMapping提到类上面,用来定义所有方法共同的访问路径。

  • 每个方法的@RequestMapping注解中都要使用method属性定义请求方式,重复性太高:使用@GetMapping @PostMapping @PutMapping @DeleteMapping代替。

  • 每个方法响应json都需要加上@ResponseBody注解,重复性太高:将ResponseBody提到类上面,让所有的方法都有@ResponseBody的功能;使用@RestController注解替换@Controller与@ResponseBody注解,简化书写。

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
@RestController
@RequestMapping("/books")
public class BookController {
@PostMapping
public String save(@RequestBody Book book){
System.out.println("book save..." + book);
return "{'module':'book save'}";
}
@DeleteMapping("/{id}")
public String delete(@PathVariable Integer id){
System.out.println("book delete..." + id);
return "{'module':'book delete'}";
}
@PutMapping
public String update(@RequestBody Book book){
System.out.println("book update..." + book);
return "{'module':'book update'}";
}
@GetMapping("/{id}")
public String getById(@PathVariable Integer id){
System.out.println("book getById..." + id);
return "{'module':'book getById'}";
}
@GetMapping
public String getAll(){
System.out.println("book getAll...");
return "{'module':'book getAll'}";
}
}

RESTful案例

此次案例的重点是在SpringMVC中如何使用RESTful实现前后台交互,所以本案例并没有和数据库进行交互,所有数据使用假数据来完成开发。

需求分析

需求一:图书列表查询,从后台返回数据,将数据展示在页面上。

需求二:新增图书,将新增图书的数据传递到后台,并在控制台打印。

环境准备

image-20230618161050752

后台接口开发

步骤1:编写Controller类并使用RESTful进行配置

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
@RestController
@RequestMapping("/books")
public class BookController {
// 查询全部
@GetMapping
public List<Book> getAll(){
// 不与数据库进行交互,这里使用假数据
ArrayList<Book> bookList = new ArrayList<>();
Book book1 = new Book();
book1.setName("C# primer");
book1.setType("编程图书");
book1.setDescription("C语言入门图书");
bookList.add(book1);
Book book2 = new Book();
book2.setName("计算机网络:自顶向下");
book2.setType("计算机网络");
book2.setDescription("计算机四大件之计算机网络");
bookList.add(book2);
return bookList;
}
// 添加
@PostMapping
public String save(@RequestBody Book book){
System.out.println("book save =====> " + book);
return "'module':'Book save successfully...'";
}
}

步骤2:使用PostMan进行测试

  • 测试新增
image-20230618163951612
  • 测试查询全部
image-20230618164145531

页面访问处理

步骤1:拷贝静态页面

image-20230618165134339

步骤2:访问pages目录下的books.html

image-20230618165232338

报错的原因是:SpringMVC拦截了静态资源,根据/pages/books.html去controller找对应的方法,找不到所以会报404的错误。

因为在ServletInitConfig配置文件中拦截了静态资源

1
2
3
4
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}

所以必须将静态资源在ServletInitConfig中进行放行:创建一个新的SpringMvcSupport配置类!

1
2
3
4
5
6
7
8
9
10
11
12
//设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {

protected void addResourceHandlers(ResourceHandlerRegistry registry){
//当访问/pages/????时候,从/pages目录下查找内容
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}
}

该配置类是在config目录下,SpringMVC扫描的是controller包,所以该配置类还未生效,要想生效需要将SpringMvcConfig配置类进行修改:

1
@ComponentScan({"com.Lijiacheng.controller","com.Lijiacheng.config"})

步骤3:修改books.html页面

1
2
3
4
5
6
7
8
9
10
11
//添加
saveBook () {
axios.post("/books",this.formData).then((res)=>{
});
},
//主页列表查询
getAll() {
axios.get("/books").then((res)=>{
this.dataList = res.data;
});
},

image-20230618170855805

image-20230618171004140

前端的新增图书请求到后端来接收:

image-20230618171022178