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

🔥个人主页:北极的代码(欢迎来访)

🎬作者简介: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 冰箱 存储数据,保证持久化 存放食材的大冰箱

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

相关推荐
高梦轩6 分钟前
MySQL 故障排查与优化
数据库·mysql
吴声子夜歌21 分钟前
Node.js——操作MySQL数据库
数据库·mysql·node.js
爱丽_23 分钟前
MySQL 锁等待与死锁进阶:怎么看等待、怎么降冲突(工程化套路)
数据库·mysql
心有—林夕33 分钟前
MySQL 误操作恢复完全指南
android·数据库·mysql
夕除34 分钟前
Mysql--15
java·数据库·mysql
野生技术架构师1 小时前
掌握SQL窗口函数,轻松处理复杂数据分析
数据库·sql·数据分析
会飞的大可1 小时前
NoSQL:从原理到实践的全景指南
数据库·nosql
bilI LESS1 小时前
Spring Boot接收参数的19种方式
java·spring boot·后端
刘~浪地球1 小时前
Redis 从入门到精通(四):字符串操作详解
数据库·redis·缓存
web前端进阶者2 小时前
Rust初学知识点快速记忆
开发语言·后端·rust