Spring Boot 3 实战:构建高可用 RESTful API 最佳实践
一、背景介绍
在企业级应用开发中,RESTful API 是前后端通信的核心方式。Spring Boot 3 基于 Jakarta EE 10,带来了诸多改进和新特性。本文将从零开始,带你构建一个生产级的高可用 RESTful API 项目。
二、项目搭建
2.1 初始化项目
使用 Spring Initializr 创建项目,选择以下依赖:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> </dependency> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <version>2.3.0</version> </dependency> </dependencies>2.2 统一响应封装
统一的 API 响应格式是高质量接口的基础:
public class ApiResponse<T> { private int code; private String message; private T data; private long timestamp; public static <T> ApiResponse<T> success(T data) { ApiResponse<T> response = new ApiResponse<>(); response.setCode(200); response.setMessage("success"); response.setData(data); response.setTimestamp(System.currentTimeMillis()); return response; } public static <T> ApiResponse<T> error(int code, String message) { ApiResponse<T> response = new ApiResponse<>(); response.setCode(code); response.setMessage(message); response.setTimestamp(System.currentTimeMillis()); return response; } }三、核心功能实现
3.1 全局异常处理
使用 @RestControllerAdvice 统一处理异常:
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<ApiResponse<Void>> handleNotFound(ResourceNotFoundException ex) { return ResponseEntity.status(HttpStatus.NOT_FOUND) .body(ApiResponse.error(404, ex.getMessage())); } @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ApiResponse<Map<String, String>>> handleValidation( MethodArgumentNotValidException ex) { Map<String, String> errors = new HashMap<>(); ex.getBindingResult().getFieldErrors() .forEach(err -> errors.put(err.getField(), err.getDefaultMessage())); return ResponseEntity.badRequest() .body(ApiResponse.error(400, "参数校验失败")); } @ExceptionHandler(Exception.class) public ResponseEntity<ApiResponse<Void>> handleGeneral(Exception ex) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(ApiResponse.error(500, "服务器内部错误")); } }3.2 请求参数校验
使用 Jakarta Validation 注解进行参数校验:
public class UserCreateRequest { @NotBlank(message = "用户名不能为空") @Size(min = 2, max = 20, message = "用户名长度2-20个字符") private String username; @NotBlank(message = "邮箱不能为空") @Email(message = "邮箱格式不正确") private String email; @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确") private String phone; }3.3 RESTful Controller 设计
@RestController @RequestMapping("/api/v1/users") @Tag(name = "用户管理", description = "用户 CRUD 接口") public class UserController { private final UserService userService; public UserController(UserService userService) { this.userService = userService; } @PostMapping @Operation(summary = "创建用户") public ResponseEntity<ApiResponse<UserVO>> create( @Valid @RequestBody UserCreateRequest request) { UserVO user = userService.create(request); return ResponseEntity.status(HttpStatus.CREATED) .body(ApiResponse.success(user)); } @GetMapping("/{id}") @Operation(summary = "查询用户") public ResponseEntity<ApiResponse<UserVO>> getById(@PathVariable Long id) { UserVO user = userService.findById(id); return ResponseEntity.ok(ApiResponse.success(user)); } @GetMapping @Operation(summary = "分页查询用户") public ResponseEntity<ApiResponse<PageResult<UserVO>>> list( @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size) { PageResult<UserVO> result = userService.list(page, size); return ResponseEntity.ok(ApiResponse.success(result)); } @PutMapping("/{id}") @Operation(summary = "更新用户") public ResponseEntity<ApiResponse<UserVO>> update( @PathVariable Long id, @Valid @RequestBody UserUpdateRequest request) { UserVO user = userService.update(id, request); return ResponseEntity.ok(ApiResponse.success(user)); } @DeleteMapping("/{id}") @Operation(summary = "删除用户") public ResponseEntity<ApiResponse<Void>> delete(@PathVariable Long id) { userService.delete(id); return ResponseEntity.ok(ApiResponse.success(null)); } }四、高可用设计
4.1 接口限流
使用 Bucket4j + Redis 实现分布式限流:
@Aspect @Component public class RateLimitAspect { @Around("@annotation(rateLimit)") public Object around(ProceedingJoinPoint point, RateLimit rateLimit) throws Throwable { String key = "rate_limit:" + point.getSignature().getName(); Bucket bucket = bucketRegistry.buildBucket(key, rateLimit); if (bucket.tryConsume(1)) { return point.proceed(); } throw new RateLimitExceededException("请求过于频繁,请稍后再试"); } }4.2 请求日志记录
@Component public class RequestLoggingFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { long start = System.currentTimeMillis(); chain.doFilter(request, response); long duration = System.currentTimeMillis() - start; log.info("[{}] {} {} - {}ms", request.getMethod(), request.getRequestURI(), response.getStatus(), duration); } }4.3 健康检查端点
@RestController @RequestMapping("/actuator") public class HealthController { @Autowired private DataSource dataSource; @GetMapping("/health") public ResponseEntity<Map<String, Object>> health() { Map<String, Object> health = new LinkedHashMap<>(); health.put("status", "UP"); health.put("timestamp", Instant.now().toString()); try (Connection conn = dataSource.getConnection()) { health.put("database", conn.isValid(2) ? "UP" : "DOWN"); } return ResponseEntity.ok(health); } }五、总结
本文从项目搭建到核心实现,再到高可用设计,完整展示了一个生产级 Spring Boot 3 RESTful API 的最佳实践:
- 统一响应封装:标准化 API 返回格式
- 全局异常处理:优雅的错误响应
- 参数校验:Jakarta Validation 保证数据合法性
- 接口限流:保护系统稳定性
- 请求日志:便于排查问题
- 健康检查:支持监控告警
掌握这些最佳实践,你就能构建出高质量、高可用的 RESTful API 服务!
