尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

SpringBoot+Thymeleaf+MySQL宠物医院管理系统实战

SpringBoot+Thymeleaf+MySQL宠物医院管理系统实战 简介本资源是一套基于SpringBoot开发的宠物医院管理系统完整项目面向计算机专业本科生毕业设计、Java初学者及中小型宠物医疗机构的技术人员旨在解决宠物诊疗服务数字化管理难题覆盖用户注册登录、医生排班、宠物档案、健康监测、预约挂号等核心业务场景。压缩包共2个文件1个SQL数据库脚本用于初始化MySQL数据1个7z项目源码包含前后端完整代码总大小54.1MB结构清晰、开箱即用。已有99人学习下载适合快速部署演示或二次开发。读者可直接导入数据库并运行SpringBoot后端配合ThymeleafHTML/CSS/JS前端实现全功能访问系统已集成角色权限管理、用户与医生双端模块、日常健康记录及疫苗接种追踪等实用功能代码规范、注释完整是理解企业级Java Web系统分层架构与宠物行业信息化落地的优质实践案例。1. 这不是又一个CRUD毕设它用SpringBootMySQL真实跑通了宠物医院“人-宠-医-约-健”五维闭环你可能已经点开过十几个标着“SpringBoot宠物医院管理系统”的压缩包解压后发现只有半截登录页、空荡荡的/admin路由、连数据库都连不上的application.yml——这不是教学演示是真实部署场景下能立刻接手运维的完整系统。它不依赖Vue或React前端工程而是基于Thymeleaf模板引擎直出HTML所有页面含医生排班表、预约日历、健康趋势图全部由后端渲染规避了前后端分离带来的跨域、token续期、静态资源托管等新手高频卡点。项目自带phms.sql建库脚本执行后即生成12张表从pet_info含品种、绝育状态、芯片号、vaccination_record疫苗名称、厂商、有效期、appointment含时段锁定、医生ID、状态机待确认/已就诊/已取消到health_monitoring体重、体温、便便性状、异常标记。它解决的不是“怎么写Controller”而是“如何让兽医在早高峰30秒内完成一只布偶猫的复诊登记驱虫开单下次体检提醒”。适合Java初学者做毕设答辩也适合刚转岗的后端工程师练手真实业务建模——因为它的每张表字段设计都带着临床逻辑比如appointment表里没有简单的status VARCHAR(20)而是拆成appointment_status TINYINT0待确认,1已就诊,2已取消,3爽约cancel_reason VARCHAR(100)仅当status2/3时必填这种细节才是企业级系统和课程Demo的本质分水岭。2. ThymeleafSpringBoot双渲染模式为什么放弃Vue而选择服务端模板2.1 Thymeleaf不是过时技术而是降低交付风险的务实选择当前主流毕设项目常陷入“前端太重、后端太轻”的失衡学生花两周配Vue环境却在axios跨域403上卡三天而本系统采用Thymeleaf 3.1.x其核心优势在于零构建步骤、天然防XSS、模板即静态HTML。所有.html文件放在src/main/resources/templates/下无需npm run dev启动SpringBoot应用后直接通过http://localhost:8080/login访问。关键在于Thymeleaf的th:fragment复用机制——layout.html中定义header th:fragmentheader所有子页面用div th:replace~{layout :: header}/div引入修改导航栏只需改一处。对比Vue的router-view这里没有路由守卫、没有Vuex状态同步、没有v-if嵌套导致的DOM重绘性能问题。对于宠物医院这种强表单、弱交互的场景90%操作是增删改查PDF导出服务端渲染反而更稳。2.2 实现医生排班动态渲染从数据库到HTML的完整链路医生排班模块需展示7天×3时段上午/下午/夜间的可预约状态且支持管理员手动调整。实现逻辑如下数据库表doctor_schedule包含字段doctor_id,work_date DATE,time_slot TINYINT1上午,2下午,3夜间,is_available BOOLEAN,max_appointments TINYINTController层GetMapping(/schedule/{date}) ResponseBody public ListDoctorScheduleVO getScheduleByDate(PathVariable(date) String dateStr) { LocalDate date LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(yyyy-MM-dd)); return scheduleService.getScheduleForDate(date); }Thymeleaf模板中循环渲染div classschedule-grid th:eachday,iter : ${weekDays} h3 th:text${#dates.format(day,MM/dd E)}/h3 div classtime-slots div classslot th:eachslot : ${timeSlots} th:classappend${scheduleMap[day_slot]?.isAvailable} ? available : unavailable th:text${slot 1} ? 上午 : (${slot 2} ? 下午 : 夜间) /div /div /div提示scheduleMap是Controller中预处理的MapString, DoctorScheduleVOkey为2024-05-20_1避免模板中多次查询数据库。这是Thymeleaf性能优化的关键技巧——绝不允许在th:each循环内调用Service方法。2.3 登录态与权限控制基于Spring Security的RBAC落地系统角色分为ADMIN(超级管理员)、DOCTOR(执业兽医)、NURSE(助理)、OWNER(宠物主人)权限粒度精确到按钮级。例如OWNER只能看到自己宠物的/pet/list不能访问/doctor/listDOCTOR可编辑/health-monitoring/{id}/update但不可删除/vaccination-record/{id}/delete实现方式自定义UserDetailsServiceImpl加载用户时将角色和权限列表一并注入SimpleGrantedAuthorityListGrantedAuthority authorities userRoles.stream() .map(role - new SimpleGrantedAuthority(ROLE_ role.getRoleName())) .collect(Collectors.toList()); // 同时加载按钮权限如 btn:appointment:cancel userPermissions.stream() .map(p - new SimpleGrantedAuthority(p.getPermissionCode())) .forEach(authorities::add);在Thymeleaf中使用sec:authorize控制元素显隐!-- 只有ADMIN和DOCTOR能看到预约取消按钮 -- button typebutton sec:authorizehasAnyAuthority(btn:appointment:cancel) th:onclickcancelAppointment(${appt.id}) 取消预约 /button注意sec:authorize必须配合thymeleaf-extras-springsecurity6依赖非旧版5否则在SpringBoot 3.x中会报NoClassDefFoundError。本项目已适配SpringBoot 2.7.18兼容JDK 8和3.1.12需JDK 17具体版本见pom.xml中的spring-boot.version。3. MySQL数据库深度建模从宠物档案到健康趋势分析的12张表设计3.1 核心实体关系为什么pet_info不直接关联owner_id常见错误设计是pet_info.owner_id外键直连user_info.id但这会导致无法处理“多主一宠”如夫妻共同养猫或“一主多宠”同一用户养狗猫仓鼠场景。本系统采用中间表pet_owner_relation字段类型说明idBIGINT PK主键pet_idBIGINT FK指向pet_info.idowner_idBIGINT FK指向user_info.idrelation_typeTINYINT1主人,2监护人,3临时看护is_primaryBOOLEAN是否为主要联系人此设计使pet_info表保持纯净只存宠物生物属性而关系逻辑交由中间表管理。查询某用户所有宠物时SELECT p.* FROM pet_info p JOIN pet_owner_relation por ON p.id por.pet_id WHERE por.owner_id ? AND por.is_primary 1;3.2 健康监测数据的时序存储与聚合查询health_monitoring表记录宠物每日健康快照关键字段pet_id外键record_date DATE日期非DATETIME因每日只记一次weight DECIMAL(5,2)体重kgtemperature DECIMAL(4,1)体温℃stool_condition ENUM(normal,soft,diarrhea,constipation)便便性状用ENUM而非VARCHAR节省空间且防脏数据abnormal_flag TINYINT异常标记0正常,1需关注,2紧急要生成“布偶猫‘雪球’近30天体重趋势图”后端执行SELECT record_date, weight FROM health_monitoring WHERE pet_id ? AND record_date DATE_SUB(CURDATE(), INTERVAL 30 DAY) ORDER BY record_date;提示stool_condition字段在Java实体类中映射为StoolConditionEnum枚举MyBatis自动完成字符串↔枚举转换避免switch-case硬编码。3.3 预约系统的并发控制防止同一时段被重复预约appointment表中time_slot字段仅表示“上午/下午/夜间”实际时段由start_time和end_time精确到分钟字段类型示例start_timeTIME09:00:00end_timeTIME09:30:00doctor_idBIGINT1001work_dateDATE2024-05-20为防止并发预约冲突插入前执行校验SQLSELECT COUNT(*) FROM appointment WHERE doctor_id ? AND work_date ? AND ( (? BETWEEN start_time AND end_time) OR (? BETWEEN start_time AND end_time) OR (start_time BETWEEN ? AND ?) OR (end_time BETWEEN ? AND ?) ) AND status IN (0,1); -- 排除已取消的预约参数按顺序传入start_time, end_time, start_time, end_time, start_time, end_time。此SQL覆盖所有时间重叠场景A完全在B内、B完全在A内、A左重叠B、A右重叠B。4. 从零部署三步启动可运行的宠物医院管理系统4.1 环境准备与数据库初始化必备组件JDK 8u2XX 或 JDK 17根据pom.xml中java.version确定MySQL 5.7推荐8.0.33已验证兼容Maven 3.6IDEIntelliJ IDEA推荐对SpringBoot支持最佳数据库初始化步骤创建数据库CREATE DATABASE phms CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;执行phms.sqlmysql -u root -p phms phms.sql验证关键表数据-- 检查默认管理员账号用户名admin密码123456 SELECT username, password, role_name FROM user_info u JOIN user_role ur ON u.idur.user_id JOIN role r ON ur.role_idr.id WHERE u.usernameadmin; -- 检查测试宠物数据 SELECT p.name, p.breed, o.username FROM pet_info p JOIN pet_owner_relation por ON p.idpor.pet_id JOIN user_info o ON por.owner_ido.id LIMIT 3;4.2 SpringBoot配置文件详解application.yml中需修改的三项spring: datasource: url: jdbc:mysql://localhost:3306/phms?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: root password: your_mysql_password # ← 必须修改 thymeleaf: cache: false # 开发时关闭模板缓存修改HTML立即生效 enabled: true prefix: classpath:/templates/ suffix: .html encoding: UTF-8 servlet: content-type: text/html注意serverTimezoneAsia/Shanghai是MySQL 8.0必需参数缺失会导致java.sql.SQLException: The server time zone value XXX is unrecognized错误。4.3 启动与首次访问验证在IDE中右键PhmsApplication.java→Run PhmsApplication观察控制台输出出现Tomcat started on port(s): 8080表示Web容器启动成功出现Started PhmsApplication in X.XXX seconds表示Spring上下文加载完成浏览器访问http://localhost:8080/login→ 输入admin/123456登录后台http://localhost:8080/register→ 注册普通用户邮箱需真实用于后续密码找回http://localhost:8080/pet/add→ 添加宠物时检查品种下拉框是否加载breed_dict字典表数据若登录后跳转/admin/dashboard但页面空白请检查浏览器控制台若报Failed to load resource: the server responded with a status of 404 ()说明Thymeleaf模板路径错误确认templates/admin/dashboard.html存在且无拼写错误若报Uncaught ReferenceError: $ is not defined说明jQuery未加载检查templates/layout.html中script src/js/jquery.min.js/script路径是否正确静态资源在src/main/resources/static/js/5. 生产级增强添加健康数据可视化与预约超时自动释放5.1 用Chart.js绘制宠物健康趋势图系统在/pet/detail/{id}页面嵌入体重/体温双Y轴折线图。实现步骤在static/js/chart.min.js引入Chart.js 4.4.0已内置HTML中定义画布canvas idhealthChart height200/canvasJavaScript中动态渲染// 从Thymeleaf模型获取JSON数据 const healthData JSON.parse([[${healthJson}]]); // 后端Controller中model.addAttribute(healthJson, objectMapper.writeValueAsString(list)); new Chart(document.getElementById(healthChart), { type: line, data: { labels: healthData.map(d d.recordDate), datasets: [{ label: 体重(kg), data: healthData.map(d d.weight), borderColor: rgb(75, 192, 192), tension: 0.1 }, { label: 体温(℃), data: healthData.map(d d.temperature), borderColor: rgb(255, 99, 132), yAxisID: y1, tension: 0.1 }] }, options: { responsive: true, scales: { y: { beginAtZero: true }, y1: { position: right, beginAtZero: true } } } });提示healthJson由Controller中ObjectMapper序列化避免前端用JSON.stringify()二次处理减少XSS风险。5.2 预约超时自动释放用Spring Boot Scheduler实现未支付的预约需在30分钟内释放时段避免资源锁定。实现方案在application.yml启用定时任务spring: task: scheduling: enabled: true创建调度类Component public class AppointmentScheduler { Scheduled(fixedRate 300000) // 每5分钟执行一次 public void releaseTimeoutAppointments() { LocalDateTime now LocalDateTime.now(); LocalDateTime timeoutThreshold now.minusMinutes(30); // 查找创建超30分钟且未支付的预约 ListAppointment timeoutList appointmentMapper.selectTimeoutAppointments(timeoutThreshold); for (Appointment appt : timeoutList) { // 更新状态为已取消并记录原因 appt.setStatus(AppointmentStatus.CANCELLED); appt.setCancelReason(超时未支付自动释放); appointmentMapper.updateById(appt); // 发送短信/邮件通知此处省略集成代码 System.out.println(Released appointment ID: appt.getId()); } } }对应的MyBatis XMLselect idselectTimeoutAppointments resultTypeAppointment SELECT * FROM appointment WHERE create_time lt; #{timeoutThreshold} AND status 0 -- 0待确认即未支付 AND payment_status 0 -- 0未支付 /select注意Scheduled在SpringBoot中默认使用单线程池若任务执行时间超过fixedRate间隔下次执行会被延迟。生产环境建议配置线程池EnableSchedulingTaskSchedulerBean。5.3 关键参数调优表应对高并发预约场景当宠物医院日预约量超500单时需调整以下参数参数位置默认值建议值说明spring.servlet.session.timeoutapplication.yml1800秒3600秒延长用户会话避免频繁重新登录spring.datasource.hikari.maximum-pool-sizeapplication.yml1020HikariCP连接池最大连接数server.tomcat.max-connectionsapplication.yml819216384Tomcat最大连接数mybatis.configuration.default-statement-timeoutapplication.ymlnull30MyBatis SQL执行超时秒logging.level.com.phms.mapperDEBUGapplication.ymlINFODEBUG开发期开启SQL日志上线前改为INFO修改后重启应用用jmeter模拟100并发用户提交预约请求观察actuator/metrics/jvm.memory.used和actuator/metrics/http.server.requests指标确保95%响应时间1.5秒。本文还有配套的精品资源点击获取
返回列表