
做这套宠物管理系统的时候我最大的感受是技术难度其实不算高真正费精力的是把“宠物档案、领养申请、寄养预约、疫苗接种”这些日常业务在数据库和接口层面梳理清楚让一套 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) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT宠物档案表;这里有几个细节值得注意。状态字段我用数字常量而不是字符串因为程序里判断更高效前端再通过字典映射成文字显示。创建时间和更新时间单独拎出来对排查数据和做统计报表很有帮助。字符集统一用 utf8mb4因为宠物名字里可能出现生僻字或者特殊符号这个字符集能完整存储。2.2 领养状态机与数据一致性领养模块是这套系统里业务逻辑最复杂的地方核心在于状态管理。我把领养申请状态设计成四个待审核、已通过、已拒绝、已完成。这个设计对应一个简单的状态机用户提交申请后状态为待审核管理员通过后变为已通过随后线下完成交接后标记为已完成如果审核不通过则直接变为已拒绝。状态机的意义在于让数据流转有规则可循。后端代码里我专门写了一个状态校验逻辑不允许无理由的状态跳变比如从已拒绝直接改成已完成这在业务上是说不通的。这样设计既方便前端控制按钮显示也让后端接口更安全。另一个关键问题是数据一致性。当领养申请通过时宠物表里对应记录的状态必须同步从“待领养”改成“已领养”。如果只改申请状态不改宠物状态前台用户依然能看到这只宠物并提交申请就会出现一宠多领的数据错误。我在 service 层用事务保证这两步操作是原子的任何一步失败都会整体回滚。这就是为什么后端不能只写增删改查还需要理解业务之间的关联。2.3 数据库设计的三个避坑点第一不要把宠物类型和品种写死在用户输入里。我一开始图省事让用户直接填文本结果数据五花八门统计时根本没法归类。后来改成预设选项加自由输入的组合方案既保证录入效率也保留灵活性。第二寄养预约的时间字段一定要设计成时间段而不是单个日期。最开始我设计的是开始日期和结束日期两个字段看起来没问题后来发现需要判断“某只宠物在某个日期是否已有寄养记录”两个字段也能查但 SQL 写起来很别扭。改成时间段后判断交集就可以直接用索引友好的条件查询。第三所有外键关联字段统一格式。用户 ID、宠物 ID 这类字段全部用 bigint命名统一不带前缀避免出现 userId、petId、user_id 混用的情况。命名规范直接影响联表查询的效率和代码的可读性。3. 后端核心功能实现3.1 基于 JWT 的登录鉴权流程登录鉴权我选的是 JWT 拦截器方案。用户登录成功后后端生成一个带过期时间的 token 返回给前端前端把 token 存在本地每次请求都放进请求头后端通过拦截器统一校验。这个方案的好处是无需在服务器保存会话信息前后端分离场景下非常自然。真实的实现流程是这样的用户提交账号密码后端先从数据库查出用户记录用 BCrypt 校验密码。验证通过后用用户 ID 和用户名生成 JWTJWT 秘钥放在配置文件中过期时间设置成两个小时代币。生成 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 这套组合之所以常被选为真实项目的开发方案是因为它稳定、资料多、团队协作成本低。真正让项目拉开差距的地方在于业务梳理领养状态怎么流转、寄养时间怎么防冲突、图片文件怎么管理这些细节直接决定交付质量。如果你正在做类似的系统我建议先花一天时间把业务状态和表关系图画清楚再动手写代码这样后面返工的几率会大大降低。这套项目的源码、数据库脚本和文档我所有章节里提到的结构都对应上了你照着数据结构搭建、按接口文档联调遇到问题就回看速查表能少走很多弯路。