欢迎光临
我们一直在努力

第十课实战版:Controller 层的正确打开方式 —— 接口不是业务层

一、这一课在整个后端体系中的位置

如果说:

  • 第9课解决的是:系统如何稳定地“失败”

  • 那第10课解决的是:系统如何“正确地被调用”

👉 第9课是底座(Infrastructure)
👉 第10课是门面(Interfaces)

Controller 所在的层,不是业务层,而是:

协议适配层(Protocol Adapter Layer)

就像 Android 的 Activity / ViewModel:
负责接输入、做校验、转模型、调业务、给输出。

二、Controller 层的唯一定位(一句话定生死)

👉 Controller 只做五件事:
接请求 → 校验 → 转换 → 调用 → 返回

除此之外,一律禁止。

三、工程目录规范(可直接用)

interfaces
└── http
├── controller // 接口入口
├── dto
│ ├── request // 请求模型
│ └── response // 返回模型
└── assembler // DTO ↔ 内部模型转换

配合第9课:

infrastructure/common
├── result
├── exception
├── error
├── web

👉 这两块,就是“接口系统”的全部骨架。

四、Controller 层允许 & 禁止清单(工程红线)

✅ Controller 允许做的

  • 接收 HTTP 参数
  • 参数校验
  • DTO ↔ Command / Query 转换
  • 调用 Application Service
  • 返回 Result

❌ Controller 严禁做的

  • 写业务 if/else
  • 控事务
  • 捕获业务异常
  • 调 Repository
  • 拼复杂领域对象
  • 处理状态流转

👉 一句话:Controller 脏,系统必烂。

五、参数校验:接口质量第一道防线

1️⃣ 请求 DTO(只为接口存在)

public class RegisterReq {

@NotBlank(message = "手机号不能为空")
@Pattern(regexp = "^1[3-9]\\\\d{9}$", message = "手机号格式不正确")
private String phone;

@NotBlank(message = "密码不能为空")
@Size(min = 6, max = 20, message = "密码长度必须 6-20 位")
private String password;
}

👉 DTO 只服务协议,不参与业务。

2️⃣ Controller 开启校验

@PostMapping("/users")
public Result<UserDTO> register(@Validated @RequestBody RegisterReq req) {

}

参数非法 → ValidationException → 第9课异常体系。

六、Assembler:接口边界隔离器

Assembler 的作用只有一个:

👉 隔离“接口模型”和“系统模型”

防止 HTTP 把你的系统结构污染掉。

Request → Command

public class UserAssembler {

public static RegisterUserCommand toCommand(RegisterReq req) {
RegisterUserCommand cmd = new RegisterUserCommand();
cmd.setPhone(req.getPhone());
cmd.setPassword(req.getPassword());
return cmd;
}
}

Domain → Response DTO

public static UserDTO toDTO(User user) {
UserDTO dto = new UserDTO();
dto.setId(user.getId());
dto.setPhone(user.getPhone());
return dto;
}

👉 这一步,相当于 Android 的:

  • VO ↔ Entity
  • NetworkModel ↔ UIModel

七、标准接口最小闭环(工程模板)

① Request DTO

RegisterReq

② Command(application 层)

RegisterUserCommand
 

③ Controller

@RestController
@RequestMapping("/users")
public class UserController {

@PostMapping
public Result<UserDTO> register(@Validated @RequestBody RegisterReq req) {
RegisterUserCommand cmd = UserAssembler.toCommand(req);
UserDTO dto = userAppService.register(cmd);
return Result.ok(dto, RequestId.get());
}
}

④ Application Service

public UserDTO register(RegisterUserCommand cmd) {
// 业务编排(事务、规则、领域调用)
}

👉 Controller 到此为止,不往下越界。

八、Controller 与第9课异常体系的协作

Controller 层只处理两种“失败”:

  • 参数非法(校验异常)
  • 协议错误(404 / 405 / JSON 错误)

其余:

  • 业务失败 → BizException
  • 系统失败 → Exception

全部由 GlobalExceptionHandler 兜底。

👉 Controller 无 try-catch。

九、第10课完成标准(项目自检表)

  • ✅ Controller 中无业务 if/else
  • ✅ Controller 不出现 Repository
  • ✅ 所有接口参数都有 DTO
  • ✅ DTO 不复用 Entity
  • ✅ 所有接口都有校验
  • ✅ 所有转换在 Assembler
  • ✅ 所有异常交给第9课

十、这一课对你意味着什么

从这一课开始,你已经不再是:

❌ 写接口的人
而是在做:

✅ 接口系统设计
✅ 协议边界治理
✅ 工程规范制定
✅ 质量防线构建

这是从“能写功能”迈向“能控系统”的标志。

十一、结尾总结

Controller 不是业务层,
而是系统的“前台大厅”。

大厅越干净,系统越稳定;
边界越清晰,系统越可控。

赞(0)
未经允许不得转载:171主机测评 » 第十课实战版:Controller 层的正确打开方式 —— 接口不是业务层
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址