☰
宠物管理系统实战:Java + Vue 前后端分离项目从设计到部署
2026/10/19 10:15:45 网站建设 项目流程

做这套宠物管理系统的时候,我最大的感受是:技术难度其实不算高,真正费精力的是把“宠物档案、领养申请、寄养预约、疫苗接种”这些日常业务在数据库和接口层面梳理清楚,让一套 Java + Vue 的前后端分离项目真正能落地运行。这个项目最终交付的内容包括完整源码、数据库初始化脚本和配套开发文档,整套东西跑通以后,我发现它非常适合作为毕业设计、课程设计或者第一份外包练手项目的参考模板。这篇文章不聊虚的,直接讲清楚整个系统的业务设计、数据库建模、核心接口实现、前端页面搭建,以及我在开发过程中踩过的一堆坑。

1. 项目整体设计与技术选型

1.1 宠物管理系统到底解决什么问题

宠物管理系统本质上是一个面向宠物店、流浪动物救助站或者社区宠物服务机构的业务管理平台。它需要处理的信息很典型:宠物基本信息(品种、年龄、健康状况)、疫苗接种时间线、领养申请和审核流程、寄养预约排期,以及后台管理员对不同角色的权限控制。

我见过很多人一上来就写代码,结果做到一半发现表结构对不上业务逻辑,领养状态不知道怎么流转,寄养时间冲突没地方判断。所以我在动手之前先做了一件事:把业务角色列清楚。这套系统里有两类核心角色:前台用户(浏览宠物、提交领养申请、预约寄养)和后台管理员(审核领养、维护档案、管理疫苗记录)。角色明确以后,功能模块和数据库设计的边界就清晰了。

这套系统解决的实际问题可以归纳为三点:第一,把宠物信息从 Excel 表格或者纸质档案里解放出来,统一线上管理;第二,让领养流程从“口头沟通”变成“线上申请、线上审核、状态可查”;第三,通过系统记录疫苗接种时间,避免因为忘打疫苗导致的健康风险。

1.2 为什么选择 Java + Vue 这套组合

后端用 Java、前端用 Vue,这几乎是目前中小型管理系统最主流的组合之一。我个人的选型理由主要基于三点。

第一是生态成熟。Java 这边有 Spring Boot 系列框架,配套的 MyBatis Plus、Spring Security、JWT 等工具链非常完善。Vue 这边有 Element UI 这种现成的后台组件库,做出来的管理界面不需要从零写 CSS,开发效率极高。

第二是岗位需求和参考案例多。Java 是大量业务系统的后端语言,Vue 在前端框架里的使用率一直很高。这套组合意味着遇到任何问题都能快速搜到解决方案,对开发者非常友好。

第三是前后端分离架构本身的好处。前端只管页面渲染和数据交互,后端专注业务逻辑和数据处理,两者通过 JSON 接口通信,后续如果要换前端框架,后端基本不用动。我在搭建时用了 Spring Boot 2.x 搭配 Vue 2.x 加 Element UI,这个组合稳定性高,网上资料最全,对新手最友好。

1.3 系统模块划分与项目结构

整个系统按照功能拆成了六个核心模块:用户管理、宠物档案管理、领养管理、寄养管理、疫苗管理和统计分析。

用户管理负责注册登录、角色权限和基本信息维护;宠物档案管理是核心模块,负责宠物信息的增删改查、图片上传和状态管理;领养管理处理申请提交、管理员审核、状态流转;寄养管理处理寄养预约和排期;疫苗管理记录每次接种信息;统计分析则是用图表展示宠物数量、领养成功率等数据,为管理员决策提供参考。

后端项目结构我按标准的三层架构来组织:controller(接收请求并返回结果)、service(处理业务逻辑)、mapper(操作数据库),再加上 entity、dto、config 这些辅助包。前端按 Vue 项目的常规结构分成 views(页面组件)、components(公共组件)、router(路由配置)、store(状态管理)、utils(工具封装)几大块。这个结构不花哨,但足够清晰,团队协作时每个人负责一个模块,互相不干扰。

2. 数据库设计与核心表结构

2.1 六张核心业务表的设计思路

数据库设计是整个项目的地基。我花了一个下午反复调整表结构,最终保留了六张核心表:用户表、宠物表、领养申请表、寄养预约表、疫苗接种表、系统日志表。

用户表是最基础的表,需要区分管理员和普通用户。宠物表记录宠物所有档案信息,包括品种、年龄、健康状况、目前状态等关键字段。领养申请表关联用户和宠物,记录申请理由和审核结果。寄养预约表管理寄养时间段,需要设计时间字段来避免重复预约。疫苗接种表记录每只宠物历次接种情况,形成一个可追溯的健康档案。

宠物表的结构我实际开发中用得很顺手,关键字段包括:

CREATE TABLE `pet` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '宠物ID', `name` varchar(50) NOT NULL COMMENT '宠物名称', `type` varchar(20) DEFAULT NULL COMMENT '宠物类型:猫/狗/其他', `breed` varchar(50) DEFAULT NULL COMMENT '品种', `gender` tinyint(1) DEFAULT NULL COMMENT '性别:0母 1公', `age` int(11) DEFAULT NULL COMMENT '年龄(月)', `weight` decimal(5,2) DEFAULT NULL COMMENT '体重(kg)', `health_status` varchar(500) DEFAULT NULL COMMENT '健康状况描述', `vaccine_status` varchar(100) DEFAULT NULL COMMENT '疫苗状态:已接种/未接种', `cover_image` varchar(255) DEFAULT NULL COMMENT '封面图片URL', `status` tinyint(1) DEFAULT '0' COMMENT '状态:0待领养 1已领养 2已下架', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `update_time` datetime DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='宠物档案表';

这里有几个细节值得注意。状态字段我用数字常量而不是字符串,因为程序里判断更高效,前端再通过字典映射成文字显示。创建时间和更新时间单独拎出来,对排查数据和做统计报表很有帮助。字符集统一用 utf8mb4,因为宠物名字里可能出现生僻字或者特殊符号,这个字符集能完整存储。

2.2 领养状态机与数据一致性

领养模块是这套系统里业务逻辑最复杂的地方,核心在于状态管理。我把领养申请状态设计成四个:待审核、已通过、已拒绝、已完成。这个设计对应一个简单的状态机:用户提交申请后状态为待审核,管理员通过后变为已通过,随后线下完成交接后标记为已完成;如果审核不通过则直接变为已拒绝。

状态机的意义在于让数据流转有规则可循。后端代码里我专门写了一个状态校验逻辑,不允许无理由的状态跳变,比如从已拒绝直接改成已完成,这在业务上是说不通的。这样设计既方便前端控制按钮显示,也让后端接口更安全。

另一个关键问题是数据一致性。当领养申请通过时,宠物表里对应记录的状态必须同步从“待领养”改成“已领养”。如果只改申请状态不改宠物状态,前台用户依然能看到这只宠物并提交申请,就会出现一宠多领的数据错误。我在 service 层用事务保证这两步操作是原子的,任何一步失败都会整体回滚。这就是为什么后端不能只写增删改查,还需要理解业务之间的关联。

2.3 数据库设计的三个避坑点

第一,不要把宠物类型和品种写死在用户输入里。我一开始图省事让用户直接填文本,结果数据五花八门,统计时根本没法归类。后来改成预设选项加自由输入的组合方案,既保证录入效率,也保留灵活性。

第二,寄养预约的时间字段一定要设计成时间段而不是单个日期。最开始我设计的是开始日期和结束日期两个字段,看起来没问题,后来发现需要判断“某只宠物在某个日期是否已有寄养记录”,两个字段也能查,但 SQL 写起来很别扭。改成时间段后,判断交集就可以直接用索引友好的条件查询。

第三,所有外键关联字段统一格式。用户 ID、宠物 ID 这类字段全部用 bigint,命名统一不带前缀,避免出现 userId、petId、user_id 混用的情况。命名规范直接影响联表查询的效率和代码的可读性。

3. 后端核心功能实现

3.1 基于 JWT 的登录鉴权流程

登录鉴权我选的是 JWT + 拦截器方案。用户登录成功后,后端生成一个带过期时间的 token 返回给前端,前端把 token 存在本地,每次请求都放进请求头,后端通过拦截器统一校验。这个方案的好处是无需在服务器保存会话信息,前后端分离场景下非常自然。

真实的实现流程是这样的:用户提交账号密码,后端先从数据库查出用户记录,用 BCrypt 校验密码。验证通过后,用用户 ID 和用户名生成 JWT,JWT 秘钥放在配置文件中,过期时间设置成两个小时代币。生成 token 后还需要把用户基本信息一起返回,前端要根据角色判断跳转到用户端还是管理端。

拦截器是鉴权的核心,我遇到的很多人都把逻辑写在 controller 里,导致每个接口都要重复写校验代码。正确做法是创建一个拦截器专门处理 token 解析,在 WebMvcConfig 里对所有非公开接口做拦截,公开接口(比如登录、注册)放行,同时把解析出的用户信息放进请求上下文,方便后续业务代码直接取用。

3.2 宠物档案的增删改查与图片上传

宠物档案接口是整个系统的体力活,核心就是标准的增删改查。但有两个点值得多说几句。

第一个是分页查询。宠物列表页需要支持按类型、状态、品种做筛选,分页是刚需。我用 MyBatis Plus 的分页插件,controller 层接收页码和每页条数,加上筛选条件即可。这里有一个经验:筛选条件一定要选择性地拼接,不能傻乎乎地拿一个空值去数据库里查,否则用户不选任何条件时会把全部数据捞出来,影响效率。

第二个是图片上传。宠物需要展示封面图,图片文件的存储方案我选的是上传到本地服务器目录,然后把相对路径存进数据库,同时用静态资源映射让前端能直接访问。这样做比存 base64 字符串进数据库更节省资源,也比依赖第三方图床更可控。

图片上传接口我用 MultipartFile 接收文件,校验类型和大小后,用 UUID 重命名文件,避免文件名冲突。另一个容易忽略的点是做格式限制,不能只在前端做,后端必须再做一次校验,否则绕过前端直接调接口就能上传非法文件。

3.3 领养审核流程的接口设计

领养审核流程涉及三个接口:用户提交领养申请、管理员查询申请列表、管理员审核通过或拒绝。

提交申请时,后端要做的不仅是插入一条申请记录,还要检查该宠物是否已经被领养。我最初忽略了这个校验,测试时出现了同一只宠物被申请两次的情况。正确做法是在提交接口里先查宠物状态,如果不是待领养状态,直接抛出异常提示用户。

管理员审核时,后端要在一个事务里完成三件事:更新申请状态、更新宠物状态、写入审核意见。审核通过时宠物状态改为已领养,申请状态改为已通过;审核拒绝时只改申请状态和审核意见,宠物状态保持不变,这样宠物可以继续被别人申请。

这个模块还有一个前端的联动逻辑:用户提交申请后按钮立即进入禁用状态,同时展示“审核中”的标识,这样用户体验会好很多。后端接口返回的状态码和提示信息要规范化,统一格式,方便前端统一处理。

3.4 后端开发踩过的一些坑

后端开发过程中我集中踩过几个问题,第一个是 LocalDateTime 序列化格式问题。Spring Boot 默认把 LocalDateTime 序列化成数组形式,前端拿到的不是友好的字符串,要在配置类里统一指定格式才能正确显示。

第二个是跨域问题。前端在 localhost:8080,后端在 localhost:9090,浏览器默认会拦截跨域请求。我一开始在 controller 里挨个加跨域注解,后来发现太繁琐,就专门建了一个跨域配置类统一处理,同时配置允许携带凭证,否则前端带 token 的请求会被浏览器拒绝。

第三个是数据库连接池的报错。有时候系统运行一段时间后接口突然变慢,后来排查发现是连接池没有正确配置最大连接数,默认值过低导致在高并发下等待连接。性能优化不需要上来就上缓存,先检查连接池、索引、慢查询这些基础项,收益最明显。

4. 前端 Vue 项目实战

4.1 前端工程化结构与路由设计

前端我使用的是 Vue CLI 构建的标准项目,目录结构围绕系统功能组织。views 下面分 user 和 admin 两个目录,对应前端两个角色的页面,两者权限不同,入口也不同。这样划分的好处是页面之间不会互相干扰,权限管理也更直观。

路由设计的核心在于路由守卫。我在 router 配置文件里给需要登录的页面添加 meta 元信息,标注 requiresAuth 和角色要求。全局前置守卫里做三件事:检查是否有 token、检查路由是否需要登录、检查用户角色是否匹配页面权限。如果没有 token 而直接访问管理端页面,直接跳转登录页。这个过程比在每个页面生命周期里写判断要优雅得多,也符合工程化思维。

页面和组件的拆分也遵循一个原则:可复用的部分抽成组件,比如用户信息卡片、宠物状态标签、分页组件。列表页我抽了几个公共组件,不同页面复用之后,整体代码量少了不少。

4.2 Axios 请求封装与登录态管理

Axios 请求封装是前端项目的基础设施。我的封装思路是在 utils 目录下创建一个 request 模块,统一的 baseURL 指向后端的接口前缀。在请求拦截器里,从本地存储取出 token 加进请求头;在响应拦截器里,统一处理 HTTP 状态码和业务状态码。

这里最核心的是 401 处理逻辑。当后端返回 401 时,说明 token 过期或者非法,前端需要清除本地登录态并跳转登录页。这个逻辑必须在拦截器里实现,而不是在每个请求的返回值里手动判断。响应拦截器还要统一处理业务异常,后端返回的提示信息直接通过框架的消息提示组件弹出,这样代码里不会到处是 try-catch 处理弹窗。

登录态管理我用的是 Vuex。用户信息、token 放在 store 里,页面通过 mapState 读取。token 同时存在 localStorage 里,刷新页面后从本地重新加载到 store,实现登录态的持久化。

4.3 宠物列表和领养申请页面核心实现

宠物列表页是这套系统前台最核心的页面。它包含顶部筛选条件、宠物卡片列表、分页器三个部分。筛选条件用 Element UI 的表单组件,拉平布局,选完直接触发查询。宠物卡片展示了封面图、名称、品种、状态标签等信息,点击卡片可以进入详情页。

详情页里最关键的是领养申请表单。用户需要填写申请理由,如果表单校验通过,就调用后端接口提交申请。提交成功后,页面做出反馈:按钮置灰并显示审核中,防止重复提交。这个交互细节看似简单,但实际开发时很多系统都没考虑到,导致用户重复点击产生了多条申请记录。

后台管理端里比较重要的是宠物管理表格。表格用 el-table 呈现所有宠物,行内提供编辑和删除按钮。编辑操作我用对话框内嵌表单实现,表单回填要注意数据格式转换,比如后端返回的状态是数字 0 或 1,而前端下拉框期望的是字符串,需要在编辑前做一次映射。

4.4 让后台管理页面好用的几个细节

这里分享几个直接提升后台页面体验的实用细节。

第一个是表格数据在筛选条件变化时自动重置页码。很多初学者的代码是筛选条件变了但页码没重置,用户处于第二页时筛选结果可能只剩一两条数据,页面却是空白。我在 watch 筛选条件时强制把页码重置为 1。

第二个是操作后的反馈和列表刷新。管理员审核领养申请后,不能只弹一个成功的提示就完了,还要刷新列表数据,让用户看到状态产生的变化。我在表单提交成功后手动调用列表查询接口,刷新当前页数据。

第三个是空数据的展示。宠物列表在没有数据时,不要只显示一个空白区域,至少展示“暂无数据”的文案,如果条件允许可以再放一个图标。这个细节虽然小,但对用户体验的影响很大。

还有一个后台管理特有的大坑:删除操作的二次确认。直接一行代码调用删除接口,一旦点错就是数据丢失。我在所有删除按钮上加了确认弹层,并提示用户删除的到底是哪条记录,大大减少了误操作的风险。

第五版优化建议:真实交付和部署上线章节再加一段包括Nginx反向代理实现细节的说明,作为补充。

5. 部署上线与联调实录

5.1 本地联调的三个关键配置

本地联调是开发完到上线前最折磨人的阶段,这里我整理出常出问题的三个配置项。

第一个是后端跨域配置。前端跑在 8080 端口,后端跑在 9090 端口,二者域名或端口不同就必然产生跨域。我的做法是在后端建一个统一的跨域配置类,允许指定域名访问,同时设置 allowCredentials 为 true。这个设置容易遗漏,遗漏之后前端请求能发出去,但带 token 的请求会被浏览器拦截,控制台报错信息有时候不太直观。

第二个是静态资源映射。后端上传的宠物图片需要能被前端访问,如果不做静态资源映射,前端拿到的图片地址是 404。我用 WebMvcConfig 把本地某个目录映射成 /files/** 这个访问路径,这样图片 URL 就能直接从数据库里存的值访问了。

第三个是接口路径前缀。我统一使用 /api 前缀区分前后端接口,Nginx 反向代理时可以直接把 /api 开头的请求转发到后端服务。这个规划要提前做,避免后面前端请求地址写得五花八门。

5.2 打包部署到服务器的完整流程

部署流程我非常建议在生产环境动手前先在本地完整过一遍。后端先清理并打包项目,生成可直接运行的 jar 文件。随后把它放到服务器,用启动命令运行,并配合日志文件和使用日志收集工具,方便进程在后台长时间稳定运行和后期排查问题。

前端打包则执行 Vue 构建命令,生成 dist 静态目录。这个目录下是纯静态文件,交给 Nginx 托管即可。Nginx 配置的时候有一个关键点:单页应用刷新会 404。因为 Vue 路由用的是 history 模式,刷新时 Nginx 找不到对应的真实文件路径,必须在配置里加一个 fallback,把所有路由请求都指向 index.html。

数据库这边同样要做一次初始化。我使用的是从开发环境导出的 SQL 脚本,在服务器上执行后,还需要同时修改后端配置文件里的数据库连接地址,从本地的 localhost 改成服务器的实际 IP。第一次部署时常常出现连不上数据库的问题,多数时候就是数据库地址、账号密码和后端配置没对上。

5.3 上线后容易忽略的问题

第一个是上传目录的路径问题。开发时图片直接传到项目目录,部署后项目在 jar 包里面,没有可写的目录结构。我后来在配置文件里把上传目录设为服务器某个独立的绝对路径,比如在应用目录下创建一个专门的 images 存储目录,再把这个路径映射到静态资源。这样升级服务时不会因为重新打包导致图片丢失。

第二个是数据库时区问题。服务器和本地时区不一致,导致时间字段相差八小时。解决方法是连接数据库的 URL 配置加时区参数,同时数据库连接池要选择合适的驱动版本。

第三个是资源清理问题。上传的图片在宠物被删除后并不会自动删除,需要写一个定时任务或者手动清理脚本定期扫描孤儿文件。我最初完全没考虑这个,直到服务器磁盘差点满了才发现问题。文件系统管理的细节在开发和测试阶段很容易被忽略,但上线后它迟早会成为问题。

6. 常见问题速查与排错经验

6.1 前后端联调高频报错

联调阶段报错主要集中在跨域、请求格式和状态码处理上,我把高频问题整理成了一张速查表。

现象可能原因快速解决方案
浏览器控制台出现 CORS 报错后端跨域配置缺失或 allowCredentials 未开启检查后端跨域配置类,确认放行前端的完整地址
请求 404 且路径看起来没问题后端接口路径与前端请求地址不一致在浏览器 Network 面板比对实际请求 URL 与后端 Controller 注解路径
提交表单时后端收到的是 null前端未设置请求头 Content-Type,或传参格式不匹配统一使用 JSON 格式,Axios 设置 application/json 请求头
token 失效但页面不跳转响应拦截器未处理 401 状态在 Axios 响应拦截器里统一清空登录态并跳转登录页
日期字段显示数组形式后端 LocalDateTime 序列化格式未配置在后端配置 Jackson 的时间格式,统一为 yyyy-MM-dd HH:mm:ss

这些问题的排查思路有一个共同点:先看浏览器 Network 面板里请求的真实状态和响应体,再决定是改前端还是改后端。不要凭空猜测,我曾经为了一个 404 问题反复改前端代码,最后发现只是后端启动时端口被占用导致服务没起来。

6.2 业务逻辑相关的典型问题

业务逻辑的问题往往比技术问题更隐蔽,因为它们不会直接报错,而是表现为数据不对或者流程异常。第一个典型问题是领养申请重复提交。用户连点两次申请按钮,后端收到了两条请求,最终产生了两条领养申请记录。解决方法是前端提交后立即禁用按钮,后端接口再加一层校验,使用分布式锁或者乐观锁机制保证幂等性。

第二个典型问题是寄养时间冲突。用户预约寄养时没有检查该宠物在相同时间段是否已有预约,导致同一只宠物被重复预约。我后来在接口里加入了时间范围重叠的判断逻辑,当前端传来的开始时间和结束时间与已有记录存在交集时,直接拒绝申请并提示用户选择其他时间。

第三个典型问题是数据删除后的连带问题。删除宠物时没有同步处理关联的领养申请表和疫苗记录,数据库里会出现一堆孤儿数据。我的解决方案是在删除接口的事务里同时处理关联表的逻辑删除,或者在外键层面设置级联操作。

这个问题的通用排查思路是先通过管理端把业务全流程走一遍,每一步都检查数据库实际变化,往往能快速定位是前端没调接口、后端逻辑写错还是数据库状态没同步。我每次排这种问题都直接看数据库,先确认数据对不对,再回头看代码,要比盯着代码猜快很多。

最后再分享几句实在话

这个宠物管理系统做完,我最深的体会是技术选型不需要追求新奇,Java + Vue 这套组合之所以常被选为真实项目的开发方案,是因为它稳定、资料多、团队协作成本低。真正让项目拉开差距的地方在于业务梳理:领养状态怎么流转、寄养时间怎么防冲突、图片文件怎么管理,这些细节直接决定交付质量。如果你正在做类似的系统,我建议先花一天时间把业务状态和表关系图画清楚,再动手写代码,这样后面返工的几率会大大降低。这套项目的源码、数据库脚本和文档我所有章节里提到的结构都对应上了,你照着数据结构搭建、按接口文档联调,遇到问题就回看速查表,能少走很多弯路。

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

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

立即咨询