Spring Boot怎么写REST?

wen python案例 2

本文目录导读:

Spring Boot怎么写REST?

  1. 基础配置
  2. 基本REST控制器
  3. 请求参数处理
  4. 返回结果封装
  5. 异常处理
  6. 数据验证
  7. 版本管理
  8. 高级特性
  9. 最佳实践建议

我来详细介绍Spring Boot编写REST API的几种方式。

基础配置

添加依赖

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

基本REST控制器

简单CRUD示例

@RestController
@RequestMapping("/api/users")
public class UserController {
    // GET - 获取所有用户
    @GetMapping
    public List<User> getAllUsers() {
        return userService.findAll();
    }
    // GET - 获取单个用户
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        return userService.findById(id)
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build());
    }
    // POST - 创建用户
    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public User createUser(@Valid @RequestBody User user) {
        return userService.save(user);
    }
    // PUT - 更新用户
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable Long id, 
                                          @Valid @RequestBody User user) {
        return userService.update(id, user)
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build());
    }
    // DELETE - 删除用户
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        if (userService.deleteById(id)) {
            return ResponseEntity.noContent().build();
        }
        return ResponseEntity.notFound().build();
    }
}

请求参数处理

@RestController
@RequestMapping("/api/products")
public class ProductController {
    // 路径参数
    @GetMapping("/category/{categoryId}")
    public List<Product> getByCategory(@PathVariable Long categoryId) {
        return productService.findByCategory(categoryId);
    }
    // 查询参数
    @GetMapping("/search")
    public List<Product> searchProducts(
            @RequestParam(required = false) String name,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size) {
        return productService.search(name, page, size);
    }
    // 多个参数
    @GetMapping("/filter")
    public List<Product> filterProducts(
            @RequestParam Map<String, String> allParams) {
        return productService.filter(allParams);
    }
}

返回结果封装

// 统一响应格式
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ApiResponse<T> {
    private int code;
    private String message;
    private T data;
    public static <T> ApiResponse<T> success(T data) {
        return new ApiResponse<>(200, "success", data);
    }
    public static <T> ApiResponse<T> error(int code, String message) {
        return new ApiResponse<>(code, message, null);
    }
}
// 使用统一响应
@RestController
@RequestMapping("/api/orders")
public class OrderController {
    @GetMapping("/{id}")
    public ApiResponse<Order> getOrder(@PathVariable Long id) {
        return orderService.findById(id)
            .map(ApiResponse::success)
            .orElse(ApiResponse.error(404, "订单不存在"));
    }
    @PostMapping
    public ApiResponse<Order> createOrder(@RequestBody Order order) {
        Order saved = orderService.save(order);
        return ApiResponse.success(saved);
    }
}

异常处理

@RestControllerAdvice
public class GlobalExceptionHandler {
    // 处理资源不存在
    @ExceptionHandler(ResourceNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ApiResponse<?> handleResourceNotFound(ResourceNotFoundException ex) {
        return ApiResponse.error(404, ex.getMessage());
    }
    // 处理参数验证失败
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ApiResponse<?> handleValidationExceptions(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getFieldErrors().forEach(error -> 
            errors.put(error.getField(), error.getDefaultMessage()));
        return ApiResponse.error(400, "参数验证失败");
    }
    // 处理其他异常
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ApiResponse<?> handleGenericException(Exception ex) {
        return ApiResponse.error(500, "服务器内部错误");
    }
}

数据验证

@Data
public class User {
    private Long id;
    @NotBlank(message = "用户名不能为空")
    @Size(min = 2, max = 50, message = "用户名长度2-50个字符")
    private String username;
    @NotBlank(message = "邮箱不能为空")
    @Email(message = "邮箱格式不正确")
    private String email;
    @Min(value = 1, message = "年龄必须大于0")
    @Max(value = 150, message = "年龄必须小于150")
    private Integer age;
    @Pattern(regexp = "^\\d{11}$", message = "手机号格式不正确")
    private String phone;
}

版本管理

// URL路径版本
@RestController
@RequestMapping("/api/v1/users")
public class UserV1Controller {
    // ...
}
@RestController
@RequestMapping("/api/v2/users")
public class UserV2Controller {
    // ...
}
// 请求头版本
@RestController
@RequestMapping(value = "/api/users", headers = "API-VERSION=1")
public class UserV1Controller {
    // ...
}

高级特性

// 支持HATEOAS
@RestController
@RequestMapping("/api/articles")
public class ArticleController {
    @GetMapping("/{id}")
    public EntityModel<Article> getArticle(@PathVariable Long id) {
        Article article = articleService.findById(id)
            .orElseThrow(() -> new ResourceNotFoundException("article", id));
        return EntityModel.of(article,
            linkTo(methodOn(ArticleController.class).getArticle(id)).withSelfRel(),
            linkTo(methodOn(ArticleController.class).getAllArticles()).withRel("articles"));
    }
}
// 分页支持
@GetMapping
public Page<Article> getAllArticles(
        @PageableDefault(size = 20, sort = "createdAt") Pageable pageable) {
    return articleService.findAll(pageable);
}

最佳实践建议

  1. 使用统一的响应格式 - 方便前端统一处理
  2. 正确处理HTTP状态码 - 合理使用200、201、204、400、404、500等
  3. 添加适当的验证 - @Valid、@Validated注解
  4. 实现异常处理 - 全局异常处理器
  5. API版本管理 - 便于接口演进
  6. 添加文档 - 使用Swagger/OpenAPI
  7. 使用DTO - 避免直接暴露实体类

这样你就有了一个完整的Spring Boot REST API实现。

抱歉,评论功能暂时关闭!