当前位置: 首页 > news >正文

苍穹外卖:菜品新增功能全流程解析

🔥个人主页:北极的代码(欢迎来访)
🎬作者简介:java后端学习者
❄️个人专栏:苍穹外卖日记,SSM框架深入,JavaWeb
命运的结局尽可永在,不屈的挑战却不可须臾或缺!

前言:前面我们讲解了新增菜品的前面的一部分,主要是文件的上传原理及其具体操作步骤,这里我们具体详解新增菜品的业务操作及其业务难点。

功能流程概览:

详细流程的代码实现:

Controller层:

@RestController @RequestMapping("/admin/dish") @Api(tags = "菜品管理接口") @Slf4j public class DishController { @Autowired private DishService dishService; /** * 新增菜品 * @param dishDTO 前端传来的菜品数据 * @return 操作结果 */ @PostMapping @ApiOperation("新增菜品") public Result save(@RequestBody DishDTO dishDTO) { log.info("接收到新增菜品请求:{}", dishDTO // 调用service层处理业务 dishService.saveWithFlavor(dishDTO); log.info("菜品新增成功"); return Result.success(); } }

作用:

  • ✅ 接收前端请求(接电话)

  • ✅ 参数校验(确认菜单没写错)

  • ✅ 调用Service层(喊厨师长过来)

  • ✅ 返回结果(告诉顾客收到了)

形象比喻:就像餐厅门口接待员,接过顾客的菜单,喊一声"后厨接单",然后告诉顾客"好的,稍等"。

DTO类(DishDTO.java)

package com.sky.dto; import com.sky.entity.DishFlavor; import lombok.Data; import java.io.Serializable; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; /** * 菜品数据传输对象 * 用于接收前端传递的菜品数据 */ @Data public class DishDTO implements Serializable { private Long id; // 菜品ID(新增时为null) private String name; // 菜品名称 private Long categoryId; // 分类ID private BigDecimal price; // 价格 private String image; // 图片路径 private String description; // 描述信息 private Integer status; // 状态 0:停用 1:启用 // 口味列表 private List<DishFlavor> flavors = new ArrayList<>(); }

Service层(DishServiceImpl.java)

@Autowired private DishMapper dishMapper; @Autowired private DishFlavorMapper dishFlavorMapper; /** * 新增菜品和对应的口味 * @param dishDTO 菜品数据 */ @Override @Transactional // 事务管理,保证数据一致性 public void saveWithFlavor(DishDTO dishDTO) { // ========== 第一步:准备菜品数据 ========== Dish dish = new Dish(); BeanUtils.copyProperties(dishDTO, dish); // 属性拷贝 //设置公共字段 LocalDateTime now = LocalDateTime.now(); Long currentId = BaseContext.getCurrentId(); // 获取当前登录用户 ID dish.setCreateTime(now); // 创建时间 dish.setUpdateTime(now); // 更新时间 dish.setCreateUser(currentId); // 创建人 dish.setUpdateUser(currentId); // 修改人 dish.setStatus(1); // 默认为启用状态 // ========== 第二步:保存菜品基本信息 ========== log.info("保存菜品基本信息:{}", dish); dishMapper.insert(dish); // 获取数据库生成的菜品ID Long dishId = dish.getId(); log.info("菜品保存成功,生成的ID:{}", dishId); // ========== 第三步:保存口味信息 ========== List<DishFlavor> flavors = dishDTO.getFlavors(); if (flavors != null && !flavors.isEmpty()) { // 为每个口味设置菜品ID flavors.forEach(flavor -> { flavor.setDishId(dishId); }); // 批量保存口味 log.info("保存口味信息:{}", flavors); dishFlavorMapper.insertBatch(flavors);

作用:

  • 核心业务逻辑(怎么搭配菜品)

  • 事务管理(要么全部成功,要么全部失败)

  • 数据处理(DTO转成Entity)

  • 调用Mapper(指挥厨师干活)

  • 形象比喻就像厨师长,研究菜品做法,安排厨师炒菜,还要确保主菜和配菜能完美搭配。

Mapper层(DishMapper.java)

@Mapper public interface DishMapper { /** * 插入菜品数据 * @param dish 菜品对象 */ @Insert("insert into dish(name, category_id, price, image, description, " + "status, create_time, update_time, create_user, update_user) " + "values(#{name}, #{categoryId}, #{price}, #{image}, #{description}, " + "#{status}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})") @Options(useGeneratedKeys = true, keyProperty = "id") // 主键返回配置 void insert(Dish dish); }

作用:

  • 执行SQL(真的去炒菜)

  • 主键返回(给菜品贴编号)

  • 操作数据库(和冰箱打交道)

形象比喻:就像真正的厨师,负责具体炒菜、装盘、贴标签。

口味Mapper(DishFlavorMapper.java)

@Mapper public interface DishFlavorMapper { /** * 批量插入口味数据 * @param flavors 口味列表 */ void insertBatch(List<DishFlavor> flavors); }

数据库相关操作:

  • 持久化存储(保存食材)

  • 数据关联(主菜和调料对应)

  • 事务支持(保证数据完整)

形象比喻就像后厨的大冰箱,所有食材都存放在这里,需要时取出,用完放回。

关键点说明

事务管理 @Transactional
@Transactional public void saveWithFlavor(DishDTO dishDTO) {// 如果口味保存失败,菜品数据也会回滚 // 保证数据一致性:要么全部成功,要么全部失败 }
主键返回 @Options

为什么需要主键返回,因为。dishId是数据库自动生成的主键。先保存菜品,数据库生成ID

,再用这个ID关联口味等其他信息,前端在新增时不传递dishId

@Options(useGeneratedKeys = true, keyProperty = "id") // 作用:插入后自动将数据库生成的ID设置到dish对象的id属性
ThreadLocal保存用户信息
BaseContext.getCurrentId() // 作用:在多线程环境下,每个线程都能获取到自己的登录用户ID

类比理解

现实世界程序世界
你看菜单、跟服务员沟通前端页面(用户界面)
服务员记录你的需求Controller层(接收请求)
厨师长研究怎么做Service层(业务逻辑)
厨师具体炒菜Mapper层(数据操作)
冰箱里存放食材数据库(数据存储)
最后菜端到你桌上返回结果

层级角色职责生活中的例子
前端点菜员收集用户输入,展示结果拿着菜单让你勾选的人
Controller接待员接收请求,调用服务,返回结果门口接单喊"后厨接单"的人
Service厨师长业务逻辑,事务管理研究菜品做法,安排工作的人
Mapper厨师操作数据库,执行SQL真正炒菜、放冰箱的人
DB冰箱存储数据,保证持久化存放食材的大冰箱

结语:如果对你有一点点的帮助,请点赞,关注,收藏,你的支持就是我最大的鼓励!

http://www.jsqmd.com/news/449367/

相关文章:

  • 模板代码跨平台适配
  • 嵌入式C++调试技术
  • 代码覆盖率工具实战
  • 实时数据压缩库
  • 分布式文件系统设计
  • 聊聊GEO推广费用,江西鲸荣科技为企业节省成本攻略 - 工业品牌热点
  • 聊聊2026年酒柜定制品牌企业,这些值得关注 - mypinpai
  • 分布式数据库代理
  • 嵌入式C++开发注意事项
  • 分析江苏好用的橡胶辊生产商有哪些,哪家性价比更高值得选 - myqiye
  • Django全栈开发入门:构建一个博客系统
  • 数控弯管机价格多少钱,明正精密机械产品值得选购吗 - mypinpai
  • 深聊抛丸机公司哪家可靠,河北地区高口碑企业如何选择 - 工业推荐榜
  • 2026.3.8博客
  • 2026年通过式抛丸机选购指南,靠谱厂家江苏鼎坚分享经验 - myqiye
  • OpenSpec 完全使用指南:用规格驱动 AI 编码
  • 探寻2026年推荐电地暖制造商,各地区好用的品牌排名情况 - 工业品网
  • 2026年北京好用的紫外光固化管道修复公司推荐,售后完善的品牌有哪些 - 工业推荐榜
  • CDN 安全防护的重要性
  • 看看2026无锡不错的橡胶板制造商,口碑品牌不容错过 - 工业设备
  • Easy Dataset 零代码构建教程(非常详细),大模型微调数据集从入门到精通,收藏这一篇就够了!
  • 2026年上海地区窗帘加盟品牌推荐,技术研发强且安装售后靠谱之选 - 工业品网
  • tauri2.10+deepseek+vite7客户端ai系统|Tauri2+Vue3.5桌面AI程序Exe
  • 说说南京靠谱的绝缘橡胶板制造商,绝缘橡胶板好用的品牌有哪些 - 工业设备
  • #define与其他代码的对比替代(C++)
  • [FMQL30TAI开发]FPAI开发相关重要概念梳理
  • 简单了解一下页表
  • 打开软件就弹出d3dx10_37.dll如何修复? 附免费下载方法分享
  • 用Python制作一个文字冒险游戏
  • C++动态链接库开发