1. 业务逻辑核心
这个功能不仅仅是"改个状态"那么简单,它包含了一个隐形的级联逻辑。
-
起售 (Status = 1):
-
逻辑 :非常简单,只修改菜品表 (
dish) 的状态即可。 -
影响:不影响其他表。
-
停售 (Status = 0):
-
逻辑 :"连坐机制"。
-
核心规则:如果一道菜(如"宫保鸡丁")不卖了,那么包含这道菜的所有套餐(如"超值双人餐")也必须立刻停止售卖。
-
原因:防止用户点了套餐,结果厨房发现缺菜做不出来,导致客诉。
2. 接口设计与参数传递
- 接口地址 :
POST /admin/dish/status/{status}?id={id} - 参数解剖:
| 参数位置 | 形式 | 注解 | 含义 |
|---|---|---|---|
| 路径 (Path) | /status/{status} |
@PathVariable |
做什么操作? (1=起售, 0=停售) |
| 查询 (Query) | ?id=xxx |
Long id |
操作哪个对象? (菜品ID) |
3. 核心代码实现 (Code Implementation)
3.1 Service 层 (DishServiceImpl)
使用了 Builder模式 构建对象,并使用了 批量更新 优化了级联逻辑。
java
@Override
@Transactional // 1. 事务控制:保证"菜品停售"和"套餐停售"原子性
public void startOrStop(Integer status, Long id) {
// 修改菜品状态
Dish dish = Dish.builder()
.id(id)
.status(status)
.build();
dishMapper.update(dish);
// 如果是停售操作,还需要将关联的套餐也停售
if (status.equals(StatusConstant.DISABLE)) {
// 查询关联的套餐id
List<Long> setmealIds = setmealDishMapper.getSetmealIdsByDishIds(Arrays.asList(id));
// 2. 判空防止 NPE (NullPointerException)
if (setmealIds != null && !setmealIds.isEmpty()) {
// 3. 批量将关联的套餐全部停售 (性能优化点)
setmealMapper.updateStatusBatch(setmealIds, StatusConstant.DISABLE);
}
}
}
3.2 Mapper 层 (动态 SQL)
这里有两个关键的 XML 配置,分别对应单条更新 和批量更新。
(1) DishMapper.xml - 单条动态更新
必须使用 <if> 标签,防止将未传入的字段误更新为 null。
xml
<update id="update">
update dish
<set>
<if test="name != null">name = #{name},</if>
<if test="categoryId != null">category_id = #{categoryId},</if>
<if test="price != null">price = #{price},</if>
<if test="image != null">image = #{image},</if>
<if test="description != null">description = #{description},</if>
<if test="status != null">status = #{status},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="updateUser != null">update_user = #{updateUser},</if>
</set>
where id = #{id}
</update>
(2) SetmealMapper.xml - 批量更新
使用 <foreach> 标签配合 IN 语句,实现一次交互更新多条数据。
xml
<update id="updateStatusBatch">
update setmeal set status = #{status} where id in
<foreach collection="setmealIds" item="setmealId" separator="," open="(" close=")">
#{setmealId}
</foreach>
</update>