RESTful 风格(详细介绍 + 案例实现)
这里写目录标题
- RESTful 入门
- 一、什么是 API(应用程序接口)
- 二、传统模式和前后端分离模式对比
- 1. 传统开发模式
- 2. 前后端分离模式
- 三、RESTful 风格
- 1. 概念
- 2. 资源
- 3. 请求方式
- 4. 传统模式 URI 和 RESTful 风格对比
- 5. 返回值-按需求决定
- 6. HTTP响应状态码
- 7. 同一个资源具有多种表现形式(xml,json等)
- 8. 使用Ajax来发送各种请求方法的请求
- 9. 相关注解
- 10. RequestMapping标签的属性
- 四、例题
- 1. 前端界面
- 2. 控制器
- 3. 输出结果
RESTful 入门
一、什么是 API(应用程序接口)
概念
API,英文全称Application Programming Interface,翻译为“应用程序编程接口”。就是将一些功能(逻辑)封装成组件,目的是提供一个应用程序接口给其它程序与开发人员访问,而这些访问人员不需要访问源码以及理解内部工作原理就可以直接使用。
举例
在 WEB 项目中 A 应用暴露一个请求映射方法,B应用通过调用这个请求映射方法从而得到对应功能(请求映射方法赋予的功能)
二、传统模式和前后端分离模式对比
1. 传统开发模式
在传统开发模式的应用中,前端写好静态的html页面交给后端开发,后端把html渲染或重定向到前端界面。这样前端页面看到的效果都是由后端控制的,也就是后端需要控制前端的展示,这样会出现很多严重的问题。
- 弊端
【1】前后端耦合严重,前端会嵌入后端代码,导致代码混乱,可维护性差;
【2】开发出的软件响应速度慢,质量差,用户体现差;
【3】开发人员需要前后端兼顾,开发效率低下,开发周期变长;
【4】与前端开发人员之间沟通成本高,前后端开发进度相互影响,从而大大降低开发效率。
2. 前后端分离模式
前后端分离并不只是开发模式,也是web应用的一种架构模式。在开发阶段,前后端人员约定好数据交互接口,即可并行开发与测试。
前端开发完成可以独自进行mock测试,后端也可以使用postman等接口测试工具进行测试。最后可进行功能联调测试。
说通俗点就是后端项目里面看不到页面(JSP|HTML),后端给前端提供接口,前端调用后端提供的REST风格接口就行,前端专注写页面(html|jsp)和渲染(JS|CSS|各种前端框架);后端专注写代码就行。 前后端分离的核心:后台提供数据,前端负责显示
- 优点
【1】可以实现真正的前后端解耦,前后端可以并行开发与测试,提高开发效率;
【2】减少后端服务器的并发/负载压力,提高系统的性能;
【3】异步加载的方式,可以很好的应对复杂多变的前端需求;
【4】前后端代码不再混乱,增强了代码的可维护性。
三、RESTful 风格
1. 概念
RESTFUL是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用 XML 格式定义或 JSON 格式定义。最常用的数据格式是JSON。由于JSON能直接被JavaScript读取,所以,使用JSON格式的REST风格的API具有简单、易读、易用的特点。
2. 资源
REST 是面向资源的,每个资源都有一个唯一的资源定位符(URI)。每个URI代表一种资源(resource),所以URI中不能有动词,只能有名词,而且所用的名词往往与数据库的表名对应。一般来说,数据库中的表都是同种记录的"集合"(collection),所以URI中的名词也应该使用复数。
例如:
// 查询所有员工
@RequestMapping(value = "/employees", method = RequestMethod.GET)
@ResponseBody
public List<Employee> list() {...
}
3. 请求方式
请求方式 | 含义 |
---|---|
GET(SELECT) | 从服务器取出资源(一项或多项) |
POST(CREATE) | 在服务器新建一个资源 |
PUT(UPDATE) | 在服务器更新资源(更新完整资源) |
PATCH(UPDATE) | 在服务器更新资源, PATCH更新个别属性 |
DELETE(DELETE) | 从服务器删除资源 |
4. 传统模式 URI 和 RESTful 风格对比
【1】查询
查询 | 传统 | REST | REST 后台接收 |
---|---|---|---|
查询所有 | http://localhost:8080/employee/list | http://localhost:8080/employees | @RequestMapping(value = “/employees”, method = RequestMethod.GET) |
查询单个 | http://localhost:8080/employee/list?id=1 | http://localhost:8080/employees/1 |
@RequestMapping(value = “/employees/{id}”, method = RequestMethod.GET) @ResponseBody public Employee queryById(@PathVariable Long id) {} |
【2】添加
添加 | 传统 | REST | REST 后台接收 |
---|---|---|---|
添加 | http://localhost:8080/employee/add | http://localhost:8080/employees |
@RequestMapping(value = “/employees”, method = RequestMethod.POST) public Employee add(@ModelAttribute(“emp”) Employee employee) {} |
【3】修改
修改 | 传统 | REST | REST 后台接收 |
---|---|---|---|
修改 | http://localhost:8080/employee/update | http://localhost:8080/employees |
@RequestMapping(value = “/employees”, method = RequestMethod.PUT) public Employee update(@ModelAttribute(“emp”) Employee employee) {} |
【4】删除
查询 | 传统 | REST | REST 后台接收 |
---|---|---|---|
删除 | http://localhost:8080/employee/delete | http://localhost:8080//employees/{id} |
@RequestMapping(value = “/employees/{id}”, method = RequestMethod.DELETE) @ResponseBody public JsonResult delete(@PathVariable Long id) {} |
注意:
【1】当参数非常多的时候,不建议使用参数路径方式;
【2】如果参数名非常敏感,建议使用参数路径方式,可以隐藏参数名。
5. 返回值-按需求决定
GET /collection:返回资源对象的列表(数组)
GET /collection/resource:返回单个资源对象
POST /collection:返回新生成的资源对象
PUT /collection/resource:返回完整的资源对象
PATCH /collection/resource:返回完整的资源对象
DELETE /collection/resource:返回一个空文档
6. HTTP响应状态码
状态码 | 含义 |
---|---|
200 OK - [GET] | 服务器成功返回用户请求的数据 |
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 - [*] | 用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的 |
405 Method Not Allowed | 方法不允许,服务器没有该方法 |
406 Not Acceptable - [GET] | 用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式) |
410 Gone -[GET] | 用户请求的资源被永久删除,且不会再得到的 |
422 Unprocesable entity - [POST/PUT/PATCH] | 当创建一个对象时,发生一个验证错误 |
500 INTERNAL SERVER ERROR - [*] | 服务器发生错误,用户将无法判断发出的请求是否成功 |
7. 同一个资源具有多种表现形式(xml,json等)
比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,也可以用PNG格式表现。
它的具体表现形式,应该在HTTP请求的头信息中用Accept和Content-Type字段指定,这两个字段才是对"表现"的描述。
accept:application/json
content-type:application/json
Accept与Content-Type的区别
【1】Accept属于请求头, Content-Type属于实体头。
Http报头分为通用报头,请求报头,响应报头和实体报头。
请求方的http报头结构:通用报头|请求报头|实体报头
响应方的http报头结构:通用报头|响应报头|实体报头【2】Accept代表发送端(客户端)希望接受的数据类型。
比如:Accept:application/json;
代表客户端希望接受的数据类型是json类型,后台返回json数据;【3】Content-Type代表发送端(客户端|服务器)发送的实体数据的数据类型。
比如:Content-Type:application/json;
代表发送端发送的数据格式是json, 后台就要以这种格式来接收前端发过来的数据。
8. 使用Ajax来发送各种请求方法的请求
$.get('/employees',function(){})$.post('/employees',params,function(){})$.ajax({url:"/employees/1",type:"put",data:paramssuccess:function(){}
})$.ajax({url:"/employees/1",type:"DELETE",success:function(){}
})
- SpringBoot 2.2.x 中 Put 请求和 Delete 请求不起作用
# application.properties 中配置
spring.mvc.hiddenmethod.filter.enabled=true
- springMVC默认不支持处理put请求,需要配置处理put或patch请求方式的过滤器
<filter><filter-name>httpMethodFilter</filter-name><filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping><filter-name>httpMethodFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
SpringMVC 中的 delete 请求
$.ajax({type: "post",url:url,data: {"contentId": id, "_method": "delete"},success: function (data) {if (data.status == 0) {alert("成功!");location.reload();} else {alert("操作失败!" + data.reason);}}
});
9. 相关注解
注解 | 作用 |
---|---|
@RestController | 由 @Controller + @ResponseBody组成(返回 JSON 数据格式) |
@PathVariable | URL 中的 {xxx} 占位符可以通过@PathVariable(“xxx“) 绑定到控制器处理方法的形参中 |
@RequestMapping | 注解用于请求地址的解析,是最常用的一种注解 |
@GetMapping | 查询请求 |
@PostMapping | 添加请求 |
@PutMapping | 更新请求 |
@DeleteMapping | 删除请求 |
@RequestParam | 将请求参数绑定到你控制器的方法参数上(是springmvc中接收普通参数的注解) |
@RequestParam语法
语法:@RequestParam(value=”参数名”,required=”true/false”,defaultValue=””)value:参数名required:是否包含该参数,默认为true,表示该请求路径中必须包含该参数,如果不包含就报错。defaultValue:默认参数值,如果设置了该值,required=true将失效,自动为false,如果没有传该参数,就使用默认值
10. RequestMapping标签的属性
value/path:映射路径;
method:限定请求的方式,枚举:
public enum RequestMethod {
GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
}params:限定要处理请求的参数,只有匹配该参数的请求,才会被该方法处理;
@GetMapping(value = "list",params="version=1") public Object list() {return "ok"; }
- headers:限定要处理请求的请求头信息,只有匹配该请求头内容的请求,才会被该方法处理;
@GetMapping(value = “/test”, headers = “content-type=text/*”)
四、例题
1. 前端界面
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../js/jquery.min.js"></script><script>$(function () {// 查询所有$('#btn1').click(function () {$.get('/employees', function (data) {console.log(data);});});// 查询一个$('#btn2').click(function () {$.get('/employees/10', function (data) {console.log(data);});});// 添加$('#btn3').click(function () {$.post('/employees', "id=11", function (data) {console.log(data);});});// 修改$('#btn4').click(function () {$.ajax({url: "/employees",type: "PUT",data: {id: 1, name: "小肥羊", age: 10},success: function (data) {console.log(data);}});});// 删除$('#btn5').click(function () {$.ajax({url: "/employees/13",type: "DELETE",data: {id: 1},success: function (data) {console.log(data);}});});});</script>
</head>
<body>
<button id="btn1">查询所有</button>
<button id="btn2">查询一个</button>
<button id="btn3">添加</button>
<button id="btn4">修改</button>
<button id="btn5">删除</button>
</body>
</html>
2. 控制器
package com.yy.web.controller;import com.yy.domain.Employee;
import com.yy.util.JsonResult;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.*;import java.util.Arrays;
import java.util.List;/*** @program: restful-demo* @ClassName: EmployeeController* @description:* @author: YanYang* @create: 2021-06-23 15:04**/
@RestController
@RequestMapping("employees")
public class EmployeeController {/*** 2个接口设计都是用相同资源,相同请求方法,此时 SpringMVC 无法识别,* 认为是同一方法,报错:Ambiguous mapping. [模糊映射]** RESTful 解决方案:使用 参数路径 方式* 具体实现:将参数作为请求映射路径一部分,[参与映射路径区分]* 比如:查询指定 id 的员工信息接口设计* @RequestMapping(value = "/employees/{id}", method = RequestMethod.GET)* 其中 "/employees/{id}" 参数路径,{id} 就是路径参数** 访问该接口时:http:localhost:8080/employees/1 其中 1 是 id 参数* 接口接收路径参数:使用 @PathVariable,表示将参数路径上的参数解析,并赋值给指定变量* 如果路径参数与变量名不一致,使用 @PathVariable("eid")明确指定**/// 查询所有(数据是模拟的)
// @RequestMapping(value = "/employees", method = RequestMethod.GET)@GetMappingpublic List<Employee> list() {return Arrays.asList(new Employee(1L,"小肥羊", 10), new Employee(2L, "熊大", 11));}// 查询单个(数据是模拟的)
// @RequestMapping(value = "/employees/{id}", method = RequestMethod.GET)@GetMapping("/{eid}")public Employee queryById(@PathVariable("eid") Long id) {System.out.println("查询单个 = " + id);return new Employee(3L, "熊二", 8);}// 添加(数据是模拟的)
// @RequestMapping(value = "/employees", method = RequestMethod.POST)@PostMappingpublic Employee add(@ModelAttribute("employee") Employee employee) {System.out.println("添加 = " + employee.getId());return employee;}// 修改(数据是模拟的)
// @RequestMapping(value = "/employees", method = RequestMethod.PUT)@PutMappingpublic Employee update(@ModelAttribute("employee") Employee employee) {System.out.println("修改 = " + employee.getId());employee.setId(employee.getId());employee.setName(employee.getName());employee.setAge(employee.getAge());return employee;}// 删除(数据是模拟的)
// @RequestMapping(value = "/employees/{id}", method = RequestMethod.DELETE)@DeleteMapping("/{id}")public String delete(@PathVariable Long id) {System.out.println("删除 = " + id);if (id != null && 1 == id) {return "删除成功";}return "删除失败";}
}
3. 输出结果
- 控制台输出
查询单个 = 10
添加 = 11
修改 = 1
删除 = 13
- 浏览器打印
RESTful 风格(详细介绍 + 案例实现)相关推荐
- 【Node.js】关于Node.js接口的详解和案例--restful风格接口。案例:添加商品接口,添加员工接口,删除员工接口
1.首先我们需要知道,接口是什么? 接口是后端为前端提供的数据--动态资源:Node.js通过每一个路由就可以实现接口 2.RESTful接口:是一种接口的架构风格 1.请求的URL(资源) 在资源前 ...
- rest规范 ; restful 风格; gradel介绍 ; idea安装 ;
[说明]上午整理了一下心情:下午继续开始任务,了解了restful,知道了那个牛人的博士论文,下载了管理工具gradle,并且部署了环境:晚上安装了idea继承环境并且建了一个简单的gradle项目( ...
- SpringBoot交友APP项目实战(详细介绍+案例源码) - 9.小视频(SpringCache缓存)
有人相爱,有人跳海 系列文章目录 1. 项目介绍及环境配置 2. 短信验证码登录 3. 用户信息 4. MongoDB 5. 推荐好友列表/MongoDB集群/动态发布与查看 6. 圈子动态/圈子互动 ...
- Dobbo微服务项目实战(详细介绍+案例源码) - 3.用户信息
想出去旅游,想出去玩,想大吃大喝 0_o 系列文章目录 1. 项目介绍及环境配置 2. 短信验证码登录 3. 用户信息 4. MongoDB 5. 推荐好友列表/MongoDB集群/动态发布与查看 6 ...
- Linux服务器开发之:chmod()函数,chmod命令,以及文件屏蔽umask命令,程序修改umask,详细介绍+案例演示
1.依赖的头文件 #include<sys/stat.h> 2.函数定义: //通过传入path中给定的文件名的方式来改变文件制定的权限 int chmod(const char * ...
- Linux服务器开发之:stat(),fstat(),lstat()详细介绍+案例演示
1.依赖的头文件 #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> 2.函数定 ...
- Dobbo微服务项目实战(详细介绍+案例源码) - 5.推荐好友列表/MongoDB集群/动态发布与查看
You are a wizard, Harry! 系列文章目录 1. 项目介绍及环境配置 2. 短信验证码登录 3. 用户信息 4. MongoDB 5.推荐好友列表/MongoDB集群/动态发布与查 ...
- Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB
安能摧眉折腰事权贵,使我不得开心颜 系列文章目录 1. 项目介绍及环境配置 2. 短信验证码登录 3. 用户信息 4.MongoDB 5. 推荐好友列表/MongoDB集群/动态发布与查看 6. 圈子 ...
- SpringBoot交友APP项目实战(详细介绍+案例源码) - 10.网关配置
系列文章目录 1. 项目介绍及环境配置 2. 短信验证码登录 3. 用户信息 4. MongoDB 5. 推荐好友列表/MongoDB集群/动态发布与查看 6. 圈子动态/圈子互动 7. 即时通讯(基 ...
最新文章
- English debate sample motion
- 华为云DevCloud重金悬赏,开发者大赛等你来战!
- 苍天饶过谁?| 今日最佳
- 第四十期:九个对Web开发者最有用的Python包,掌握这些,工资至少能涨涨
- 容量法和库仑法的异同点_卡尔费休滴定仪容量法与库仑法有什么区别
- python中类的属性一般来说_python中实例属性和类属性之间的关系
- python中集合的元素可以是任意数据类型_Python数据类型之列表
- 搭配android环境,Android Studio环境搭配所用到的工具和配置
- 单元测试用例_前端单元测试实践
- python实现点击按钮_python实现点击按钮修改数据的方法
- collections的defaultdict使用
- 数据结构导论(第一章概论)
- Macbook pro (m1)突然没有办法按住shift打出大写R
- 《软件随想录》读书笔记
- pandas(综合测试)
- JS中经纬度的正则表达式(亲测有效)
- 滴滴交通云落地济南 提速城市“智慧交通”建设
- Vue3 Suspense 组件
- 低照度图像 颜色恢复 matlab,低照度图像修复方法总结
- 商汤提出手机端实时单目三维重建系统,实现逼真AR效果和交互