厦门市建设局网站规划标准经典seo伪原创
第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 从入门到实战》学习笔记