AI摘要
文章系统梳理RESTful API设计全流程:资源导向URL、状态码、版本策略;统一请求响应与分页格式;分组参数校验;Swagger/Spring REST Docs文档化;JWT安全、限流及性能监控切面实践,为前后端协作提供可落地规范。
(一) RESTful API设计深度实践
1. 资源导向的URL设计
@RestController
@RequestMapping("/api/v1")
public class UserController {
// 好的设计:资源导向,HTTP方法明确
@GetMapping("/users") // 获取用户列表
@PostMapping("/users") // 创建用户
@GetMapping("/users/{id}") // 获取特定用户
@PutMapping("/users/{id}") // 全量更新用户
@PatchMapping("/users/{id}") // 部分更新用户
@DeleteMapping("/users/{id}") // 删除用户
// 针对资源的操作
@PostMapping("/users/{id}/activate") // 激活用户
@GetMapping("/users/{id}/orders") // 获取用户的订单
}2. HTTP状态码的正确使用
@RestController
public class ResponseCodeController {
@PostMapping("/users")
public ResponseEntity<UserVO> createUser(@Valid @RequestBody UserDTO userDTO) {
try {
UserVO user = userService.createUser(userDTO);
return ResponseEntity.status(HttpStatus.CREATED).body(user);
} catch (DuplicateUserException e) {
return ResponseEntity.status(HttpStatus.CONFLICT).build();
}
}
@GetMapping("/users/{id}")
public ResponseEntity<UserVO> getUser(@PathVariable Long id) {
return userService.findById(id)
.map(user -> ResponseEntity.ok(user))
.orElse(ResponseEntity.notFound().build());
}
@PutMapping("/users/{id}")
public ResponseEntity<UserVO> updateUser(@PathVariable Long id,
@Valid @RequestBody UserDTO userDTO) {
try {
UserVO user = userService.updateUser(id, userDTO);
return ResponseEntity.ok(user);
} catch (UserNotFoundException e) {
return ResponseEntity.notFound().build();
}
}
}3. 版本管理策略对比
// 方案1:URI路径版本(最常用)
@RestController
@RequestMapping("/api/v1/users")
public class UserControllerV1 { /* ... */ }
@RestController
@RequestMapping("/api/v2/users")
public class UserControllerV2 { /* ... */ }
// 方案2:请求头版本
@GetMapping(value = "/users", headers = "API-Version=1")
public ResponseEntity<?> getUsersV1() { /* ... */ }
@GetMapping(value = "/users", headers = "API-Version=2")
public ResponseEntity<?> getUsersV2() { /* ... */ }
// 方案3:媒体类型版本
@GetMapping(value = "/users", produces = "application/vnd.company.v1+json")
public ResponseEntity<?> getUsersV1() { /* ... */ }(二) 请求和响应设计规范
1. 统一的请求/响应格式
@Data
public class ApiRequest<T> {
private String requestId; // 请求ID,用于链路追踪
private Long timestamp; // 请求时间戳
private T data; // 请求数据
private Map<String, String> ext; // 扩展字段
}
@Data
public class ApiResponse<T> {
private Boolean success; // 是否成功
private Integer code; // 状态码
private String message; // 消息
private T data; // 响应数据
private String traceId; // 链路追踪ID
private Long timestamp; // 响应时间戳
public static <T> ApiResponse<T> success(T data) {
ApiResponse<T> response = new ApiResponse<>();
response.setSuccess(true);
response.setCode(200);
response.setMessage("成功");
response.setData(data);
response.setTimestamp(System.currentTimeMillis());
return response;
}
public static ApiResponse<?> error(Integer code, String message) {
ApiResponse<Object> response = new ApiResponse<>();
response.setSuccess(false);
response.setCode(code);
response.setMessage(message);
response.setTimestamp(System.currentTimeMillis());
return response;
}
}2. 分页响应标准化
@Data
public class PageResponse<T> {
private List<T> list; // 当前页数据
private Long total; // 总记录数
private Integer pageSize; // 每页大小
private Integer pageNum; // 当前页码
private Integer totalPages; // 总页数
private Boolean hasNext; // 是否有下一页
private Boolean hasPrevious; // 是否有上一页
public static <T> PageResponse<T> of(List<T> list, Long total, Integer pageNum, Integer pageSize) {
PageResponse<T> response = new PageResponse<>();
response.setList(list);
response.setTotal(total);
response.setPageNum(pageNum);
response.setPageSize(pageSize);
response.setTotalPages((int) Math.ceil((double) total / pageSize));
response.setHasNext(pageNum < response.getTotalPages());
response.setHasPrevious(pageNum > 1);
return response;
}
}
// 在Controller中的使用
@GetMapping("/users")
public ApiResponse<PageResponse<UserVO>> getUsers(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
UserQuery query) {
PageHelper.startPage(pageNum, pageSize);
List<UserVO> users = userService.findUsers(query);
PageInfo<UserVO> pageInfo = new PageInfo<>(users);
PageResponse<UserVO> pageResponse = PageResponse.of(
users, pageInfo.getTotal(), pageNum, pageSize
);
return ApiResponse.success(pageResponse);
}(三) 参数校验和错误处理
1. 验证注解的深度使用
@Data
public class UserDTO {
@NotBlank(message = "用户名不能为空")
@Size(min = 2, max = 20, message = "用户名长度必须在2-20之间")
@Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "用户名只能包含字母、数字和下划线")
private String username;
@Email(message = "邮箱格式不正确")
private String email;
@NotNull(message = "年龄不能为空")
@Min(value = 1, message = "年龄必须大于0")
@Max(value = 150, message = "年龄必须小于150")
private Integer age;
@NotNull(message = "创建时间不能为空")
@Past(message = "创建时间必须是过去时间")
private LocalDateTime createTime;
@Valid // 嵌套验证
private AddressDTO address;
@AssertTrue(message = "密码和确认密码必须一致")
public boolean isPasswordMatch() {
return password != null && password.equals(confirmPassword);
}
}
@Data
public class AddressDTO {
@NotBlank(message = "省份不能为空")
private String province;
@NotBlank(message = "城市不能为空")
private String city;
}2. 分组验证
// 定义验证组
public interface CreateGroup {}
public interface UpdateGroup {}
@Data
public class UserDTO {
@Null(groups = CreateGroup.class, message = "创建时ID必须为空")
@NotNull(groups = UpdateGroup.class, message = "更新时ID不能为空")
private Long id;
@NotBlank(groups = {CreateGroup.class, UpdateGroup.class})
private String username;
}
// 在Controller中使用分组验证
@PostMapping("/users")
public ApiResponse<?> createUser(@Validated(CreateGroup.class) @RequestBody UserDTO userDTO) {
// 创建用户逻辑
}
@PutMapping("/users/{id}")
public ApiResponse<?> updateUser(@PathVariable Long id,
@Validated(UpdateGroup.class) @RequestBody UserDTO userDTO) {
// 更新用户逻辑
}(四) API文档化和测试
1. 使用Swagger/OpenAPI生成文档
@Configuration
@EnableOpenApi
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.controller"))
.paths(PathSelectors.any())
.build()
.globalRequestParameters(globalRequestParameters())
.globalResponses(HttpMethod.GET, globalResponseMessages());
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("用户服务API文档")
.description("用户管理相关接口")
.version("1.0")
.contact(new Contact("开发团队", "", "dev@example.com"))
.build();
}
}
// 在Controller中使用注解
@RestController
@Api(tags = "用户管理")
@RequestMapping("/api/v1/users")
public class UserController {
@ApiOperation("创建用户")
@ApiImplicitParams({
@ApiImplicitParam(name = "userDTO", value = "用户信息", required = true)
})
@ApiResponses({
@ApiResponse(code = 201, message = "创建成功"),
@ApiResponse(code = 400, message = "参数错误")
})
@PostMapping
public ResponseEntity<UserVO> createUser(@Valid @RequestBody UserDTO userDTO) {
// ...
}
}2. 使用Spring REST Docs生成文档
@SpringBootTest
@AutoConfigureRestDocs
class UserApiDocumentation {
@Test
void getUserExample() throws Exception {
mockMvc.perform(get("/users/1").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("get-user",
pathParameters(
parameterWithName("id").description("用户ID")
),
responseFields(
fieldWithPath("id").description("用户ID"),
fieldWithPath("username").description("用户名"),
fieldWithPath("email").description("邮箱")
)
));
}
}(五) API安全和性能优化
1. 安全措施
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/public/**").permitAll()
.antMatchers("/api/**").authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
// 接口限流
@RestController
@Slf4j
public class RateLimitedController {
private final RateLimiter rateLimiter = RateLimiter.create(100); // 每秒100个请求
@GetMapping("/api/limited")
public ApiResponse<?> limitedApi() {
if (!rateLimiter.tryAcquire()) {
log.warn("接口限流触发");
return ApiResponse.error(429, "请求过于频繁");
}
// 正常业务逻辑
return ApiResponse.success("操作成功");
}
}2. 性能监控
@Aspect
@Component
@Slf4j
public class ApiPerformanceAspect {
@Around("@within(org.springframework.web.bind.annotation.RestController)")
public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
String methodName = joinPoint.getSignature().getName();
try {
Object result = joinPoint.proceed();
long costTime = System.currentTimeMillis() - startTime;
// 记录慢查询
if (costTime > 1000) {
log.warn("API执行缓慢: {}, 耗时: {}ms", methodName, costTime);
}
// 推送到监控系统
Metrics.counter("api.cost", "method", methodName).increment(costTime);
return result;
} catch (Exception e) {
Metrics.counter("api.error", "method", methodName).increment();
throw e;
}
}
}总结: 良好的API设计是前后端高效协作的基础。通过统一的规范、完善的文档、严格的校验和全面的监控,可以构建出健壮、易用、可维护的API体系。API设计不仅仅是技术实现,更是工程规范和团队协作的体现。