企业培训笔记:外卖平台后端--套餐管理模块--新建套餐信息
文章目录
- 新建套餐信息
- (一)SetmealMapper接口添加方法
- (二)SetmealMapper.xml文件添加sql语句
- (三)SetmealService业务层接口添加方法
- (四)SetmealServiceImpl接口实现类重写方法
- (五)SetmealController控制层类添加方法
新建套餐信息
在外卖管理系统中,新建套餐是核心功能之一。新建套餐不仅需要保存套餐的基本信息(如名称、所属分类、价格、图片等),还必须同步保存“套餐与菜品的关联关系”(即该套餐包含哪些菜品、每种菜品的数量)。下方图片展示的是新建套餐的前端操作界面,界面中清晰划分了“套餐基本信息填写区”和“菜品选择区”,用户完成信息录入后提交,后端将通过以下步骤处理请求。

(一)SetmealMapper接口添加方法
Mapper接口是数据访问层的入口,新建套餐首先需要定义“插入套餐基本信息”的方法。这里通过注解和自定义注解结合,简化开发并保证公共字段的自动填充。

/** * 新增套餐(仅插入套餐基本信息,不包含关联菜品) * @param setmeal 封装了套餐基本信息的实体类(如名称、分类ID、价格等) */
@AutoFill(OperationType.INSERT)
void insert(Setmeal setmeal);
- @AutoFill(OperationType.INSERT):这是自定义的“自动填充注解”,作用是在执行插入操作时,自动为
Setmeal实体的公共字段(如createTime创建时间、updateTime修改时间、createUser创建人、updateUser修改人)赋值,无需手动编写代码,减少重复工作。 - 方法作用:仅负责将套餐的基本信息插入到
setmeal表中,关联菜品的插入会由其他方法处理。
(二)SetmealMapper.xml文件添加sql语句
Mapper接口的insert方法需要通过XML编写具体的SQL,同时配置“获取自动生成的主键”——因为后续关联菜品时,需要用这个主键(套餐ID)绑定关系。

<!-- 新增套餐信息(插入套餐基本数据到setmeal表) -->
<insert id="insert" parameterType="Setmeal" useGeneratedKeys="true" keyProperty="id"> insert into setmeal (category_id, name, price, status, description, image, create_time, update_time, create_user, update_user) values (#{categoryId}, #{name}, #{price}, #{status}, #{description}, #{image}, #{createTime}, #{updateTime},#{createUser}, #{updateUser})
</insert>
- 关键配置解析:
useGeneratedKeys="true":开启“获取数据库自动生成的主键”功能(适用于主键自增的表,如setmeal表的id字段)。keyProperty="id":将数据库生成的主键值,赋值给Setmeal实体的id属性——后续通过setmeal.getId()就能拿到新建套餐的ID,用于关联菜品。- SQL字段说明:
category_id对应套餐所属分类ID,status表示套餐状态(0下架/1起售),image是套餐封面图的路径,其余字段为自动填充的公共字段。
(三)SetmealService业务层接口添加方法
Service层负责封装业务逻辑,新建套餐的核心业务是“同时保存套餐基本信息和套餐-菜品关联关系”,因此定义saveWithDish方法(“WithDish”强调包含菜品关联)。

/** * 新增套餐,同时保存套餐和菜品的关联关系 * @param setmealDTO 封装了“套餐基本信息+关联菜品列表”的DTO(数据传输对象) */
void saveWithDish(SetmealDTO setmealDTO);
- 为什么用SetmealDTO而非Setmeal?
Setmeal实体仅对应setmeal表的字段,而前端提交的请求中,除了套餐基本信息,还包含setmealDishes(关联的菜品列表,如“鱼香肉丝x2份”“米饭x1份”)。SetmealDTO在Setmeal基础上新增了setmealDishes属性,刚好能接收前端的完整数据,避免用多个参数传递。
(四)SetmealServiceImpl接口实现类重写方法
Service实现类是业务逻辑的核心执行层,这里需要通过事务控制保证“套餐插入”和“关联菜品插入”同时成功或失败,避免数据不一致(比如套餐插成功了,但关联菜品没插,导致套餐是空的)。

/** * 新增套餐,同时保存套餐和菜品的关联关系 * @param setmealDTO 前端传递的完整套餐数据(基本信息+关联菜品) */
@Transactional // 事务注解:确保以下操作要么全成功,要么全回滚(比如关联菜品插入失败,套餐也会回滚删除)
public void saveWithDish(SetmealDTO setmealDTO) { // 1. 将DTO转成Setmeal实体(用于插入套餐基本信息) Setmeal setmeal = new Setmeal(); // 2. 设置公共字段(这里手动设置,也可通过@AutoFill注解自动填充,视项目配置而定) setmeal.setCreateTime(LocalDateTime.now()); // 创建时间设为当前时间 setmeal.setUpdateTime(LocalDateTime.now()); // 修改时间设为当前时间 setmeal.setCreateUser(BaseContext.getCurrentId()); // 创建人:从上下文拿当前登录用户ID setmeal.setUpdateUser(BaseContext.getCurrentId()); // 修改人:同创建人 // 3. 插入套餐基本信息到setmeal表(调用Mapper方法) setmealMapper.insert(setmeal); // 4. 获取新建套餐的ID(由Mapper的XML配置自动赋值到setmeal的id属性) Long setmealId = setmeal.getId(); // 5. 处理关联菜品列表:给每个菜品绑定套餐ID(否则关联表不知道菜品属于哪个套餐) List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();setmealDishes.forEach(setmealDish -> { // 遍历所有关联菜品 setmealDish.setSetmealId(setmealId); // 给当前菜品设置套餐ID }); // 6. 批量插入关联数据到setmeal_dish表(批量插入比循环单条插入效率更高) setmealDishMapper.insertBatch(setmealDishes);
}
- 核心步骤拆解:
- DTO转实体:因为
setmealMapper.insert需要Setmeal类型参数,所以先创建Setmeal对象,用于存储基本信息。 - 公共字段赋值:
BaseContext.getCurrentId()是从ThreadLocal中获取当前登录用户的ID(比如管理员ID),确保操作人信息准确。 - 获取套餐ID:插入套餐后,通过
setmeal.getId()拿到数据库自动生成的ID,这是关联菜品的关键。 - 绑定关联关系:遍历前端传的
setmealDishes,给每个菜品设置setmealId,相当于给“菜品”贴了“所属套餐”的标签。 - 批量插入关联数据:用
insertBatch批量插入关联表,减少数据库交互次数,提升性能。
- DTO转实体:因为
(五)SetmealController控制层类添加方法
Controller层是前端请求的入口,负责接收前端提交的套餐数据、调用Service层执行业务、清理缓存(保证数据最新),并返回结果给前端。

/** * 新增套餐(接收前端请求并响应) * @param setmealDTO 前端以JSON格式提交的“套餐基本信息+关联菜品”数据 * @return 统一响应结果(告知前端新增成功) */
@PostMapping // 用POST请求处理“新增”操作(符合HTTP语义,POST用于提交数据)
@ApiOperation("新增套餐") // Swagger注解:生成接口文档时说明接口功能
@CacheEvict(cacheNames = "setmealCache",key = "#setmealDTO.categoryId") // 清理缓存:避免前端拿到旧的套餐列表
public Result save(@RequestBody SetmealDTO setmealDTO) { // 调用Service层的核心业务方法,执行新增逻辑 setmealService.saveWithDish(setmealDTO); // 返回成功响应:前端收到后会提示“新增成功”,并刷新套餐列表 return Result.success();
}
- 关键注解说明:
@RequestBody SetmealDTO setmealDTO:将前端提交的JSON数据,自动转化为SetmealDTO对象,无需手动解析JSON。@CacheEvict:清理缓存的注解。如果系统缓存了“某个分类下的套餐列表”(比如cacheNames="setmealCache",key是分类ID),新增套餐后需要清空该分类的缓存,避免前端刷新后仍显示旧列表(比如新增“快餐”分类的套餐后,“快餐”列表要实时更新)。Result.success():统一响应格式,前端收到后会触发“新增成功”的提示(如弹窗提示),并重新加载套餐列表,展示新建的套餐。
通过以上步骤,前端提交新建套餐的请求后,后端会完整完成“套餐基本信息插入”和“套餐-菜品关联插入”,同时保证数据一致性和缓存时效性,最终实现新建套餐的功能。
