ARTICLE DETAIL

资讯详情

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

Java毕业设计实战:基于Spring Boot的智能防疫物资采购系统

Java毕业设计实战:基于Spring Boot的智能防疫物资采购系统 作为一个做过不少Java毕业设计、也帮人看过很多代码的人我拿到这个题目第一反应是这题看似是个普通的“管理系统”但仔细拆一下“疫情下”“物资采购”“物流”这几个词它其实比常见的图书管理、学生管理系统复杂一个档次。如果只是把传统的进销存改个名字交上去答辩的时候很容易被问住。这篇文章我会完整梳理一遍这类系统从需求拆解、技术选型、数据库设计到核心代码落地、踩坑排查的全过程。你要做的是照着这个思路把逻辑理清楚而不是直接复制粘贴某段代码就完事——那样答辩也扛不住。1. 这个课题到底在做什么从题目拆解出真正的需求很多同学拿到题目就开始建表、写代码结果做着做着发现功能越做越乱。我在指导这类毕业设计时第一步永远是逼着自己把题目里每个词都翻译成具体的业务功能。1.1 疫情场景下的业务约束为什么不是普通进销存“疫情下”不是一个装饰词它会给物资采购系统带来几个普通进销存没有的硬约束物资分类有优先级。普通超市进货不用分优先级疫情下的防护物资、药品、生活保障物资、消杀物资每一类的紧缺程度和审批流程是不同的。比如N95口罩和消毒酒精的采购审批流就比普通办公用品要快、要严。库存上下限要有预警机制。疫情物资的核心目标不是“库存够用”而是“库存不能断”。当库存低于某个阈值时系统要能自动触发采购建议而不是等人去查报表才发现没了。部门之间物资要能调拨和计算平衡。医院、社区、街道、后勤仓库之间物资不是各买各的而是需要统一协调、集中采购、分区发放。系统里如果只有“采购”功能没有“调拨”和“需求汇总”业务上就不完整。采购价格和供应商记录要有追溯。疫情时期的物资价格波动很大系统里必须能记录物资的历史采购价、供应商资质信息方便事后对账和审计。把上面这几点列出来之后系统的功能模块基本就浮出水面了模块核心功能难点系统管理用户、角色、权限、菜单RBAC权限模型设计物资档案物资分类、规格、计量单位分类需要支持多级供应商管理供应商档案、资质、历史报价价格追溯采购管理采购申请、审批、订单、入库状态流转、审批流库存管理入库、出库、调拨、盘点库存联动、预警需求管理部门需求上报、汇总批量合并报表统计采购报表、库存报表、出入库流水可视化展示1.2 “智能”两个字怎么体现不是噱头是具体功能题目里有“智能防疫物资采购系统”这个表述很多同学不知道“智能”体现在哪。其实在毕业设计这个层面“智能”不需要上机器学习它可以从三个方面落地第一是库存阈值预警。给每种物资设置安全库存线和补货线低于补货线就自动生成一条采购建议记录推送给采购员。第二是采购建议自动计算。根据近期的日均消耗量、当前库存、在途订单量计算出建议采购数量公式大概是建议采购量 日均消耗量 × 补货周期 - 当前库存 - 在途订单量 安全库存。这个逻辑写进Service层就是能讲清楚的核心亮点。第三是采购单号自动生成、审批流程自动流转。单据号按规则生成审批通过后自动进入订单环节整个过程不需要人工二次录入。1.3 毕业设计角度先明确你要展示什么做毕设和做产品不一样。你的目标是让答辩老师30分钟内看懂你做了什么、怎么做的、为什么这么做。因此你不需要做一个功能多到爆炸的系统但你需要把关键链路做完整——从用户登录、采购申请、审批、下单、入库、库存变动到报表输出一条线串下来再加上一个亮眼细节比如库存预警或采购建议这就够了。我在看很多学生代码时发现一个普遍问题菜单做了一堆点击进去全是“暂无数据”。与其这样不如把五张表的流程做穿比三十张空表有价值得多。2. 技术选型为什么这套Java技术栈最合适题目明确了用Java那么技术栈怎么搭配需要结合“毕业设计”这个场景来考虑。我的建议是用最主流、最稳妥、方便答辩讲道理的组合而不是为了炫技引入过于复杂的东西。2.1 Spring Boot MyBatis Plus MySQL毕业设计的黄金三角这套组合现在几乎是Java毕设的标配原因很现实Spring Boot解决了配置地狱问题让项目结构干净适合快速开发。MyBatis Plus比原生MyBatis的开发效率高得多。你不需要手写单表CRUD的SQLBaseMapper里面自带selectById、insert、updateById这些方法。更关键的是Wrapper可以让你用面向对象的方式拼查询条件比如LambdaQueryWrapper比手写XML拼接SQL要舒服很多。MySQL开箱即用各种资料多答辩解释也容易。我在实际开发这类订单型系统时最常用的是 MyBatis Plus 的这几个能力// 条件构造器按状态查询采购申请单 LambdaQueryWrapperPurchaseApply wrapper new LambdaQueryWrapper(); wrapper.eq(PurchaseApply::getStatus, 1) .eq(PurchaseApply::getCreateBy, currentUserId) .orderByDesc(PurchaseApply::getCreateTime); ListPurchaseApply list purchaseApplyMapper.selectList(wrapper);这段代码对应的SQL不需要你手写但它生成的逻辑你答辩时一定要能说清楚eq对应等值条件orderByDesc对应排序Lambda写法的好处是编译期就能发现问题。2.2 前端选型Vue Element UI 是最稳的方案很多同学纠结前端要不要用Vue。我的建议是如果时间充裕用Vue Element UI 做前后端分离如果时间紧张让后端用Thymeleaf渲染页面也可以但效果会略逊一筹。为什么推荐Vue因为Element UI的表格、表单、对话框组件可以直接套用写出来的界面比JSP年代的管理系统观感好一个时代。答辩时界面好看老师的第一印象就差不了。技术上你只需要掌握几个核心操作axios调后端接口、v-for渲染表格、this.$message弹出提示。前后端分离之后前端项目用npm run dev起在8081端口后端Spring Boot起在8080端口联调时在vue.config.js里配一下代理即可module.exports { devServer: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }这个配置的意思是前端发出的所有以/api开头的请求都转发到后端的8080端口。答辩时如果老师问“前后端怎么联调”这就是答案。2.3 环境准备JDK、Maven、IDEA 的细节这部分的坑在于环境变量配置。Java做开发JDK和Maven必须配好。有些同学代码写完了运行时报java.lang.UnsupportedClassVersionError就是JDK版本不一致导致的。毕业设计这边我建议统一用JDK 8或JDK 17两者都可以但不要混用。Spring Boot 2.x.x 适配JDK 8更省心Spring Boot 3.x.x 需要JDK 17以上。如果你用的是Spring Boot 2.7.x JDK 8这是我最推荐的组合网上资料最多遇到问题一搜就能解决。Maven 配置需要注意两点一是本地仓库路径不要放C盘二是默认镜像源换成国内镜像否则下载依赖时能卡到你怀疑人生。settings.xml里这样配mirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror换成阿里云镜像之后首次导入项目的依赖下载时间能从半小时缩到几分钟。这个细节虽然不起眼却非常影响开发体验。3. 数据库设计从业务出发反推表结构别一上来就建数据库设计是这类系统能不能讲明白的核心。我见过太多人把表建得跟字段堆砌一样没有外键关联没有状态字段业务直接没法走通。正确的做法是先把业务流程图画一遍再决定每一张表长什么样。3.1 核心表划分围绕“一个流程”展开疫情物资采购管理系统最重要的流程是部门上报需求 → 采购员发起申请 → 领导审批 → 生成采购单 → 供应商供货 → 入库登记 → 库存增加 → 领用出库 → 库存减少。围绕这条链路核心表至少有这些表名用途关键字段设计sys_user用户表username唯一、password加密存储sys_role角色表采购员、审批人、仓库管理员、系统管理员material_info物资表category_id、safety_stock、current_stock、unitmaterial_category物资分类表parent_id支持多级分类supplier_info供应商表contact、phone、qualificationpurchase_apply采购申请表apply_no、status、total_amountpurchase_apply_item申请表明细material_id、apply_quantity、estimate_pricepurchase_order采购订单表order_no、supplier_id、statuspurchase_order_item订单明细表material_id、order_quantity、pricestock_in入库单表order_id、operator、remarkstock_out出库单表领用部门、领用人、用途stock_alert预警记录表material_id、alert_type、status这里我要特别强调主表明细表的设计思想。很多初学者会把采购单做成一张表里面存一堆物资字段这是错的。一单采购可能包含多种物资只有拆成采购申请表申请明细表两张表用apply_id关联才能正确表达“一对多”关系。同理采购订单和订单明细也是这个套路。答辩时把这个讲清楚老师就知道你的数据库设计有基本功。3.2 状态字段是流程型系统的灵魂采购申请单的状态我建议用数字表示存一个status字段从0到30 表示“待审批”1 表示“审批通过”2 表示“已生成订单”3 表示“已入库”。如果被驳回可以用 -1 表示或者单独加一个5表示“已驳回”。为什么要用数字而不是字符串因为数字做条件查询效率更高而且状态流转用代码控制更严谨。后端代码里可以写一个常量类public class ApplyStatus { public static final int PENDING 0; public static final int APPROVED 1; public static final int ORDERED 2; public static final int STOCKED 3; public static final int REJECTED 4; }状态流转控制的核心原则是任何状态跳转必须是单向的、可追踪的。审批通过之后不能直接改回待审批入库之后不能回到已生成订单状态。这需要在Service层写判断逻辑而不是前端改了状态就完事。说白了前端的按钮只负责调用接口真正的状态校验和流转逻辑必须写在后端。3.3 三个容易忽略但很重要的设计点第一个是逻辑删除。不要物理删除采购单、物资档案。用MyBatis Plus的TableLogic注解实现逻辑删除本质上就是给表加一个deleted字段查询时自动带上deleted0条件。这样数据始终有历史后面要做报表追踪才能说得通。TableLogic private Integer deleted;第二个是金额字段的类型。涉及金额的字段一律用BigDecimal不要用double或float。数据库端用DECIMAL(10,2)。这个不做说明就会踩精度丢失的坑。我用一个真实情况举例计算某次采购的总金额时有同学用double计算 0.1 0.2得到 0.30000000000000004对账对不上后台数据一查就知道。这在财务相关字段上是不能接受的。第三个是时间和操作人。每张业务表都应该有create_time、update_time、create_by、update_by这些公共字段一方面是为了排查问题另一方面是答辩时讲“操作留痕”这个概念有实际支撑。MyBatis Plus可以用TableField(fill FieldFill.INSERT)配合MetaObjectHandler实现自动填充Component public class MyMetaObjectHandler implements MetaObjectHandler { Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, createTime, LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, updateTime, LocalDateTime.class, LocalDateTime.now()); } Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, updateTime, LocalDateTime.class, LocalDateTime.now()); } }这个自动填充机制能保证你写代码时不用手动给每个createTime赋值省力是一方面更重要的是不会漏。4. 核心功能落地采购审批、库存联动与智能建议数据库结构定好了接下来就是把这些表“串”起来。我挑三个最容易出问题也最值得展开写的核心功能讲清楚实现逻辑和意图。4.1 采购申请单的创建与审批流程实现采购申请从创建到审批核心代码在Service层。这里我以一个典型场景为例某个科室需要1000个医用口罩发起了申请审批人登录系统看到这条申请点击通过。后台处理的逻辑分三步先校验当前用户是否有审批权限再校验申请单状态必须是“待审批”最后更新状态并把审批人和审批意见记录进去。Transactional(rollbackFor Exception.class) public void approveApply(Long applyId, Long approverId, String opinion) { PurchaseApply apply purchaseApplyMapper.selectById(applyId); if (apply null) { throw new RuntimeException(采购申请单不存在); } if (!apply.getStatus().equals(ApplyStatus.PENDING)) { throw new RuntimeException(当前状态不允许审批); } // 权限校验 boolean canApprove applyService.checkApprovePermission(approverId); if (!canApprove) { throw new RuntimeException(该用户没有审批权限); } apply.setStatus(ApplyStatus.APPROVED); apply.setApprover(approverId); apply.setApproveOpinion(opinion); apply.setApproveTime(LocalDateTime.now()); purchaseApplyMapper.updateById(apply); }这里面的Transactional注解很关键。这段代码涉及查询和更新两步操作如果不加事务万一更新过程中异常中断数据就可能出现“审批人已经填了但状态没变”这种不一致情况。rollbackFor Exception.class的意思是所有运行时异常都会触发回滚。权限校验单独提一个方法逻辑在真实的RBAC模型里可以复用。如果你用了Spring Security或者自己写拦截器第一步会先走认证授权但Service层再校验一次并不多余——这叫“纵深防御”答辩时说到这点会很加分。4.2 入库加库存、出库减库存事务双写的正确姿势库存变更是这类系统最容易出错的业务环节。一个常见的错误是前端调用入库接口插入一条入库记录然后发起一次库存更新的SQL。如果两个操作不是同一个事务插入成功但更新失败库存就和流水对不上了。所以这两个操作必须放在同一个事务方法里Transactional(rollbackFor Exception.class) public void stockIn(PurchaseOrder order, ListStockInItem items) { // 1. 校验订单状态为“已下单” if (!order.getStatus().equals(OrderStatus.CREATED)) { throw new RuntimeException(订单状态不允许入库); } // 2. 写入入库单主表和明细表 StockIn stockIn new StockIn(); stockIn.setOrderId(order.getId()); stockIn.setOperator(loginUserId); stockInMapper.insert(stockIn); for (StockInItem item : items) { item.setStockInId(stockIn.getId()); stockInItemMapper.insert(item); // 3. 同步更新物资库存 materialInfoMapper.increaseStock(item.getMaterialId(), item.getQuantity()); } // 4. 修改订单状态 order.setStatus(OrderStatus.STOCKED); purchaseOrderMapper.updateById(order); }这里我特意用了自定义SQL而不是MyBatis Plus自带的update。因为current_stock current_stock 数量这个操作如果用先查询再更新的两步式写法并发场景下就会丢更新。用自定义SQL的一条UPDATE material_info SET current_stock current_stock #{qty} WHERE id #{id}就把读改写压缩成一步从根上避免并发覆盖。对应的Mapper代码Update(UPDATE material_info SET current_stock current_stock #{quantity} WHERE id #{materialId}) int increaseStock(Param(materialId) Long materialId, Param(quantity) Integer quantity);这张表对应的是“出入库影响库存”这个核心联动。同样出库就是current_stock - quantity但需要在写SQL时加一个条件——扣减后的库存不能为负数Update(UPDATE material_info SET current_stock current_stock - #{quantity} WHERE id #{materialId} AND current_stock #{quantity}) int decreaseStock(Param(materialId) Long materialId, Param(quantity) Integer quantity);这样写的好处是数据库层面的条件判断帮我们在并发场景下挡住了超扣库存的可能。返回值为0时说明库存不足代码里直接抛异常。4.3 智能采购建议怎么把计算逻辑讲得清晰前面提到“智能”可以落地为自动计算采购建议。这个功能的实现思路是遍历物资表找出当前库存低于补货线的物资然后参考近7天的出库流水算出日均消耗量最后得出建议补货量。public ListPurchaseSuggestion generateSuggestions() { ListMaterialInfo materials materialInfoMapper.selectList(null); ListPurchaseSuggestion result new ArrayList(); for (MaterialInfo material : materials) { if (material.getCurrentStock() material.getReorderLine()) { int dailyAvg stockOutMapper.selectAvgDailyByMaterial(material.getId(), 7); int suggestedQty dailyAvg * material.getRestockCycDays() - material.getCurrentStock() - material.getInTransitQty(); if (suggestedQty 0) { PurchaseSuggestion suggestion new PurchaseSuggestion(); suggestion.setMaterialId(material.getId()); suggestion.setSuggestedQty(suggestedQty); suggestion.setReason((material.getCurrentStock() material.getSafetyStock()) ? 库存低于安全线 : 低于补货线); result.add(suggestion); } } } return result; }这段逻辑并不复杂但它是题目里“智能”二字的直接落脚点。答辩时老师大概率会问“你的智能体现在哪”你可以直接打开页面演示把某个物资的库存改到安全线以下点击“生成建议”系统自动跳出一条采购建议记录数量还能跟着历史消耗量动态变化。这里需要补充说明的是dailyAvg是StockOut流水里的近7天日均出库量。如果你的系统没有历史流水可以先用一个固定值模拟但建议是把真实流水做进去这样演示更有说服力。4.4 报表统计用一张折线图或柱状图收尾报表功能不是核心但它是演示时的“门面”。我建议用ECharts在管理首页放三个可视化卡片本月采购总额、当前库存预警数量、近7天出入库趋势。前端从后端接口拉统计数据接受一个JSON数组前端渲染到图表里即可。后端接口的写法非常简单GetMapping(/dashboard) public Result dashboard() { MapString, Object data new HashMap(); data.put(monthPurchaseAmount, purchaseOrderMapper.selectMonthAmount()); data.put(alertCount, materialInfoMapper.selectAlertCount()); data.put(stockTrend, stockInOutMapper.selectTrend7Days()); return Result.success(data); }这里的Result是自己封装的一个统一返回对象包含code、message、data三个字段。为什么要统一返回格式因为前后端分离后前端拿数据不需要分别判断不同接口的返回结构。这是非常基础的工程化素养写在代码里面试和答辩都能提。5. 踩坑与排查并发扣库存、事务失效、软删唯一索引冲突这一部分我觉得才是干货最多的。每个做管理系统的人都会遇到类似问题我把实际排查过程中总结的链路写下来你可以对照自己的代码检查。5.1 场景一并发扣库存导致超卖怎么定位现象库存剩100个两个人同时领用80个最后系统里库存显示60。从常理推断两人总领用160个应该有一个失败才对但两个请求都成功了。排查链路第一步看SQL是不是“先查后改”也就是select current_stock拿到100然后update set current_stock 100 - 80。如果是这种写法两个请求可能同时查到100然后各自减去80最后结果是20而不是-60因为第二个更新覆盖了第一个。第二步看Service层方法有没有加事务和锁。如果你在方法上加了synchronized但用的是Spring默认的单例模式它能保证一个JVM内并发安全但如果你没加就会丢更新。修复方案换成我上文写的原子更新SQLUPDATE material_info SET current_stock current_stock - #{qty} WHERE id #{id} AND current_stock #{qty}。这一步就把“读改写”压缩成“单个条件更新”数据库层面保证原子性代码层面配合判断受影响行数来决定是否抛异常。5.2 场景二Transactional 失效数据只写了一半现象入库记录写成功了库存却没增加。排查了半天发现方法没走事务。排查链路第一步检查方法是不是public。Spring的声明式事务默认基于AOP代理private方法不会被代理事务注解自然失效。第二步检查方法是不是this调用了本类的另一个方法。比如你写了一个中间方法调用了this.stockIn()这在同一个类内部调用不经过代理事务同样失效。第三步检查异常是不是被try-catch吞掉了。Transactional默认只回滚运行时异常如果你在方法里把异常捕获了事务感知不到异常照样提交。Transactional(rollbackFor Exception.class) public void stockIn(PurchaseOrder order, ListStockInItem items) { try { // 业务逻辑 } catch (Exception e) { // 不要在这里吞异常让事务感知到异常才能回滚 throw new RuntimeException(入库失败, e); } }另外特别提醒事务方法里不要做耗时的外部调用比如发短信、调远程接口否则会长时间持有数据库连接怼上并发量会拖垮连接池。学到一个词是“事务边界尽量小”这是我自己实操时最深刻的体会之一。5.3 场景三逻辑删除和唯一索引冲突现象给物资表的material_name字段加了一个唯一索引处于逻辑删除状态的数据仍然占着这个索引位置。第二次新增同名物资时插入失败报唯一键冲突但查询时又看不到这条“已删除”的记录。排查链路这是逻辑删除方案的通病。物理删除可以直接删记录唯一索引很容易保证逻辑删除只是打标记数据库层面依旧认为那条数据存在。修复方案列举三种依项目复杂度取舍。简单方案是唯一索引的字段拼接一个删除标记后缀比如把物资编码改成“N95-001-deleted-123456”删除时同时更新名字这样新数据就能用原名了。另一种方案是建一个中间表存已删除名称再清理唯一索引。还有一种方案是干脆允许重名靠编码字段做唯一。毕业设计场景下推荐优先用第一种实现简单、好讲、也不影响正常业务。5.4 场景四MyBatis Plus分页查不到数据现象前端表格显示“暂无数据”但数据库里明明有记录。排查链路第一反应是看控制台SQL。如果打印出来的SQL没有LIMIT说明MyBatis Plus的分页插件没配置。注意MyBatis Plus的分页不是引入依赖就自动生效的必须在配置类里添加PaginationInnerInterceptor否则selectPage方法不会真正执行分页数据量大了还会全表查询。Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); PaginationInnerInterceptor paginationInterceptor new PaginationInnerInterceptor(DbType.MYSQL); paginationInterceptor.setOverflow(false); paginationInterceptor.setMaxLimit(500L); interceptor.addInnerInterceptor(paginationInterceptor); return interceptor; }setMaxLimit(500L)是防止有人恶意传超大页码把数据库拖垮。这个虽然折腾但配置一次就再也不用担心分页问题了。6. 演示与答辩如何把系统讲得有价值而不只是点按钮系统做完了最后一步是演示和答辩。这一步很多同学栽跟头不是代码写得差而是不会讲。我建议你准备一条“演示动线”按照业务闭环来走而不是打开菜单一个个点过去。6.1 现场演示路线怎么设计我的经验是分五步演示登录说明不同角色的权限差异。先演示管理员登录看一下菜单比普通采购员多哪些模块。新增物资档案录入物资名称、分类、计量单位、安全库存为后面的智能建议做铺垫。提交采购申请→审批用采购员账号发起申请带出明细切换审批人账号审批通过。生成采购单→入库审批通过后一键生成订单给订单维护供应商和采购价执行入库操作回到物资列表查看库存变化。触发预警→展示报表把库存改成低于安全线点击“生成采购建议”系统自动给出建议采购量最后切到首页看图表。这五步是一条完整的业务闭环每一步都在展示一个明确功能点老师跟着你的流程走不需要自己摸索印象分会高很多。6.2 高频答辩问题怎么准备提前准备几个问题答得流畅整个答辩氛围就会很好Q为什么选Spring Boot MyBatis PlusASpring Boot简化了配置和部署适合快速搭建独立服务MyBatis Plus在MyBatis之上提供了通用CRUD、条件构造器和分页插件提升了单表操作的开发效率让我把精力集中到采购、审批、库存联动这些核心业务逻辑上。Q库存扣减如何保证数据一致性A数据库层面用的是原子更新SQLUPDATE ... SET current_stock current_stock - ? WHERE current_stock ?代码层面通过事务保证入库流水和库存更新的原子性再配合统一异常回滚确保数据在并发场景下也不会超扣。Q系统做了哪些权限控制A采用RBAC模型用户绑定角色角色绑定菜单和操作权限后端在拦截器里校验接口权限Service层对关键操作如审批、入库再次校验保证越权请求无法执行。Q未来可以怎么扩展A可以做消息通知审批通过后通过WebSocket实时推送也可以引入消息队列削峰或者对接第三方物流系统实时跟踪在途物资节点。不要只说不做列举具体的扩展点。6.3 代码之外的一些细节建议写代码的间隙我有几个实际体会想分享给你。环境问题要提前解决。别在答辩当天换新电脑演示也别用依赖没拉全的IDE开始现场讲解。我之前帮学生检查项目有位同学到了答辩教室才发现8080端口被占用项目起不来最后只能干讲PPT非常可惜。提前一天把Clean、Install、Run都跑一遍是最基本的仪式感。写一个README.md把项目的环境要求、启动步骤、默认账号密码写清楚。这不是给老师看的是给你自己看的——答辩当天紧张起来大脑空白时照着README操作可以救命。我发现准备越细致的项目演示时越从容因为你对每一步都有把握。如果时间允许把日志加上。Spring Boot自带的Logback配置一下在控制台打印SQL和基础业务日志。演示时如果报错你能快速定位而不是对着一个诡异的异常信息抓瞎。哪怕是答辩现场能通过日志迅速解释清楚问题原因也是一种很好的工程素养展示。最后想说做这个题目最大的价值不是说你的代码能扛多少并发而是你在整个过程中理解了“一个业务流程怎么落地成表结构、Service逻辑、前端页面”以及“异常情况怎么排查、数据一致性怎么保证”。把这条链路走通毕业设计这件事基本就稳了。答辩时拿出真实的排查过程和思考逻辑比背十篇论文都有说服力。
返回列表