ARTICLE DETAIL

资讯详情

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

Java+Springboot+Vue口腔牙科诊所预约管理系统源码实战:环境搭建、排班冲突校验与二次开发

Java+Springboot+Vue口腔牙科诊所预约管理系统源码实战:环境搭建、排班冲突校验与二次开发 简介这份源码面向计算机相关专业的毕业设计、课程设计学生以及需要搭建口腔牙科诊所预约系统的开发者采用Java、Springboot与Vue实现前后端分离架构可解决诊所线上预约、资料管理与服务预约等信息化需求。压缩包共393个文件约10.41MB其中83个Java源文件承载后端业务逻辑40个Vue组件与24个TypeScript脚本、22个JavaScript文件构建前端交互界面另有126个JPEG与23个PNG图片用于视觉展示9个XML配置、1个SQL脚本及yml、json等文件支撑系统配置与数据存储目录划分清晰。已有486人学习下载。项目包含表结构文档、代码说明与readme使用指南后端涵盖控制器、拦截器与业务实现类前端组件化程度高便于读者理解前后端分离的完整开发流程也可在此基础上二次开发出更贴合实际诊所需求的预约管理软件。1. 从一份牙科诊所排班表说起这套 JavaSpringbootVue 源码到底能跑出什么上周帮朋友的口腔诊所看他们排班前台还在用一张 Excel 表手动改时间医生临时请假就得挨个打电话通知患者。这种场景下一套前后端分离的预约管理系统就不是练手项目那么简单了它直接对应着真实诊所里号源冲突、医生排班、患者改约这三件最磨人的事。这份基于 Java Springboot Vue 的口腔牙科诊所预约管理系统源码走的是标准的前后端分离架构后端 Springboot 提供 REST 接口前端 Vue 做单页应用中间靠 JSON 通信。它适合两类人——一类是想找一个业务闭环完整、能直接改造成毕设或课程设计的开发者另一类是诊所里懂点技术、想自己搭一套内部预约工具的负责人。整套代码覆盖了患者端预约、医生排班、号源管理、后台维护这几条主线不是那种只有登录注册的半截子项目。下面我按能跑起来 → 能改得动 → 不踩坑的顺序把这份源码拆开讲。2. 环境搭建与前后端分离骨架从 JDK 到 npm run serve 的完整链路拿到一份前后端分离源码第一件翻车的事往往不是代码写错而是环境版本对不上。Springboot 对 JDK 版本敏感Vue 对 Node 版本敏感这两个卡住后面全白搭。这一章先把运行环境钉死再把前后端两个工程的启动链路走通。2.1 后端 Springboot 工程的依赖与启动配置这份源码的后端是典型的 Springboot MyBatis 结构数据库用 MySQL。我一般会先确认三件事JDK 版本、Maven 依赖能不能拉下来、数据库连接串改没改。Springboot 2.x 配 JDK 8 最稳如果你本地装了 JDK 17启动时容易在反射相关的地方报错这是血泪经验。先看pom.xml里几个关键依赖确认版本区间!-- pom.xml 关键依赖片段 -- parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.6/version !-- 2.7.x 对 JDK8 友好别盲目上 3.x -- /parent dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.3.1/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency /dependencies这段依赖的逻辑很直白spring-boot-starter-web负责把内嵌 Tomcat 和 SpringMVC 拉进来mybatis-spring-boot-starter负责 ORM 映射MySQL 驱动只在运行时需要。参数上唯一要盯的是 parent 的版本号——2.7.x 是 JDK8 生态里兼容性最好的一个区间如果你看到源码里写的是 3.x那基本要求 JDK17别硬降。数据库配置在application.yml里改这几行spring: datasource: url: jdbc:mysql://localhost:3306/dental_clinic?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.clinic.entity server: port: 8080serverTimezoneAsia/Shanghai这个参数别省牙科预约系统里全是时间字段时区不对会导致预约时间整体偏移 8 小时患者看到的号和实际存的号对不上这种玄学问题排查起来能耗一下午。mapper-locations指向 XML 映射文件的位置如果启动报Invalid bound statement八成是这里路径写错了。启动命令就一句mvn spring-boot:run # 或者先打包再跑 mvn clean package -DskipTests java -jar target/clinic-0.0.1-SNAPSHOT.jar看到控制台打印出 Tomcat started on port 8080 就算后端通了。这一步失败最常见的原因是数据库没建、表结构没导入源码里一般会带一个sql目录先把它执行了再启动。2.2 前端 Vue 工程的依赖安装与接口代理前端是 Vue CLI 或 Vite 搭的工程先看package.json里的 scripts 和依赖版本。Vue 2 和 Vue 3 的写法差异很大这份源码如果用的是 Vue 2 Element UI那 Node 版本别超过 16Node 18 以上装依赖经常报ERR_OSSL_EVP_UNSUPPORTED这是新手最容易卡住的地方。# 进入前端目录 cd frontend # 安装依赖Node 16 环境下最稳 npm install # 如果 Node 版本高报错加这个环境变量临时绕过 export NODE_OPTIONS--openssl-legacy-provider # 启动开发服务器 npm run servenpm install卡住或报错先换国内镜像源再删掉node_modules和package-lock.json重来别在残留依赖上反复折腾。启动成功后默认跑在 8081 或 8082 端口。前后端分离的关键在接口代理。前端直接请求localhost:8080会跨域所以要在vue.config.js里配 proxy// vue.config.js module.exports { devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, // 后端地址 changeOrigin: true, pathRewrite: { ^/api: } // 去掉前缀再转发 } } } }changeOrigin: true是为了让后端收到的 Host 头正确pathRewrite决定前端/api/xxx转发到后端时是否保留/api前缀。这两个参数配错表现就是前端页面能打开但所有数据都是空的控制台一堆 404。配好之后前端调/api/appointment/list实际打到后端就是/appointment/list。前后端都起来后用浏览器打开前端地址能登录、能看到预约列表这条链路就算通了。接下来才是真正要动脑子的业务部分。3. 预约与排班核心业务号源生成、时间冲突校验和状态流转环境通了不代表系统能用牙科预约系统的核心难点全在业务逻辑上号源怎么生成、两个患者抢同一个时段怎么拦、预约状态怎么流转。这一章把这几块拆开讲清楚源码里对应的实现思路和你要改的地方。3.1 号源生成与医生排班的数据模型牙科诊所和普通门诊不一样一个医生一天能看的号是有限的而且不同项目洗牙、补牙、种植耗时不同。源码里一般用三张表撑起这块医生表、排班表、号源表。表名关键字段作用doctorid, name, title, department医生基本信息scheduleid, doctor_id, work_date, time_slot, max_num医生某天某时段的排班appointmentid, patient_id, schedule_id, status, create_time患者预约记录排班表里的time_slot通常存上午/下午或具体时间段max_num是这个时段最大接诊数。号源不是提前把每个号都插一条记录而是用排班容量 - 已预约数实时算出来的这样医生临时加号或减号都好处理。生成排班的逻辑一般放在后台管理端核心是批量插入// ScheduleServiceImpl.java 批量生成排班 public void batchCreateSchedule(Long doctorId, LocalDate startDate, LocalDate endDate, int maxNum) { ListSchedule list new ArrayList(); for (LocalDate date startDate; !date.isAfter(endDate); date date.plusDays(1)) { // 跳过周末牙科诊所一般周末也营业这里按实际业务改 if (date.getDayOfWeek() DayOfWeek.SUNDAY) continue; for (String slot : Arrays.asList(上午, 下午)) { Schedule s new Schedule(); s.setDoctorId(doctorId); s.setWorkDate(date); s.setTimeSlot(slot); s.setMaxNum(maxNum); list.add(s); } } scheduleMapper.batchInsert(list); // 一条 SQL 批量插入别循环单条插 }这段逻辑的参数说明startDate和endDate控制排班区间maxNum是每个时段的最大号数。batchInsert一定要用批量插入循环单条 insert 在生成一个月排班时会慢到让你怀疑人生。跳过周末那行按你实际诊所的营业时间改很多口腔诊所周日是开的。3.2 预约时间冲突校验与并发抢号处理这是整个系统最容易出问题的地方。两个患者同时点预约如果不做校验就会超卖。源码里通常有两层防护应用层查重 数据库唯一约束。应用层的校验逻辑// AppointmentServiceImpl.java 预约前的冲突校验 public Result createAppointment(Long patientId, Long scheduleId) { Schedule schedule scheduleMapper.selectById(scheduleId); // 1. 查该排班已预约数量 int booked appointmentMapper.countByScheduleId(scheduleId); if (booked schedule.getMaxNum()) { return Result.fail(该时段号源已满); } // 2. 查该患者是否在同一时段已有预约防止重复约 int dup appointmentMapper.countByPatientAndSchedule(patientId, scheduleId); if (dup 0) { return Result.fail(您已预约该时段请勿重复提交); } // 3. 插入预约记录 Appointment appt new Appointment(); appt.setPatientId(patientId); appt.setScheduleId(scheduleId); appt.setStatus(0); // 0待就诊 appt.setCreateTime(new Date()); appointmentMapper.insert(appt); return Result.success(预约成功); }逻辑上分三步先判断号源是否已满再判断患者是否重复预约最后落库。但这段代码在并发下是有漏洞的——两个线程同时查到booked maxNum然后都插入就超卖了。常见做法是在appointment表上加一个(schedule_id, patient_id)的唯一索引同时在 service 方法上加Transactional和行级锁或者用 Redis 做分布式锁。如果只是单机部署给查询排班那行加SELECT ... FOR UPDATE也能挡住大部分并发。状态流转这块预约记录一般有四个状态待就诊、已就诊、已取消、爽约。改状态要走专门的接口别让前端直接改数据库字段// 状态流转只有待就诊状态才能取消 public Result cancelAppointment(Long appointmentId) { Appointment appt appointmentMapper.selectById(appointmentId); if (appt.getStatus() ! 0) { return Result.fail(当前状态不可取消); } appt.setStatus(2); // 2已取消 appointmentMapper.updateById(appt); return Result.success(已取消); }参数上要盯的是状态码的定义源码里如果用的是魔法数字0、1、2、3建议你改成枚举不然改到后面自己都记不清哪个数字对应哪个状态。取消后号源要不要释放如果号源是实时算的取消后countByScheduleId自然就少了不用额外操作如果是预扣减模式就得手动加回去这点要看源码用的是哪种方案。4. 避坑与常见问题排查从跨域到时间字段的五个真实翻车点这份源码跑起来不难难的是跑通之后各种看起来对但就是不对的问题。下面五条是我在类似项目里反复踩过的按现象、原因、解决三段写清楚。4.1 前端请求全部 404但后端接口单独测是通的现象浏览器控制台一堆 404但用 Postman 直接打后端接口能返回数据。原因vue.config.js里的 proxy 没配或者pathRewrite把该保留的前缀去掉了。解决确认前端请求路径带/apiproxy 的 target 指向后端端口pathRewrite按后端实际路由决定是否去掉前缀。改完必须重启npm run serve热更新不会重载 proxy 配置。4.2 预约时间存进去差 8 小时现象前端选的是下午 3 点数据库里存的是早上 7 点。原因JDBC 连接串没配serverTimezone或者实体类用的是java.util.Date而数据库是datetime中间转换丢了时区。解决连接串加serverTimezoneAsia/Shanghai实体类时间字段统一用LocalDateTimeMyBatis 映射时确认jdbcType是TIMESTAMP。4.3 并发下同一个号被约了两次现象压测或手动快速点击时一个号源出现两条预约记录。原因应用层校验和插入之间有时间窗口没有原子性。解决给appointment表加(schedule_id, patient_id)唯一索引兜底service 方法加Transactional高并发场景引入 Redis 锁或数据库悲观锁。唯一索引是最后一道防线别省。4.4 npm install 报 ERR_OSSL_EVP_UNSUPPORTED现象Node 18 以上装依赖或启动时报 OpenSSL 相关错误。原因新版 Node 的 OpenSSL 3.0 和旧版 webpack 不兼容。解决临时方案是export NODE_OPTIONS--openssl-legacy-provider根治方案是用 nvm 把 Node 降到 16。别去改 webpack 配置改到最后依赖树全乱。4.5 后台改了医生排班前端号源没更新现象管理端删了一个排班患者端还能看到并预约。原因前端缓存了排班列表或者号源计算依赖的字段没跟着变。解决确认前端是否用了 keep-alive 缓存页面改完排班后强制刷新号源如果是实时算的检查countByScheduleId是否把已取消的预约也算进去了已取消的应该排除。5. 二次开发与验证把通用预约系统改造成真正的口腔诊所工具源码能跑、坑也避了接下来是让它真正贴合口腔诊所的业务。通用预约系统最大的问题是把看牙当成看感冒处理忽略了牙科特有的复诊、疗程、项目时长这几个维度。这一章讲怎么改以及改完怎么验证没改坏。5.1 增加诊疗项目与疗程关联牙科的核心业务是项目 疗程。补牙可能一次搞定种植牙要分好几次复诊。建议在原有表结构上加两张表treatment_item诊疗项目含预计时长、价格和treatment_plan疗程计划关联患者和项目记录第几次复诊。-- 新增诊疗项目表 CREATE TABLE treatment_item ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(64) NOT NULL, -- 项目名如种植牙一期 duration INT NOT NULL, -- 预计耗时分钟 price DECIMAL(10,2), -- 参考价格 need_revisit TINYINT DEFAULT 0 -- 是否需要复诊 ); -- 疗程计划表把预约和疗程关联起来 CREATE TABLE treatment_plan ( id BIGINT PRIMARY KEY AUTO_INCREMENT, patient_id BIGINT NOT NULL, item_id BIGINT NOT NULL, current_stage INT DEFAULT 1, -- 当前第几阶段 total_stage INT DEFAULT 1, -- 总阶段数 next_appointment_id BIGINT -- 下次预约记录ID );加完之后预约接口要能接收itemId根据项目时长去匹配排班时段。比如种植牙一期要 90 分钟就不能塞进 30 分钟的普通号里。这一步改完系统才从通用预约变成牙科预约。5.2 验证改造是否成功的三个检查点改完别急着交付走一遍这三个检查点检查点验证方法通过标准号源容量把某时段 maxNum 设为 2用两个账号同时约第二个提示号满数据库只有两条记录时间一致性前端选 15:00查数据库 create_time 和 work_date时间不偏移时区正确状态流转预约→取消→再约同一时段取消后号源释放能重新约上这三个点过了基本功能就稳了。进阶一点可以加一个定时任务每天凌晨把前一天待就诊但没来的记录自动标记为爽约释放号源给当天现场挂号的患者。这个逻辑用 Springboot 的Scheduled就能实现cron 表达式写0 0 1 * * ?凌晨 1 点跑。从那以后我每次拿到一份前后端分离的预约类源码都强制先走一遍环境版本 → 数据库时区 → 并发校验这三步再谈业务改造。顺序反了后面全是返工。希望这份拆解能帮你少走点弯路把这份源码真正用起来。本文还有配套的精品资源点击获取
返回列表