☰
Reggie1项目二:菜品管理 + 套餐管理
2026/10/22 10:45:46 网站建设 项目流程

前言:

今日核心收获:完成了管理端最核心的两个模块——菜品管理和套餐管理。真正理解了 Spring Boot 分层架构中 Controller、Service、Mapper、DTO 各司其职的意义。更重要的是,今天踩的每一个坑,都是面试时可以讲出来的“实战经验”。

一、今日完成的功能模块

模块完成的功能
分类管理修改分类、删除分类(含关联校验)
菜品管理新增菜品(含口味)、分页查询、修改菜品、启售/停售、删除菜品
套餐管理新增套餐(含关联菜品)、分页查询、修改套餐、启售/停售、删除套餐
全局异常处理统一处理业务异常和数据库异常
图片上传下载文件上传、下载、路径处理

二、今天学到的核心技术点(面试重点)

2.1 Spring Boot 分层架构

面试官常问:你能说一下项目中你是怎么分层的吗?每一层的作用是什么?

我的回答(以今天做的“新增菜品”为例):

层级类的命名今天做的事一句话总结
ControllerXxxController接收前端请求,调用 Service,返回结果接客
Service 接口XxxService定义业务方法定规矩
ServiceImplXxxServiceImpl写具体业务逻辑,加@Transactional办事
MapperXxxMapper继承BaseMapper,执行 SQL跑腿
EntityXxx和数据库表一一对应表映射
DTOXxxDto继承 Entity,扩展字段传

为什么要这么分层?

  • 职责清晰:改 SQL 只动 Mapper,改业务逻辑只动 Service,改接口只动 Controller

  • 便于测试:每一层都可以单独 Mock

  • 事务管理:在 Service 层加@Transactional,保证多表操作的一致性

2.2 DTO 的作用(今天最重要的理解)

面试官常问:你为什么用 DTO?直接用 Entity 不行吗?

我的回答:

今天做“新增菜品”时,前端提交的数据包含:

  • 菜品基本信息(name、price、categoryId 等)

  • 口味列表(flavors)

但Dish实体类里只有菜品基本信息,没有flavors字段。如果用 Entity 接收,口味数据就丢了。

解决方案:创建DishDto继承Dish,加上flavors字段。

public class DishDto extends Dish { private List<DishFlavor> flavors; // 新增时需要 private String categoryName; // 查询时需要 }

DTO 的两个典型场景:

  1. 接收参数时:Entity 不够用,需要扩展字段

  2. 返回数据时:需要关联其他表的数据(如菜品列表要显示分类名称,而不是分类ID)

2.3 MyBatis-Plus 核心功能

功能用法今天用在哪
分页查询Page+MybatisPlusInterceptor菜品列表、套餐列表
条件构造器LambdaQueryWrapper根据分类ID查询菜品、根据名称模糊搜索
公共字段填充MetaObjectHandler+@TableField自动填充 createTime、updateTime、createUser、updateUser
逻辑删除@TableLogic删除菜品/套餐时标记删除,不物理删除

2.4 全局异常处理

面试官常问:你的项目怎么处理异常的?如果用户删除一个正在售卖中的套餐,前端会看到什么?

我的回答:

我写了一个GlobalExceptionHandler,用@RestControllerAdvice统一处理所有异常。

@RestControllerAdvice public class GlobalExceptionHandler { // 处理业务异常(如:删除启售套餐) @ExceptionHandler(CustomException.class) public R<String> handleCustomException(CustomException ex) { return R.error(ex.getMessage()); // 返回:套餐正在售卖中,不能删除 } // 处理数据库唯一约束异常(如:重复的分类名称) @ExceptionHandler(SQLIntegrityConstraintViolationException.class) public R<String> handleSQLException(SQLIntegrityConstraintViolationException ex) { if (ex.getMessage().contains("Duplicate entry")) { return R.error("分类名称已存在"); } return R.error("未知错误"); } }

这样设计的好处:

  • 前端能收到友好的错误提示,而不是一堆看不懂的堆栈信息

  • 代码复用:不用在每个 Controller 里写 try-catch

2.5 事务管理

面试官常问:新增菜品时要操作两张表,怎么保证数据一致性?

我的回答:

在 Service 实现类的方法上加@Transactional注解。

@Transactional public void saveWithFlavor(DishDto dishDto) { // 1. 保存菜品基本信息 this.save(dishDto); // 2. 保存菜品口味 dishFlavorService.saveBatch(dishDto.getFlavors()); }

如果第二步失败了,第一步会自动回滚,不会出现“菜品保存成功但口味没保存”的情况。

三、今日遇到的错误及解决方案(面试加分项)

面试官非常看重你“踩过什么坑、怎么解决的”。以下每个错误都可以在面试时讲出来。

错误1:类型不匹配

现象:

不兼容的类型。实际为 'long',需要 'int'

代码:

int count = dishService.count(wrapper); // ❌

原因:MyBatis-Plus 的count()方法返回的是long,不是int。

解决:

long count = dishService.count(wrapper); // ✅

面试能说的:做分类删除时,需要先查询这个分类下有没有关联菜品。MyBatis-Plus 的count()返回long,但教材代码写的是int。这说明教材用的是旧版本,我用的是新版本。以后要注意看源码。

错误2:菜品列表显示分类ID而不是分类名称

现象:页面上“菜品分类”列显示的是1397844263642378242,不是“湘菜”。

原因:Dish实体类里只有categoryId,没有categoryName。前端需要显示名称。

解决:创建DishDto,增加categoryName字段。分页查询后,遍历数据,用categoryId去查询分类名称,设置进去。

面试能说的:这就是 DTO 的典型应用场景。Entity 只负责和数据库映射,DTO 负责和前端交互。用 DTO 的好处是:不污染 Entity,前端要什么字段我就给什么字段。

错误3:新增菜品时口味数据丢失

现象:菜品保存成功了,但口味没保存。

原因:前端提交的flavors数据无法被Dish实体类接收。

解决:在DishDto中增加List<DishFlavor> flavors字段。Service 层先保存菜品,拿到dishId,再为每个flavor设置dishId,最后批量保存。

面试能说的:这是一个典型的“一对多”场景。一张菜品表对应多张口味表。DTO 在这里起到了“聚合数据”的作用。

错误4:图片上传后不显示

现象:上传图片成功,文件夹里也有文件,但页面不显示。

原因:路径拼接缺少分隔符。

错误代码:

new File(basePath + fileName); // 结果:D:/img八宝粥.png

正确代码:

new File(basePath + File.separator + fileName); // 结果:D:/img/八宝粥.png

面试能说的:这是一个非常细节的 Bug。Windows 和 Linux 的路径分隔符不一样,用File.separator可以跨平台。以后写文件路径都要养成这个习惯。

错误5:删除启售套餐返回500,不是业务提示

现象:控制台打印了“套餐正在售卖中,不能删除”,但前端显示 500 错误。

原因:GlobalExceptionHandler里没有处理CustomException。

解决:添加@ExceptionHandler(CustomException.class)方法。

面试能说的:这说明全局异常处理不完整。写完异常处理器后,要记得测试所有自定义异常是否都能被正确捕获。这个问题暴露了我对全局异常处理理解不够全面。

四、今天的内容对后端开发的重要性

知识点企业招聘看重程度说明
分层架构⭐⭐⭐⭐⭐必考。每个后端岗位都会问
DTO 设计⭐⭐⭐⭐体现分层思想,实习生会这个很加分
MyBatis-Plus 使用⭐⭐⭐⭐大部分公司用 MP 或 JPA
事务管理⭐⭐⭐⭐⭐涉及多表操作、金钱相关,必须掌握
全局异常处理⭐⭐⭐⭐体现代码规范,实习生能写出来很加分
文件上传下载⭐⭐⭐常见功能,但不是核心

是否涉及后端核心?

✅是的,今天的内容覆盖了 Java 后端开发的 80% 核心:

  • 数据库 CRUD

  • 多表操作

  • 事务管理

  • 统一异常处理

  • 分层架构设计

唯一缺的:微服务、消息队列、高并发(这些是高级阶段,实习生不会也正常)。

五、项目运行截图

菜品管理页面(分页 + 图片显示)

  • 访问http://localhost:8080/backend/index.html→ 菜品管理

  • 显示 10 条菜品信息(八宝粥、王老吉、米饭、北冰洋、上汤焗龙虾、老火靓汤、清蒸河鲜海鲜、脆皮乳鸽、烤乳猪、白切鸡)

  • 图片正常显示

  • 每条记录有:修改、停售、删除按钮

  • 底部显示:共 24 条,10 条/页

套餐管理页面

  • 访问套餐管理页面

  • 显示超值幼儿园大餐、大老板超值套餐

  • 图片正常显示

  • 每条记录有:修改、停售、删除按钮

六、今日总结

今天最大的收获不是“写完了代码”,而是真正理解了每一层为什么存在。

写简历时,我可以这样描述:

“负责瑞吉外卖后台的菜品管理和套餐管理模块,基于 Spring Boot + MyBatis-Plus 实现。通过 DTO 解决多表关联查询和参数接收问题,使用全局异常处理器统一返回业务提示,通过事务注解保证多表操作的一致性。项目中遇到并解决了类型匹配、路径分隔符、全局异常处理不完整等问题。”

面试官看到这段描述,会问什么?

  • 你为什么要用 DTO?

  • 你的全局异常处理器是怎么设计的?

  • 你是怎么保证多表操作的一致性的?

  • 你遇到过什么难忘的问题?

今天的内容,足够回答这些问题。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询