6.2 构建 RESTful 应用接口
第6章 构建 RESTful 服务
6.1 RESTful 简介
6.2 构建 RESTful 应用接口
6.3 使用 Swagger 生成 Web API 文档
6.4 实战:实现 Web API 版本控制
6.2 构建 RESTful 应用接口
6.2.1 Spring Boot 对 RESTful 的支持
Spring Boot 提供的spring-boot-starter-web组件完全支持开发 RESTful API,提供了与 REST 操作方式(GET、POST、PUT、DELETE)对应的注解:
- @GetMapping:处理 GET 请求,获取资源。
- @PostMapping:处理 POST 请求,新增资源。
- @PutMapping:处理 PUT 请求,更新资源。
- @DeleteMapping:处理 DELETE 请求,删除资源。
- @PatchMapping:处理 PATCH 请求,用于部分更新资源。
通过这些注解就可以在 Spring Boot 项目中轻松构建 RESTful 接口。其中比较常用的是 @GetMapping、@PostMapping、@PutMapping、@DeleteMapping 四个注解。
使用 Spring Boot 开发 RESTful 接口非常简单,通过 @RestController 定义控制器,然后使用 @GetMapping 和 @PostMapping 等注解定义地址映射,实现相应的资源操作方法即可。
示例:
RESTfulController.java
package com.example.restfulproject.controller;import com.example.restfulproject.model.User;
import org.springframework.web.bind.annotation.*;/*** RESTful 接口简单案例(增删改查)*/
@RestController
public class RESTfulController {@GetMapping(value = "/user/{id}")public String getUserById(@PathVariable String id) {return "getUserById:" + id;}@PostMapping(value = "/user")public String save(@RequestBody User user) {String name = user.getName();return "save successed";}@PutMapping(value = "/user")public String update(@RequestBody User user) {return "update successed";}@DeleteMapping(value = "/user/{id}")public String delete(@PathVariable String id) {return "delete id:" + id;}/*// 上面的注解是 @RequestMapping 注解的简化:@RequestMapping(value = "/user/{id}", method = RequestMethod.GET)public String getUserById(@PathVariable String id) {return "getUserById:" + id;}@RequestMapping(value = "/user", method = RequestMethod.POST)public String save(User user) {return "save successed";}@RequestMapping(value = "/user", method = RequestMethod.PUT)public String update(User user) {return "update successed";}@RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE)public String delete(@PathVariable String id) {return "delete id:" + id;}
*/
}
6.2.2 Spring Boot 实现 RESTful API
1. 设计API
在 RESTful 架构中,每个网址代表一种资源,所以 URI 中建议不要包含动词,只包含名词即可,而且所用的名词往往与数据库的表名对应。
(1)接口定义
下表是用户管理模块的接口定义,实际项目的 RESTful API 文档要更详细,还会定义全部请求的数据结构体。
用户管理模块API说明
| HTTP Method | 接口地址 | 接口说明 |
|---|---|---|
| POST | /user | 创建用户 |
| GET | /user/id | 根据id获取用户信息 |
| PUT | /user | 更新用户 |
| DELETE | /user/id | 根据id删除对应的用户 |
上表中定义了用户管理模块的接口,根据 REST 的定义,我们将用户定义为一种资源,通过 POST、DELETE、PUT、GET 等 HTTP Method 实现对用户的增、删、改、查。
(2)状态码和提示信息定义
除了设计 URL 接口之外,还需要定义服务端向客户端返回的状态码和提示信息。详细状态码说明见下表。
用户管理模块状态码说明:
| 状态码 | 状态说明 |
|---|---|
| 200 | Ok,请求成功 |
| 201 | Created,新增成功 |
| 203 | Updated,修改成功 |
| 204 | Deleted,删除成功 |
除了定义用户管理相关的业务状态码之外,还需要定义通用的错误码,如 400 对应数据校验错误、401 对应数据无权限等。
用户管理模块错误码说明:
| 错误码 | 错误说明 |
|---|---|
| 400 | 数据验证错误 |
| 401 | 无权限 |
| 404 | 资源不存在 |
| 500 | 服务端错误 |
2. 实现用户管理接口
UserManagementController.java
package com.example.restfulproject.controller;import com.example.restfulproject.comm.utils.JSONResult;
import com.example.restfulproject.model.User;
import org.springframework.web.bind.annotation.*;/*** Spring Boot 实现 RESTful API*/
@RestController
@RequestMapping("/userManagement")
public class UserManagementController {/*** 用户新增*/@PostMapping(value = "/user")public JSONResult save(@RequestBody User user) {System.out.println("用户创建成功:" + user.getName());return JSONResult.ok(201, "用户创建成功");}/*** 用户修改*/@PutMapping(value = "/user")public JSONResult update(@RequestBody User user) {System.out.println("用户修改成功:" + user.getName());return JSONResult.ok(203, "用户修改成功");}/*** 用户删除*/@DeleteMapping(value = "/user/{userId}")public JSONResult delete(@PathVariable String userId) {System.out.println("用户删除成功:" + userId);return JSONResult.ok(204, "用户删除成功");}/*** 获取用户*/@GetMapping(value = "/user/{userId}")public JSONResult queryUserById(@PathVariable String userId) {User user = new User();user.setId(userId);user.setName("zhangsan");user.setAge(20);System.out.println("获取用户成功:" + userId);return JSONResult.ok(200, "获取用户成功", user);}}
JSONResult.java
package com.example.restfulproject.comm.utils;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;import java.util.List;/*** 定义数据处理类** @Title:: JSONResult.java* @Package com.example.webproject.comm.utils* @Description: 自定义响应数据结构* 200: 表示成功* 500: 表示错误,错误信息在 msg 字段中* 501: bean 验证错误,无论多少个错误都以 map 形式返回* 502: 拦截器拦截到用户 token 出错* 555: 异常抛出信息* Copyright: Copyright (c) 2023** @create: 2023-02-05 17:35:54* @Modify: 2023-02-17 19:41:30* @version V1.1*/
public class JSONResult {// 定义 jackson 对象 (关于jackson的使用详解请参考:https://juejin.cn/post/6844904166809157639)private static final ObjectMapper MAPPER = new ObjectMapper();// 响应业务状态private Integer code;// 响应消息private String msg;// 响应中的数据private Object data;public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public Object getData() {return data;}public void setData(Object data) {this.data = data;}public JSONResult() {}public JSONResult(Integer code, String msg, Object data) {this.code = code;this.msg = msg;this.data = data;}public JSONResult(Object data) {this.code = 200;this.msg = "OK";this.data = data;}// // 是否成功
// public Boolean isSuccess() {
// return this.code == 200;
// }// 构建返回的数据public static JSONResult build(Integer status, String msg, Object data) {return new JSONResult(status, msg, data);}// 200:成功,有返回值public static JSONResult ok(Object data) {return new JSONResult(data);}// 200:成功,没有返回值public static JSONResult ok() {return new JSONResult(null);}//200:成功,没有返回值public static JSONResult ok(Integer code, String msg) {return new JSONResult(code, msg, null);}// 200: 成功public static JSONResult ok(Integer code, String msg, Object data) {return new JSONResult(code, msg, data);}//500:错误,错误信息在 msg 字段中public static JSONResult errorMsg(String msg) {return new JSONResult(500, msg, null);}//501:bean 验证错误,无论多少个错误都以 map 形式返回public static JSONResult errorMap(Object data) {return new JSONResult(501, "error", data);}//502:拦截器拦截到用户 token 出错public static JSONResult errorTokenMsg(String msg) {return new JSONResult(502, msg, null);}//555:异常抛出信息public static JSONResult errorException(String msg) {return new JSONResult(555, msg, null);}/*** @Description: 将 json 结果集转化为 JSONResult 对象,需要转换的对象是一个类** @param jsonData* @param clazz* @return*/public static JSONResult formatToPojo(String jsonData, Class<?> clazz) {try {if (clazz == null) {return MAPPER.readValue(jsonData, JSONResult.class);}JsonNode jsonNode = MAPPER.readTree(jsonData);JsonNode data = jsonNode.get("data");Object obj = null;if (clazz != null) {if (data.isObject()) {obj = MAPPER.readValue(data.traverse(), clazz);} else if (data.isTextual()) {obj = MAPPER.readValue(data.asText(), clazz);}}return build(jsonNode.get("code").intValue(), jsonNode.get("msg").asText(), obj);} catch (Exception e) {return null;}}/*** @Description: 没有 object 对象的转化** @param json* @return*/public static JSONResult format(String json) {try {return MAPPER.readValue(json, JSONResult.class);} catch (JsonProcessingException e) {e.printStackTrace();}return null;}/*** @Description: Object 是集合转化,需要转换的对象是一个list** @param jsonData* @param clazz* @return*/public static JSONResult formatToList(String jsonData, Class<?> clazz) {try {JsonNode jsonNode = MAPPER.readTree(jsonData);JsonNode data = jsonNode.get("data");Object obj = null;if(data.isArray() && data.size() > 0) {obj = MAPPER.readValue(data.traverse(), MAPPER.getTypeFactory().constructCollectionType(List.class,clazz));}return build(jsonNode.get("code").intValue(), jsonNode.get("msg").asText(), obj);} catch (Exception e) {return null;}}}
3. 验证测试
(1)获取用户:http://localhost:8080/userManagement/user/2001

(2)用户新增:http://localhost:8080/userManagement/user

(3)用户修改:http://localhost:8080/userManagement/user

(4)用户删除:http://localhost:8080/userManagement/user/2001

来源:《Spring Boot 从入门到实战》学习笔记
相关文章:
6.2 构建 RESTful 应用接口
第6章 构建 RESTful 服务 6.1 RESTful 简介 6.2 构建 RESTful 应用接口 6.3 使用 Swagger 生成 Web API 文档 6.4 实战:实现 Web API 版本控制 6.2 构建 RESTful 应用接口 6.2.1 Spring Boot 对 RESTful 的支持 Spring Boot 提供的spring-boot-starter-web组件完全…...
20230218英语学习
How Italian Artist’s Mild Colors Dominate World of Design 温柔的“莫兰迪色”,如何引领设计时尚? The Morandi color scheme has become an across-the-board fashion that now prevails in the world of design.Soft and sophisticated Morandi c…...
Linux单一服务管理systemctl
基本上systemd这个启动服务机制只有systemctl命令来处理,所以全部的操作都需要使用systemctl systemctl管理单一服务 一般来说服务的启动有两个阶段,一个是开机是否启动,以及现在是否启动 systemctl【command】【unit】 command主要有&…...
【GStreamer 】 TX1中CPU和GPU解码显示海康相机RTSP流
大家好,我是虎哥,今天找了一套海康的相机,想后续测试一下DeepStream用网络相机RTSP流做输入看看后续目标识别和分类。但是还是想先实时看看视频,当然,可以选择VLC去查看,顺道我也用GStreamer 来测试了一下&…...
匿名内部类、Lambda表达式、方法引用对比分析
文章目录一、匿名内部类1. 语法格式2. 使用方法① 传统方式② 匿名内部类方式二、Lambda表达式1. 语法格式2. 使用方法① 匿名内部类方式② Lambda表达式方式三、方法引用1. 语法格式2. 使用方法① 类型的静态方法引用② 类型的构造方法引用③ 类型的实例方法引用④ 对象的实例…...
ESXi主机CVE-2021-21972漏洞复现安全处置建议
一、漏洞简介 vSphere 是 VMware 推出的虚拟化平台套件,包含 ESXi、vCenter Server 等一系列的软件。其中 vCenter Server 为 ESXi 的控制中心,可从单一控制点统一管理数据中心的所有 vSphere 主机和虚拟机。 vSphere Client(HTML5…...
研报精选230217
目录 【行业230217毕马威】奢侈品行业新气象【行业230217国信证券】医药生物行业2023年2月投资策略:持续关注疫后复苏和创新两大主线【行业230217国金证券】航空锻造:稳定格局筑专业化壁垒,顺势而为拓产业链深度【个股230217西南证券_招商轮船…...
c++11 标准模板(STL)(std::unordered_set)(一)
定义于头文件 <unordered_set> template< class Key, class Hash std::hash<Key>, class KeyEqual std::equal_to<Key>, class Allocator std::allocator<Key> > class unordered_set;(1)(C11 起)namespace pmr { templ…...
【C语言进阶】你听说过柔性数组吗?
👦个人主页:Weraphael ✍🏻作者简介:目前是C语言学习者 ✈️专栏:C语言航路 🐋 希望大家多多支持,咱一起进步!😁 如果文章对你有帮助的话 欢迎 评论💬 点赞&a…...
[LeetCode]1237. 找出给定方程的正整数解
题目链接:https://leetcode.cn/problems/find-positive-integer-solution-for-a-given-equation/description/ 题目描述: 样例1: 输入:function_id 1, z 5 输出:[[1,4],[2,3],[3,2],[4,1]] 解释:functi…...
【路径规划】基于A*算法和Dijkstra算法的路径规划(Python代码实现)
👨🎓个人主页:研学社的博客💥💥💞💞欢迎来到本博客❤️❤️💥💥🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密…...
蓝桥杯 stm32 PWM 设置占空比
本文代码使用 HAL 库。 文章目录 前言一、创建CubeMX 工程 ,占空比分析:二、相关函数:1. 获取 CNT函数2.设置CNT为 0 函数(计算器清零)3.开启TIM2_CH1的输入捕获中断函数4.TIM 回调函数三、设置上升沿,下降沿四、在lcd上显示 R40 占空比 详细代码五、设置占空比,输出 PW…...
React 合成事件理解
1 事件三个阶段 捕获、目标、处理 (具体百度,后面有空补全)2import React from "react";class Test extends React.Component {parentRef;childRef;constructor(props) {super(props);this.parentRef React.createRef();this.chil…...
202302|读书笔记——国图点滴
杂志剪影|看一本赚一本系列 anywhere 随心而行随心而动,极简相生复古文艺 热情洋溢 色彩斑斓 极致优雅 深邃魅力 新生绽放 灿若星空 异彩纷呈含苞待放 惊艳绽放 爱在云端 空中婚礼 暗夜浪漫 策马逐梦橘影相映 浆果红唇 梦幻无暇 永无止境浮光掠影 微酥清风低调奢华…...
Linux 操作系统原理 — NUMA 架构中的多线程调度开销与性能优化
目录 文章目录 目录前言NUMA 架构中的多线程性能开销1、跨 Node 的 Memory 访问开销2、跨 Core 的多线程 Cache 同步开销3、多线程上下文切换开销4、多线程模式切换开销5、中断处理的开销6、TLB 缓存失效的开销7、内存拷贝的开销NUMA 架构中的性能优化:使用多核编程代替多线程…...
OpenGL - 如何理解 VAO 与 VBO 之间的关系
系列文章目录 LearnOpenGL 笔记 - 入门 01 OpenGLLearnOpenGL 笔记 - 入门 02 创建窗口LearnOpenGL 笔记 - 入门 03 你好,窗口LearnOpenGL 笔记 - 入门 04 你好,三角形 文章目录系列文章目录1. 前言2. 渲染管线的入口 - 顶点着色器2.1 顶点着色器处理过…...
Linux中sed的使用
语法: sed [选项] [sed内置命令字符] [输入文件]选项: 参数说明-n取消默认色的输出常与sed内置命令p一起使用-i直接将修改结果写入文件,不用-i,sed修改的是内存数据-e多次编译,不需要管道符了-r支持正则扩展 sed的内…...
[软件工程导论(第六版)]第1章 软件工程学概述(复习笔记)
文章目录1.1 软件危机1.1.1 软件危机的介绍1.1.2 产生软件危机的原因1.1.3 消除软件危机的途径1.2 软件工程1.2.1 软件工程的介绍1.2.2 软件工程的基本原理1.2.3 软件工程方法学1.3 软件生命周期组成1.4 软件过程概念1.4.1 瀑布模型1.4.2 快速原型模型1.4.3 增量模型1.4.4 螺旋…...
ISP相关
Internet Service Provider,网络提供商/运营商,如电信、联通、移动等。 1. 与ISP互联的出口带宽 IDC或云提供商会与各运营商互联,互联的具体带宽数值一旦泄露,就会被恶意的攻击者利用。例如,若DDos攻击者知道了被攻击…...
vTESTstudio - VT System CAPL Functions - VT2004(续1)
成熟,就是某一个突如其来的时刻,把你的骄傲狠狠的踩到地上,任其开成花或者烂成泥。vtsStartStimulation - 启动激励输出功能:自动激励输出注意:在启动激励输出之前,一定要设置好输出模式Target:目标通道变量空间名称,例…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...
