很多朋友拿到一套Java SpringBoot + 微信小程序的宠物医院系统源码,第一反应是“代码能跑吗”,第二反应是“这系统到底能做什么”。说实话,我见过太多人卡在环境配置和依赖冲突上,最后连后端都没启动起来就放弃了。这套宠物医院挂号就诊服务预约项目,恰恰是那种“麻雀虽小五脏俱全”的全栈案例:后端用SpringBoot撑起业务接口,小程序端负责用户交互,中间夹着MySQL存储和微信登录授权。这篇文章我就从业务设计、后端结构、小程序联调、运行部署、踩坑记录和二次扩展六个方面,把整套系统从头到尾拆开讲清楚。如果你正准备拿它做毕业设计、课程项目,或者只是想学一下SpringBoot + 小程序的完整开发链路,这篇内容可以帮你少走很多弯路。
1. 这套宠物医院系统到底做了什么
很多项目源码光看名字很唬人,打开数据库才发现只有两张表。这套宠物医院系统不是那种空壳,它的核心链路是“用户注册登录 → 选择科室/医生 → 预约挂号 → 到院就诊 → 查看记录”,整个流程是闭环的。我先不急着讲代码,先把业务捋清楚,因为后面所有的表结构和接口设计,都是在为这条业务线服务。
1.1 三种用户角色与业务闭环
系统里一共有三类角色:普通用户(宠物主人)、医生、管理员。用户通过微信小程序端操作,医生和管理员则通过后台管理端处理业务。
普通用户的核心动作是:维护自己的宠物档案,查看医院科室和医生排班,选择一个时间段提交挂号预约,之后在“我的预约”中查看状态,就诊完成后还能回看历史记录。医生端的动作是:查看自己被预约的号源,更新预约状态(比如“待就诊”改成“已完成”),填写简单的诊断结果。管理员端则负责基础数据维护:科室管理、医生信息管理、排班规则设置,以及全局的预约记录查看。
这三个角色不是各玩各的,而是通过一张“预约记录表”串联起来的。用户提交预约时生成一条状态为“待确认”或“已预约”的记录,医生在处理时修改这条记录的状态,管理员看到的是全部记录。把数据流转想明白之后,再去看Controller和Service层,就不会觉得代码是散的。
1.2 核心功能清单梳理
按模块划分,这套系统主要包括:
- 用户端登录注册:基于微信小程序登录,后端通过code换openid,生成自定义token。
- 宠物档案管理:每个用户可以添加多个宠物,记录宠物名称、品种、年龄、性别、疫苗情况等。
- 科室与医生查询:浏览科室列表,按科室查看医生,查看医生简介和排班日期。
- 预约挂号:选择日期、时间段、医生,选择就诊宠物,提交预约。
- 预约记录管理:展示我预约的列表,支持取消预约(在未就诊前)。
- 医生端看板:医生查看自己名下的预约,标记就诊状态,填写诊断信息。
- 后台管理:科室/医生/排班的增删改查,预约总览。
如果你是做完整个项目的人,会发现这些功能恰好覆盖了一个小型诊所的日常运营场景:客户管理、宠物档案、医生资源、预约流转。没有做支付和在线问诊,但这反而降低了上手门槛,适合作为学习项目。
1.3 为什么选SpringBoot + 微信小程序这套组合
这个选型可以说是当前校园项目和中小企业内部工具的“标准答案”。SpringBoot胜在开发效率高,内嵌Tomcat,不用单独部署Web服务器,加上Spring Data JPA或MyBatis,单机跑起来非常省事。微信小程序则天然解决了“用户使用成本”的问题——不用下载App,扫码就能用,而且用户体系直接复用微信授权,省去了繁琐的手机号注册流程。
从学习价值来看,这个组合还有一个好处:前后端完全分离。小程序端是一个独立的工程,后端是另一个工程,两者只通过HTTP/HTTPS接口通信。练到的技能点包括RESTful API设计、JSON数据交互、Token鉴权、跨域处理、微信登录流程等,这些都是实际工作中非常通用的能力。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 后端设计思路:从分层到核心表结构
后端是整套系统的心脏。我拿到源码之后,第一件事就是看包结构和数据库脚本。常见问题有两个:包结构混乱,所有类塞在同一个包下;表字段缺失,连个创建时间都没有。这套系统的后端设计得比较规矩,适合作为模板来参考。
2.1 分层架构与包结构
源码里后端工程是标准的Maven结构,包名一般叫com.xxx.pet或者类似的。核心分层是这样的:
controller:只接收请求参数,调用service,返回统一结果集。service:写业务逻辑,比如创建预约时校验排班是否冲突、是否还有剩余号源。mapper或dao:数据库操作层,基于MyBatis或MyBatis-Plus。entity或domain:数据库实体映射。config:放配置类,包括跨域配置、MyBatis配置、微信相关配置。utils:工具类,比如JWT生成、时间格式化。common或common.result:统一返回结果封装。
个别项目为了省事,会在controller里直接写SQL,这种代码跑起来没毛病,但你要是拿它去答辩或者做二次开发,会很痛苦。规范分层的意义在于:改一个功能时,你清楚地知道去哪一层改。比如预约状态更新,controller只是入口,真正的状态判断逻辑在service层,数据库字段变更只动entity和mapper,三层互不干扰。
2.2 核心表结构设计
这套系统的表数量不算多,一般在7到10张之间。核心表有这些:
| 表名 | 作用 | 关键字段 |
|---|---|---|
| user | 用户表 | id, openid, nickname, avatar, phone |
| pet | 宠物档案表 | id, user_id, name, breed, age, gender, vaccine |
| department | 科室表 | id, name, description, status |
| doctor | 医生表 | id, department_id, name, title, intro, avatar, status |
| schedule | 排班表 | id, doctor_id, work_date, start_time, end_time, total_slots, remain_slots |
| appointment | 预约记录表 | id, appointment_no, user_id, pet_id, doctor_id, schedule_id, appointment_date, time_slot, status, remark |
重点理解schedule表和appointment表的关系:一个医生一天可以有多个排班,一个排班对应一个时间段,时间段里有剩余号源。用户预约时,不是直接插一条appointment就完事,而是要先检查remain_slots是否大于0,然后remain_slots减1,再插入预约记录。这两步必须放在一个事务里,否则并发请求下会出现“超卖”问题。
还有一张表不能忽略,就是time_slot相关设计。有的系统把时间段写死成“上午、下午、晚上”,有的做成每个排班多个时间段。这套系统更常见的是在schedule表里直接指定时间段,比如“2025-06-10 09:00-11:00”,每个排班的号源数就是该时段的放号数。设计不算复杂,但对理解业务足够用了。
2.3 登录态与鉴权
小程序登录这块,后端处理流程是这样的:小程序调用wx.login()拿到临时code,把code传给后端接口;后端再用code + AppID + AppSecret去微信接口服务换openid和session_key;拿到openid之后查user表,如果不存在就自动注册一个新用户,存在就直接登录;最后后端生成一个自定义登录态token返回给小程序,小程序后续所有请求都在header里带上这个token。
源码里token的实现方式可能有几种:有的是用JWT,有的是自己生成UUID存redis。如果是学习项目,大概率是JWT。你要注意JWT的过期时间配置,以及拦截器里如何从请求头解析token。我第一次看的时候以为很复杂,其实核心就三步:拦截器获取token → 解析openid/用户id → 放入ThreadLocal或request属性供业务方法使用。
2.4 预约挂号的并发控制
这是整个系统里最有含金量的地方,也是面试官最爱问的点。用户点击“提交预约”的一瞬间,如果5个人同时抢同一个医生的最后一个号,怎么保证不会超卖?
最简单的做法是用数据库行锁或乐观锁。比如执行更新SQL:update schedule set remain_slots = remain_slots - 1 where id = ? and remain_slots > 0,然后判断受影响行数,如果为0说明没有号了。这套系统如果用了MyBatis-Plus,可以在service层用UpdateWrapper带条件更新,或者直接在SQL里写死条件。把这个逻辑跑通之后,你可以再研究Redis分布式锁,但现阶段不需要。
3. 小程序端设计:用户看到的每一页都怎么来
小程序端是整个系统的门面,用户感知最直接。源码里的小程序项目一般是用原生微信小程序开发的,没有引入Vue或React,这意味着你不需要构建工具,微信开发者工具直接打开就能跑。下面我按页面维度说说每个核心页面的实现逻辑。
3.1 小程序目录结构与公共逻辑
小程序工程的典型结构是:
code复制pages/
index/
department/
doctor/
appointment/
my/
login/
record/
utils/
request.js
auth.js
app.js
app.json
utils/request.js是所有接口请求的统一封装。它会读取app.js中保存的baseURL,在请求头里带上token,对返回结果做统一处理,遇到401就跳转登录页。我在实际开发中也建议你保留这个封装,不要每个页面都直接写wx.request,否则改接口地址的时候会改到怀疑人生。
app.js里通常存着全局变量:baseURL、用户信息、token。小程序的wx.setStorageSync会把登录态持久化,下次冷启动时直接从本地读取,不用每次重新登录。
3.2 微信登录与用户信息授权
小程序首页第一次打开时,会判断本地有没有token,没有就弹出一个登录提示。点击登录后,走的是wx.login拿code,然后调用后端/api/user/login接口。需要注意,微信官方已经把wx.getUserProfile的授权弹窗改了,现在只能获取头像昵称填写能力,所以很多源码里会引导用户点击头像昵称进行“快捷填写”,再提交到后端更新用户信息。
如果你拿到源码后发现登录按钮调的是wx.getUserInfo,在小程序基础库2.27.1以上版本里会直接失败。解决办法就是改成“头像昵称填写能力”,具体是用button的open-type="chooseAvatar"和input的type="nickname"。这是源码运行视频里可能不会细讲但实际必踩的坑。
3.3 首页、科室医生与预约页面的联动
首页一般展示医院简介、轮播图、功能入口,以及推荐医生。点击某个科室入口,跳转到科室列表页;再点击某个科室,跳转到医生列表页,这时候会传一个departmentId过去。医生列表页不仅展示医生简介,还会直接显示这个医生未来几天的排班情况。怎么显示排班?通常是后端提供一个接口,根据医生id查询最近7天的schedule记录,小程序端把日期和剩余号源渲染成可点击的格子。
预约页是核心业务页面。它需要传入医生id,然后加载日期可选列表,点击某个日期后再加载该日期下的时间段,选择时间段后选择宠物,最后提交。整个交互过程涉及三个接口:查排班日期、查排班时段、提交预约。小程序端要注意的是,异步请求返回后需要setData更新界面,如果用户快速点击,会触发重复提交。源码里一般会用一个submitting标志位来防止重复点击。
3.4 预约记录与状态流转
“我的预约”页面展示当前用户的预约列表,每条记录里有宠物名、医生名、时间段、状态。状态一般包括:待就诊、已完成、已取消。用户可以在“待就诊”状态下点击取消。取消操作在业务上不只是把预约记录的状态改成“已取消”,还要把对应的排班号源remain_slots加回来。这个逻辑听起来简单,但很多同学会忘记,导致用户取消后号源没恢复。
医生端的小程序页面一般不是给医生用的,源码里更常见的是有一个单独的管理后台Web页面,或者医生也通过小程序的一个特定入口查看。如果你拿到源码只有一个用户端小程序,也没关系,这种项目通常会在后端预留医生角色接口,管理后台可能是简单的Vue页面,也可能只是一组接口加Swagger文档,看你手上的版本而定。
4. 从源码到跑起来的完整过程
源码跑不起来是很多人的痛点。我按自己实际操作顺序,把从下载源码到能演示完整流程的步骤写一遍。前提是你电脑上已经装好JDK、Maven、MySQL和微信开发者工具。如果没装,后面每一步都得卡住。
4.1 本地环境准备清单
- JDK 1.8或11。如果源码是SpringBoot 2.x,JDK8没问题;如果是SpringBoot 3.x,必须JDK17以上。我用这个项目时遇到过“源发行版17需要目标发行版17”的报错,就是因为本地默认识别成了JDK17,而项目指定的是8,后面会细说。
- Maven 3.6或以上。
- MySQL 5.7或8.0,建议8.0,字符集选utf8mb4。
- 微信开发者工具,稳定版即可。
- 选装:Navicat或DBeaver,用于导入数据库脚本。
- 选装:Redis。如果源码里用了Redis做缓存或token存储,那必须启动一个本地Redis服务;如果只是MySQL,就不需要。
4.2 后端配置修改要点
后端配置文件常见的是application.yml或application.properties,你需要改的核心配置主要有这几项:
yaml复制server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/pet_hospital?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
redis:
host: localhost
port: 6379
wx:
appid: 你的小程序AppID
secret: 你的小程序AppSecret
注意数据库连接串里的serverTimezone=Asia/Shanghai,不写的话MySQL 8会报时区错误。wx.appid和wx.secret需要去微信公众平台注册一个小程序账号获取。如果只是本地调试,AppID先用测试号也行,但登录功能会受限。
4.3 数据库初始化
源码包里一般会带一个sql文件夹,里面是数据库初始化脚本,比如pet_hospital.sql。用Navicat新建数据库,字符集选utf8mb4,然后运行SQL脚本。跑完之后检查一下表数量和核心数据:是否有管理员账号、是否有科室和医生数据。如果没有管理员账号,去user表手动插入一条角色为admin的记录。
检查数据非常重要,不然你小程序端打开科室列表是空的,会以为后端接口有问题。如果脚本里没有测试数据,建议自己补几条,方便演示。
4.4 后端启动顺序
先启动MySQL和Redis,然后在IDEA中打开后端工程。如果你是第一次导入Maven项目,等待依赖下载完成,这是一个漫长的过程。网络不好的话,建议用阿里云Maven镜像。
启动类通常在src/main/java下,类名类似PetHospitalApplication,右键运行。看到SpringBoot的启动日志和Tomcat started on port 8080,说明后端起来了。接着可以访问http://localhost:8080/或Swagger文档地址验证,如果配置了Knife4j,一般是/doc.html。
4.5 小程序导入与联调
微信开发者工具中“导入项目”,选择小程序前端目录,AppID如果用自己的就填自己的,如果只是体验就用测试号。有一个关键设置:在“详情-本地设置”里勾选“不校验合法域名、web-view(业务域名)、TLS版本以及HTTPS证书”。因为本地调试时,后端地址是http://localhost:8080,而微信默认要求小程序请求必须是HTTPS且域名备案。关闭校验后才能在开发者工具里正常请求。
然后在utils/request.js或app.js里把baseURL改成http://localhost:8080。如果你用的是真机调试,不能填localhost,要填电脑的局域网IP,比如http://192.168.1.5:8080,并且手机和电脑要在同一个Wi-Fi下,否则联调失败。
5. 实际运行踩坑记录与排查思路
这一部分是我最想写的。很多源码本身没问题,跑不起来纯粹是因为环境或配置细节。下面这些坑,我基本都踩过,按从高频到低频的顺序整理。
5.1 后端启动失败:端口、JDK版本、依赖下载
最常见的启动失败场景是IDEA里报Port 8080 was already in use,多半是本地某个进程占了8080端口。解决办法是改端口,或者找出占用进程并关闭。Windows下用netstat -ano | findstr 8080查PID,然后在任务管理器结束进程。
还有一类报错是java: 警告: 源发行版 17 需要目标发行版 17。这其实就是项目编译级别和JDK版本不匹配。如果你本地安装的是JDK17,而项目里面pom.xml的java.version是1.8,IDEA会按项目配置编译,但其他模块的SDK可能还是17。解决方式是:Project Structure里把Project SDK和Modules的Language Level都改成8,Settings里把Java Compiler的Target bytecode version也改成8。如果你装的本来就是JDK8,基本不会遇到。
Maven依赖下载失败是另一个常见问题。看到Cannot resolve ...多半是网络源问题。在settings.xml里配置阿里云镜像:
xml复制<mirror>
<id>aliyunmaven</id>
<url>https://maven.aliyun.com/repository/public</url>
<mirrorOf>central</mirrorOf>
</mirror>
配置完重新刷新Maven项目,能解决90%的依赖下载问题。
5.2 数据库连接失败与字符集问题
如果启动时日志报Access denied for user 'root'@'localhost',就是数据库账号密码不对。检查application.yml里的用户名密码,不要和本地MySQL实际密码搞混。
另一个典型问题是SQL脚本导入时报错或导入后中文乱码。这个跟文件编码有关,建议用Navicat导入之前先把SQL文件用UTF-8编码保存;导入时数据库字符集选utf8mb4,否则中文数据会变成问号。
5.3 小程序请求500/404排查链路
小程序控制台报request:fail或者后端接口返回500、404,是最让人头大的。我按这个顺序排查:先看后端控制台有没有异常堆栈,如果有,根据异常提示定位,通常是SQL语句错误或空指针,用Postman直接调一下接口看看请求参数是不是对得上。如果控制台没有日志,那就是请求根本没到后端,检查baseURL是否正确、开发者工具是否勾选了不校验域名。注意request:fail也可能是跨域问题,但小程序不是浏览器,不存在浏览器跨域限制,只要后端设置了CorsFilter或@CrossOrigin即可,实际上小程序端不受CORS限制,主要问题是域名校验。
404的话,要看路径是否匹配。后端Controller里的@RequestMapping路径、小程序请求的URL路径以及server.servlet.context-path,三者必须一致。如果项目设置了context-path: /api,那请求必须写成http://localhost:8080/api/user/login。
5.4 真机调试时的局域网IP坑
开发者工具里跑通了,真机一调试就废。最常见原因是真机上无法访问电脑上的localhost。把请求地址改成局域网IP后仍然不行,先排查电脑防火墙是否放行了8080端口。Windows系统需要添加入站规则,允许Tomcat或Java进程访问。再排查手机和电脑是否在同一网段,有的公司网络AP隔离,设备之间不能互访,那就只能换成云服务器或用ngrok内网穿透,但这不在本项目范围内。
5.5 微信登录失败:code无效或AppID不匹配
报invalid code或appid mismatch,大概率是前端AppID和后端配置的AppID不一致。同一个小程序项目,微信开发者工具里导入时的AppID,和后端application.yml里的wx.appid必须是同一个。如果你用的是测试号,后端却配了正式小程序的AppSecret,必然失败。另外,wx.login生成的code只能使用一次,且有效期很短,不要在调试时手动重复提交同一个code。
再补充一个点:很多人在本地没有注册小程序,只是用测试号,但后端调用微信接口需要真实AppID和AppSecret,否则登录流程走不通。一个变通办法是代码里把登录接口改成“允许模拟登录”,即前端传一个固定的手机号或用户名,后端直接返回一个测试token。这种做法不推荐上线,但用于本地演示已经完全够用。
6. 拿到源码后如何二次开发和扩展
源码只是起点,不是终点。如果你有答辩展示、项目完善或上线部署的需求,下面的扩展方向可以优先考虑。
6.1 功能扩展建议:从“能用”到“好用”
当前系统的预约流程是单科室挂号的逻辑。你可以在此基础上加一个“医生排班管理”的后台页面,让管理员可以批量生成一周的排班,而不是手动逐条插入。排班生成可以设计成:选择医生、选择日期区间、选择时间段、设置号源数,一键生成多天记录。这个功能能提升系统的完整度,同时也是答辩时很好的展示点。
另一个值得加的是“就诊评价”。在预约状态变成“已完成”后,用户可以对该次就诊进行评价和打分。数据上需要新增一张评价表,关联预约记录,前端在预约详情页加一个评价入口。加了评价之后,系统闭环就从“预约-就诊”延伸到了“反馈”,业务上更自然。
6.2 接入微信支付:预约挂号费在线支付
如果想让系统具备真实落地能力,支付是绕不开的。微信支付接入流程大概是:小程序端调用wx.requestPayment,后端先调用微信统一下单API生成预支付单,返回给前端五个参数,前端调起支付,支付成功后微信服务器回调后端通知接口,后端再更新预约状态。
支付很考验你的耐心,因为涉及到商户号、API密钥、证书等一堆东西,如果没有商户号,本地只能调模拟支付。对学习项目来说,可以先把支付回调接口写好,前端用假支付按钮模拟,等到真条件时再切换密钥。
6.3 消息订阅通知:预约提醒与就诊提醒
微信小程序的订阅消息功能非常适合这个场景:预约成功后,向用户发送一条“挂号成功通知”;就诊前一天,再发送一条“就诊提醒”。后端需要对接微信的subscribeMessage.send接口,获取用户的openid和模板ID。这个功能对用户体验提升非常大,而且技术实现并不复杂,前端在预约按钮点击时先请求wx.requestSubscribeMessage弹出授权,后端保存用户的订阅记录即可。
要注意的是,订阅消息一次授权只能发送一次,且用户每次触发时都要再申请。所以前端要在用户每次预约时都弹一次订阅授权,而不是只在注册时弹一次。
6.4 上线部署注意事项:域名、HTTPS与备案
本地跑通只是第一步。真要部署上线,有几个硬性门槛:后端要部署在云服务器,比如阿里云或腾讯云,使用java -jar启动,或者用Docker容器化;数据库和Redis也要迁移到服务器;小程序端请求地址要改成已备案的HTTPS域名,微信公众平台需要配置request合法域名,并且域名必须支持HTTPS。
如果你用的是SpringBoot内置Tomcat,直接打包成jar运行最省事。打包命令是mvn clean package -DskipTests,生成target目录下的jar文件,上传服务器后用nohup java -jar pet-hospital.jar &启动。如果想要更稳定,可以用systemd服务托管,但学习项目先用nohup就行。
部署这块还有一个容易被忽略的点:数据库数据迁移时,要把本地MySQL的字符集和时区也保持一致,否则线上会出现中文乱码和日期偏移。我的习惯是先用mysqldump导出,再在服务器上用source命令导入,导入后立刻查几条带中文的数据,确认无乱码再做下一步。
回到开头说的那个问题:源码能不能跑起来,关键不在于代码本身,而在于你是否理解它背后的业务和设计。这套宠物医院系统最好的学习方式是先把流程走通,再尝试改一个功能,比如把固定号源改成可以配置的,或者加一个“我的宠物”编辑页面。改通一个功能,你就真正掌握这套技术栈了。如果只是照着运行视频点一遍,那只能叫“看过”,不能叫“会做”。我始终觉得,项目源码是老师,运行视频是辅助,而你自己动手改代码的那几个小时,才是真正进步的时候。
