首页 / 资讯中心 / 文章详情

医院挂号预约小程序源码解析:Java全栈毕设工程跑通与避坑指南

医院挂号预约小程序源码解析:Java全栈毕设工程跑通与避坑指南 ★ FEATURED ARTICLE
简介医院挂号预约系统微信小程序毕业设计项目面向计算机相关专业毕业设计或课程设计人群提供一套基于Java后端、微信小程序前端与MySQL数据库的完整可运行源码亦可用于课程设计答辩演示或二次开发起点。系统含管理员与用户双角色覆盖用户管理、医生/医院/科室信息维护、预约与取消、留言板、公告资讯等典型模块包含前端小程序页面与后端服务分层组织接口与页面划分清晰适合需要快速搭建同类型管理系统或理解前后端交互逻辑的开发者参考。压缩包内含1321个文件大小27.14MB主要文件包括Java后端源码、小程序前端页面、vue组件、SQL数据库脚本、XML配置及多张图片素材另有PDF使用说明和开发工具配置文件目录结构完整便于按模块查看和部署。源码附带数据库文件与详细环境说明JDK1.8、MySQL5.7、Tomcat7及微信开发者工具可帮助毕业生节省环境搭建时间快速跑通项目并在此基础上进行功能扩展或二次开发已有78人学习浏览。1. 医院挂号预约小程序源码毕业设计能直接改的Java全栈工程如果你现在手里拿到的是一个医院挂号预约系统的微信小程序压缩包里面同时有Java后端、MySQL数据库文件、小程序前端和一堆.bat批处理脚本这说明你拿到的不是那种缺胳膊少腿的残缺源码。这个项目对应的是典型的本科毕业设计选题微信小程序端给用户注册、登录、查看医院和医生信息、在科室里预约和取消预约后台管理端给管理员维护用户、医生、医院、科室、预约记录、取消记录、留言板以及系统公告。技术栈是Java JDK1.8 MySQL5.7 Tomcat7这套组合在高校毕设里非常成熟重点不是技术新潮而是结构完整、能跑通、能讲清楚。适合两类人一类是准备Java方向毕业设计或课程设计的学生另一类是刚学完Java Web想拿一个全栈案例练手的小程序开发者。2. 拆工程结构从 .bat 到 .vue.bak先搞清项目里有什么2.1 三个批处理脚本install、run、build 到底做了什么打开压缩包先看根目录你会看到1-install.bat、2-run.bat、3-build.bat。这三个文件是作者为了让环境一键跑起来写的。我一般拿到源码第一件事不是import到IDE而是先看脚本内容能省掉很多手动配置。1-install.bat的常见做法是执行mvn install把Maven依赖装进本地仓库同时把数据库脚本放到固定目录方便后面导入。里面一般长这样echo off cd /d %~dp0 echo [1/3] 编译后端项目... call mvn clean install -DskipTests echo [2/3] 拷贝数据库初始化脚本... copy /Y sql\hospital.sql mysql-init\init.sql echo 安装完成请先导入数据库后再执行2-run.bat pause逻辑不复杂mvn clean install -DskipTests是把Java后端打成war包并跳过单元测试避免测试类报错中断编译。copy把SQL脚本复制到mysql-init目录这是为了让数据库初始化脚本集中管理不用翻遍全项目去找建表语句。cd /d %~dp0是让脚本从任何路径双击都自动切换到自身所在目录这是批处理最常见的坑——少了它后面的相对路径全部失效。2-run.bat负责启动Tomcat或直接用Maven插件跑后端。常见内容是echo off cd /d %~dp0 echo 启动Tomcat... call startup.bat echo Tomcat已启动请访问 http://localhost:8080/hospital/这里的startup.bat需要系统环境变量里配好CATALINA_HOME否则会报“找不到命令”。所以很多工程会改成用mvn tomcat7:run这种插件方式Maven3.3对tomcat7-maven-plugin的兼容性最好直接用插件启动能避开Tomcat目录配置的问题。3-build.bat通常是给后台Vue管理端或小程序端用的构建脚本比如执行npm run build把.vue组件编译成静态资源。三个脚本的顺序很关键必须先装依赖、再导数据库、最后构建前端。2.2 前后端分离又没完全分离Java后端 Vue后台 微信小程序这个项目的结构不是单层的。后端是Java的SSM工程SpringMVC负责接口后台管理端用的是Vue组件你会看到main.css.bak、IndexMain.vue.bak、IndexAsideStatic.vue.bak这类文件。.vue.bak是Vue单文件组件的备份IndexMain.vue是主框架IndexAsideStatic.vue是侧边栏菜单BreadCrumbs.vue是面包屑导航update-password.vue.bak是密码修改页的备份。这些备份文件不是无用垃圾改坏了可以拿.bak把原文件覆盖回去比git恢复还直观。微信小程序端是独立的前端工程里面放pages目录、utils工具类、app.js全局逻辑。小程序的接口通过HTTP请求指向后端的/hospital这个context路径JSON格式交互。前后端通过HTTP协议通信但又在同一个压缩包里交付所以叫“分离又没完全分离”——没有独立的网关和前端部署更适合毕业设计演示不需要额外搭NginxTomcat一个容器全搞定。2.3 那些.bak文件不是垃圾是修改前的后悔药很多初学者会把.bak文件当成无用文件直接删掉我强烈建议不要删。update-password.vue.bak保留了修改前的版本当你把密码修改页改到接口报错时直接执行cp update-password.vue.bak update-password.vue就能回滚。我见过有人删了.bak之后改坏了整个后台页面又找不到原版最后花两天重写。血泪经验拿到工程先保留所有.bak哪怕解压后体积大一点也值。.classpath文件是Eclipse的工程配置如果你用Eclipse导入这个文件能帮你自动识别源目录和JAR包用Idea的话它会被忽略但也不要删。3. 数据库设计与初始化mysql 5.7下建库、导数据、改连接3.1 先看懂表关系用户、医生、科室、预约是怎么关联的医院挂号系统的核心不是界面是表关系。先打开sql目录下的脚本或直接用Navicat连接后看库。典型的设计表大概有这些表名作用关键字段user小程序注册用户id, username, password, phonehospital医院信息id, name, address, leveldepartment科室信息id, hospital_id, name, introdoctor医生信息id, department_id, name, title, scheduleappointment预约记录id, user_id, doctor_id, dept_id, date, time, statusnotice公告资讯id, title, content, create_timemessage留言板id, user_id, content, reply关系是一个医院有多个科室一个科室有多个医生一个用户可以预约多个医生。预约表里通常同时带doctor_id和department_id这是为了方便小程序端“在科室信息里面进行预约”——用户先选科室再选该科室下的医生所以预约记录要冗余科室ID否则列表查询时要多join一次。管理员端的“医生信息管理”“科室信息管理”就是维护这些表的增删改查。个别设计还会把医生表跟科室表做逻辑外键但实际上MyBatis里直接用关联查询更灵活。3.2 SQL脚本怎么导入Navicat11和命令行两种方式如果用的是Navicat11操作方法是新建一个连接库名建议用hospital字符集选utf8mb4然后把.sql文件拖进去执行。但Navicat11有些老版本对utf8mb4支持不太好所以更稳妥的是用命令行。我一般习惯这么做mysql -uroot -p123456 CREATE DATABASE hospital DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE hospital; SOURCE /path/to/hospital.sql;参数说明utf8mb4比utf8多支持表情符号小程序留言板里用户发emoji时utf8会报 “Incorrect string value” 错误这是常见的翻车点。SOURCE后面必须用绝对路径用/分隔Windows下也别用反斜杠否则MySQL解析会出错。导入后随便查一下appointment表有无几条测试数据有数据说明脚本完整。如果导入时报 “Unknown character set”先打开SQL文件把头部改成SET NAMES utf8mb4;再执行。3.3 改数据库连接jdbc.properties配置里的三个位置后端连数据库的配置一般在src/main/resources/jdbc.properties。这个文件短但改错一个参数后端就起不来。默认内容长这样jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/hospital?useUnicodetruecharacterEncodingutf8useSSLfalse jdbc.usernameroot jdbc.password123456需要改的就是jdbc.url里的localhost:3306、jdbc.username、jdbc.password三处。有三个坑第一MySQL5.7的驱动类名是com.mysql.jdbc.Driver如果你机器上装了MySQL8.0并换成了新版驱动要改成com.mysql.cj.jdbc.Driver否则启动报 “ClassNotFoundException”。第二URL里务必带useSSLfalseTomcat7自带的SSL配置经常跟新版驱动冲突不带会在启动时报SSL握手警告。第三密码不要带#或这种特殊字符会被当成URL参数截断导致Access denied。如果改了还是连不上先确认你输入的是不是root密码资源里默认通常是root/123456但也有作者本机密码是root看jdbc.properties原值最靠谱。4. 后端工程跑起来Maven3.3 Tomcat7 JDK1.8的兼容性4.1 JDK和Tomcat版本为什么是“老组合”这个项目指定JDK1.8、MySQL5.7、Maven3.3、Tomcat7看着老但这是毕业设计里最稳的组合。Tomcat7对应Java EE 6支持Servlet 3.0和SSM框架的依赖兼容性最好。如果你非要用Tomcat9甚至Tomcat10SSM里用的javax.servlet包在Tomcat10里被替换成jakarta.servlet代码里的import javax.servlet.*全部报红改起来涉及几十个文件直接翻车。JDK1.8编译出来的class文件用Tomcat7运行没有任何问题但如果你本机装的是JDK17Maven3.3会识别不了编译直接报 “Unsupported class file major version 61”。所以我一般会在本机保留一个JDK8专门跑这类毕设项目别的项目用JDK17互不影响。Maven3.3是配套JDK1.8的版本在pom.xml里maven-compiler-plugin的source和target都是1.8。不要自动升级Maven到3.6或3.9很多老插件的pluginManagement在Maven3.6下会报 “Unsupported major.minor version 52.0”这个错误很抽象其实就是Maven和JDK版本不匹配。记住一个原则拿到源码先看pom.xml里java.version和maven.compiler.source把你本地的Maven、JDK对齐到和它一样。4.2 从导入到启动Eclipse/Idea里最稳的四个步骤我拿到这种工程不管用Eclipse还是Idea都按固定顺序来能避免八成启动失败。第一步确认版本。命令行分别执行java -version mvn -v必须看到1.8字样。如果java -version显示17或21去控制面板或.bash_profile里把JDK切到8。第二步导入Maven工程。Eclipse用 Import → Existing Maven Projects选到包含pom.xml的根目录Idea用 Open 直接选pom.xml。导入后等依赖下载完检查pom.xml里有没有spring-webmvc、mybatis、mysql-connector-java这几个坐标。缺少任何一个启动都会报 “NoSuchBeanDefinitionException”。第三步配置Tomcat7。Idea里先添加 Tomcat Server再把war exploded部署到Server中Application context填/hospital。这里有个关键context路径必须跟小程序端wx.request里的url前缀匹配。比如小程序端写的http://localhost:8080/hospital/api/login你context写成了/Hospital大小写不一致也会404。如果小程序端写了端口8081你Tomcat跑8080那更连不上。第四步启动前先确认数据库已经导入。否则Spring启动时SqlSessionFactoryBean初始化失败报Failed to configure a DataSource。我习惯是先启动MySQL服务再启动Tomcat看到Initializing Spring root WebApplicationContext日志后再等三秒。启动成功后访问http://localhost:8080/hospital/login能看到后台登录页说明后端起来了。如果页面报404先检查Tomcat的部署列表里有没有这个app没有就重新deploy。4.3 后端接口长什么样以预约模块为例看Controller和Service你如果在答辩时要讲代码不需要讲整个项目把一个核心接口讲透就够了。以“小程序提交预约”为例经典Controller是这样Controller RequestMapping(/api/appointment) public class AppointmentController { Autowired private AppointmentService appointmentService; RequestMapping(value /add, method RequestMethod.POST) ResponseBody public Result add(RequestBody Appointment appointment) { // 1. 校验用户是否已登录 if (appointment.getUserId() null) { return Result.error(未登录); } // 2. 校验医生和科室参数 if (appointment.getDoctorId() null || appointment.getDepartmentId() null) { return Result.error(医生或科室参数缺失); } // 3. 调用service插入预约返回自增id int id appointmentService.addAppointment(appointment); if (id 0) { return Result.success(预约成功, id); } return Result.error(预约失败可能已有重复预约); } }这里的RequestBody表示接收JSON字符串所以小程序端必须用wx.request的method: POST并且设置header[content-type]为application/json。有些同学按表单方式传data: user_id1doctor_id2后端用RequestBody解析会拿到null。反过来如果Controller写的是RequestParam小程序端就要用form格式传或者手动拼在url后面。参数说明Appointment实体里的date建议用String接收yyyy-MM-ddtime用HH:mm不要直接用java.util.Date接前端字符串因为JSON解析日期格式经常报400。等跑通基础流程后再在Service里做重复预约的校验第五章会专门讲这个坑。5. 小程序端常见问题与避坑导航栏高度、手机号授权、预约冲突的排查记录这一章是踩坑合集。很多毕设源码后台能启动但小程序一跑就废问题集中在下面几个点。我会先理清楚小程序和后端的请求链路再一个个给排查方法。5.1 先理一遍小程序端请求链路wx.request → Java接口 → MySQL小程序端的代码不是直接从页面跳数据库的。完整链路是wx.request发HTTP请求 → Tomcat接收 → SpringMVC路由到Controller → Service业务逻辑 → MyBatis操作MySQL → 结果JSON返回。排错时按这条链路一步步看就像查网络分层模型一样先看请求到没到后端。最常翻车的点是wx.request的url。小程序开发工具里如果这样写wx.request({ url: http://localhost:8080/hospital/api/appointment/add, method: POST, header: { content-type: application/json }, data: { doctorId: 1, departmentId: 2, date: 2025-04-10, time: 09:00 }, success: res console.log(res.data) })在开发者工具模拟器里可能能通因为模拟器的localhost指向电脑本机。但真机预览时手机访问localhost是访问手机自己不是电脑。这里必须改成电脑的局域网IP比如http://192.168.1.101:8080/hospital/...。同时如果以后要发布体验版需要在小程序后台“开发设置”→服务器域名里配置HTTPS域名。本地调试阶段可以勾选开发者工具右上角的“不校验合法域名、web-view、TLS版本以及HTTPS证书”来绕过。5.2 问题一真机调试连不上本地后端一直转圈现象手机打开小程序请求一直pending最后报errMsg: request:fail。原因手机和电脑不在同一个WiFi或者Tomcat只监听了127.0.0.1。Tomcat默认监听所有网卡但如果你在Idea里用Tomcat集成启动可能被配置成只监听localhost。解决先用电脑查IP再检查Tomcat端口状态。命令行执行ipconfig telnet 192.168.1.101 8080ipconfig能看到无线网卡的IPv4地址比如192.168.1.101。telnet能通说明网络通畅通不了就去Windows防火墙里放行8080端口。然后确认apache-tomcat/conf/server.xml里Connector没有写address127.0.0.1如果写了就把它注释掉。改完重启Tomcat再把小程序url里的localhost替换成局域网IP。注意iPhone和电脑连的WiFi如果开了“AP隔离”即使在同一路由器下也互相访问不了这种人少的局部网络故障就改用Android手机连热点测。5.3 问题二顶部导航栏高度在iPhone上遮住内容现象小程序里用了自定义导航栏在iPhone X及以上的机型上胶囊按钮和状态栏重叠页面标题被顶到屏幕外面。这是微信小程序顶部导航栏高度最经典的坑。原因自定义导航栏后小程序不再自动让开状态栏需要你手动获取statusBarHeight和胶囊按钮位置来计算导航栏总高度。不同机型的状态栏高度不一样iPhone的刘海屏是44px很多安卓是24px写死一个数就会在某些机型上翻车。解决在app.js里计算一次并存入globalDataApp({ onLaunch() { const sys wx.getSystemInfoSync() const menu wx.getMenuButtonBoundingClientRect() this.globalData.statusBarHeight sys.statusBarHeight this.globalData.navBarHeight (menu.top - sys.statusBarHeight) * 2 menu.height } })然后在你自定义导航栏的页面wxss里用padding-top撑开安全区。statusBarHeight是状态栏高度navBarHeight是状态栏到胶囊按钮底部的完整导航栏高度。如果你压根不用自定义导航栏就用小程序默认导航栏这个坑自动消失。但毕设项目里为了好看很多作者都写了自定义导航栏跑真机时一定要测iPhone机型。5.4 问题三登录时手机号授权弹窗不出现现象点击“获取手机号”按钮没有反应或者控制台提示getPhoneNumber需要用户点击行为。原因微信的规则是手机号授权必须由用户主动点击button open-typegetPhoneNumber按钮才能触发不能在onLoad或onShow里自动调wx.getPhoneNumber。另外该接口需要小程序完成企业或个人主体认证个人开发者的小程序调用会直接报功能未开通。解决在页面里放显式按钮回调函数里取e.detail.codebutton open-typegetPhoneNumber bindgetphonenumberonGetPhone获取手机号/buttononGetPhone(e) { if (e.detail.code) { wx.request({ url: http://192.168.1.101:8080/hospital/api/user/phone, method: POST, data: { code: e.detail.code }, success: res console.log(手机号绑定成功, res.data) }) } else { console.log(用户拒绝了授权) } }这里的e.detail.code是临时code需要后端拿着它去调微信接口换手机号不能直接信任前端传过来的明文手机号。毕业设计演示时如果没有认证主体可以做个“模拟登录”让用户手动填手机号反正管理员端能看到手机号就行。重点是别在onLoad里自动弹窗微信官方已经把这个口子堵死了。5.5 问题四重复预约同一时段没被拦截现象同一个用户对同一个医生同一时段点了两次预约生成了两条记录管理员后台看到重复数据。原因后端没有做唯一性校验。预约表里没有联合唯一索引Service里也没有查询重复的逻辑。解决两层都做。先给appointment表加联合唯一索引ALTER TABLE appointment ADD UNIQUE KEY uk_user_doctor_date_time (user_id, doctor_id, date, time);这样数据库层面能拦截重复但第二次插入会抛DuplicateKeyException用户看到的是500错误页。所以还要在Service里先查再插给用户友好提示public int addAppointment(Appointment appointment) { int count appointmentMapper.checkExist( appointment.getUserId(), appointment.getDoctorId(), appointment.getDate(), appointment.getTime()); if (count 0) { return 0; } return appointmentMapper.insert(appointment); }这个checkExist对应的SQL是SELECT COUNT(*) FROM appointment WHERE user_id#{userId} AND doctor_id#{doctorId} AND date#{date} AND time#{time} AND status ! 2注意把“已取消”的记录排除掉否则用户取消后再约同个时段会被误拦截。我一般两个方案都做数据库唯一索引兜底Service查重给提示。只加索引不写查重用户体会不到“友好提示”只写查重不加索引并发双击下仍可能插两条。5.6 问题五返回时间格式变成一串数字现象预约列表页里时间显示成1714567890这种数字用户“我的预约”页一片乱码。原因后端Date类型序列化时没指定格式SpringMVC默认调用了Jackson把Date转成了时间戳。解决在实体字段上加JsonFormat或者写全局配置。最省事的是字段注解JsonFormat(pattern yyyy-MM-dd HH:mm:ss, timezone GMT8) private Date createTime;加了这行之后接口返回的JSON就是2025-04-10 09:00:00这种正常文本。注意timezone必须写GMT8否则服务器时区是UTC返回的时间会比本地时间少8小时。这个问题在毕设答辩时很容易被评委注意到因为他们会拿手机小程序给你现场演示看到一个时间戳数字特别尴尬。6. 进阶从毕业设计到能演示的挂号系统——会话保持、状态机与数据统计6.1 用Token或Session保持登录态这个小程序的后端接口通常靠sessionId判断是否已登录但小程序没有Cookie机制所以更稳的做法是登录成功后后端生成一个UUID形式的token存到内存Map或redis里小程序每次请求放在header[Authorization]中。后端用一个SpringMVC拦截器统一校验省得每个Controller都写一遍“if usernull”。如果不想引redis直接用ConcurrentHashMap也行毕设场景没有高并发压力Map足够。答辩时你还能说“这里考虑了扩展性后期可以替换成redis”。6.2 预约状态机预约状态建议用数字0待就诊、1已完成、2已取消。取消预约不是删除记录而是把状态改成2。管理员后台的“预约取消管理”就是查状态为2的列表。用户端“我的预约”还能显示历史记录比你直接delete更有说服力。关键SQL是更新状态时带上条件WHERE id#{id} AND user_id#{userId} AND status0这样即使用户同时点了两次取消也只成功一次且不知道别人的预约。6.3 一个加分的小功能在管理员首页加一个统计接口统计每个科室的医生数量和预约数用一条GROUP BY就能完成。比如SELECT d.name AS department_name, COUNT(DISTINCT doc.id) AS doctor_count, COUNT(app.id) AS appointment_count FROM department d LEFT JOIN doctor doc ON doc.department_id d.id LEFT JOIN appointment app ON app.department_id d.id GROUP BY d.id, d.name;返回结果里appointment_count是预约总量可以配一个小程序或Vue图表答辩的演示效果远好于空白的个人中心。如果你还想更亮眼可以统计公告里最近三天的资讯数或者留言板的回复率。从那以后我每次跑这类毕设源码都会先按“脚本、数据库、后端、小程序、常见坑”这个顺序过一遍而不是急着写代码。遇到.bak文件也不删先留着——那是你的后悔药。希望帮到你把这份资源跑通再把它改成你自己的东西。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站