Java宠物管理系统实战:从数据库设计到定时任务与权限控制
2026/9/23 23:13:57 网站建设 项目流程

简介:这是一套面向高校计算机专业毕业设计场景的Java宠物管理系统完整实现方案,适合正在准备毕设或需要Java Web项目实战练手的同学。系统采用前后台分离设计,前台支持用户注册登录、商品查找与类别导航,后台由管理员完成订单、商品、公告、会员、用户及个人信息维护等核心功能,并重点设计了五张关键数据表。资源包共14个文件,约132.62MB,包含4段mp4项目辅导视频、3份doc论文与任务书文档、1份pptx答辩演示、1个zip源码包、1个sql数据库脚本及配套截图与说明文件,覆盖从数据库创建、项目部署到前后台模块实现的全流程。目前已有267人学习下载。借助源码、录屏与论文资料,读者可快速理解系统架构与业务逻辑,对照视频完成环境搭建与功能调试,并参考文档整理出符合规范的毕业设计成果。

1. 从一份 .rar 说起:宠物管理系统到底在解决什么问题

宠物医院前台还在用 Excel 记病历,宠物店老板靠微信群接预约,寄养客户想知道自家猫今天吃没吃饭只能打电话问——这类场景我见过太多。基于 JAVA 的宠物管理系统,本质就是把「宠物档案、主人信息、预约就诊、寄养记录、疫苗提醒」这几件事从散落的表格和聊天记录里收拢到一个后台,用数据库保证数据不丢、用权限保证不同角色看到不同内容。它适合三类人:一是做 Java 课程设计或毕业设计的学生,需要一套能跑通、能讲清楚、能写进论文的完整项目;二是中小型宠物门店的经营者,想低成本搭一个内部管理工具;三是刚学完 Java 基础、想找一个真实 CRUD 项目练手的开发者。这个标题背后其实包含四样东西:可运行的源码、配套视频、数据库脚本、以及一篇论文。四者缺一不可,因为光有代码讲不清设计思路,光有论文又落不了地。接下来我按「先跑起来、再改得动、最后讲得出」的顺序,把这条路走一遍。

2. 技术选型与数据库设计:为什么这套组合最稳

2.1 后端为什么选 Spring Boot 而不是纯 Servlet

很多人一看「Java 课程设计」就默认用 JSP + Servlet,理由是「老师只教了这个」。但真做起来你会发现,纯 Servlet 要手写大量重复的 JDBC 连接、事务提交、参数解析代码,一个宠物档案的增删改查就能写两百行,最后论文里全是样板代码,答辩时老师问「你的分层设计在哪」你答不上来。我一般会选 Spring Boot + MyBatis,原因很实际:Spring Boot 内置 Tomcat,一个 main 方法就能启动,省掉配置 web.xml 的玄学;MyBatis 把 SQL 写在 XML 或注解里,宠物表字段改了只改一处;再加上 Spring MVC 的注解,一个 Controller 方法对应一个接口,论文里的「系统架构图」能画得清清楚楚。

选型不是越新越好。有人上来就上 Spring Cloud 微服务,结果一个宠物店管理系统拆出五个服务,本地跑都跑不起来,这就是典型的过度设计。单体应用对这类项目完全够用,部署一台服务器、一个 jar 包、一个数据库,运维成本几乎为零。

2.2 数据库表怎么设计才不会被论文答辩挑刺

数据库是这套系统的地基,也是论文里最容易被追问的部分。我见过太多人只建一张pet表,主人信息、就诊记录全塞进去,字段冗余到爆炸。正确的做法是按实体拆表,至少包含下面这几张核心表。

表名作用关键字段
user系统登录用户(管理员/店员/医生)id, username, password, role
owner宠物主人id, name, phone, address
pet宠物档案id, owner_id, name, species, breed, birth_date
appointment预约就诊id, pet_id, doctor_id, appoint_time, status
medical_record病历记录id, pet_id, diagnosis, prescription, visit_time
vaccine疫苗接种记录id, pet_id, vaccine_name, next_date

建表时有两个细节必须注意。第一,pet表的owner_id要加外键约束指向owner.id,这样删除主人时不会留下孤儿宠物记录,论文里可以写「保证参照完整性」。第二,appointment.status用枚举值(0 待确认、1 已确认、2 已完成、3 已取消),不要用中文直接存,否则后期做统计查询时排序会乱。

CREATE TABLE pet ( id INT PRIMARY KEY AUTO_INCREMENT, owner_id INT NOT NULL, name VARCHAR(50) NOT NULL, species VARCHAR(20) COMMENT '猫/狗/其他', breed VARCHAR(50), birth_date DATE, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_pet_owner FOREIGN KEY (owner_id) REFERENCES owner(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

这段建表语句里,AUTO_INCREMENT让主键自增省去手动赋值,utf8mb4是为了存宠物名字里的生僻字和 emoji(真有客户给猫起名叫「🐱」),ENGINE=InnoDB是必须的,因为只有它支持外键和事务。如果你用的是 MySQL 5.7 以下版本,DEFAULT CURRENT_TIMESTAMP在 DATETIME 上可能不生效,改成 TIMESTAMP 或者升级版本。

2.3 从零把项目跑起来的最小步骤

拿到源码压缩包后,别急着双击运行,按下面顺序来能少踩一半坑。

第一步,确认本地 Java 环境。命令行执行java -version,看到 1.8 或以上即可。没有的话去装 JDK,配好JAVA_HOMEPATH,这是所有 Java 项目的前提,环境变量配错后面全是报错。

第二步,导入数据库。用 Navicat 或命令行把pet_system.sql执行一遍,确认六张表都建出来了。命令行方式如下:

mysql -u root -p # 输入密码后 CREATE DATABASE pet_system DEFAULT CHARSET utf8mb4; USE pet_system; SOURCE /你的路径/pet_system.sql; SHOW TABLES;

SOURCE后面跟的是 sql 文件的绝对路径,Windows 下路径用正斜杠或双反斜杠,单反斜杠会被当成转义符。执行完SHOW TABLES能看到六张表就说明导入成功。

第三步,改配置文件。打开application.yml,把数据库连接改成你自己的:

spring: datasource: url: jdbc:mysql://localhost:3306/pet_system?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver

serverTimezone=Asia/Shanghai这个参数不加,MySQL 8 会报时区错误,这是血泪经验。characterEncoding=utf8保证中文不乱码。

第四步,启动项目。在 IDEA 里找到主启动类,右键 Run,控制台出现Started Application in x seconds就成功了,浏览器访问http://localhost:8080即可。

3. 核心功能实现:增删改查之外的真实业务逻辑

3.1 宠物档案管理:一个接口要处理多少种情况

宠物档案看着简单,实际写起来要考虑的边界不少。新增宠物时,主人可能还没录入,所以前端要先选主人或现场新建;宠物品种如果是「其他」,要允许手动输入;出生日期选未来日期要拦截。这些校验放在后端做,前端校验只是体验优化,不能当安全防线。

下面是一个新增宠物的 Controller 方法,用 Spring Boot 的注解方式:

@PostMapping("/pet/add") public Result addPet(@RequestBody Pet pet) { // 校验必填字段 if (pet.getOwnerId() == null || pet.getName() == null) { return Result.error("主人和宠物名不能为空"); } // 校验出生日期不能晚于今天 if (pet.getBirthDate() != null && pet.getBirthDate().after(new Date())) { return Result.error("出生日期不能是未来"); } petService.save(pet); return Result.success(); }

@RequestBody表示接收 JSON 格式的请求体,前端用 axios 发 POST 时Content-Type要设成application/json,否则会报 415 错误。Result是我自己封装的统一返回类,包含 code、msg、data 三个字段,这样前端处理响应时逻辑统一,论文里也能体现「统一响应格式」的设计。

查询列表时不要SELECT *,宠物表字段多了以后性能会下降,而且把主人 ID 直接返回给前端,前端还得再查一次主人名字。正确做法是用 JOIN 一次查出来:

SELECT p.id, p.name, p.species, p.breed, o.name AS ownerName, o.phone FROM pet p LEFT JOIN owner o ON p.owner_id = o.id WHERE p.name LIKE CONCAT('%', #{keyword}, '%') ORDER BY p.create_time DESC;

LEFT JOIN而不是INNER JOIN,是因为万一主人记录被误删,宠物档案还能查出来,方便排查数据问题。CONCAT('%', #{keyword}, '%')是 MyBatis 的模糊查询写法,#{}是预编译占位符,能防 SQL 注入,千万别用${}拼接字符串。

3.2 预约与疫苗提醒:定时任务怎么写才不翻车

预约功能的核心不是存一条记录,而是状态流转和提醒。客户预约后状态是「待确认」,店员确认后变「已确认」,就诊完变「已完成」。每次状态变更都要记录操作时间,方便追溯。

疫苗提醒更实用。宠物打完疫苗后,下次接种日期通常是 21 天或一年后,系统要能自动提醒。用 Spring 的@Scheduled注解做定时任务:

@Scheduled(cron = "0 0 8 * * ?") public void vaccineRemind() { // 每天早上8点执行,查出7天内需要接种的宠物 List<Vaccine> list = vaccineMapper.findUpcoming(7); for (Vaccine v : list) { // 给主人发短信或站内信 messageService.send(v.getOwnerPhone(), "您的宠物该打疫苗了"); } }

cron = "0 0 8 * * ?"表示每天 8 点整执行,六个字段依次是秒、分、时、日、月、周。这里有个坑:定时任务默认是单线程的,如果发送短信很慢,会阻塞后面的任务。生产环境要配线程池,在配置类里加@EnableScheduling并自定义TaskScheduler,把池大小设成 5 到 10。

findUpcoming(7)对应的 SQL 要处理日期边界:

SELECT v.*, o.phone AS ownerPhone FROM vaccine v JOIN pet p ON v.pet_id = p.id JOIN owner o ON p.owner_id = o.id WHERE v.next_date BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 7 DAY) AND v.reminded = 0;

reminded字段是后悔药,防止同一条记录被重复提醒。发完短信后把它置为 1,第二天就不会再查出来。这个字段设计论文里可以写成「幂等性保证」,答辩时是个加分项。

3.3 权限控制:三种角色看到的东西必须不一样

系统里有管理员、店员、医生三种角色。管理员能管用户和所有数据,店员只能管宠物和预约,医生只能看自己的预约和病历。用 Spring Security 或简单的拦截器都能实现,课程设计级别用拦截器更轻量。

核心思路是在登录成功后把角色写进 Session 或 JWT,每次请求拦截器校验当前路径是否在角色允许列表里:

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String role = (String) request.getSession().getAttribute("role"); String uri = request.getRequestURI(); // 医生不能访问用户管理接口 if (uri.startsWith("/user/") && !"admin".equals(role)) { response.setStatus(403); return false; } return true; }

这里要注意,拦截器要排除登录接口和静态资源,否则登录页都打不开。在WebMvcConfigurer里用excludePathPatterns("/login", "/css/**", "/js/**")配置。另外,前端菜单也要根据角色动态渲染,不然医生看到「用户管理」菜单点进去报 403,体验很差。

4. 避坑与排查:那些让我加班到凌晨的问题

4.1 中文乱码:从数据库到浏览器要过几道关

现象:宠物名字存进去是「??」,或者页面显示「å® ç‰©」。原因:字符集在数据库、连接、页面三个环节中有一环没统一。解决:数据库建库时用utf8mb4,连接 URL 加characterEncoding=utf8,前端 HTML 加<meta charset="UTF-8">,Tomcat 的server.xmlConnectorURIEncoding="UTF-8"。四处都对齐,乱码基本绝迹。

4.2 外键约束导致删除失败

现象:删除主人时报Cannot delete or update a parent row。原因:pet表有外键指向owner,主人还有宠物时不能直接删。解决:要么先删宠物再删主人,要么把外键设成ON DELETE CASCADE级联删除。我一般选前者,因为级联删除太危险,误删主人会连带删掉所有宠物病历,数据没了哭都来不及。

4.3 定时任务在服务器上不执行

现象:本地测试提醒正常,部署到服务器后一条短信都没发。原因:服务器时区是 UTC,cron 表达式按 UTC 时间跑,8 点变成了北京时间 16 点。解决:启动 jar 时加-Duser.timezone=Asia/Shanghai,或者在application.yml里配spring.jackson.time-zone和 JVM 参数。这个坑很隐蔽,日志里任务确实执行了,只是时间不对。

4.4 分页查询总数不对

现象:列表显示共 100 条,翻到第 3 页就没数据了。原因:分页 SQL 的LIMIT算错,或者 count 查询带了 JOIN 导致数量翻倍。解决:count 语句单独写,不要和列表查询共用;LIMIT的偏移量是(pageNum - 1) * pageSize,pageNum 从 1 开始而不是 0。用 PageHelper 插件能省掉手写,但要注意它只对紧跟其后的第一条查询生效。

4.5 论文查重率过高

现象:论文提交后查重 40%,全是代码和通用描述。原因:直接复制网上的系统设计章节,或者把代码原样贴进论文。解决:架构图自己画,数据库表说明用自己的话描述,代码只贴核心片段并加注释说明设计意图。论文框架按「需求分析→总体设计→详细设计→实现→测试」走,每章结合自己的项目写,查重自然降下来。

5. 进阶技巧:让这套系统从「能跑」到「能讲」

5.1 用接口文档工具把论文的「接口设计」章节填满

论文里有一章叫「系统接口设计」,很多人不知道写什么。用 Swagger 或 Knife4j 自动生成接口文档,每个接口的路径、参数、返回值一目了然,截图放进论文既专业又省事。集成方式很简单,加依赖后写个配置类:

@Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket docket() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(new ApiInfoBuilder().title("宠物管理系统接口文档").version("1.0").build()) .select() .apis(RequestHandlerSelectors.basePackage("com.pet.controller")) .paths(PathSelectors.any()) .build(); } }

启动后访问http://localhost:8080/doc.html,所有接口按 Controller 分组展示。basePackage要填你自己的 controller 包路径,填错了文档是空的。这个工具还能直接发请求测试,联调时不用等前端。

5.2 数据库备份与恢复:答辩前一定要做的事

答辩前一天数据库崩了,这种事我见过不止一次。养成习惯,改完数据先导出:

mysqldump -u root -p pet_system > pet_system_backup.sql

恢复时:

mysql -u root -p pet_system < pet_system_backup.sql

mysqldump导出的文件包含建表和插入语句,换台电脑也能一键还原。如果数据量大,加--single-transaction参数避免锁表。这个操作写进论文的「系统部署」章节,能体现你有运维意识。

5.3 视频和源码怎么配合看才高效

配套视频不要从头看到尾,那样太慢。我的习惯是:先自己把项目跑起来,遇到报错再定位到视频里对应的章节看。比如数据库连不上,就跳到「环境配置」那一段;某个功能不理解,就跳到「核心代码讲解」。视频的价值在于演示操作步骤和调试过程,这些是文字教程替代不了的。源码则要对照着改,比如把宠物品种的枚举值换成你自己定义的,改完跑一遍,确认没问题再继续。

5.4 一个验证系统是否真的可用的方法

别只看页面能打开就以为成功了。做一轮完整业务流:新建主人 → 给主人加两只宠物 → 预约明天的就诊 → 医生登录看到预约 → 完成就诊写病历 → 给宠物加疫苗记录 → 手动触发定时任务看是否提醒。这一圈走下来,任何一环报错都说明系统有隐藏问题。我一般还会故意输错数据,比如手机号填字母、日期填 13 月,看系统是友好提示还是直接 500 错误。能扛住异常输入的系统,才算真正能交付。

这套东西我从头搭过几遍,最大的教训是:别一上来就追求功能多,先把一条主线跑通,再往上加。数据库设计花两天想清楚,比后面改表结构省一周。论文也别拖到最后写,每完成一个模块就记一段设计说明,最后拼起来就是初稿。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询