生产级 Spring Boot API — 第2部分:清晰代码结构、控制器与 DTO
发布: (2026年1月18日 GMT+8 03:52)
3 min read
原文: Dev.to
Source: Dev.to
本文涵盖内容
- 控制器职责(API 边界,而非业务逻辑)
- 为什么
@RestController不止是“返回 JSON” - 构造函数注入(以及它为何是强制性的)
- Spring 的 stereotype 注解以及语义为何重要
- 实体 vs DTO(以及为何暴露实体是危险的)
- 在生产系统中使用 Lombok
- 为什么 ModelMapper 能保持层次清晰
控制器层(API 边界)
@RestController
@RequestMapping("/orders")
public class OrderController {
private final OrderService orderService;
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
}
@RestController 的真实含义
- 将类注册为 HTTP 请求处理器
- 返回 JSON(而非视图)
- 与
DispatcherServlet集成
该类定义 API 合约,而不是业务逻辑。
构造函数注入(生产环境不可或缺)
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
为何使用构造函数注入:
- 依赖显式化
- 对象不可变
- 易于测试
- 启动时快速失败(如果缺少依赖,应用不应启动)
Stereotype 注解(语义很重要)
| 注解 | 用途 |
|---|---|
@Service | 业务逻辑 |
@Repository | 数据访问 |
@Controller | MVC 层 |
@RestController | REST API |
它们都继承自 @Component,但会添加意义、可读性以及层级特定的行为。
实体 vs DTO(绝不暴露实体)
实体
- 映射到数据库表
- 仅用于持久化
DTO
- 用于 API 通信
- 保护内部结构
实体随数据库需求变化;DTO 随 API 需求变化。
Lombok(生产环境的福音)
没有 Lombok 时:
- 缺少 setter → JSON 字段为
null - 缺少 getter → 响应为空
- 大量样板代码
使用 Lombok:
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Order {
private Long id;
private String description;
// other fields...
}
- 自动生成 getter / setter、构造函数、builder 等
- 让实体保持简洁
在大型 Spring Boot 代码库中,Lombok 几乎是必需的。
ModelMapper(保持层次分离)
- 在实体 ⇄ DTO 之间转换
- 让控制器保持简洁
- 防止泄露持久化模型
持久化指数据在应用运行时之外仍然存在(如存入数据库)。
这是一系列 3 篇文章中的第 2 篇,主题为 Production‑Grade Spring Boot API Design。
👉 第 3 篇 讨论一致的 API 响应、BaseResponse、ResponseEntity 以及全局异常处理。