BACK TO WRITING

从一份 Spring Boot 骨架说起:分层到底在分什么

Controller、Service、Mapper 各管什么,以及我在边界上踩过的坑。

刚开始写 Spring Boot 时,我把分层理解成「把代码分开放」:Controller 放接口,Service 放业务,Mapper 放 SQL。写着写着才发现,分层真正要解决的是职责边界——谁负责参数校验、谁负责事务、谁负责把数据变成前端需要的形状。

每一层该管什么

  • Controller:只做协议相关的事。接收参数、做基础校验、调用 Service、包装响应,不写业务判断。
  • Service:业务规则和事务边界都在这里,一个方法对应一个完整的业务动作。
  • Mapper:只负责数据读写,不掺业务判断。

我踩过的两个边界问题

事务开在哪一层。 一开始我把 @Transactional 加在 Controller 上,看起来也能跑。但当两个 Service 方法互相调用时,事务的传播行为就变得难以预测。后来统一规定:事务只加在 Service 的公开方法上。

DTO 和实体不要混用。 直接用实体接收前端参数,最直接的问题是:多出来的字段会被一起写进数据库。现在我给每个接口单独定义 DTO,返回时再转成 VO,虽然多写了几个类,但接口的边界清楚了。

一点体会

分层不是目录洁癖,而是让「改一处」时能预判影响范围。想清楚每一层不做什么,比想清楚它做什么更重要。