SpringBootVue 医院药品管理系统这个标题在毕设、课设资源里出现的频率相当高JavaMySQL 的全栈组合功能覆盖药品信息管理、库存监控、采购入库、处方销售这些典型业务。不管是拿来交毕业设计、课程作业还是作为学完 Spring Boot 和 Vue 之后练手的第一个完整项目它都是一个非常合适的选择。这几年我带过不少同学的毕业设计和课程项目反复接触过类似的管理系统。这类项目最有价值的一点是它不是一个简单的增删改查 Demo而是真实医院药品流转的缩略版。你从中能学到的不只是代码还有业务单据怎么流转、库存如何控制、角色权限怎么区分这些在课堂作业和拼凑的小练习里很难完整遇到。本文会从整体架构拆解、数据库设计、后端关键逻辑、前端页面实现、本地运行操作、常见问题排查这几个维度把这类系统的完整脉络讲清楚。1. 先弄明白这套系统到底解决什么问题1.1 医院药品管理的核心业务链路医院药剂科每天面对的工作远不只是进货、卖药这么简单。一支抗生素从供应商送抵药库到它最终被门诊医生开给患者中间要经历验收入库、库存存储、效期监控、药房领药、处方审核、发药出库、用药记录归档这好几个环节。任何一个环节出错轻则库存对不上账重则过期药品流入临床。这类系统就是为这个过程服务的。它把药品从进院到离院的全生命周期管理起来核心业务链路大致是药品资料建档 → 供应商采购 → 入库审核 → 库存更新 → 药房/临床科室领用 → 门诊处方销售 → 库存扣减 → 效期与库存预警。此外还有用户管理、登录鉴权、操作日志、统计报表等支撑性功能。在做项目拆解之前建议先把上面这条链路画一遍。你会发现所有功能模块本质上都是这条链上的一个节点理解了业务流代码再复杂也不会走偏。1.2 技术栈选型的真实原因市面上同类系统不少有的用 SSMSpring Spring MVC MyBatis有的用 Spring Boot Thymeleaf 服务端渲染而SpringBoot Vue MySQL这套组合之所以在毕设和课设项目中成为主流有它的现实原因。Spring Boot 最大的价值是自动配置 约定优于配置它帮开发者省掉了大量 XML 配置和繁琐的依赖管理。用 Spring Boot 写后端只需要一个标注了SpringBootApplication的入口类配合若干 Controller、Service、Mapper 就能跑起来一个完整的 Web 服务。配合 MyBatis-Plus单表的增删改查基本不用手写 SQL开发效率明显高于传统的 Spring Spring MVC。前端选择 Vue是因为 Vue 的学习曲线在三大前端框架里相对平缓而且 Vue 的单文件组件结构非常直观。模板、脚本、样式写在一个.vue文件里对于 Java 后端同学来说非常容易上手。再搭配 Element UI 或者 Element Plus 这样的组件库表格、表单、弹窗、分页器几乎都是现成的。一个基础还算扎实的同学两周时间可以完整做出来毕设进度压力不会太大。数据库选 MySQL 则是最稳的选择它足够成熟、社区资料多、Navicat 等图形化工具齐全部署和学习成本在校园网环境里基本没有门槛。1.3 这类系统的三重用途毕业设计看重的是功能完整度 技术覆盖面 论文可写性。药品管理系统涵盖了权限管理、业务单据、库存预警、统计图表这些都能拆成独立章节写进论文答辩时也容易讲清楚。课程设计看重的是结构清晰、调试方便、一人能完成。这种规模的系统刚好卡在一个不太大也不太简单的点上同理不容易出现代码多到看不完的情况也不会被老师说工作量不足。日常练手看重的是学到了什么。通过这套系统你能把 Vue 前端、Axios 请求、Spring Boot 接口开发、MyBatis 持久层、MySQL 表设计、JWT 鉴权这些知识串成一个闭环这是做几百道练习题换不来的经验。2. 系统模块拆解与数据库设计2.1 功能模块怎么划分最合理动手写代码之前先按业务域把系统切成几个模块。参考我见过的大多数项目一个功能完整、答辩经得起问的药品管理系统通常包含以下几个模块模块核心功能对应的典型页面系统管理用户登录、账号管理、角色权限、修改密码、操作日志登录页、用户列表、角色分配药品信息管理药品档案的增删改查、药品分类、处方药/非处方药标记药品列表、药品详情、新增/编辑弹窗库存管理入库登记、出库发放、库存查询、库存流水、效期提醒库存列表、入库单、出库单、预警列表供应商管理供应商档案、联系方式、历史供药记录供应商列表、供应商编辑采购与入库采购订单生成、到货审核确认、自动写库存流水采购单创建、待收货列表、入库确认处方/销售门诊处方录入、销售记录、销售明细统计销售开单、销售记录查询统计报表月度出入库统计、销售金额排行、库存周转分析图表看板、排行榜功能模块的划分要遵循一个原则每个模块之间的关系要单向依赖避免循环引用。比如药品库存模块可以依赖药品信息和供应商模块但供应商模块就不要反向去查库存表的统计结果否则后面维护起来非常头疼。模块划分好之后前后端的菜单结构、路由结构、权限控制点基本都定下来了。后端的包结构建议按模块而不是按技术层来建包也就是先建controller、service、mapper、entity四大层再在层内按业务模块分包比如entity/drug、entity/purchase、entity/system。这样代码量大了之后依然能找到头绪。2.2 核心数据表结构与设计思路数据库设计决定了这个项目的质量上限。很多同学拿着别人的源码导入数据库发现表之间外键散落、字段类型混乱改一个功能牵连出一堆 Bug。我按实际项目的标准梳理出最核心的几张表用户表sys_user字段类型说明idbigint主键usernamevarchar(50)登录名唯一passwordvarchar(100)BCrypt 加密后的密码real_namevarchar(50)姓名rolevarchar(20)角色标识admin / pharmacist / buyerstatustinyint是否禁用create_timedatetime创建时间药品信息表drug_info字段类型说明idbigint主键drug_codevarchar(30)药品编码唯一drug_namevarchar(100)药品名称category_idbigint药品分类IDspecificationvarchar(50)规格如 0.25g*24粒unitvarchar(10)单位盒/瓶/袋manufacturervarchar(100)生产厂家prescription_flagtinyint是否处方药1是0否retail_pricedecimal(10,2)零售价stock_thresholdint库存预警阈值statustinyint上下架状态库存表drug_stock字段类型说明idbigint主键drug_idbigint关联药品IDbatch_novarchar(50)批次号quantityint当前数量expire_datedate有效期至supplier_idbigint来源供应商warehouse_posvarchar(50)库位这里单独立一张库存表而不是把库存数量直接写在药品表里是因为药品存在批次的概念。同一款药品不同批次的有效期不同、采购价格不同混在一起没法做效期管理。这也是毕设答辩时一个非常容易被追问的设计亮点。销售记录表sale_record字段类型说明idbigint主键record_novarchar(30)销售单号drug_idbigint药品IDquantityint销售数量amountdecimal(10,2)销售金额user_idbigint操作人sale_timedatetime销售时间加上供应商表、分类表、采购入库单表、库存流水表总共七八张核心表就可以支撑一套完整系统了。表设计时注意统一主键策略推荐ASSIGN_ID雪花算法不要用数据库自增因为后续做数据迁移和分布式部署时自增主键容易冲突。2.3 药品库存与有效期关系的细节这是一个容易踩坑的点。如果你只在药品表里放一个总库存数量字段遇到同一药品有两个入库批次、有效期各不相同时就没办法区分哪些接近过期。而医院药房实际发药时是有原则的近效期先出、先进先出。所以在设计库存流水stock_flow时除了记录入/出/调整类型、数量、经办人、时间之外还要额外记录批次号、关联的单据号。这样拿着批号就能反查某一批药进出情况效期预警按expire_date倒排把 90 天内过期的批次单独拉出来。如果部分源码中药品表直接存总库存也能满足基本演示但答辩时如果老师问同一药品两个批次如何管理只靠一个数字字段是答不上来的。所以我在系统设计里强烈建议库存用批次表存。3. 后端核心逻辑从登录鉴权到库存扣减3.1 工程结构与依赖配置一个规范的 Spring Boot 后端工程至少要分成这些包com.example.hospital ├── config // 配置类、拦截器、跨域配置 ├── controller // 接口层 ├── service // 业务逻辑层 ├── mapper // 数据访问层 ├── entity // 实体类 ├── common // 通用工具类、统一返回结果、异常处理 └── HospitalApplication.java // 启动类依赖管理建议直接使用 Spring Initializr 生成然后手动添加 MyBatis-Plus、MySQL 驱动、JWT 相关依赖、Lombok。核心依赖如下dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt/artifactId version0.9.1/version /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependencyMyBatis-Plus 的使用值得多说两句。它内置了BaseMapperT把单表的增删改查、分页查询、条件构造器都封装好了。比如查某个分类下的所有药品传统 MyBatis 要写select标签和对应 SQL用 MyBatis-Plus 直接这样写LambdaQueryWrapperDrugInfo wrapper new LambdaQueryWrapper(); wrapper.eq(DrugInfo::getCategoryId, categoryId); wrapper.eq(DrugInfo::getStatus, 1); ListDrugInfo list drugInfoMapper.selectList(wrapper);Lambda 写法能避免硬编码字段名字段名改了也会在编译期暴露问题比手写字符串安全。这是提升开发效率最明显的一环。3.2 JWT 登录鉴权和角色权限控制系统里不同角色看到和能操作的菜单不一样管理员可以管理用户、查看全部数据药剂师可以开销售单采购员负责录入采购和入库。所以登录校验之后还要做权限控制。登录接口的处理逻辑很简单根据用户名查用户表用 BCrypt 校验密码不要让自己成为不会加密的反面教材校验通过生成 JWT Token将userId、role写进 token 的 claims返回 token 给前端前端后续请求在请求头Authorization里带上。String token Jwts.builder() .setSubject(user.getUsername()) .claim(userId, user.getId()) .claim(role, user.getRole()) .setExpiration(new Date(System.currentTimeMillis() 2 * 60 * 60 * 1000)) .signWith(SignatureAlgorithm.HS256, secretKey) .compact();光生成 token 还不够还要写一个拦截器或过滤器在所有接口请求进来时做校验。我习惯在HandlerInterceptor里做先放行登录接口再校验其他请求的 tokenOverride public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (request.getMethod().equals(OPTIONS)) { return true; } String token request.getHeader(Authorization); if (token null || !token.startsWith(Bearer )) { throw new BusinessException(未登录或登录已过期); } // 解析并校验 token将 userId 放入 request attribute return true; }关于密码存储这里强烈建议使用 BCrypt。它每次加密的结果是随机的但校验结果一致就算数据库泄露反推明文密码的成本也极高。代码实现上用 Spring Security 里的BCryptPasswordEncoder或者 jBCrypt 库都可以。3.3 库存扣减的并发安全处理这是整个系统里最有技术含量的地方也是最能体现你有没有真正理解业务的点。我们先看一个错误示范。很多同学写销售出库是这样DrugStock stock stockMapper.selectById(stockId); if (stock.getQuantity() quantity) { stock.setQuantity(stock.getQuantity() - quantity); stockMapper.updateById(stock); }先查出来再修改。如果两个请求同时操作同一批次库存都查出来quantity 10各自减 5两边都认为扣减成功最终数据库可能只变成 5而不是 0。这在并发访问量稍高的系统里必然出问题。正确做法是用一条带条件的 SQL 完成扣减这也是我在项目里采用的方案int rows stockMapper.deductStock(drugId, batchNo, quantity); if (rows 0) { throw new BusinessException(库存不足或批次不存在); }对应的 Mapper SQLUPDATE drug_stock SET quantity quantity - #{quantity} WHERE drug_id #{drugId} AND batch_no #{batchNo} AND quantity #{quantity}UPDATE语句自带行锁两个事务同时执行时第二个事务会等待第一个事务提交后再基于最新数据判断quantity ?是否成立。如果第二个请求扣减数量超过了剩余库存影响行数就是 0业务层抛异常回滚即可。这套方案非常简单不需要引入 Redis 分布式锁但对单机应用已经足够。同时每次扣减后别忘了写一条库存流水。流水记录的不仅是操作行为也是日后对账、排查问题的唯一线索。这个环节在答辩时提出来老师基本都会认可。3.4 药品有效期预警与库存阈值报警预警功能是药品管理系统区别于普通商品管理系统的标志之一学生时代很容易忽略但医院药剂科非常看重。效期预警的实现逻辑是查询所有库存批次把expire_date距离当前日期小于 90 天的批次筛选出来。90 天这个阈值建议直接做成配置不要写死在 SQL 里。SQL 大概是这样SELECT * FROM drug_stock WHERE expire_date BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 90 DAY)库存阈值报警是在药品信息表里设置一个stock_threshold字段比如某药品低于 50 盒就报警。统计当前库存小于阈值的药品时可以用一条带子查询的语句SELECT d.*, s.total_quantity FROM drug_info d LEFT JOIN ( SELECT drug_id, SUM(quantity) AS total_quantity FROM drug_stock GROUP BY drug_id ) s ON d.id s.drug_id WHERE s.total_quantity d.stock_threshold把这两类预警查出来之后管理系统里做一个醒目的库存预警菜单前端进入页面就触发一次查询有预警数据时在导航栏展示红点或徽标数。这样系统一下子就从一个记录工具升级成了管理工具。4. 前端 Vue 实现页面交互与数据对接4.1 前端工程结构与路由划分前端部分我见过两种方案一种是纯 Vue Vue Router Vuex/Pinia Axios自己手写全部页面另一种是直接使用若依RuoYi这类开源脚手架做二次开发。先说结论自己从零写前端更推荐因为你得真正理解页面数据是怎么来的而不是一直停留在改别人模板的层面。推荐的前端工程结构src ├── api // 按模块封装的请求接口 │ ├── drug.js │ ├── stock.js │ ├── sale.js │ └── user.js ├── assets // 静态资源 ├── components // 公共组件 ├── layout // 主界面布局包含侧边栏和顶栏 ├── router // 路由配置 ├── store // 全局状态管理 ├── utils // 请求封装、工具函数 ├── views // 页面组件 │ ├── login │ ├── drug │ ├── stock │ ├── purchase │ └── report ├── App.vue └── main.js路由配置要按照后端模块一一对应。比如{ path: /drug, component: Layout, meta: { title: 药品管理, roles: [admin, pharmacist, buyer] }, children: [ { path: list, component: () import(/views/drug/list.vue), meta: { title: 药品列表 } }, { path: category, component: () import(/views/drug/category.vue), meta: { title: 药品分类 } } ] }路由的meta.roles是后端返回的角色标识前端在路由守卫里判断用户角色是否有权限进入。光有前端路由守卫其实不够后端接口也要做权限校验。前端控制只是把没权限的菜单隐藏掉真正的安全防线必须放在后端这个原则在答辩时被问到安全问题可以着重讲。4.2 药品管理页面的增删改查药品列表页是整个前端最核心也最典型的页面它几乎涵盖了所有你会在项目中反复使用的交互方式条件查询、分页表格、新增弹窗、编辑回显、删除确认。具体实现时页面加载时调用getDrugPage(params)接口返回的分页数据包含records和total。表格绑定records分页组件绑定total切换页码或改变每页数量时重新调用接口。新增/编辑药品用 Dialog 弹窗表单字段和后端实体对齐。这里有个小建议表单校验规则可以用 Element UI 内置的rules比如必填项、数字范围、价格精度。提交前做一次整体校验能拦住大部分低级错误减少后端处理脏数据的负担。删除操作用this.$confirm弹出确认框确认后调用删除接口成功后刷新列表。这类看似简单的内容很多同学会漏掉删除后的关联处理比如直接删除一个药品而库存表和销售记录表里还引用着这个药品ID就会产生脏数据。所以合理的做法是有库存或者有销售记录的药品不能物理删除只能用status字段做逻辑下线。这个细节非常能够体现一名开发者的工程意识。4.3 Axios 封装与跨域处理如果前端代码里每个页面都写axios.get(url).then(...)那叫能用不叫工程。实际项目里我会先在utils/request.js里做 Axios 实例封装import axios from axios import { Message } from element-ui import router from /router const service axios.create({ baseURL: process.env.VUE_APP_BASE_URL, timeout: 10000 }) // 请求拦截器自动携带token service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] Bearer token } return config }) // 响应拦截器统一处理返回状态码 service.interceptors.response.use( response { const res response.data if (res.code ! 200) { Message.error(res.msg) if (res.code 401) { router.push(/login) } return Promise.reject(res) } return res }, error { Message.error(error.message) return Promise.reject(error) } ) export default service这样每个 API 模块只需要这样调用import request from /utils/request export function getDrugPage(data) { return request({ url: /api/drug/page, method: post, data }) }开发环境的跨域处理有两种常用办法。第一种是后端写CrossOrigin或者全局 CORS 配置第二种是前端用 devServer 的 proxy把/api开头的请求代理到http://localhost:8080后端地址// vue.config.js module.exports { devServer: { port: 3000, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }我在实际开发中更推荐用前端代理而不是在后端开启跨域。因为后端开启跨域等于允许所有来源访问而开发环境代理只存在于本地开发阶段部署上线后由 Nginx 统一转发后端接口可以保持同源安全策略更清晰。4.4 可视化统计与告警展示药品管理系统一般会加一个统计看板展示销售趋势、库存预警数量、药品分类占比。这些图表用 ECharts 实现比较方便。销售趋势图的逻辑是后端按天聚合销售金额返回一组{ date, amount }数据前端把数据放进去const chart echarts.init(document.getElementById(saleChart)) chart.setOption({ xAxis: { data: dates }, yAxis: {}, series: [{ type: line, data: amounts, areaStyle: {} }] })库存预警的数字展示则可以用一个 Statistic 组件把warningCount以醒目的红色数字放在看板右上角点击可跳转到库存预警列表。这类视觉内容也是答辩展示时的加分项。老师通常不会逐行看代码但看到界面上的图表和数字会形成第一印象这个项目不是空壳。5. 本地运行实操从环境准备到项目跑通5.1 环境准备与工具版本搭配把项目从源码变成能跑的系统这一趴写给完全没起步的新手老手可以直接跳到 5.3。推荐的环境版本如下组件推荐版本说明JDK1.8 或 11Spring Boot 2.x 首选Maven3.6管理后端依赖MySQL5.7 或 8.0项目数据库Node.js14 或 16Vue2 项目的运行环境npm / yarnnpm 6 或 yarn前端包管理这里有一个很重要的经验不要用最新的 JDK 版本跑 Spring Boot 2.x 项目。JDK 17 或更高版本虽然能启动基础项目但会遇到一些反射访问受限、依赖不兼容的问题对于学习和调试来说毫无必要。Spring Boot 2.7 配 JDK 8 或 11 是最稳的组合。5.2 数据库初始化与配置文件修改拿到项目源码后通常在根目录或sql目录下能找到init.sql或hospital_db.sql这样的文件。用 Navicat 或命令行执行mysql -u root -p hospital_db.sql执行完以后确认数据库hospital_db存在并且能看到sys_user、drug_info、drug_stock等表和数据。然后修改后端的application.yml把数据库地址、用户名、密码改成你自己的server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/hospital_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456这里serverTimezoneAsia/Shanghai一定要加否则 MySQL 8.0 会报时区相关的错误。如果你的数据库密码是空password那行留空也可以但不建议这么做。5.3 后端启动步骤在项目根目录包含pom.xml的目录打开终端执行mvn spring-boot:run第一次启动会下载大量依赖可能需要几分钟到十几分钟取决于网络情况。启动成功的标志是控制台出现Started HospitalApplication in x.x seconds并且没有红色报错。如果mvn命令不可用用 IDEA 打开项目等待右下角 Maven 依赖导入完成后直接运行启动类也可以。建议直接使用 IDEA 的 Maven 面板点击spring-boot:run比命令行更方便调试。启动后可以用浏览器访问http://localhost:8080如果配置了欢迎页则能看到效果否则访问任意接口路径会得到 JSON 或 404。至少能证明程序没有崩。5.4 前端启动与页面验证前端代码在vue或frontend目录下。进入目录先安装依赖npm installnpm install 是新手最容易卡住的环节。如果下载极慢或者报错换成国内镜像npm config set registry https://registry.npmmirror.com依赖安装完成之后直接启动npm run serve默认情况下 Vite 或 Vue CLI 会起一个本地服务端口一般在 8080 或 3000你需要在vue.config.js里把代理目标地址指到后端的8080就像 4.3 节写的那样避免跨域问题。启动成功后访问前端地址用初始账号登录。常见的初始账号密码会在项目的README.md里说明如果源码里没有直接在sys_user表里看数据通常就是admin/admin123。登录后检查药品列表能否正常加载新增一条药品再刷新能出现就说明前后端联调成功。6. 常见问题排查与毕设答辩加分点6.1 高频问题排查表把我在指导项目中遇到的最典型问题和解决方式整理成下面的表很多坑都是反复出现的高频问题。问题现象可能原因解决办法前端页面能打开但列表数据一直加载不出来后端没启动 / 接口代理路径配错检查后端控制台看 8080 是否在监听检查/api代理是否指对了后端报 Access denied for user数据库用户名或密码写错用 Navicat 验证账号能否登录再去改 application.yml前端报 401 Unauthorizedtoken 过期或未携带用浏览器开发者工具查看请求头确认 Authorization 字段存在MySQL 提示 Unknown database没导入 SQL 或导错库确认init.sql完整执行并确认连接的是同一个库名控制台报端口占用8080 或 3000 被其他进程占用Windows 用 netstat -anoMaven 依赖下载报红本地仓库缺包 / 镜像未配配置阿里云 Maven 镜像IDEA 中File - Settings - Maven - Mirror添加中文乱码数据库字符集不对建库时指定DEFAULT CHARSET utf8mb4连接 URL 加characterEncodingutf8分页查询返回 total 始终为 0忘记配置 MyBatis-Plus 分页插件在 config 类中添加PaginationInnerInterceptor6.2 润毕设/课设时的几个切入点如果这个项目拿来当毕业设计不建议直接原封不动交上去。答辩老师对热门项目的源码往往非常熟悉翻来覆去就是那几套不加点自己的东西很容易被质疑工作量。我建议从几个方向做增量优化第一个方向是增加多级审核流程。采购入库单不直接生效而是先创建待审核状态由管理员或药房主任审核后方可入库。这个改动需要加审核状态字段、审核时间字段、审核人字段业务复杂度立刻上升一个档次论文里可以写一章业务流程设计与审批模型。第二个方向是增加报表模块。除了简单的查询列表用 ECharts 按药品分类做月度销售雷达图、按供应商做采购占比饼图。后端用日期函数做分组统计即可前端只用 ECharts 呈现履历上写数据可视化模块观感好很多。第三个方向是引入 Redis 缓存。把登录 token 存到 Redis设置过期时间顺便实现登录验证码的存储。这个改动虽然不大但涉及 Redis 的使用能在技术栈上加一分。注意如果你的毕设只要求 Java MySQL引入 Redis 前先确认一下老师的要求不要额外给自己挖坑。第四个方向是优化密码找回与个人信息管理。增加修改密码的强校验流程例如旧密码校验、密码强度校验这类细节在课设答辩时很容易获得好评。6.3 这套系统再扩展还能怎么玩药品管理系统虽然在业务上看起来比较传统但它的扩展潜力不小。可以把它往移动端方向扩展开发一个小程序或 H5 版本的药师端实现移动审批和库存盘点也可以往数据分析方向扩展除了销售金额增加药品滞销分析、效期消耗率、科室领药频次统计等指标让系统从记录工具变成决策工具。如果你对微服务感兴趣可以把用户模块、药品模块、库存模块拆开用 Spring Cloud Alibaba 的方式做服务化改造。改动幅度很大但对学习和简历讲述来说是一次完整的架构升级锻炼。做这一步之前先想想自己的时间投入如果是在准备论文的关键阶段不建议轻易动刀。我在实际带项目的过程中发现很多同学把大部分时间耗在改 bug和倒腾环境上反而没有时间去深究那些能体现设计能力的地方比如严格的库存批次管理、逻辑删除策略、权限模型的角色粒度划分。而答辩聊得深的往往不是功能多不多而是某个关键业务问题你是怎么思考的。这套系统从头到尾走一遍恰好能把这些问题都覆盖到。最后分享一个很实用的小技巧项目开发过程中每次启动前把application.yml里数据库密码错填一次强迫自己看一遍报错日志。连续几次下来你对 Spring Boot 启动链路上的常见报错会变得非常敏感以后再遇到类似排错问题基本一眼就能定位。这种动手排查的能力才是做这类项目沉淀下来最值钱的东西。
阅读完成 · 觉得有帮助?