【MapSheep】
[好记性不如烂笔头]

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。

常见误区

  1. 简单查询,直接Controller调用Mapper行不行?
    不推荐。即使简单查询,也建议过一层Service。后续业务迭代要加校验、缓存、日志,不用改动Controller。
  2. 一个Mapper方法对应一个Service方法?
    不是。一个Service业务方法,可以调用N个Mapper方法。比如下单,调用库存mapper、订单mapper、订单明细mapper。
  3. 事务写在Controller?
    绝对不可以。Controller是web层,AOP事务切面会失效,而且web层会有异常、http超时等干扰。
  4. Service里面不要写sql,sql全部下沉Mapper

分层数据流走向

前端http请求
    ↓
Controller(DTO) → 参数校验,转发给Service
    ↓
Service【流程编排、事务、业务逻辑】 ←→ 多个Mapper
    ↓
Mapper ↔ MySQL数据库
    ↓
Service返回数据 → Controller组装VO返回前端

扩展:复杂业务再拆分

当Service业务太重,可以继续拆分:

  • BO层/Manager层:复杂业务编排,把大Service拆小,Service做流程调度,Manager做原子业务片段。
  • DTO:前端入参;DO:数据库实体;VO:返回前端对象。
posted on 2026-08-30 15:05  (Play)  阅读(17)  评论(0)    收藏  举报