简介:这份资源是面向计算机专业毕业设计场景的微信小程序医院预约挂号系统配套文档,适合正在准备Java方向毕设的本科生或需要参考完整项目方案的自学者。文档围绕微信小程序前端、Spring Boot与SSM后端、MySQL数据库的技术组合展开,涵盖项目背景与意义、技术选型分析、系统架构设计、用户管理、医生管理、预约管理、通知提醒等关键模块,并讨论了数据安全、高并发处理与系统稳定性等实现难点及解决思路,可作为选题论证、论文撰写与答辩准备的材料。资源包共1个docx文件,约883KB,内容为结构完整的说明文档而非可运行代码。目前已有382人学习下载,适合需要快速理清挂号类小程序业务逻辑与论文框架的读者参考借鉴。
1. 从排队两小时到点开小程序:这套医院预约挂号源码到底解决了什么
上周帮一个做医疗信息化的朋友看毕业设计,他吐槽说现在医院挂号窗口早上六点半就有人搬小板凳排队,专家号放出来三分钟就没了,窗口护士一边敲键盘一边接电话,出错率还高。这个场景其实正是这套微信小程序医院预约挂号系统要解决的问题——把挂号从线下窗口搬到微信里,患者打开小程序就能看科室、查医生、选时段、提交预约,后台管理员统一维护医生排班和预约记录。整套源码包含小程序端、后台管理端和 MySQL 数据库脚本,技术栈是微信小程序原生开发加 Java 后端(Spring Boot / SSM 两种常见组织方式),适合做毕业设计、课程设计,也适合想练手一个完整前后端分离项目的开发者。它不追求高并发架构,但把「科室—医生—排班—预约—审核」这条业务链路走通了,拿来改造成社区医院、诊所的预约工具完全够用。
2. 技术栈与目录结构:小程序端、Java 后端、MySQL 三件套怎么摆
2.1 技术选型拆解:为什么是微信小程序 + Spring Boot + MySQL
这套源码的选型逻辑很清晰,属于「够用、好部署、答辩讲得清」的组合。前端用微信小程序原生框架,.wxml写结构、.wxss写样式、.js写逻辑、.json写配置,四个文件放在同一目录下对应一个页面,学习成本低,微信开发者工具直接导入就能预览。后端用 Java,摘要里同时出现了 Spring Boot 和 SSM 两个关键词,实际项目里常见两种组织方式:一种是 Spring Boot 单体,pom.xml里引spring-boot-starter-web和mybatis-spring-boot-starter,启动类一跑就起服务;另一种是传统 SSM,需要配web.xml、spring-mvc.xml、mybatis-config.xml,再丢进 Tomcat 跑。两种都能跑通同一套业务,区别只在启动方式和配置量。
数据库选 MySQL 8.0,存用户、患者、科室、医生、排班、预约、公告、反馈这几类数据。选它的理由很实在:关系模型清晰,科室和医生是一对多,医生和排班是一对多,排班和预约是一对多,用外键和联表查询表达起来直观;而且 MySQL 免费、社区资料多,毕设环境里装个 phpStudy 或者 Docker 一条命令就起来了。
提示:如果你拿到的源码是 SSM 版本,先看根目录有没有
pom.xml里的packaging是war还是jar。war要配 Tomcat,jar直接java -jar启动,别混着来,否则会卡在「找不到主类」这种玄学问题上。
2.2 目录结构:一份源码里到底有哪些东西
拿到压缩包解压后,典型结构如下(不同版本目录名可能略有差异,但职责划分基本一致):
hospital-appointment/ ├── miniprogram/ # 微信小程序端 │ ├── app.js # 全局逻辑,登录态、请求封装 │ ├── app.json # 页面路由、tabBar 配置 │ ├── app.wxss # 全局样式 │ ├── pages/ │ │ ├── index/ # 首页:科室入口、公告 │ │ ├── department/ # 科室列表 + 医生列表 │ │ ├── doctor/ # 医生详情 + 预约按钮 │ │ ├── appointment/ # 预约提交、我的预约 │ │ ├── mine/ # 个人中心 │ │ └── feedback/ # 意见反馈 │ ├── utils/ │ │ └── request.js # wx.request 统一封装 │ └── images/ # 图标、占位图 ├── server/ # Java 后端 │ ├── src/main/java/ │ │ └── com/hospital/ │ │ ├── controller/ # 接口层:DoctorController 等 │ │ ├── service/ # 业务层:预约校验、排班扣减 │ │ ├── mapper/ # MyBatis 接口 │ │ ├── entity/ # 实体类,对应数据库表 │ │ └── config/ # 跨域、拦截器配置 │ ├── src/main/resources/ │ │ ├── application.yml # 数据库连接、端口 │ │ └── mapper/ # MyBatis XML │ └── pom.xml ├── admin/ # 后台管理端(若为前后端不分离,则是 JSP/HTML 模板) │ ├── login.html │ ├── doctor-manage.html │ ├── appointment-manage.html │ └── ... └── sql/ └── hospital.sql # 建库建表 + 初始数据这个结构的关键点在于:小程序端只负责展示和收集用户操作,所有业务判断(比如「这个号还能不能约」「是否重复预约」)都放在后端service层,数据库只做存储。这样改需求时不用动小程序代码,改后端接口就行,二次开发时省事。
2.3 数据库表设计:五张核心表撑起整条业务链
摘要里提到用户表、患者表、科室表、医生表,实际落地时还需要排班表和预约表。核心字段可以按下面这样理解:
| 表名 | 作用 | 关键字段 |
|---|---|---|
user | 小程序登录用户 | id、openid、nickname、phone |
patient | 就诊人信息 | id、user_id、name、id_card、gender |
dept | 科室 | id、dept_name、description |
doctor | 医生 | id、dept_id、name、title、specialty、avatar |
schedule | 排班 | id、doctor_id、work_date、time_slot、total_num、left_num |
appointment | 预约记录 | id、patient_id、schedule_id、status、create_time |
schedule表里的left_num是整套系统的命门——预约成功就减一,取消就加一,后台管理员改排班时也要同步。很多同学做毕设只建了预约表,没建排班表,结果「同一个医生同一天能约无限次」,答辩时被问一句就露馅。这套源码把排班单独拆出来,是它比同类 Demo 更完整的地方。
3. 核心模块拆解:从科室浏览到预约落库的完整链路
3.1 小程序端请求封装:一个request.js管住所有接口
小程序里如果每个页面都写一遍wx.request,后面换域名、加 token 会改到崩溃。这套源码在utils/request.js里做了统一封装,常见写法如下:
// utils/request.js const BASE_URL = 'http://127.0.0.1:8080/api'; // 本地调试地址,上线换成备案域名 function request(url, method = 'GET', data = {}) { return new Promise((resolve, reject) => { wx.request({ url: BASE_URL + url, method, data, header: { 'content-type': 'application/json', 'token': wx.getStorageSync('token') || '' // 登录后存下的凭证 }, success(res) { if (res.statusCode === 200 && res.data.code === 0) { resolve(res.data.data); // 约定 code=0 为成功 } else { wx.showToast({ title: res.data.msg || '请求失败', icon: 'none' }); reject(res.data); } }, fail(err) { wx.showToast({ title: '网络异常', icon: 'none' }); reject(err); } }); }); } module.exports = { request };这段代码做了三件事:统一拼接BASE_URL,避免每个页面写死地址;统一携带token,后端拦截器据此判断登录态;统一处理code约定,业务成功走resolve,失败弹提示并reject。参数说明上,method默认 GET,提交预约时传 POST;data是请求体,GET 时会自动拼成 query。改造成本很低——换服务器只改BASE_URL一行。
3.2 科室与医生列表:一次联表查询把层级数据带出来
科室页面的交互是左边科室、右边医生,数据来源通常是两个接口:/dept/list拿科室,/doctor/list?deptId=x拿该科室下的医生。后端 MyBatis 的 XML 里常见这样写:
<!-- mapper/DoctorMapper.xml --> <select id="selectByDeptId" resultType="com.hospital.entity.Doctor"> SELECT d.id, d.name, d.title, d.specialty, d.avatar, dept.dept_name AS deptName FROM doctor d LEFT JOIN dept ON d.dept_id = dept.id WHERE d.dept_id = #{deptId} AND d.status = 1 ORDER BY d.title DESC </select>#{deptId}是前端传进来的科室主键,status = 1过滤掉已停诊的医生,ORDER BY d.title DESC让主任医师排在前面——这是医疗类列表的常见排序习惯。返回的Doctor实体里多带一个deptName字段,小程序端渲染医生卡片时就不用再查一次科室名。这里容易翻车的地方是LEFT JOIN写成INNER JOIN,一旦某个医生没绑科室就查不出来,调试时表现为「明明数据库有数据,页面就是空的」。
3.3 预约提交:后端事务里做「查余号—扣减—写记录」
预约是整个系统最不能出错的一步。前端点「确认预约」后,调用/appointment/submit,后端 Service 层的核心逻辑大致如下:
// service/AppointmentServiceImpl.java @Transactional(rollbackFor = Exception.class) public Result submitAppointment(Long patientId, Long scheduleId) { // 1. 查排班,行锁防止并发超卖 Schedule schedule = scheduleMapper.selectByIdForUpdate(scheduleId); if (schedule == null) { return Result.fail("排班不存在"); } if (schedule.getLeftNum() <= 0) { return Result.fail("该时段号源已约满"); } // 2. 校验是否重复预约同一排班 int exist = appointmentMapper.countByPatientAndSchedule(patientId, scheduleId); if (exist > 0) { return Result.fail("您已预约过该时段,请勿重复提交"); } // 3. 扣减余号 scheduleMapper.decreaseLeftNum(scheduleId); // 4. 写入预约记录,状态 0=待就诊 Appointment appt = new Appointment(); appt.setPatientId(patientId); appt.setScheduleId(scheduleId); appt.setStatus(0); appt.setCreateTime(new Date()); appointmentMapper.insert(appt); return Result.ok(appt.getId()); }逐段看:@Transactional保证扣号和写记录要么都成功要么都回滚,这是血泪经验——早期版本没加事务,扣了号但插入失败,号就凭空消失了。selectByIdForUpdate对应 SQL 里的SELECT ... FOR UPDATE,在事务内锁住这一行排班,防止两个用户同时读到left_num=1然后都扣成功。重复预约校验放在扣减之前,避免用户手抖连点两次。decreaseLeftNum的 SQL 建议写成UPDATE schedule SET left_num = left_num - 1 WHERE id = #{id} AND left_num > 0,用数据库层面的条件更新兜底,比先查再改更稳。
注意:
FOR UPDATE必须在事务里才生效,如果 Service 方法没加@Transactional,行锁会立刻释放,并发场景下照样超卖。这是排查「压测时余号变负数」问题的第一检查点。
3.4 后台管理端:医生信息与预约审核的两条主线
后台管理端承担两类操作:一是医生和科室的增删改查,二是预约记录的查看与状态流转。医生信息管理的接口通常是/admin/doctor/save、/admin/doctor/update、/admin/doctor/delete,删除一般做逻辑删除(status置 0),因为历史预约记录还关联着这个医生,物理删除会导致联表查询出现空指针。预约管理则是列表加分页,支持按医生、日期、状态筛选,管理员可以把预约状态从「待就诊」改成「已完成」或「已取消」,取消时要把left_num加回去。
后台页面如果是传统 HTML + Ajax,注意登录态用 Session 还是 Token 要统一。常见翻车点是后台用 Session、小程序用 Token,两套拦截器各管各的,改起来很乱。我一般建议统一走 Token,后台登录成功后也返回一个 token 存 localStorage,拦截器只认 header 里的 token,逻辑就一条线。
4. 本地跑起来:环境准备、建库、启动、联调四步走
4.1 环境清单与版本建议
跑这套源码不需要多高配置,一台 8G 内存的开发机足够。需要装的东西如下:
| 工具 | 建议版本 | 用途 |
|---|---|---|
| JDK | 8 或 11 | 编译运行 Java 后端 |
| Maven | 3.6+ | 拉依赖、打包 |
| MySQL | 8.0 | 存业务数据 |
| 微信开发者工具 | 稳定版 | 预览小程序 |
| IDEA / Eclipse | 任选 | 看后端代码 |
| Tomcat | 9(仅 SSM war 包需要) | 部署后端 |
JDK 版本要和pom.xml里的maven.compiler.source对上,源码写 1.8 你就用 JDK 8 或 11,别直接上 17,否则可能遇到javax包找不到的问题。
4.2 建库导数据:先跑 SQL 再改配置
打开 MySQL 客户端,执行源码sql/目录下的脚本:
# 登录 MySQL mysql -u root -p # 创建数据库并导入(脚本里通常已含 CREATE DATABASE) source /path/to/hospital-appointment/sql/hospital.sql; # 确认表和数据都在 use hospital; show tables; select count(*) from doctor;导入完成后,改后端application.yml里的连接信息:
spring: datasource: url: jdbc:mysql://127.0.0.1:3306/hospital?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver server: port: 8080serverTimezone必须写,否则 MySQL 8 驱动会报时区错误,表现为启动时连不上库。characterEncoding=utf8保证中文科室名不乱码。
4.3 启动后端与小程序联调
后端启动:Spring Boot 版本直接跑启动类的main方法,控制台出现Started ... on port 8080即成功;SSM 版本把 war 丢进 Tomcat 的webapps,启动 Tomcat 后访问http://127.0.0.1:8080/项目名/。启动后先用浏览器或 Postman 测一个接口,比如http://127.0.0.1:8080/api/dept/list,能返回 JSON 就说明后端通了。
小程序端:微信开发者工具「导入项目」,目录选miniprogram/,AppID 可以选「测试号」。然后改utils/request.js里的BASE_URL指向本机后端。这里有个必踩的坑——开发者工具默认不校验合法域名,但真机预览会校验,本地调试时要在工具右上角「详情 → 本地设置」里勾上「不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书」。勾完之后,首页科室列表能刷出来,就说明前后端联调成功。
4.4 一条完整验证路径:从登录到预约成功
跑通环境后,按这条路径验证业务闭环:小程序端授权登录 → 进入个人中心补全就诊人信息 → 回首页选科室 → 选医生 → 选排班时段 → 提交预约 → 在「我的预约」里看到记录 → 打开后台管理端登录 → 在预约管理里看到这条记录并改成「已完成」。这条链路走完,说明登录态、联表查询、事务扣号、后台权限都没问题。任何一步卡住,先看后端控制台有没有异常堆栈,再看小程序 Network 面板里接口返回的code和msg,比盲目改代码高效得多。
5. 避坑与排查:五个真实会卡住你的问题
5.1 预约成功但余号没变,或者变成负数
现象:提交预约后appointment表有记录,但schedule.left_num没减;压测时甚至出现负数。原因通常是 Service 方法漏了@Transactional,或者扣减 SQL 写成了「先查再改」而不是条件更新。解决:给提交方法加@Transactional(rollbackFor = Exception.class),扣减语句改成UPDATE schedule SET left_num = left_num - 1 WHERE id = ? AND left_num > 0,并检查影响行数是否为 1,为 0 就回滚并提示约满。
5.2 小程序请求全部 404 或跨域报错
现象:开发者工具里接口返回 404,或者浏览器控制台报 CORS。原因一是BASE_URL少了/api前缀,和后端@RequestMapping对不上;二是后端没配跨域,后台管理页面用 Ajax 调接口时被浏览器拦。解决:先核对 Controller 类上的路径和方法上的路径拼起来是否等于前端请求路径;跨域在 Spring Boot 里加一个WebMvcConfigurer的addCorsMappings,允许本地来源,别图省事写*又带凭证,那样浏览器照样拒绝。
5.3 中文乱码,科室名显示成问号
现象:数据库里查出来是正常中文,页面显示乱码。原因多在连接串缺characterEncoding=utf8,或者建表时没指定DEFAULT CHARSET=utf8mb4。解决:连接串补上编码参数,建表语句统一用utf8mb4,已经建好的表执行ALTER TABLE dept CONVERT TO CHARACTER SET utf8mb4。改完重启后端,清一次小程序缓存再试。
5.4 后台删除医生后,历史预约列表报空指针
现象:管理员删了某个医生,预约管理页面加载失败。原因是物理删除医生后,预约记录联表查医生信息得到 null,代码里直接调了doctor.getName()。解决:医生删除改逻辑删除,status置 0;查询预约时用LEFT JOIN并对 null 做兜底显示「医生已停诊」;实体类字段判空再取值。
5.5 真机预览能打开页面但接口全失败
现象:开发者工具里一切正常,手机扫码预览时列表空白。原因是真机访问的是手机网络,127.0.0.1指向手机自己,根本连不到你电脑上的后端。解决:把BASE_URL改成电脑的局域网 IP(比如http://192.168.1.100:8080/api),确保手机和电脑在同一 Wi-Fi 下,电脑防火墙放行 8080 端口。这一步没有捷径,IP 填错就是连不上。
6. 二次开发改造:把「能跑」变成「能用在真实场景」
这套源码跑通之后,真正有价值的是按自己的场景改。我一般从三个方向下手,按投入产出比排序。
第一个方向是预约规则增强。现有逻辑只校验余号和重复预约,真实场景还需要「同一患者同一天最多约两个号」「取消预约需提前 24 小时」「爽约三次进黑名单」。这些规则加在AppointmentServiceImpl里,用查询计数加状态判断就能实现,不需要改表结构。比如限制每日预约数:
// 在 submitAppointment 里、扣减余号之前插入 int todayCount = appointmentMapper.countByPatientAndDate(patientId, schedule.getWorkDate()); if (todayCount >= 2) { return Result.fail("同一就诊人每日最多预约 2 个号"); }countByPatientAndDate对应一条SELECT COUNT(*) FROM appointment a JOIN schedule s ON a.schedule_id = s.id WHERE a.patient_id = ? AND s.work_date = ? AND a.status IN (0,1),状态 0 是待就诊、1 是已完成,取消的不算。参数2建议抽成配置项放application.yml,不同医院规则不一样,硬编码后面还得改。
第二个方向是消息提醒。摘要里提到「通过微信消息推送提醒患者」,落地时用微信小程序的订阅消息:用户提交预约时调wx.requestSubscribeMessage申请授权,后端在就诊前一天用定时任务(Spring 的@Scheduled)查当天排班,调微信服务端接口发提醒。注意订阅消息是一次授权一次发送,不能反复骚扰,模板 ID 要在小程序后台申请后填到配置里。
第三个方向是后台权限细化。现在只有一个管理员角色,真实场景至少分「超级管理员」和「科室管理员」,后者只能管自己科室的医生和排班。做法是在user表加role和dept_id字段,拦截器解析 token 后把角色塞进上下文,Service 层按角色过滤查询条件。改造时先加字段、再改查询、最后改前端菜单显隐,顺序别乱,否则会出现「菜单藏了但接口还能调」的假权限。
验证改造是否生效,我习惯用一条固定回归路径:新用户登录 → 约满两个号 → 尝试约第三个被拦 → 取消一个 → 再约成功 → 后台看到状态流转正确。每次改完业务逻辑都走一遍,比写一堆单元测试快,也不容易漏。
说个自己的教训:早期我改这类毕设项目,总喜欢先动前端样式,觉得页面好看就算完成,结果后端事务和权限的坑留到最后,联调时一个余号超卖问题查了一整晚。从那以后我每次拿到这类源码,都强制先把「建库 → 启动后端 → 接口测通 → 小程序走完预约闭环」这条链路跑一遍,再动任何一行展示层代码。希望这套拆解能帮你少走几个弯路,把这份源码真正跑成自己能讲清楚、能改得动的项目。
本文还有配套的精品资源,点击获取