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

《苍穹外卖》套餐管理核心业务代码精讲【从零到一实战解析】

1. 从零理解《苍穹外卖》套餐管理架构第一次接触《苍穹外卖》项目时最让我头疼的就是套餐管理模块的业务逻辑。这个模块看似简单实际涉及Controller、Service、Mapper三层协作还有复杂的菜品关联关系。经过三个版本的迭代优化我总结出这套最清晰的代码结构。先看整体架构图前端请求通过SetmealController进入系统调用SetmealService处理核心业务逻辑最终由SetmealMapper和SetmealDishMapper操作数据库。关键点在于套餐与菜品的关联关系处理这直接影响到新增、修改、查询等核心功能。举个例子当用户创建包含5道菜的套餐时系统需要在setmeal表插入套餐基础信息获取自动生成的套餐ID在setmeal_dish表批量插入5条关联记录这种主表关联表的设计模式非常经典但新手常犯的错误是忘记处理事务。比如插入套餐成功但关联菜品失败时如果没有事务管理就会导致数据不一致。我们在ServiceImpl中使用的Transactional注解就是解决这个问题的关键。2. 新增套餐的完整实现解析2.1 Controller层设计要点SetmealController的代码看似简单但有几个设计细节值得注意PostMapping public Result save(RequestBody SetmealDTO setmealDTO){ setmealService.saveWithSetmealDish(setmealDTO); return Result.success(); }这里使用SetmealDTO接收前端数据而不是直接使用Entity对象这是遵循了DTO设计模式。DTO可以包含套餐基础信息和菜品列表避免了多次请求。我曾在早期版本中使用两个独立接口分别保存套餐和菜品结果前端调用变得非常复杂。日志记录也很有讲究log.info(新增套餐:{},setmealDTO)这行代码会在控制台输出完整的请求数据。建议开发阶段保持这个习惯排查问题时能快速定位到具体数据。2.2 Service层事务处理实战ServiceImpl中的saveWithSetmealDish方法是核心中的核心Transactional public void saveWithSetmealDish(SetmealDTO setmealDTO) { // 转换DTO为Entity Setmeal setmeal new Setmeal(); BeanUtils.copyProperties(setmealDTO,setmeal); // 设置默认状态 setmeal.setStatus(StatusConstant.ENABLE); // 插入套餐主表 setmealMapper.insert(setmeal); // 处理关联菜品 Long setmealId setmeal.getId(); ListSetmealDish setmealDishes setmealDTO.getSetmealDishes(); setmealDishes.forEach(dish - dish.setSetmealId(setmealId)); // 批量插入关联表 setmealDishMapper.insertBatch(setmealDishes); }这里有几个技术要点BeanUtils.copyProperties实现对象属性拷贝比手动set更简洁状态字段设置默认值避免前端遗漏获取自增主键后立即设置到关联对象中使用批量插入提高性能特别注意Transactional注解要加在public方法上才有效。曾经有同事把它加在private方法上调试了半天才发现事务没生效。2.3 Mapper层SQL优化技巧MyBatis的XML映射文件中有几个值得学习的写法insert idinsert useGeneratedKeystrue keyPropertyid insert into setmeal(...) values (...) /insertuseGeneratedKeys和keyProperty配合使用可以自动回填自增ID这是获取主键的标准做法。早期版本我曾在插入后立即执行select last_insert_id()查询既麻烦又存在并发问题。批量插入的SQL也很有讲究insert idinsertBatch insert into setmeal_dish values foreach collectionlist itemitem separator, (#{item.setmealId},#{item.dishId},...) /foreach /insert这种写法比循环执行单条insert语句效率高10倍以上。当套餐包含20个菜品时执行时间从200ms降到20ms左右。注意values后面的逗号分隔符要和foreach的separator保持一致。3. 套餐分页查询的进阶实现3.1 动态SQL构建技巧分页查询最大的特点是条件动态变化MyBatis的动态SQL完美解决了这个问题select idpageQuery resultTypecom.sky.entity.Setmeal select * from setmeal where if testname ! null and name ! and name like concat(%,#{name},%) /if if testcategoryId ! null and category_id #{categoryId} /if if teststatus ! null and status #{status} /if /where order by update_time desc /select这里的where标签会自动处理条件前缀的and/or问题。记得有次我直接在SQL里写where 11被技术主管指出这是不良实践。正确的做法是使用where标签它能智能处理以下情况无条件时自动移除where关键字有条件时自动去除第一个and/or模糊查询使用concat函数比直接拼接更安全可以避免SQL注入问题。排序字段建议使用update_time而不是create_time这样最新修改的套餐会排在前面。3.2 分页参数处理方案Controller接收的分页参数是这样的GetMapping(/page) public ResultPageResult page(SetmealPageQueryDTO dto){ PageResult result setmealService.pageQuery(dto); return Result.success(result); }Service层使用PageHelper实现物理分页public PageResult pageQuery(SetmealPageQueryDTO dto) { PageHelper.startPage(dto.getPage(), dto.getPageSize()); PageSetmeal page setmealMapper.pageQuery(dto.getName(),...); return new PageResult(page.getTotal(), page.getResult()); }这里容易踩的坑是PageHelper的startPage必须紧挨着Mapper调用中间不能有其他SQL查询否则分页会失效。建议在Service方法开头就启动分页避免意外插入其他数据库操作。4. 批量删除的业务逻辑深度剖析4.1 状态校验的必要性删除套餐前必须检查是否处于启售状态这是典型的业务规则校验public void delete(ListLong ids) { ListSetmeal setmeals setmealMapper.getById(ids); setmeals.forEach(setmeal - { if (setmeal.getStatus() StatusConstant.ENABLE) { throw new DeletionNotAllowedException(套餐正在售卖中); } }); // 执行删除操作 setmealMapper.deleteBatch(ids); setmealDishMapper.deleteBatch(ids); }这里使用先查询再判断的方式虽然多了一次查询但保证了数据一致性。曾经尝试过直接在delete语句中添加status条件但会导致部分成功部分失败的情况不利于给用户明确反馈。异常消息使用常量定义是个好习惯比如MessageConstant.SETMEAL_ON_SALE。这样修改提示文本时只需改一个地方还能支持国际化。4.2 批量删除的SQL优化关联表的批量删除SQL值得学习delete iddeleteBatch delete from setmeal_dish where setmeal_id in foreach collectionids itemid open( close) separator, #{id} /foreach /delete这种in语句的批量删除方式比循环执行单条delete效率高得多。当删除100个套餐时执行时间从2秒降到0.1秒左右。注意参数名ids要和Mapper接口中的参数名完全一致否则会报绑定异常。5. 套餐修改的完整流程解析5.1 先删后增的关联处理策略修改套餐的特殊之处在于需要先删除旧关联再建立新关联public void update(SetmealDTO setmealDTO) { // 更新主表 Setmeal setmeal new Setmeal(); BeanUtils.copyProperties(setmealDTO, setmeal); setmealMapper.update(setmeal); // 处理关联菜品 Long setmealId setmealDTO.getId(); setmealDishMapper.deleteBySetmealId(setmealId); ListSetmealDish dishes setmealDTO.getSetmealDishes(); dishes.forEach(dish - dish.setSetmealId(setmealId)); setmealDishMapper.insertBatch(dishes); }这种模式虽然会产生额外的删除操作但实现简单且不易出错。替代方案是比对新旧菜品列表只增删变化的部分但代码复杂度会大幅增加。对于菜品数量不超过50的套餐来说直接全量替换是更合理的选择。5.2 MyBatis动态更新语法主表更新使用了动态字段处理update idupdate update setmeal set if testcategoryId ! nullcategory_id#{categoryId},/if if testname ! nullname#{name},/if ... /set where id#{id} /updateset标签会自动去除末尾的逗号比手动拼接set语句更优雅。注意每个条件判断要周全比如字符串字段既要判null又要判空字符串否则可能导致意外清空字段。6. 启停状态的业务规则实现6.1 嵌套查询的性能考量启售套餐时需要检查包含的菜品是否都已启售public void startOrStop(Integer status, Long id) { if (status StatusConstant.ENABLE) { ListDish dishes dishMapper.getBySetmealId(id); dishes.forEach(dish - { if (dish.getStatus() StatusConstant.DISABLE) { throw new SetmealEnableFailedException(包含未启售菜品); } }); } // 更新状态 setmealMapper.update(Setmeal.builder() .status(status) .id(id) .build()); }这里通过left join一次性查询出所有关联菜品比循环查询效率更高。Builder模式创建实体对象比newsetter更简洁特别是在只更新部分字段时。6.2 状态枚举的最佳实践状态常量定义成枚举类更规范public enum Status { ENABLE(1, 启售), DISABLE(0, 停售); private final int code; private final String desc; // 构造方法、getter省略 }相比直接使用魔法数字1和0枚举类型更安全易懂。系统中有5处状态判断使用枚举后代码可读性明显提升修改状态值时也只需改一个地方。

相关文章:

《苍穹外卖》套餐管理核心业务代码精讲【从零到一实战解析】

1. 从零理解《苍穹外卖》套餐管理架构 第一次接触《苍穹外卖》项目时,最让我头疼的就是套餐管理模块的业务逻辑。这个模块看似简单,实际涉及Controller、Service、Mapper三层协作,还有复杂的菜品关联关系。经过三个版本的迭代优化&#xff0c…...

基于51单片机的毕设实战:从传感器采集到低功耗通信的完整链路实现

最近在帮学弟学妹们看基于51单片机的毕业设计,发现一个挺普遍的现象:大家能把各个模块(比如传感器、显示屏、蓝牙)单独调通,但一旦组合起来,系统就变得不稳定,要么功耗飙升,要么数据…...

BGRL实战:用GAT编码器在ogbn-arXiv数据集上刷到SOTA的保姆级教程

BGRL实战:用GAT编码器在ogbn-arXiv数据集上刷到SOTA的保姆级教程 在自监督图表示学习领域,BGRL(Bootstrapped Graph Latents)正迅速成为研究者们的新宠。这个无需负样本的框架不仅突破了传统对比学习的计算瓶颈,更在多…...

为什么92%的Dify评估系统上线后准确率低于68%?——4个被官方文档隐藏的配置陷阱与修复方案

第一章:Dify自动化评估系统(LLM-as-a-judge)配置全景概览Dify 的自动化评估系统基于 LLM-as-a-judge 范式,允许开发者将大语言模型作为评判者,对提示工程效果、RAG 输出质量、对话连贯性等维度进行结构化打分。该能力内…...

SOLIDWORKS新手必看:IGS文件导入后的5个常见修复技巧(附迪威模型网对比)

SOLIDWORKS新手必看:IGS文件导入后的5个常见修复技巧(附迪威模型网对比) 当你第一次将IGS文件导入SOLIDWORKS时,可能会遇到各种令人头疼的问题——模型表面出现破洞、曲面无法缝合、实体转换失败...这些问题对于刚接触CAD软件的新…...

Phi-3-mini-128k-instruct解析VLOOKUP等Excel函数:跨表匹配与公式优化

Phi-3-mini-128k-instruct解析VLOOKUP等Excel函数:跨表匹配与公式优化 你是不是也经常被Excel里的数据匹配搞得头大?尤其是当数据分散在不同表格里,需要手动一个个去核对的时候,那种感觉真是既费时又容易出错。我见过不少同事&am…...

jsontop.cn 介绍 - 一站式开发者工具集,JSON 格式化之外的全能助手

作为开发者,日常工作中总会遇到各种琐碎的开发需求:JSON 数据格式化校验、Base64 编码转换、时间戳解析、正则表达式测试…… 如果每一个需求都要找对应的在线工具,不仅要记忆大量网址,还会频繁切换页面,大幅降低工作效…...

公考图形推理实战:从基础规律到快速解题技巧

1. 图形推理基础规律全解析 图形推理作为公考判断推理的必考题型,考察的是考生对图形特征的敏感度和规律提取能力。我刚开始备考时经常被各种图形绕晕,后来发现只要掌握核心规律体系,80%的题目都能快速破解。下面就把我实战总结的六大基础规律…...

Lingyuxiu MXJ LoRA部署教程:SDXL底座兼容性验证与LoRA冲突排查

Lingyuxiu MXJ LoRA部署教程:SDXL底座兼容性验证与LoRA冲突排查 1. 为什么需要专门验证MXJ LoRA与SDXL的兼容性? 很多人以为“LoRA能跑通就是兼容”,结果在实际生成中频繁遇到五官错位、光影崩坏、皮肤质感发灰、人物比例失真等问题——这些…...

OpenClaw多模型切换:Qwen3-VL:30B与CodeLlama飞书双助手

OpenClaw多模型切换:Qwen3-VL:30B与CodeLlama飞书双助手 1. 为什么需要多模型切换? 去年我在团队内部推广AI助手时遇到一个典型问题:当同事发送一张产品截图问"这个UI组件的React代码该怎么实现"时,通用模型要么只回答…...

即席查询框架大比拼:Druid、Kylin、Presto等7种工具如何选?

即席查询技术全景解析:7大框架深度对比与选型指南 在数据驱动的商业环境中,即席查询能力已成为企业数据团队的核心竞争力。当业务部门突然提出"上个月华东地区电子品类中哪些子类目在周末销量异常?"这类非预设问题时,传…...

永磁同步电机转动惯量与阻尼系数辨识:带遗忘因子递推最小二乘法实战

带遗忘因子的递推最小二乘法参数辨识,永磁同步电机转动惯量辨识,阻尼系数辨识,采用s函数编写,也有m函数。 有相关文档。在永磁同步电机(PMSM)的控制领域中,准确辨识转动惯量和阻尼系数对于优化电…...

Keil调试器不为人知的秘密:用Command窗口实现自动化测试

Keil调试器不为人知的秘密:用Command窗口实现自动化测试 在嵌入式开发领域,Keil MDK作为一款广受欢迎的集成开发环境,其调试功能一直被工程师们频繁使用。然而,大多数开发者仅停留在基础断点调试的层面,对Command窗口这…...

Axis1.4远程命令执行漏洞复现:从环境搭建到漏洞利用的全流程指南

Axis1.4远程命令执行漏洞深度剖析与实战复现指南 在Web应用安全研究领域,历史遗留系统的漏洞分析始终保持着独特的价值。Axis1.4作为早期广泛使用的Web服务框架,其远程命令执行漏洞(CVE-2019-0227)的复现过程不仅是一次技术演练&a…...

Opencv实战:中值滤波(cv2.medianBlur)在图像去噪中的高效应用

1. 为什么中值滤波是图像去噪的"神器"? 第一次接触图像处理时,我对着满是椒盐噪声的图片发愁。试过各种线性滤波方法,结果要么噪声没去掉,要么图片糊得像打了马赛克。直到遇到中值滤波,才明白什么叫"对…...

GitHub打不开的备选方案:本地部署Lingbot-Depth-Pretrain-ViTL-14进行模型研究与开发

GitHub打不开的备选方案:本地部署Lingbot-Depth-Pretrain-ViTL-14进行模型研究与开发 最近不少做AI开发的朋友都在抱怨,GitHub又抽风了,模型代码下不来,依赖包装不上,项目进度直接卡住。特别是当你急需复现某个前沿模…...

Asian Beauty Z-Image Turbo作品展示:不同年龄层(少女/青年/中年)东方人物建模能力

Asian Beauty Z-Image Turbo作品展示:不同年龄层(少女/青年/中年)东方人物建模能力 1. 工具简介 Asian Beauty Z-Image Turbo是一款专注于东方美学风格的本地化图像生成工具,基于通义千问Tongyi-MAI Z-Image底座模型&#xff0c…...

从汽车减震到建筑抗震:阻尼比ξ如何影响你的日常生活?

从汽车减震到建筑抗震:阻尼比ξ如何影响你的日常生活? 开车经过减速带时,你是否注意过不同车辆的颠簸程度差异?高层建筑遭遇强风时,为什么有些楼宇摇晃明显而另一些却稳如磐石?这些现象背后都隐藏着一个关键…...

gte-base-zh Python入门实战:零基础构建你的第一个文本相似度应用

gte-base-zh Python入门实战:零基础构建你的第一个文本相似度应用 你是不是经常在想,怎么让电脑理解两句话是不是在说同一个意思?或者,怎么从一篇长文章里快速提炼出核心内容?听起来很复杂,但今天&#xf…...

M2LOrder服务高可用部署架构:基于Kubernetes的容器编排方案

M2LOrder服务高可用部署架构:基于Kubernetes的容器编排方案 最近在星图GPU平台上折腾M2LOrder服务的部署,发现单实例运行虽然简单,但一遇到流量高峰或者节点故障,服务就很容易挂掉,严重影响稳定性。对于生产环境来说&…...

伪造技术亲缘:让系统认我当“数字父亲”——软件测试从业者的高阶攻防指南

亲缘伪造的测试价值在血缘关系图谱系统(如家族树、遗传分析工具)的测试中,技术亲缘伪造通过篡改对象依赖关系(如父子/兄弟映射),强制系统将测试者识别为“父节点”,成为验证系统鲁棒性、安全性和…...

树莓派SD卡备份与迁移 — 从入门到精通

1. 为什么需要备份树莓派SD卡? 玩树莓派的朋友们应该都遇到过这样的场景:你花了好几天配置好的开发环境,突然因为SD卡损坏全部丢失;或者好不容易调试好的智能家居系统,因为误操作导致系统崩溃。这时候如果有个完整的备…...

Excel党必看!用Claude3.5自动生成测试用例的3种进阶玩法(含异常测试模板)

Excel党必看!用Claude3.5自动生成测试用例的3种进阶玩法(含异常测试模板) 在传统测试团队中,Excel仍然是管理测试用例的主力工具。虽然市面上有各种专业的测试管理平台,但Excel的灵活性、易用性和与企业现有流程的无缝…...

零基础玩转DeepSeek-OCR-2:上传图片秒出文字,小白也能轻松上手

零基础玩转DeepSeek-OCR-2:上传图片秒出文字,小白也能轻松上手 1. 快速认识DeepSeek-OCR-2 1.1 什么是OCR技术 OCR(光学字符识别)技术就像给电脑装上了"眼睛",让它能看懂图片中的文字。想象一下&#xff…...

Z-Image-GGUF动态演示:KSampler参数实时调节对画面影响的可视化对比

Z-Image-GGUF动态演示:KSampler参数实时调节对画面影响的可视化对比 1. 引言:从“能用”到“用好”的跨越 如果你用过文生图AI,肯定有过这样的经历:输入一段描述,满怀期待地点击生成,结果出来的图片要么模…...

Qwen3-0.6B-FP8在计算机组成原理学习中的问答助手

Qwen3-0.6B-FP8在计算机组成原理学习中的问答助手 最近和几个计算机专业的学生聊天,发现他们普遍有个痛点:课本上的概念太抽象,遇到问题没人随时解答。像CPU流水线、缓存一致性这些内容,光看文字和图表,总觉得隔着一层…...

Docker 命令超全详解(入门到运维)

1. 命令简介docker 是一个开源的容器化平台,用于开发、发布和运行应用程序。它允许开发者将应用程序及其所有依赖项(库、运行时、系统工具等)打包到一个标准化的单元中,称为容器。容器是轻量级、可移植、自包含的软件包&#xff0…...

多模态数据标注实战指南:5大高效工具与避坑策略(含Label Studio优化技巧)

1. 多模态数据标注的核心挑战与价值 当你第一次接触多模态数据标注时,可能会被各种专业术语吓到。其实说白了,就是把不同类型的数据(比如图片、文字、语音)打上标签,让AI能看懂这些数据之间的关系。举个例子&#xff0…...

从提示词到交响曲:一文读懂AI音乐生成的技术、应用与未来

从提示词到交响曲:一文读懂AI音乐生成的技术、应用与未来 引言 想象一下,只需在输入框里键入“一段激昂的中国风电子游戏Boss战音乐”,几分钟后,一段融合了琵琶、电吉他、密集鼓点与磅礴管弦乐的完整配乐便跃然耳畔。这不再是科…...

AI头像生成器快速部署:3分钟启动Qwen3-32B头像文案服务(含端口8080)

AI头像生成器快速部署:3分钟启动Qwen3-32B头像文案服务(含端口8080) 想给自己换个酷炫的社交头像,却苦于没有设计灵感?或者有了想法,却不知道怎么描述才能让AI绘图工具理解?今天介绍的这个AI头…...