目录
SpringBoot 流程编排:Controller‑Service‑Mapper 分层职责 & 对比
核心思想:分层是职责隔离,流程编排就是把业务逻辑合理放在对应层,杜绝一层干所有活
各层基础职责
1. Controller(控制层)
定位:接收请求、参数校验、请求响应、路由,不写业务逻辑
- 接收http请求,接收前端入参(DTO)
- 参数基础校验(
@Valid、简单判空) - 调用Service,把入参传给service
- 捕获异常、封装返回结果VO、统一返回格式
- 禁止:数据库操作、复杂业务计算、事务、复杂if‑else业务逻辑
@RestController
@RequestMapping("/order")
public class OrderController {
// 只调用service
@Autowired
private OrderService orderService;
@PostMapping("/create")
public ResultVO create(@Valid @RequestBody OrderCreateDTO dto){
Long orderId = orderService.createOrder(dto);
return ResultVO.success(orderId);
}
}
2. Service(业务层,核心流程编排层)
定位:业务逻辑、流程编排、事务控制、业务规则组装,调用Mapper/其他Service
- 业务流程编排:多个数据库操作、外部接口调用、多步骤业务全部写在这里
- 事务注解
@Transactional打在此处 - 业务校验(业务规则,不是简单参数判空:比如订单金额不能为负、库存是否充足)
- DTO ↔ DO 数据转换
- 可以调用多个Mapper,也可以调用其他Service
- 禁止:接收HttpServletRequest、response,不要直接操作http响应;禁止写sql
@Service
public class OrderServiceImpl implements OrderService{
@Autowired
private OrderMapper orderMapper;
@Autowired
private StockMapper stockMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createOrder(OrderCreateDTO dto) {
// 【流程编排在这里】
//1.业务校验
//2.扣库存
//3.生成订单
//4.生成订单明细
//多步数据库操作,统一事务
}
}
3. Mapper(DAO数据访问层,MyBatis/MyBatis‑Plus)
定位:只做数据库CRUD,只负责和数据库交互,无业务逻辑
- 只写SQL/调用Mybatis‑Plus方法,增删改查
- 返回数据库实体DO
- 禁止:业务判断、循环业务逻辑、事务、调用其他mapper做业务流程>
Mapper只做“我要查什么、更新什么”,“什么时候查、查完之后做什么”交给Service编排
@Mapper
public interface OrderMapper extends BaseMapper<OrderDO> {
//仅数据库操作
}
三层核心对比表
| 维度 | Controller | Service | Mapper |
|---|---|---|---|
| 核心职责 | 请求接入、入参出参封装 | 业务流程编排、业务规则、事务 | 数据库CRUD |
| 可以写事务 | ❌ 禁止 | ✅ @Transactional |
❌禁止 |
| 可以写业务逻辑 | ❌只做转发 | ✅核心所有业务流程 | ❌不能有业务判断 |
| 依赖对象 | 依赖Service | 依赖Mapper、其他Service、Feign接口 | 仅数据库,不依赖业务层 |
| 输入输出 | DTO、VO(前端对象) | DTO/DO之间转换 | DO数据库实体 |
| 典型错误写法 | controller里面写for循环、写mapper、写大量if业务 | service写HttpServletResponse、写sql | mapper里做业务判断、多表业务逻辑 |
流程编排到底在哪做?
✅业务流程编排一定放在Service层
举例子:创建订单完整链路:参数校验→扣库存→创建主订单→创建订单明细→发送消息
这一串步骤、步骤顺序、异常回滚,全部在Service编排。
❌错误1:Controller直接调用Mapper,把业务写在controller,事务无法控制,复用困难。
❌错误2:Mapper做业务逻辑,sql写大量业务判断,业务和数据库强耦合,改业务要改SQL。
常见误区
- 简单查询,直接Controller调用Mapper行不行?
不推荐。即使简单查询,也建议过一层Service。后续业务迭代要加校验、缓存、日志,不用改动Controller。 - 一个Mapper方法对应一个Service方法?
不是。一个Service业务方法,可以调用N个Mapper方法。比如下单,调用库存mapper、订单mapper、订单明细mapper。 - 事务写在Controller?
绝对不可以。Controller是web层,AOP事务切面会失效,而且web层会有异常、http超时等干扰。 - Service里面不要写sql,sql全部下沉Mapper
分层数据流走向
前端http请求
↓
Controller(DTO) → 参数校验,转发给Service
↓
Service【流程编排、事务、业务逻辑】 ←→ 多个Mapper
↓
Mapper ↔ MySQL数据库
↓
Service返回数据 → Controller组装VO返回前端
扩展:复杂业务再拆分
当Service业务太重,可以继续拆分:
- BO层/Manager层:复杂业务编排,把大Service拆小,Service做流程调度,Manager做原子业务片段。
- DTO:前端入参;DO:数据库实体;VO:返回前端对象。
浙公网安备 33010602011771号