当前位置: 首页 > news >正文

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)对应的注解:

  1. @GetMapping:处理 GET 请求,获取资源。
  2. @PostMapping:处理 POST 请求,新增资源。
  3. @PutMapping:处理 PUT 请求,更新资源。
  4. @DeleteMapping:处理 DELETE 请求,删除资源。
  5. @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 接口之外,还需要定义服务端向客户端返回的状态码和提示信息。详细状态码说明见下表。

用户管理模块状态码说明:

状态码状态说明
200Ok,请求成功
201Created,新增成功
203Updated,修改成功
204Deleted,删除成功

除了定义用户管理相关的业务状态码之外,还需要定义通用的错误码,如 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
获取用户.png

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

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

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

来源:《Spring Boot 从入门到实战》学习笔记

http://www.lryc.cn/news/11538.html

相关文章:

  • 20230218英语学习
  • Linux单一服务管理systemctl
  • 【GStreamer 】 TX1中CPU和GPU解码显示海康相机RTSP流
  • 匿名内部类、Lambda表达式、方法引用对比分析
  • ESXi主机CVE-2021-21972漏洞复现安全处置建议
  • 研报精选230217
  • c++11 标准模板(STL)(std::unordered_set)(一)
  • 【C语言进阶】你听说过柔性数组吗?
  • [LeetCode]1237. 找出给定方程的正整数解
  • 【路径规划】基于A*算法和Dijkstra算法的路径规划(Python代码实现)
  • 蓝桥杯 stm32 PWM 设置占空比
  • React 合成事件理解
  • 202302|读书笔记——国图点滴
  • Linux 操作系统原理 — NUMA 架构中的多线程调度开销与性能优化
  • OpenGL - 如何理解 VAO 与 VBO 之间的关系
  • Linux中sed的使用
  • [软件工程导论(第六版)]第1章 软件工程学概述(复习笔记)
  • ISP相关
  • vTESTstudio - VT System CAPL Functions - VT2004(续1)
  • WeakMap弱引用
  • Springboot 使用quartz 定时任务 增删改查
  • 华为OD机试 - 猜字谜(Python) | 机试题+算法思路 【2023】
  • Linux常用命令汇总
  • 1.TCP、UDP区别、TCP/IP七层、四层模型、应用层协议(计网)
  • 气敏电阻的原理,结构,分类及应用场景总结
  • 实验10 拓扑排序与最短路径2022
  • C/C++每日一练(20230218)
  • 【C语言】预编译
  • 音频信号处理笔记(一)
  • 【深度学习】模型评估