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入门案例
环境准备
思路分析
将之前的增删改查替换成RESTful开发方式:
之前不同的请求有不同的路径,现在要将其修改成统一的请求路径
修改前:新增: /save ,修改: /update,删除 /delete …
修改后:增删改查: /users
根据GET查询、POST新增、PUT修改、DELETE删除对方法的请求方式进行限定
修改RESTful风格
新增
请求路径更改为/users,并且使用method属性限定该方法的访问方式为POST:
1 2 3 4 5 6 7 8 9
|
@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
|
@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE) @ResponseBody
public String delete(@PathVariable Integer id){ System.out.println("user delete..." + id); return "{'module':'user delete'}"; }
|
如果方法形参的名称和路径{}中的值不一致:
如果有多个参数需要传递该如何编写:
1
| public String delete(@PathVariable Integer id,@PathVariable String name)
|
修改
1 2 3 4 5 6 7 8 9
|
@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注解。
根据ID查询
1 2 3 4 5 6 7 8 9
|
@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入门开发总结
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入门开发的繁琐流程:
每个方法的@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实现前后台交互,所以本案例并没有和数据库进行交互,所有数据使用假数据来完成开发。
需求分析
需求一:图书列表查询,从后台返回数据,将数据展示在页面上。
需求二:新增图书,将新增图书的数据传递到后台,并在控制台打印。
环境准备
后台接口开发
步骤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进行测试
页面访问处理
步骤1:拷贝静态页面

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

报错的原因是: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){ 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; }); },
|

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