ARTICLE DETAIL

资讯详情

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

SpringBoot+Vue+MySQL社区医院管理系统设计与实现全流程解析

SpringBoot+Vue+MySQL社区医院管理系统设计与实现全流程解析 做社区医院管理系统这个毕业设计时我选的是 SpringBootVueMySQL 这套全栈组合。项目整体是典型的前后端分离结构前端用 Vue 写页面后端用 SpringBoot 提供接口MySQL 存业务数据最终的交付物包括平台源码、数据库脚本、论文和部署文档。这篇文章就围绕这套系统把从需求拆解、建库建表、后端接口到前端页面、打包部署的完整过程捋一遍顺便把我在实际开发中掉过的坑也写出来适合正在做类似选题、需要完整参考方案的同学。你可能会问社区医院管理系统听起来很常见做起来是不是很“水”说实话如果只做一个简单的增删改查那确实没什么含金量。但这个项目的关键在于把“挂号、就诊、开药、收费、库存”这一整条业务闭环跑通同时要考虑不同角色的权限、数据的一致性、以及最终怎么打包演示。把这些点都做扎实无论是论文写起来还是答辩演示都会顺很多。1. 项目到底做什么社区医院管理系统需求拆解1.1 真实场景里社区医院需要什么社区医院和大型三甲医院不一样科室少、人员少但日常业务并不简单。患者来了要先挂号医生接诊后要写病历、开处方收费员要按处方收费药房要发药、维护库存管理员还要看各类统计报表。单靠手工登记或者 Excel 表管理很容易出现病历丢失、药品对不上账、收费记录混乱这些问题。所以在设计系统时不能只做一个“用户管理 信息展示”的架子。我的思路是先按角色拆需求管理员管基础数据、医生写病历开处方、收费员处理挂号缴费、药房管库存发药。患者信息、挂号记录、病历、处方、药品库存这些数据要能串起来形成一条完整的流程。把这个流程落到系统里差不多是下面这个样子患者首次来院收费员或前台录入患者基本信息系统生成患者档案。挂号时选择科室和医生生成挂号记录同时产生一笔挂号费用。医生在接诊列表里看到已挂号的病人填写病历、诊断结果和处方。收费员根据处方明细完成收费收费后处方状态变为“已缴费”。药房看到已缴费的处方后进行发药同时扣除对应药品库存。这五步看起来简单但每一步都涉及状态变化和表关联。比如挂号记录要从“待就诊”变成“已就诊”处方要有“未收费/已收费/已发药”的状态药品的库存必须和发药操作联动。想清楚这个闭环数据库设计和后端接口设计就有了方向。1.2 为什么技术栈选 SpringBoot Vue MySQL技术选型是毕业设计答辩时最容易问的问题也是我在一开始纠结最久的问题。为什么最终选了这三件套而不是 ServletJSP或者 Spring Cloud 微服务那套重型方案先说 SpringBoot。它最大的价值是“约定大于配置”传统 SSM 要写一堆 XML 配置SpringBoot 里一个启动类加几个注解就能跑起来。对毕业设计来说开发效率高生态成熟遇到问题搜一下基本都有解。更重要的是SpringBoot 内置 Tomcat最后打包成 jar 直接运行演示的时候特别方便不用在答辩现场装环境。Vue 这边我选的是前后端分离的方案。Vue 负责页面渲染和交互后端只提供 JSON 接口。这样做的好处是前后端可以并行开发我先把接口定义好前端用 Mock 数据也能先做页面。而且 Vue 的组件化写法写后台管理系统很顺手表格、弹窗、表单这些东西用 Element Plus 一套组件库就能拼出来开发速度比 JSP 快了一个量级。MySQL 则是经典的稳定选择。社区医院的数据量不大用户表几千条药品表几百条MySQL 不管是安装、备份还是写 SQL 都足够轻量。配合 Navicat for MySQL 做可视化管理导入导出数据库脚本很直观论文里的“数据库设计”章节也更好写。1.3 角色权限与业务闭环怎么设计权限这块我采用的是 RBAC 模型也就是“用户-角色-权限”。用户表里存角色字段菜单栏根据角色动态显示。比如医生登录后只看到“接诊”和“病历管理”收费员登录后看到“挂号收费”和“处方收费”管理员才有系统配置和统计报表的入口。有人可能想为什么不把权限拆成菜单表、角色表和权限表我的看法是毕业设计项目可以做成标准的三表模型但实际写起来会多出很多代码。我的做法是保留三表结构在论文里写清楚但前端路由拦截只做到角色层级。这样既能体现你对权限设计的理解又不会在代码实现上把自己拖死。业务闭环的另一端是统计报表。管理员需要看到每日挂号量、收费金额、药品消耗情况。这些数据其实就是对业务表的聚合查询用几个 GROUP BY 语句就能完成。把报表功能加进去系统看起来更完整论文里的功能模块图也更饱满。2. 数据库设计把业务流程落到表上2.1 从业务反推数据模型数据库设计最忌讳的是上来就建表。我习惯先画流程图把上面说的“挂号-就诊-处方-收费-发药”每一步涉及的数据写出来再决定每个表存什么字段。以挂号来说挂号单上有什么患者姓名、性别、年龄、联系方式、就诊科室、医生、挂号时间、挂号费用、状态。患者信息应该单独建表因为一个患者可以多次挂号。科室和医生也是单独表医生和科室是多对一关系。这些关系理清楚后表结构自然就出来了。药品这块我单独建了药品信息表和库存表。药品信息存名称、规格、生产厂家、价格库存表存药品 ID、批次、数量。为什么要拆开因为同一个药品可能多次入库每批次数量不同而且查询药品列表时不应该把库存余量写在药品表里那样每次发药都要 UPDATE 药品表容易产生并发问题。拆开后药品信息不动库存单独流水记录发药只改库存表。我的实际经验是不用把表设计得特别“满”但要保证业务链路上的字段都齐全特别是状态字段。比如挂号表必须有 status处方表必须有 status这样才能支撑后续的流程流转和权限控制。状态字段最好用 TINYINT 或 VARCHAR不建议用枚举因为 Java 和 MySQL 的枚举配合起来在插入时容易踩坑。2.2 核心表结构与字段设计说明我的项目里核心表大概是这么几张表名用途关键字段sys_user系统用户id, username, password, real_name, rolepatient患者信息id, name, gender, age, phone, id_carddepartment科室id, dept_name, dept_descdoctor医生信息id, user_id, dept_id, title, introductionappointment挂号记录id, patient_id, doctor_id, dept_id, appoint_time, status, feemedical_record病历记录id, appointment_id, patient_id, doctor_id, diagnosis, adviceprescription处方id, record_id, patient_id, doctor_id, total_amount, statusprescription_item处方明细id, prescription_id, drug_id, quantity, amountdrug_info药品信息id, drug_name, spec, manufacturer, pricedrug_stock药品库存id, drug_id, batch_no, quantitysettlement收费记录id, patient_id, settlement_type, amount, create_time这里重点说一下 prescription 和 prescription_item 的关系。一张处方对应多行药品明细所以处方主表只存总金额和状态明细表存每个药品的数量和金额。收费时按明细表逐条计算总价发药后明细表不变只改库存。sys_user 和 patient 是两条独立的用户线。sys_user 是系统登录账号patient 是患者档案。可能有人觉得患者也应该可以登录系统查看自己的病历我一开始也这么想过但后来把患者登录这块砍掉了只做医生和管理端。原因很简单患者的登录认证、单点登录、隐私授权每一样都要额外写很多逻辑对社区医院管理系统这个选题来说反而容易画蛇添足。2.3 索引、外键和测试数据索引是很多同学忽略的地方。我的习惯是所有外键字段和经常查询的字段都加上普通索引。比如 patient_id、doctor_id、appointment_id、status这些字段在 JOIN 和 WHERE 里出现频率高。开发阶段数据量小看不出差别但答辩时如果你能主动说出“我在大表查询字段上加了索引”老师对你的评价会明显不一样。外键我建议“逻辑外键”就好也就是不在数据库层面强制 FOREIGN KEY而是通过 Java 代码保证关联关系。原因有两点第一数据库外键会影响插入和删除效率而且一旦数据初始化顺序不对外键检查会直接报错第二代码里用 MyBatis-Plus 做关联查询逻辑外键完全够用。不过论文里要写清楚“出于性能和解耦考虑使用逻辑外键”这句话能体现你的思考深度。测试数据一定要准备充分。我最初只插了十几条数据结果演示的时候医生接诊列表空荡荡不太好展示。后来我写了一个 SQL 脚本插了 30 多个患者、10 个医生、50 种药品再把挂号记录、处方、收费记录各造了几十条。演示的时候有真实感论文里的截图也好看。有一点要提醒测试数据里的密码不要用明文至少用 MD5最好用 BCrypt不然论文里贴数据库表截图时明文密码会让你在答辩现场很尴尬。3. 后端核心实现SpringBoot 工程搭建与接口开发3.1 工程结构与环境准备后端我用的是 IDEA 新建 SpringBoot 项目Java 版本选了 JDK 8。为什么不用更新的 JDK 17 或 21因为毕业设计很多同学用的是学校机房、旧电脑或者教师机上的老环境JDK 8 的兼容性最稳而且 SpringBoot 2.x 对 JDK 8 支持最好。如果你用 SpringBoot 3.x最低要求是 JDK 17那部署时换来换去很麻烦。Maven 项目构建这一步我直接用了 IDEA 内置的 Spring Initializr选择依赖时只勾了 Web、MySQL Driver、MyBatis-Plus 和 Lombok。MyBatis-Plus 是我强烈推荐的持久层框架它在 MyBatis 基础上封装了通用 CRUD单表查询基本不用写 SQL分页插件也内置好了。如果你还在手写 BaseMapper 和 XML效率会低很多。工程结构按阿里规范分层com.hospital ├── controller // 接口层 ├── service // 业务层 ├── mapper // 数据访问层 ├── entity // 实体类 ├── config // 配置类 ├── interceptor // 拦截器 ├── common // 通用返回结果、异常处理 └── util // 工具类这个结构的好处是职责清晰。Controller 里只做参数接收和结果封装业务逻辑全部放在 Service数据操作在 Mapper。论文画架构图时直接照着这个分层画就行完全能对应上。3.2 登录鉴权与用户体系登录接口是第一个要写的接口也是老师最容易问的接口。我采用 JWT 做无状态鉴权用户登录成功后后端生成一个 token 返回给前端前端每次请求在 Header 里带上 token后端通过拦截器校验。写起来也不复杂// 登录接口核心逻辑 public Result login(String username, String password) { String md5Password DigestUtils.md5DigestAsHex(password.getBytes()); LambdaQueryWrapperSysUser wrapper new LambdaQueryWrapper(); wrapper.eq(SysUser::getUsername, username) .eq(SysUser::getPassword, md5Password); SysUser user userMapper.selectOne(wrapper); if (user null) { return Result.error(用户名或密码错误); } String token JwtUtil.createToken(user.getId(), user.getRole()); return Result.ok().put(token, token).put(role, user.getRole()); }这里有个细节密码明文传给后端再 MD5其实并不安全。真正严谨的做法是前端用 HTTPS BCrypt。但毕业设计环境没有 HTTPS我就选择了后端 MD5 盐的方式然后在论文里专门写一段“密码加密存储设计”说明 MD5 加盐的优缺点。写作的时候这个点可以作为系统安全性的支撑材料。拦截器这边我写了一个 LoginInterceptor校验所有请求头里的 token。如果 token 无效直接返回 401有效就放行并把用户信息放进请求上下文。要注意放行登录接口本身和静态资源路径否则前端的登录请求也会被拦截就会陷入死循环。这个坑我调试了半小时才反应过来。3.3 挂号、收费、药品三个核心接口怎么实现挂号接口对外暴露 POST /api/appointment参数是 patientId、doctorId、deptId、appointTime。业务逻辑包括校验患者是否存在校验医生是否属于所选科室插入挂号记录同时生成一笔收费记录。为什么要同时生成收费记录因为社区医院通常是挂号后立即缴费所以挂号和收费是一个事务。收费接口放在处方缴费场景里。医生开出处方后处方状态为“未收费”收费员调用 POST /api/settlement传入处方 ID。系统先查询处方明细逐项计算总金额然后插入 settlement 记录同时把处方状态改为“已缴费”。这里涉及一个经典的并发问题如果两个人同时为同一张处方缴费怎么办我的做法是在 UPDATE 语句里加条件 status UNPAID更新影响行数为 0 就说明已经被别人处理过直接返回“处方状态已变更”。这种乐观锁思路在论文里也很好写。药品发药逻辑放在药房端。药房人员看到已缴费的处方后点击发药后端执行两步操作更新处方状态为“已发放”同时批量扣减药品库存。扣库存必须用事务否则可能处方显示已发药库存却扣少了。我封装了一个 Transactional 方法Transaction 里先查库存是否充足不足直接抛异常回滚充足则 UPDATE 药品库存表。Transactional(rollbackFor Exception.class) public void dispense(PrescriptionDispenseBO bo) { // 1. 校验处方状态 // 2. 遍历处方明细校验库存 // 3. 扣减库存 // 4. 更新处方状态 }写到这里你会发现核心业务其实就是“先查后写状态流转事务保证”。把这三个套路掌握了挂号、缴费、发药都能套进去甚至后续做预约、退费也只需要加一张退款表。3.4 统一返回结果、异常处理和日志前后端分离后接口返回格式必须统一。我定义了一个 Result 类规范响应格式。public class Result { private Integer code; // 200 成功500 失败401 未登录 private String msg; private Object data; }然后配合 RestControllerAdvice 做全局异常处理。业务异常抛出 BusinessException由全局处理器捕获返回 Result.error未登录异常返回 401系统异常返回 500 并记录日志。这样前端 Axios 拦截器只需要统一判断 code不需要在每一个接口里做重复的错误处理。后端日志我用 Lombok 的 Slf4j 注解在关键业务操作里记录操作人、操作内容和结果。特别是收费、发药这类金额和库存相关操作日志必须打清楚方便排查问题。论文里的“系统维护性”章节就有素材可以写了。4. 前端页面与联调Vue 端怎么做4.1 初始化 Vue 工程与目录结构前端我用的 Vue 2 Element UI。这里有人会问为什么不直接用 Vue 3 Element Plus如果是从头学我建议 Vue 3 Vite毕竟 Vite 启动速度快很多。但如果你是参考了大量现成的 SpringBootVue 毕业设计项目大概率碰到的是 Vue 2 生态插件兼容性更好教程也更多。我的建议是如果还有 1 个月以上时间用 Vue 3如果时间紧Vue 2 更稳妥。我这次用的是 Vue 2目录结构如下src ├── api // 接口定义 ├── assets // 静态资源 ├── components // 公共组件 ├── router // 路由配置 ├── store // Vuex ├── views // 页面 ├── utils // 工具主要是 request.js └── App.vue安装环境时Node.js 版本要注意。Vue CLI 5 对 Node 版本有一定要求我一开始用 Node 20 构建报错换成 Node 16 才顺利跑通。这种问题的排查思路是看 package-lock.json 里的依赖版本判断当前 Node 版本是否兼容。如果是安装依赖卡住先删 node_modules 和 package-lock.json再用 npm install 重新装能解决一大半问题。4.2 Vue Router 与权限路由前端路由我用的是 Vue Router 3。管理员、医生、收费员看到的是不同菜单所以路由不能全部写死而要按角色动态生成。我的实现思路是路由表分成两部分基础路由登录页、404固定注册业务路由放在一个路由配置数组里每个路由对象标记 meta.roles。const asyncRoutes [ { path: /appointment, component: Layout, meta: { roles: [admin, registrar] }, children: [ { path: , name: Appointment, component: () import(/views/appointment/index.vue) } ] } ]登录成功后前端拿到当前用户的 role遍历 asyncRoutes把 meta.roles 里包含当前角色的路由筛选出来再用 router.addRoutes 动态添加同时把菜单数据传给侧边栏组件。这里有个 Vue 2 的经典坑动态添加路由后刷新页面路由会消失因为 store 里的数据是内存态。解决办法是写一个全局前置守卫在 beforeEach 里判断用户信息是否存在不存在就重新调用获取用户信息接口再重新生成路由。除了权限路由还有一个很常见的功能是路由参数。比如医生列表页跳转到接诊详情页需要带上 appointmentId。我的写法是在跳转时用 query 传参this.$router.push({ path: /record/detail, query: { appointmentId: row.id } })在详情页里通过 this.$route.query.appointmentId 获取。query 方式传参刷新后参数还在 URL 上适合这种“详情页需要知道来源 ID”的场景。如果用 params 传参刷新页面参数容易丢那种用法更适合不敏感的数据传递。4.3 Axios 封装与页面联调接口请求我统一封装在 utils/request.js 里基于 axios 二次封装。核心是处理请求头、统一响应拦截和错误提示。import axios from axios const service axios.create({ baseURL: /api, timeout: 10000 }) service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] token } return config }) service.interceptors.response.use( response { const res response.data if (res.code 200) { return res } if (res.code 401) { router.push(/login) return Promise.reject(new Error(未登录)) } Message.error(res.msg) return Promise.reject(new Error(res.msg)) }, error { Message.error(网络错误) return Promise.reject(error) } )这里要注意 baseURL 我写的是 /api实际开发时前端通过 Vite/Vue CLI 的 proxy 把 /api 代理到后端地址避免跨域。Vue 2 的 vue.config.js 配置是这样module.exports { devServer: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }联调阶段最容易出的问题是接口路径对不上。我的习惯是先在 api 目录下建一个 index.js集中导出所有接口函数每个接口函数都注释好作用。这样前后端联调时只要对着这个文件检查 URL 和参数比到处翻代码高效得多。4.4 Element UI 完成核心页面搭建Element UI 的 table、form、dialog 三个组件基本上就能撑起一个后台管理页面。以挂号页面来说左边是一个患者查询表单右边是表格展示当天挂号列表。新增挂号时弹出一个 Dialog表单里选患者、科室、医生和时间。这种布局写起来很顺手页面也规范。表格里的操作列比较高频比如“接诊”“收费”“发药”这些按钮都要绑定对应操作。要注意的是按钮权限不能只靠隐藏后端接口也要校验角色。比如收费员在前端看不到“发药”按钮但如果有人模拟请求直接调发药接口后端拦截器也要校验角色双管齐下才能保证安全。前端交互细节上最容易被忽略的是表单校验。比如挂号时医生 ID 不能为空收费时金额必须大于 0。我给每个表单项加了 rules 校验规则提交前再调用 validate 方法。这个小功能看起来不起眼但答辩演示时如果你输入非法数据后系统给出提示老师会觉得你考虑得很全面。5. MySQL 安装、初始化与常见连接问题5.1 MySQL 8 安装与基本配置数据库环境我装的是 MySQL 8.0。安装过程不算复杂但有几个地方很关键。第一个是字符集安装时记得把默认字符集设置为 utf8mb4否则中文字符会乱码。第二个是 root 密码本地开发用 root 密码简单没问题但部署文档里要提示读者按自己的环境修改。第三个是认证插件MySQL 8 默认的是 caching_sha2_password而很多老版本的驱动和可视化工具兼容的是 mysql_native_password这会导致连接失败。如果安装 MySQL Installer 时遇到报错特别是 Windows 上出现 e0434352 之类的错误码通常和系统缺少 .NET Framework 组件有关。先检查系统更新和 .NET Framework 版本装好再重新运行 Installer就能继续安装。这类环境问题排查起来很烦但好在网上资料很多不要被报错吓住。安装完成后建议用命令行先验证一下服务状态net start mysql80 mysql -u root -p登录进入 MySQL 后可以通过下面的命令确认字符集和认证方式SHOW VARIABLES LIKE character_set_server; SELECT user, host, plugin FROM mysql.user WHERE user root;5.2 用 Navicat 导入数据库脚本数据库脚本我提供的是一个 hospital.sql 文件里面包含建库、建表、初始数据插入。用 Navicat for MySQL 导入很简单新建连接右键“运行 SQL 文件”选择脚本后执行。但要注意执行顺序因为表之间有逻辑关联如果脚本里没有 DROP TABLE IF EXISTS重复导入会报错。如果用的是命令行导入也可以mysql -u root -p hospital.sql导入成功后建议立刻用 Navicat 查看几个核心表的记录数确认数据都进去了。很多同学在答辩前才发现某张表是空的就是因为初始化时没仔细检查。另外数据库备份这个问题也可以在这里聊Navicat 右键数据库“转储 SQL 文件”可以生成一个包含结构数据的备份脚本我每次改完数据库都会重新导出一份覆盖掉 hospital.sql保证交付的脚本和代码是配套的。5.3 连接报错与排查SSL、时区、驱动后端连接 MySQL 时最常遇到的就是 SSL 连接错误。报错信息通常是类似“The server requested authentication method unknown to the client”或者 SSL 证书校验失败。我的解决方式是在 JDBC 连接串里指定关闭 SSL 并设置时区spring: datasource: url: jdbc:mysql://localhost:3306/hospital?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver这里有几个点要解释清楚。useSSLfalse 是开发环境的做法如果你是生产环境其实应该开启 SSL但毕业设计用不到。serverTimezoneAsia/Shanghai 是因为 MySQL 8 默认时区和 JDBC 驱动存在时区偏差日期字段会差 8 个小时。如果把这两项配置上百分之八十的连接问题都能解决。驱动版本匹配也要注意。SpringBoot 2.x 默认管理的 mysql-connector-java 版本可能是 8.0.x如果你换成 5.x 驱动需要手动指定版本否则 URL 的写法都不一样。如果出现“Loading class com.mysql.jdbc.Driver. This is deprecated”的警告就把驱动类换成 com.mysql.cj.jdbc.Driver同时更新连接串里的 SSL 和时区参数。6. 打包部署从源码到可演示项目6.1 后端 jar 打包与运行后端打包很简单在 IDEA 里执行 Maven 的 package 命令mvn clean package -DskipTests打包完成后target 目录下会生成一个 xxx.jar。运行方式java -jar hospital-backend.jar这里容易踩一个坑SpringBoot 项目默认打包成可执行 jar 时需要引入 spring-boot-maven-plugin否则打出来的 jar 用 java -jar 运行会提示“没有主清单属性”。build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId /plugin /plugins /build如果你拿到别人的 jar 想看看里边到底有哪些类可以用 IDEA 直接打开 jar 文件或者用压缩工具解压后查看目录结构。不过我不建议用反编译的方式改别人的项目代码来交差。更合理的方式是把自己的项目打好包配合部署文档和论文完整地说明每一步是怎么实现的。运行 jar 时端口默认是 8080。如果端口被占用可以加参数修改java -jar hospital-backend.jar --server.port8081后端的配置文件里数据库连接、端口、日志路径都要整理成外部可覆盖的形式用 application.yml 里的参数加上启动参数覆盖这样部署文档里就可以写“按你的实际环境修改配置”。6.2 前端构建与 Nginx 反向代理前端部署前先执行构建命令npm run build构建完成后dist 目录就是静态文件。我部署时用的是 Nginx把 dist 目录放到 Nginx 的 html 目录下然后配置反向代理把 /api 接口转发到后端服务。server { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://localhost:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }这段配置里最关键的是 try_files 这一行。Vue Router 如果用的是 history 模式刷新 /appointment 页面时Nginx 会按照路径去找真实文件找不到就返回 index.html让 Vue Router 自己去匹配路由。如果漏了这一行刷新非首页就会 404。如果你不想处理这个问题也可以把 Vue Router 改成 hash 模式URL 上会多个 #但不会出现刷新 404。跨域问题到这一步彻底解决。前端请求 /apiNginx 把 /api 转发到后端前端和后端之间的跨域由 Nginx 的代理机制绕过去。所以开发环境靠 Vue CLI proxy生产环境靠 Nginx proxy两条防线缺一不可。6.3 部署文档和论文写作的配合很多人把部署文档当成附赠品其实这部分做好了对论文和答辩反而有很大的帮助。我的部署文档里是这样组织的环境要求JDK 8、MySQL 8、Node 16、Nginx后端部署导入源码、修改 application.yml、mvn package、java -jar 运行前端部署npm install、npm run build、Nginx 配置 dist数据库初始化导入 hospital.sql、修改 root 密码常见问题端口占用、数据库连不上、前端刷新 404这样一份文档写下来几乎就等于论文里的“系统部署”章节。你只需要把步骤描述改成论文口吻加上截图章节内容立刻就充实了。而且答辩时老师问“你的系统怎么部署”你可以直接站起来演示从数据库导入开始到启动 jar、刷新页面一气呵成。这种实操能力是很加分的。6.4 避坑清单与经验总结写到最后我把这个项目里踩过的坑整理成一张速查表方便你对照排查。问题现象原因解决方案npm install 卡住或报错Node 版本与 Vue CLI 不匹配换 Node 16删除 node_modules 重装前端刷新页面 404Vue Router history 模式未配置Nginx 加 try_files 指向 index.html后端接口返回 401登录接口也被拦截器拦截拦截器放行 /login 和静态路径MySQL 连接报 SSL 错误驱动与认证方式不兼容JDBC 连接串加 useSSLfalseserverTimezoneAsia/Shanghai缴费重复提交缺少幂等控制UPDATE 带状态条件影响行数为 0 则提示端口被占用本机已有服务在 8080java -jar 加 --server.port8081数据库乱码字符集不是 utf8mb4建库时指定 utf8mb4连接串加 characterEncodingutf8jar 无法用 java -jar 运行缺少 spring-boot-maven-plugin在 pom.xml 中加入打包插件我个人在实际操作中的体会是这个系统最难的地方不在于某个技术难点而在于把整条业务链路串起来。单独写一个挂号接口不难单独写一个药品表也不难难的是挂号之后要影响就诊、处方、收费和库存。所以建议你在动手写代码之前一定先把状态流转图和数据表关系理清楚。别急着敲代码先用纸笔画一遍患者从进门到拿药的完整流程把每个步骤涉及的表和状态变化标出来。这一步花半天时间后面能帮你省下两周的返工时间。最后再分享一个小技巧整个项目开发过程中每次完成一个功能模块记得马上更新数据库脚本和部署文档。我吃过一次亏临近答辩才发现数据库脚本和代码里的字段对不上花了一个晚上重新调。如果你从第一天就养成“代码改一版脚本同步一版”的习惯最后的交付过程会特别轻松。这套 SpringBootVueMySQL 的社区医院管理系统做完之后你会对前后端分离开发、关系型数据库设计和项目交付有一个完整的概念这个收获比项目本身更有价值。
返回列表