ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Spring Boot鲜花销售管理系统从头到部署:毕设完整落地指南

Spring Boot鲜花销售管理系统从头到部署:毕设完整落地指南 1. 从毕设标题读懂这个系统的真实分量先别急着打开源码。拿到基于JavaSpringBoot的花店鲜花销售管理系统这个标题时我建议你先做一件大多数同学会跳过的事把标题拆开看一遍。这个标题看起来像是一串技术名词的堆砌但每一段都对应着一套明确的能力要求。基于JavaSpringBoot限定了技术选型范围意味着你必须在简历和论文里讲清楚Spring Boot的核心机制花店鲜花销售定义了业务场景意味着你需要有商品展示、购物流程、订单处理这些电商通用模块而后面的完整源码LW部署说明演示视频说实话这更像是商品描述但它揭示了一个残酷的事实任何毕设项目最终都要过三关——代码能跑、论文能过、答辩能讲。市场上这类系统的源码其实非常多但这恰恰是问题所在。很多同学拿到一个能启动的项目就以为万事大吉结果导师随口问一句订单状态是怎么流转的库存超卖你怎么处理当场卡壳。我见过太多例子项目是从网上找的代码确实能跑但问实现细节一问三不知甚至不知道自己的项目用的是拦截器还是过滤器做登录校验。所以这篇博文我想做的不是给你贴一遍源码而是以这个鲜花销售管理系统为载体把从需求分析、数据库设计、核心功能实现到部署上线的完整链路走一遍让你真正拥有这个项目而不是仅仅持有一份代码。这套系统适合谁来参考两类人第一类是正在做Java Web方向毕业设计的学生尤其是电商、商品管理类题目你可以直接复用里面的业务设计思路第二类是刚学完Spring Boot基础、想找一个完整项目练手的人这个系统的复杂度恰到好处——比增删改查进阶了一层有订单状态机、购物车、库存扣减这些真实业务场景但又没有微服务、消息队列那种令新手崩溃的复杂度。下面我按一个完整项目的推进顺序来讲你跟着走一遍收获会远大于解压一个zip文件。2. 鲜花销售系统的需求拆解不要让销售管理变成摆设很多毕设项目的通病是标题写的是销售管理系统做出来却只有一堆数据表格的增删改查管理员能添加花、删除花、修改花然后就没有然后了。这不是管理系统这是数据库练习。一个站得住的鲜花销售管理系统至少要回答清楚两个问题谁来用这个系统他们在什么场景下用2.1 两类核心角色与功能边界划分我的建议是先按角色把系统切成两大块。前台是面向普通用户的购物端后台是面向管理员的管理端这几乎是所有电商类项目的标准切法。前台用户端需要做这些事注册登录、浏览鲜花商品、按分类筛选比如玫瑰、百合、绿植、干花、查看商品详情、加入购物车、提交订单、查看个人订单列表、取消订单。这里面注册登录四个字看起来简单但你要决定用什么方案Session还是JWT这个问题答辩老师特别喜欢问我后面会专门说。后台管理端需要围绕卖花这件事铺开花材分类管理、鲜花商品管理上架、下架、库存修改、订单管理查看所有订单、发货、处理取消、用户管理禁用、启用、轮播图管理和公告管理、销售数据统计。注意订单管理和商品管理是这个后台的核心如果只做了商品管理而忽略了订单流转答辩时老师一句用户在你这买了花你作为商家怎么处理订单就能把你问住。2.2 鲜花的业务特性给系统提出的额外要求鲜花这个品类和普通商品不太一样有个天然痛点耗损率高、时效性强。红玫瑰放三天就蔫了所以库存不能积压节日需求波动大情人节前后订单量可能是平时的几十倍。这些业务特性反映到系统设计上至少引出三个具体需求需求一订单状态必须要有完整流转路径。用户下单后商家要能发货用户要能确认收货超时或突发情况要支持取消。下面我会专门讲订单状态机的设计。需求二库存不能做成简单的下单就扣减或永不扣减。如果下单时完全不扣库存超卖问题就来了如果用户下单付款前就把库存锁死大量未付款订单会占住库存导致真实买家买不到花。对毕设而言一个折中方案是提交订单时用乐观锁扣减库存取消订单时回补。需求三后台需要一个简单的销售统计页面。不要做复杂报表但按时间段统计订单量、销售额按花材统计销量排名这些基本功能必须要有不然管理二字的成色不够。把需求边界画清楚之后再去打开源码看代码你会发现每个Controller、每张表都是有归属的而不是一团乱麻。这一步花半天时间能帮你省下后面论文写作和答辩准备的三天时间。3. 数据模型与订单状态流转整个系统的骨架所在需求分析完成后接下来就是数据库设计。我见过太多毕设项目在数据库这层就埋了雷订单表里没有订单明细表、所有金额字段用double存、状态字段用字符串随便填。鲜花销售系统的数据库设计我建议核心围绕六张表来展开这是最稳妥、也最容易在论文里画ER图的方案。3.1 六张核心表的字段设计与关联关系第一张是用户表user字段至少包含id、用户名、密码MD5加盐存储或BCrypt、昵称、手机号、邮箱、头像、角色标识区分普通用户和管理员、注册时间、状态正常/禁用。角色这里我建议用字段区分就好不要搞Spring Security的RBAC权限模型毕设系统的复杂度不需要那么重的设计但你要能在答辩时解释为什么这样取舍。第二张是花材分类表flower_type字段就三个id、分类名、排序号。玫瑰、百合、向日葵、绿植盆栽都可以放进去。第三张是鲜花商品表flower这是核心表字段要有id、商品名、所属分类id、主图url、多图url可以用逗号分隔存、原价、促销价、库存量、销量、是否上架、创建时间、更新时间。这里提醒一句价格字段强烈建议用decimal类型不要用double。原因很简单二进制浮点数无法精确表示0.1这种十进制小数累计下来会出现金额误差答辩老师问到这块时decimal是你的加分回答。第四张是购物车表cart字段id、用户id、商品id、购买数量、加入时间。一个用户对应多个商品条目唯一约束可以建立在用户id商品id上。第五张是订单表orders注意订单表名尽量不要用order因为order在SQL里是关键字。字段id、订单编号、用户id、订单总金额、收货人姓名、收货人电话、收货地址、订单状态、下单时间、支付时间、发货时间、完成时间。第六张是订单明细表order_detail字段id、订单id、商品id、购买单价、购买数量、小计金额。订单和明细是一对多关系明细表必须冗余商品快照信息比如下单时的价格。为什么要冗余因为商品价格会变化如果用户下单后你改了商品价格订单里的交易金额也变了这在业务上是不允许的。这个点如果你能在论文或答辩里主动讲出来面试官和导师会高看你一眼。3.2 订单状态机从待付款到已完成的完整生命周期订单状态是整个系统里最值得讲清楚的部分也是体现你懂业务的关键。我的设计经验是状态字段用整型数字去存然后在Java代码里用枚举去维护不要让字符串散落在代码各个角落。用数字标识状态而非字符串核心原因有几个一是数字存储空间更小、查询性能稍好二是规避不同数据库的字符串类型差异MySQL的varchar和Oracle的varchar2在长度语义上有区别三是整型更容易做状态值范围的校验。但缺点也很明显就是代码阅读性和日志可读性变差。所以必须配合一个状态枚举类在代码层面把数字和业务语义对应起来把所有状态值的定义收敛到一处。我在实际项目中习惯这样定义状态枚举状态码从1开始往上排1代表待付款、2代表待发货、3代表已发货、4代表已完成、5代表已取消。每种状态对应一个中文描述文本这样在后台管理和前端展示时可以直接取描述不用写一堆if-else去判断数字。状态流转规则需要特别注意不是所有状态都能随便跳转。一个标准流程是用户提交订单后进入待付款→用户模拟支付后进入待发货→管理员后台点发货进入已发货→用户确认收货后进入已完成。取消操作需要区分两种来源待付款状态下用户可以自行取消已付款状态下管理员可以在后台进行取消操作。已发货之后的订单不允许取消只能走线下售后流程毕设阶段不需要实现退货入库这种复杂流程但你要能口头说清楚为什么不支持。这组状态流转逻辑建议画成一张状态图放进论文里然后写一个OrderStateEnum配合一个状态校验方法。什么情况下允许什么状态迁移用一个Map或者switch配置好比散落一堆if判断要优雅得多。3.3 索引设计与常见查询的SQL优化思路数据库设计的最后一步别忘了加索引。users表的用户名要给唯一索引flower表的花材分类id要建普通索引前台按分类筛选时要用orders表的用户id要建索引查看我的订单时高频查询orders表的订单编号要建唯一索引。订单明细表的订单id必须建索引因为每次查订单都要连带查明细。实际开发中我遇到过这样一个性能问题系统跑了一个月后订单表数据量到了几万条后台按订单状态下单时间范围筛选时查询明显变慢。分析后发现问题在于where条件的字段组合与索引顺序不匹配。解决方案是建立联合索引order_status, create_time让状态筛选和日期范围查询能同时命中索引。这种优化思路不需要写进论文但答辩时如果你能主动提到我考虑到订单量增长后的查询效率所以建了联合索引技术深度一下就上来了。4. Spring Boot落地时的技术选型与分层设计4.1 版本、ORM、模板引擎怎么选才不给自己挖坑技术选型是另一个答辩必问区域也是最容易暴露代码不是自己写的的地方。我先说结论Spring Boot版本选2.x系列不要一上来就用3.x。原因很现实3.x基于JDK 17而很多学校机房、导师电脑、网上教程的依赖配置还停留在JDK 8和Spring Boot 2.x生态。如果你用了Spring Boot 3.xMyBatis Plus的版本兼容、某些第三方工具类的引入都会遇到坑更麻烦的是大部分你搜到的报错解决方案都是针对2.x的。毕设的第一个目标是稳所以选择2.7.x这个版本是目前比较平衡的方案。ORM框架选择MyBatis Plus而不是JPA或者原生MyBatis。JPA的学习曲线太陡而且自动生成的SQL在性能调优时很难掌控原生MyBatis让你写大量xml映射效率低。MyBatis Plus在两者之间找到了一个很好的中间点单表查询不需要自己写SQL用内置的Wrapper条件构造器就能搞定复杂多表查询又能用注解或xml自己控制。用它对个人开发者来说效率很高。前端页面方案我个人极不建议在毕设里搞前后端分离。我知道Vue很火简历上也好看但前后端分离意味着你要额外处理跨域、Token鉴权、前端打包部署这些对于以通过答辩为目标的毕设来说复杂度是成倍增加的。用Thymeleaf服务端渲染配合Bootstrap写一套还过得去的页面Spring Boot的Controller直接返回视图所有数据在服务端渲染好逻辑链路简单清晰答辩时你能把请求怎么进来、数据怎么出去讲得非常顺畅。如果简历需要你可以补充一句我了解前后端分离Vue技术栈这个项目为了聚焦后端核心逻辑选用了服务端渲染方案。4.2 分层结构与统一响应写好Controller层的关键规范分层的标准做法是Controller、Service、Mapper三层经典结构但大多数人会忽略一个关键点参数校验和异常处理到底放在哪一层。Controller层只做三件事接收参数、调用Service、返回统一结果。所有业务判断都在Service层做。Controller层需要把HttpServletRequest、HttpSession这些Web容器对象隔离在业务逻辑之外这样Service层才能脱离Web环境单独测试。Service层我建议先定义接口再写实现类。虽然写两层有点繁琐但这是Java后端开发的行业惯例。而且从设计角度看Service接口本身就是对业务能力的一份目录清单把该业务的对外能力列得非常清楚。在本系统里OrderService的实现类里至少要处理订单明细插入、库存扣减、订单状态更新这三个动作而且要放在一个事务里。和事务紧密相关的一个坑是如果这三个动作中没有主动加Transactional注解那么插入订单明细成功后扣减库存如果抛异常就会出现订单没有明细但商品被扣库存的脏数据。反之如果先扣库存后建订单库存扣了但订单没建成用户会看到购物车还在但库存少了。所以事务的加法和边界是这块代码质量的分水岭。Controller层返回的数据需要定义一个统一响应体。我习惯定义Result类包含code、message、data三个字段。code为200表示成功500表示系统异常再约定几个业务错误码比如400表示参数错误。这样前端拿到响应后先判断code再处理data逻辑非常统一。如果你在Controller里一会儿直接返回字符串一会儿返回Map一会儿返回List前端处理起来会非常痛苦论文里的核心代码展示也会显得零散。4.3 登录态方案选型Session还是JWT登录这块一个高频答辩问题就是你怎么保持用户登录状态的。我推荐用Session方案理由针对毕设场景很充分Session由服务器管理天然安全不存在Token泄露后的伪造问题实现简单一个HttpSession就能搞定不需要额外引入jjwt依赖也不需要处理Token过期刷新对于单体应用来说Session完全够用不用为了看起来高级去引入无状态认证那样反而是给自己挖坑。JWT适合什么场景适合前后端完全分离、后端需要水平扩展、同一个Token要在多个服务之间共享认证信息的场景。毕设项目基本不涉及这些你用Session答辩时把这个取舍说清楚老师反而会觉得你有架构意识。具体实现上我的做法是登录成功后把用户对象存进Session然后写一个拦截器HandlerInterceptor在preHandle方法里检查Session里有没有用户没有就重定向到登录页。再用WebMvcConfigurer注册拦截器配置好放行路径登录页、注册页、商品的列表和详情页可以放行但购物车、订单相关路径必须拦截。这里有个细节要注意拦截器放行的静态资源路径比如/css、/js、/images、/fonts否则页面样式加载不出来或者图片全裂。5. 核心功能实现的硬骨头库存、购物车、价格计算5.1 库存扣减与超卖问题乐观锁到底怎么用电商类项目藏着一个必考题高并发下防止库存超卖。在毕设答辩里哪怕你的系统根本没有高并发老师也几乎一定会问如果十个用户同时买最后一枝花你的系统会怎么处理。最稳妥到位的回答是基于数据库的乐观锁方案。在花材商品表里加一个version字段更新库存的SQL写成这样update flower set stock stock - #{count}, version version 1 where id #{id} and stock #{count} and version #{version}这段SQL的巧妙之处在于把库存检查和扣减操作合并为一条原子SQL。三个where条件同时满足才更新成功库存够不够、版本号是不是当初读到的那一个、商品存不存在。更新返回的影响行数如果为0说明库存不够或者有人并发改了这条数据此时在Service层重新查询库存并抛出业务异常库存不足或商品状态变化请重试。这个方案不需要额外引入分布式锁也不用改数据库隔离级别对毕设系统来说是最平衡的选择。5.2 从Session购物车到持久化购物车的合并策略购物车的两个常见的问题是加购逻辑与合并逻辑。花店这类前台系统我建议直接做成持久化购物车也就是用户把花加入购物车时立刻往carts表插一条记录。千万不要用Cookie存购物车因为Cookie大小限制在4KB左右而且用户清除浏览器数据后购物车就消失了体验很差。毕设作品里出现这种体验问题答辩印象分会受很大影响。持久化购物车要注意一个场景用户把同一款花加入两次。第二次应该走更新数量逻辑而不是再插入一条重复记录。用MyBatis Plus的LambdaQueryWrapper查一下用户id加商品id是否存在存在就update数量不存在就insert。下单时的购物车合并逻辑同样值得重视提交订单后先把购物车里勾选中的或者全部商品条目读出来逐条检查库存然后计算总价并生成订单。一个典型的流程是这样的先查询用户购物车列表循环遍历每一项检查商品是否仍在上架状态、库存是否足够然后汇总总金额。全部通过校验后分批插入订单表和明细表同时更新商品库存最后清空购物车对应条目。5.3 金额计算的精度处理与优惠逻辑扩展金额计算这块我在前面已经强调过数据库要用decimal这里再补充代码层面的处理运算法则所有涉及金额的计算在Java里用BigDecimal不要用double和float因为精度丢失一旦发生就会造成分账不平的严重问题。两个BigDecimal相加用add方法相乘用multiply方法当你把最终结果写回数据库时一定不会有精度损失。花店的优惠玩法在毕设里不用做太复杂但你可以预留扩展点。最常用的做法是在商品表设计两个价格字段原价和促销价。没有促销活动时两个字段相同有活动时前台展示促销价、划线显示原价。再进一步你可以在订单金额计算时加一个满减判断比如订单总金额满99减10、满199减30。这个逻辑不要散落在订单创建代码里单独抽一个PriceCalculator类传订单明细和商品信息进去返回订单总价以后扩展优惠券、会员折扣时都改这一个地方。这类小设计在论文的设计模式章节里可以写成策略模式的应用属于比较自然的加分项。5.4 图片上传不引第三方存储也能实现的头像与商品图方案花店系统的商品主图、轮播图都是图片毕设阶段不需要接入阿里云OSS或七牛云但也不能让用户在前台填一个绝对路径。你的选择是在本地磁盘建一个上传目录通过Spring Boot的静态资源映射把它暴露出去。比如在application.yml里配置spring: servlet: multipart: max-file-size: 10MB max-request-size: 10MB custom: upload-dir: /data/flower-system/uploads/然后写一个UploadController接收MultipartFile把文件按日期分目录存储文件名用UUID重命名避免中文名和重名问题返回一个相对路径前端img标签的src指向这个路径。要做的是配置静态资源映射Configuration public class WebConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/uploads/**) .addResourceHandler(file: uploadDir); } }关于图片上传这里有一个非常实用的经验图片文件的真实存储路径绝对不能写进数据库数据库里只存相对URL这样将来项目迁移只要把整个uploads目录拷走就能保留全部图片。6. 部署环境准备与打包配置从本地能跑到服务器能扛6.1 环境依赖与数据库初始化部署这块很多同学误以为在IDEA里点Run跑起来就算部署完了这其实是两个完全不同的概念。真正的部署是生产环境可运行打包成可执行JAR部署到服务器上客户端通过IP端口访问。如果毕设答辩只需要本地演示那在保证本地能跑之外还是要学会打包产物和启动方式因为老师很可能会问你这个项目上线部署怎么做。环境准备清单如下JDK 1.8对应Spring Boot 2.x、Maven 3.6以上、MySQL 5.7以上、IDEA开一个Terminal窗口就可以完成全部操作。数据库初始化有讲究不要只扔一个SQL文件让评审自己导入就完事该有的初始化数据必须齐全。分类表要预置玫瑰、郁金香、百合、向日葵等6-8个分类商品表预置15-20个商品图片要真实可用管理员账号要预置好比如admin/admin123并且在README里写清楚。很多系统跑起来首页空空如也就是因为生产库没有初始化数据体验分直接崩。6.2 Maven打包参数与JAR启动方式打包前有几项需要注意。首先一定要跳过测试很多项目带了JUnit测试类如果测试类里配置了独立数据库环境打包时测试跑不过就会导致打包失败而且测试类在打包阶段跑还会拖慢速度。打包命令如下mvn clean package -DskipTests打包完成后target目录下会生成一个flower-system-0.0.1-SNAPSHOT.jar接下来把它放到服务器目录执行启动命令java -jar flower-system-0.0.1-SNAPSHOT.jar --spring.profiles.activeprod如果你是Linux服务器还要注意磁盘权限问题。日志文件写入路径、图片上传目录这些目录如果没有创建或者没有写权限启动后接口会报各种IO异常。这类问题在大学阶段的Windows环境下基本遇不到但服务器上很常见。6.3 端口、数据库、文件路径的统一配置规范Spring Boot的默认端口是8080如果你的服务器上还跑了Nginx或其他服务8080很容易冲突。解决办法有两个修改server.port配置或者在启动命令后面加--server.port8090。MySQL数据库连接信息、账号密码不要写死在代码里放到application.yml里并准备dev和prod两套配置。不要有写死localhost的习惯因为当你把项目从本地搬到服务器localhost指向的就不再是你的开发机了这种错误排查起来很耗时间。上传文件目录也要在配置文件里统一管理。Windows开发环境下先用本机某目录Linux环境用/data/flower-upload不要每次都去改Controller里的硬编码路径。6.4 演示视频录制建议标题里带了演示视频我知道很多人录视频都是点开系统像游客一样从头翻到尾。这里我想提供一点经验演示视频的脚本应该先设计场景再开始录前后台联动把数据变化录出来。比如先在后台把某款玫瑰库存改成3切回前台用户端下单买走2支再切回后台看库存变成了1、订单状态变成待发货。观众看到的是一个直接可观测的数据流转过程表格里的数字会自己说话。这样录完的视频无论答辩还是论文截图说服力都远远大于逐个页面点一遍。录视频时屏幕分辨率调到1280720或者19201080字体用默认大小不要开IDEA的代码字体放大。录制过程中不要接电话不要弹任何聊天通知一次录制尽量控制在8分钟内。7. 从本地跑不起来到线上数据异常一组典型排查链路实录我现在想用真实存在的问题来复盘几个高频故障这些案例不来自某一套特定的源码而是整合了这类项目最常见的反复被问到的坑。它们值得你在答辩前亲自走一遍因为很多代码问题本质上是环境问题和配置问题这些问题大概率会在答辩现场被导师考察。7.1 启动即崩Spring Boot版本与JDK不匹配现象很典型项目一启动立刻抛UnsupportedClassVersionError或者类似java.lang.UnsupportedClassVersionError: org/springframework/boot/loader/Launcher... Unsupported major.minor version的错误。这类问题的根因是编译版本与运行版本不一致。比如源码是用JDK 17编译的而你本地用的是JDK 8字节码版本对不上JVM拒绝加载。排查链路是这样的先确认JDK版本命令行里跑java -version确认你实际用的是哪一个再看Maven的pom.xml里maven.compiler.source和maven.compiler.target配置的是多少最后看Spring Boot版本对应的JDK要求。Spring Boot 2.7.x对应JDK 8完全可以如果源码里用了JDK 17的特有语法那就真的是代码版本选型的问题了。解决方式也很明确统一到同一条链路里。毕设系统用JDK 8Spring Boot 2.7.x是最省心的组合如果你手里代码是3.x的不要再硬着头皮降级Spring Boot直接装一个JDK 17把环境对齐比改代码快得多。7.2 数据库连接失败与时区问题MySQL 8.0以上的版本application.yml里如果配置的是url: jdbc:mysql://localhost:3306/flower_db?useSSLfalse大概率会报Access denied for user或者Communications link failure以及时区相关的ServerTimezone异常。原因是MySQL 8.0把默认时区改了而且对SSL的要求也变了。正确的连接串应该长这样url: jdbc:mysql://localhost:3306/flower_db?useUnicodetruecharacterEncodingutf-8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue这里每个参数都有实际意义useUnicode和characterEncoding解决中文乱码serverTimezone指定时区避免报时区错误allowPublicKeyRetrieval是MySQL 8.0在非SSL连接时获取密钥所需的参数。排这一条链路时你要学会看堆栈的环环相扣报错是connection refused就查MySQL端口是Connection reset就查网络层面是Unrecognized connection string就重点检查参数的写法是ServerTimezone就加时区参数。不要被最底层的一个异常片断带偏耐心把完整堆栈从上到下读一遍再对症下药。7.3 页面样式全丢拦截器挡住了静态资源现象前端页面能打开HTML框架但所有css、js、图片全部404整个页面光秃秃的。根因几乎都出在拦截器注册时放行路径没写好。很多人写拦截器只放行了/login这个路径忘了把静态资源路径放进去。Spring Boot里静态资源的默认路径一般是/static、/public、/resources、/META-INF/resources如果你在注册拦截器时配置了excludePathPatterns要这样写registry.addInterceptor(loginInterceptor) .addPathPatterns(/**) .excludePathPatterns(/login, /register, /flower/**, /flowerType/**, /css/**, /js/**, /images/**, /uploads/**);这里把商品浏览的路径和所有静态资源路径全部排除掉。如果还在用Spring Security那还要额外放行更多请求但对毕设项目直接用拦截器就足够清晰了。我排这个坑时最常用的一招是在浏览器按F12打开Network面板看加载失败的资源它们的URL长什么样一目了然。如果css资源请求的路径前面多了一个不该出现的目录前缀大概率是你在页面模板里用了绝对路径而没加上下文路径随手去改th:href的引用方式即可。7.4 订单创建成功但订单明细为0事务失守的经典现场这是一个极其隐蔽的bug用户下单orders表里多了一条记录但order_detail表都是空的或者库存减了但订单没生成。原因几乎可以锁定为一个Service层方法没有加Transactional。如果创建订单的Service方法里面先insert订单主表、再insert明细表但方法没有开启事务那每条SQL都是独立自动提交的。假设在循环插入明细的第5条时报错了前4条已经提交主表记录也已经提交这时整个订单是残缺的且无任何整体回滚。这种错误在生产环境比想象中常见排查时你会看到数据库里一堆孤儿订单。修复很简单在Service实现类的方法上加上Transactional并注意默认的rollbackFor属性。Spring的Transactional默认只对RuntimeException回滚如果你在方法里捕了一个Exception自己处理那事务也会失效。正确的做法是Service public class OrderServiceImpl implements OrderService { Transactional(rollbackFor Exception.class) Override public Order createOrder(Long userId, OrderCreateDTO dto) { // 1. 查询购物车 // 2. 校验库存和价格 // 3. 插入订单主表 // 4. 循环插入明细 // 5. 更新库存 // 6. 清空购物车 } }关于事务还有个相关细节同一个类内部方法调用事务注解默认不生效。假如你在OrderServiceImpl里有一个非事务方法A它内部调用了createOrder而createOrder上的Transactional是不起作用的因为Spring的AOP代理机制踩到这里所以要么直接调用外层的事务方法要么把事务逻辑放到独立的Service类里。8. 从毕设源码到答辩通过论文写作与演示时的加分细节8.1 论文中四张图的分量论文里最能体现工作量的其实是图。四张图必不可少系统功能结构图、系统架构图、数据库ER图、系统流程图围绕订单流转画。我不建议你只用网上的截图可以亲手画工具就用ProcessOn或者draw.io画好导出为图片插入论文。画图有一个核心原则图里出现的内容必须和代码实现一一对应。很多论文的系统功能结构图里画了用户积分管理代码里根本没有积分表老师一看就觉得内容是抄的这就非常可惜了。你在画功能结构图之前先对照Controller层的每个接口和Service层每个方法把功能盘点清楚画出来的图才会严丝合缝。8.2 测试章节不是编测试用例是证明系统可用论文里的系统测试章节不要在文末贴几十页截图堆砌。建议按功能模块来组织每个模块给一张测试表列出测试用例编号、测试项、前置条件、操作步骤、预期结果、实际结果。比如订单模块-用户提交订单后商家发货这一条操作步骤写清楚从哪登录、点什么按钮、填什么数据预期结果是订单状态从待发货变为已发货库存减少相应数值。这样写出来的测试报告阅读体验远好于满屏截图。如果你想给测试章节加分可以补一小部分接口测试的说明注明自己用Postman对订单创建、商品查询等重点接口做了接口测试验证了正常流程和异常流程比如库存不足时会返回统一错误码。这里不需要真的把Postman导出的JSON文件贴进论文只是把思路讲清楚就已足够。8.3 答辩前建议事先想清楚的几个追问我把这两年学生被问得最频繁的问题整理成了一张表每一条都要能停顿一下后给出逻辑清晰、有理有据的回答追问方向追问举例回答要点技术选型为什么用Spring Boot而不用SSM起步依赖简化配置、内嵌Tomcat、自动装配机制、社区生态成熟SSM要手动配置大量xml安全设计密码是明文存的吗使用MD5加盐或BCrypt哈希存储数据库即使泄露也无法反推用户密码并发场景库存超卖怎么解决乐观锁机制update时校验库存与version影响行数为0则判定库存不足状态设计订单状态流转规则是哪里维护的枚举定义状态码Service里专门的方法统一做状态迁移校验与流转扩展能力如果要支持手机验证码登录要改哪些地方新增验证码发送服务登录表单加验证码字段登录校验时增加验证码核对改动集中在UserService与登录接口部署上线项目现在怎么部署的JAR包运行MySQL放在同一个服务器配置prod环境参数静态资源走本地映射8.4 最后再补一个代码细节答辩之前花两个小时把代码里的System.out.println全部删掉换成logback的logger.info或者干脆不要。这不是小事评审老师万一在控制台看到满屏乱打的内容对你的代码整洁度的印象分立刻下降一个档次。同时把pom.xml里的不需要依赖比如没用的测试依赖、网上下载源码残留的swagger依赖清理一下保持依赖树干净。在我经验里答辩最关键的就是你能讲清楚自己写的每一行代码背后的设计理由。源码在谁手里从来不是核心核心是你能否对这套系统的每个设计决策做出经得起追问的解释。把这篇博文里的需求、数据模型、订单状态、库存方案、部署链路真正走一遍之后你就不是在演示一个代码包而是在展示一个你完全掌控的作品。
返回列表