SpringBoot从零搭建项目系列(四)|RESTful API设计与实现
📝 文章摘要:本文是SpringBoot系列的第四篇,深入讲解RESTful API设计原则和最佳实践,包括统一响应封装、API文档生成、接口安全防护、性能监控等核心技术,帮助读者构建高质量的Web API服务。
📋 前言与概述
在前三篇文章中,我们完成了开发环境搭建、配置管理和项目架构设计。今天我们将聚焦于RESTful API的设计与实现,这是现代Web应用的核心组成部分。优秀的API设计不仅能提升开发效率,更能为用户提供良好的使用体验。
🎯 RESTful API的重要性
核心价值:
- 🌐 标准化接口:遵循REST约束,便于理解和使用
- 🔧 松耦合设计:前后端分离,提高开发效率
- 📱 多端适配:一套API服务多种客户端
- 🚀 易于扩展:支持版本控制和功能迭代
- 🛡️ 安全保障:完善的认证授权机制
🎯 本文学习目标
学完本章后,你将能够:
- ✅ 掌握RESTful设计原则和最佳实践
- ✅ 实现统一的API响应格式封装
- ✅ 集成Swagger自动生成API文档
- ✅ 设计完善的接口安全防护机制
- ✅ 实现API性能监控和限流控制
- ✅ 处理跨域和版本控制问题
💡 前置知识:需要掌握前三篇的项目架构和异常处理内容
🌐 RESTful设计原则
2.1 REST架构约束
2.1.1 六大约束原则
// RESTful控制器设计示例
@RestController
@RequestMapping(\”/api/v1/users\”)
@Slf4j
public class UserRestController {
/**
* 统一资源标识符 (URI)
* 使用名词表示资源,避免动词
*/
// ✅ 推荐做法
@GetMapping(\”/{id}\”) // 获取单个用户
@PostMapping // 创建用户
@PutMapping(\”/{id}\”) // 更新用户(全量)
@PatchMapping(\”/{id}\”) // 更新用户(部分)
@DeleteMapping(\”/{id}\”) // 删除用户
// ❌ 避免的做法
// @GetMapping(\”/getUserById/{id}\”)
// @PostMapping(\”/createUser\”)
// @GetMapping(\”/listAllUsers\”)
/**
* 统一接口 (Uniform Interface)
* 使用标准HTTP方法操作资源
*/
@GetMapping(\”/{id}\”)
public ResponseEntity<ApiResponse<UserResponse>> getUser(@PathVariable Long id) {
// GET: 查询资源
UserResponse user = userService.findById(id);
return ResponseEntity.ok(ApiResponse.success(user));
}
@PostMapping
public ResponseEntity<ApiResponse<UserResponse>> createUser(@RequestBody UserCreateRequest request) {
// POST: 创建资源
UserResponse user = userService.create(request);
return ResponseEntity.status(HttpStatus.CREATED)
.body(ApiResponse.success(\”用户创建成功\”, user));
}
@PutMapping(\”/{id}\”)
public ResponseEntity<ApiResponse<UserResponse>> updateUser(
@PathVariable Long id, @RequestBody UserUpdateRequest request) {
// PUT: 更新资源(全量)
UserResponse user = userService.update(id, request);
return ResponseEntity.ok(ApiResponse.success(\”用户更新成功\”, user));
}
@DeleteMapping(\”/{id}\”)
public ResponseEntity<ApiResponse<Void>> deleteUser(@PathVariable Long id) {
// DELETE: 删除资源
userService.delete(id);
return ResponseEntity.noContent().build();
}
}
2.1.2 资源设计原则
// 资源层次结构设计
@RestController
@RequestMapping(\”/api/v1\”)
public class ResourceHierarchyController {
/*
* 资源层次关系示例:
*
* 用户资源: /users
* ├── 用户基本信息: /users/{id}
* ├── 用户订单: /users/{id}/orders
* ├── 用户地址: /users/{id}/addresses
* └── 用户权限: /users/{id}/permissions
*
* 订单资源: /orders
* ├── 订单详情: /orders/{id}
* ├── 订单项: /orders/{id}/items
* └── 订单支付: /orders/{id}/payment
*/
// 用户订单查询
@GetMapping(\”/users/{userId}/orders\”)
public ApiResponse<PageResponse<OrderResponse>> getUserOrders(
@PathVariable Long userId,
@RequestParam(defaultValue = \”1\”) Long page,
@RequestParam(defaultValue = \”10\”) Long size) {
// 实现逻辑…
return ApiResponse.success(orderService.getUserOrders(userId, page, size));
}
// 订单支付
@PostMapping(\”/orders/{orderId}/payment\”)
public ApiResponse<PaymentResponse> payOrder(
@PathVariable Long orderId,
@RequestBody PaymentRequest request) {
// 实现逻辑…
return ApiResponse.success(paymentService.processPayment(orderId, request));
}
}
2.2 HTTP状态码规范
// HttpStatusUtil.java – HTTP状态码工具类
public class HttpStatusUtil {
// 2xx 成功状态码
public static final HttpStatus OK = HttpStatus.OK; // 200
public static final HttpStatus CREATED = HttpStatus.CREATED; // 201
public static final HttpStatus ACCEPTED = HttpStatus.ACCEPTED; // 202
public static final HttpStatus NO_CONTENT = HttpStatus.NO_CONTENT; // 204
// 3xx 重定向状态码
public static final HttpStatus MOVED_PERMANENTLY = HttpStatus.MOVED_PERMANENTLY; // 301
public static final HttpStatus FOUND = HttpStatus.FOUND; // 302
public static final HttpStatus NOT_MODIFIED = HttpStatus.NOT_MODIFIED; // 304
// 4xx 客户端错误状态码
public static final HttpStatus BAD_REQUEST = HttpStatus.BAD_REQUEST; // 400
public static final HttpStatus UNAUTHORIZED = HttpStatus.UNAUTHORIZED; // 401
public static final HttpStatus FORBIDDEN = HttpStatus.FORBIDDEN; // 403
public static final HttpStatus NOT_FOUND = HttpStatus.NOT_FOUND; // 404
public static final HttpStatus METHOD_NOT_ALLOWED = HttpStatus.METHOD_NOT_ALLOWED; // 405
public static final HttpStatus CONFLICT = HttpStatus.CONFLICT; // 409
public static final HttpStatus TOO_MANY_REQUESTS = HttpStatus.TOO_MANY_REQUESTS; // 429
// 5xx 服务器错误状态码
public static final HttpStatus INTERNAL_SERVER_ERROR = HttpStatus.INTERNAL_SERVER_ERROR; // 500
public static final HttpStatus NOT_IMPLEMENTED = HttpStatus.NOT_IMPLEMENTED; // 501
public static final HttpStatus BAD_GATEWAY = HttpStatus.BAD_GATEWAY; // 502
public static final HttpStatus SERVICE_UNAVAILABLE = HttpStatus.SERVICE_UNAVAILABLE; // 503
}
// ApiController.java – 状态码使用示例
@RestController
@RequestMapping(\”/api/examples\”)
public class ApiController {
@GetMapping(\”/success\”)
public ResponseEntity<ApiResponse<String>> successExample() {
return ResponseEntity.ok(ApiResponse.success(\”操作成功\”));
}
@PostMapping(\”/created\”)
public ResponseEntity<ApiResponse<UserResponse>> createdExample(@RequestBody UserCreateRequest request) {
UserResponse user = userService.create(request);
return ResponseEntity.status(HttpStatusUtil.CREATED)
.body(ApiResponse.success(\”用户创建成功\”, user));
}
@GetMapping(\”/no-content\”)
public ResponseEntity<Void> noContentExample() {
// 执行某些操作但不需要返回数据
someService.doSomething();
return ResponseEntity.status(HttpStatusUtil.NO_CONTENT).build();
}
@GetMapping(\”/bad-request\”)
public ResponseEntity<ApiResponse<Void>> badRequestExample(@RequestParam String param) {
if (StringUtils.isBlank(param)) {
return ResponseEntity.badRequest()
.body(ApiResponse.error(ErrorCodeEnum.PARAM_ERROR, \”参数不能为空\”));
}
return ResponseEntity.ok(ApiResponse.success());
}
@GetMapping(\”/not-found\”)
public ResponseEntity<ApiResponse<Void>> notFoundExample(@RequestParam Long id) {
User user = userService.findById(id);
if (user == null) {
return ResponseEntity.status(HttpStatusUtil.NOT_FOUND)
.body(ApiResponse.error(ErrorCodeEnum.USER_NOT_FOUND));
}
return ResponseEntity.ok(ApiResponse.success(new UserResponse(user)));
}
}
📦 统一响应格式封装
3.1 响应对象增强
// EnhancedApiResponse.java – 增强版响应对象
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class EnhancedApiResponse<T> {
/**
* 响应状态
*/
@Schema(description = \”响应状态\”, example =


