简介:这份资源面向计算机专业毕业设计学生与Java全栈初学者,提供一套基于Spring Boot与Vue的宠物领养系统完整实现方案,可用于课程设计、毕设选题或全栈项目练手。系统功能覆盖网站首页的宠物列表、宠物详情、领养公告与个人中心,普通用户可管理我的申请、陪伴记录与宠物知识,管理员则负责种类管理、品种管理、宠物管理、领养审核、宠物回访及公告维护,并配套系统架构图、用例图、顺序图、E-R图等专业绘图。资源包共4个文件,包含2个zip源码压缩包、1个sql数据库脚本和1份docx部署文档,整体约664KB,源码、建库脚本与部署说明齐备,便于快速还原运行环境。目前已有42人学习下载,适合需要完整赛题方案、数据库设计与部署排错思路的读者参考。
1. 从一份能跑通的宠物领养系统源码说起
很多同学做毕业设计时,最怕的不是写不出代码,而是拼不出一个能演示、能答辩、能交差的完整系统。基于 SpringBoot + Vue 的宠物领养系统就是这样一个典型选题:业务不复杂,但前后端分离、数据库设计、部署上线一个都不能少。这份资源包含完整代码、数据库脚本和部署说明,适合正在做毕设的本科生、需要快速搭出管理后台的开发者,以及想拿一个真实项目练手 SpringBoot 和 Vue 的人。它解决的核心问题是:给你一套结构清晰、能本地跑起来、能改能扩的领养业务骨架,而不是让你从零去猜表该怎么建、接口该怎么写。
2. 技术选型与项目结构:为什么是 SpringBoot + Vue
2.1 前后端分离的选型理由
宠物领养系统的业务场景决定了它天然适合前后端分离。用户端要展示宠物列表、详情、申请领养,管理端要处理审核、发布、用户管理,两端交互频繁但页面逻辑差异大。如果还用传统的 JSP 或 Thymeleaf 把页面和逻辑揉在一起,后期改一个按钮样式都可能牵动后端代码,维护成本会随着功能增加迅速失控。
SpringBoot 在这里的价值是“约定大于配置”。它把 Spring 生态里那些繁琐的 XML 配置压到最低,内置 Tomcat 让项目可以直接以 main 方法启动,省去了单独装 Web 容器的步骤。对于毕设这种周期紧、要求功能完整的场景,SpringBoot 能让你把精力放在业务逻辑上,而不是环境折腾上。常见做法是用 SpringBoot 2.7.x 或 3.x 版本,搭配 MyBatis-Plus 做数据访问,MySQL 8 做存储,Maven 做依赖管理。
Vue 这边,选 Vue 3 + Element Plus 是目前比较稳的组合。Vue 的组件化让宠物卡片、申请表单、审核弹窗这些重复出现的 UI 块可以复用,路由用 vue-router 管理页面跳转,状态管理用 Pinia 或简单的 provide/inject 就够。前后端通过 Axios 发 HTTP 请求,后端返回统一格式的 JSON,前端根据 code 字段判断成功失败。这种模式在招聘市场上也是主流,写进简历里比“SSM + JSP”更有说服力。
2.2 项目目录结构与模块划分
拿到源码后,先别急着运行,花十分钟把目录结构看清楚,后面改代码会顺很多。典型的项目会分成两个顶层文件夹:一个后端 SpringBoot 工程,一个前端 Vue 工程。
后端目录一般长这样:
pet-adoption-backend/ ├── src/main/java/com/example/petadoption/ │ ├── controller/ # 接口层,处理 HTTP 请求 │ ├── service/ # 业务逻辑层 │ ├── mapper/ # MyBatis 数据访问接口 │ ├── entity/ # 数据库实体类 │ ├── config/ # 跨域、拦截器、Swagger 等配置 │ └── PetAdoptionApplication.java # 启动类 ├── src/main/resources/ │ ├── application.yml # 数据库连接、端口等配置 │ └── mapper/ # MyBatis XML 文件(如果没用注解) └── pom.xml # Maven 依赖前端目录则是标准的 Vue CLI 或 Vite 结构:
pet-adoption-frontend/ ├── src/ │ ├── api/ # 封装 Axios 请求 │ ├── views/ # 页面组件 │ ├── components/ # 可复用组件 │ ├── router/ # 路由配置 │ └── main.js # 入口文件 ├── package.json └── vite.config.js # 或 vue.config.js提示:如果源码里后端用的是
application.properties而不是application.yml,配置写法略有不同,但参数项是一样的,照着改数据库地址和密码即可。
模块划分上,核心业务一般围绕这几张表展开:用户表(user)、宠物表(pet)、领养申请表(adoption_application)、公告表(notice)。宠物表里会有品种、年龄、性别、健康状况、图片路径等字段;申请表里关联用户 ID 和宠物 ID,加上申请状态(待审核、已通过、已拒绝)。理解这些表之间的关系,后面调接口和改页面才不会迷路。
2.3 数据库设计与核心表结构
数据库是这类系统的地基,表建错了后面全是坑。这份资源里的 SQL 脚本通常包含建库、建表和初始数据。导入之前先确认 MySQL 版本,8.0 以上对字符集和排序规则的默认值跟 5.7 有差异,容易导致中文乱码或外键报错。
常见做法是给每张表加create_time、update_time和逻辑删除字段deleted,方便追溯和软删除。宠物表和申请表之间用外键关联,但实际开发中很多人会去掉物理外键,改在代码里控制,避免插入顺序和级联删除带来的麻烦。下面是一个简化的宠物表结构示例:
CREATE TABLE `pet` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', `name` varchar(50) NOT NULL COMMENT '宠物名字', `species` varchar(20) DEFAULT NULL COMMENT '物种:猫/狗/其他', `breed` varchar(50) DEFAULT NULL COMMENT '品种', `age` int DEFAULT NULL COMMENT '年龄(月)', `gender` char(1) DEFAULT NULL COMMENT '性别:M/F', `health_status` varchar(100) DEFAULT NULL COMMENT '健康状况', `image_url` varchar(255) DEFAULT NULL COMMENT '图片地址', `status` tinyint DEFAULT '0' COMMENT '状态:0待领养 1已领养', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `deleted` tinyint DEFAULT '0' COMMENT '逻辑删除', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='宠物信息表';这段 SQL 里几个参数值得注意:utf8mb4而不是utf8,因为要存 Emoji 或特殊字符;status用 tinyint 而不是 varchar,查询效率更高;deleted字段配合 MyBatis-Plus 的逻辑删除注解,查询时自动过滤已删除记录。导入脚本时如果报“Unknown collation”错误,多半是脚本里写了utf8mb4_0900_ai_ci而你的 MySQL 是 5.7,改成utf8mb4_general_ci就能过。
3. 本地跑通:后端启动与接口验证
3.1 环境准备与依赖安装
在跑代码之前,把本机环境对齐。后端需要 JDK 8 或 11(看 pom.xml 里的 source 版本),Maven 3.6+,MySQL 8。前端需要 Node.js 16+ 和 npm 或 yarn。这些装好之后,先别急着开项目,用命令行验证一下版本:
java -version mvn -v mysql --version node -v npm -v版本对不上是最常见的翻车点。比如 JDK 17 跑一个用 JDK 8 编译的 SpringBoot 2.x 项目,可能报Unsupported class file major version;Node 18 跑老版本 node-sass 会编译失败。遇到这类问题,要么换版本,要么改依赖,别硬扛。
数据库这边,用 Navicat 或命令行把 SQL 脚本导入。导入后检查一下表和数据是否完整:
USE pet_adoption; SHOW TABLES; SELECT COUNT(*) FROM pet;如果pet表里有几条测试数据,说明导入成功。接下来改后端配置文件,把数据库连接信息换成你自己的:
spring: datasource: url: jdbc:mysql://localhost:3306/pet_adoption?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.DriverserverTimezone必须设,否则 MySQL 8 会报时区错误。characterEncoding=utf8配合数据库的 utf8mb4,保证中文不乱码。
3.2 启动后端并验证接口
配置改完后,在项目根目录执行:
mvn clean install -DskipTests mvn spring-boot:run或者直接找到启动类,在 IDE 里右键 Run。控制台出现Started PetAdoptionApplication in x.x seconds就说明起来了。默认端口一般是 8080,如果被占用,在application.yml里改server.port。
启动成功后,别急着开前端,先用浏览器或 Postman 测一个接口。比如宠物列表接口:
curl http://localhost:8080/pet/list如果返回一串 JSON,包含code、msg、data字段,说明后端和数据库已经通了。如果报 500,看控制台堆栈,常见原因是数据库密码错、表名对不上、或者实体类字段和表字段映射没配好。MyBatis-Plus 默认开启驼峰转下划线,imageUrl会自动映射image_url,但如果你的字段名不规则,就得手动加@TableField注解。
注意:有些源码里接口路径带了
/api前缀,比如http://localhost:8080/api/pet/list,具体看 controller 上的@RequestMapping。别照着记忆瞎试,打开 controller 文件看一眼最稳。
3.3 前端启动与跨域处理
后端跑通后,进入前端目录:
npm install npm run servenpm install如果卡住,换淘宝源或 cnpm。启动成功后,浏览器打开http://localhost:8081(Vue CLI 默认 8080,但后端占了,所以一般会改成 8081)。这时候前端能显示页面,但调接口大概率会报跨域错误。
跨域有两种解法。一是在后端加全局 CORS 配置:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowCredentials(true) .maxAge(3600); } }二是在前端vue.config.js里配代理:
module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, pathRewrite: { '^/api': '' } } } } }两种方式选一种就行,同时用反而容易乱。代理方式的好处是前端代码里不用写完整后端地址,打包上线时也不用改。改完配置记得重启前端服务,热更新有时候不生效。
4. 功能模块拆解:领养流程与后台管理
4.1 领养申请的状态流转
领养业务的核心是一条状态流转链:用户提交申请 → 管理员审核 → 通过或拒绝 → 宠物状态变更。这条链上最容易出问题的是状态不同步。比如管理员点了“通过”,申请表状态改了,但宠物表里的status没改成“已领养”,结果这只宠物还能被其他人申请。
常见做法是在 Service 层用一个方法包住两个更新操作,加@Transactional注解:
@Transactional public void approveApplication(Long applicationId) { AdoptionApplication app = applicationMapper.selectById(applicationId); app.setStatus(1); // 1 表示通过 applicationMapper.updateById(app); Pet pet = petMapper.selectById(app.getPetId()); pet.setStatus(1); // 1 表示已领养 petMapper.updateById(pet); }@Transactional保证两个更新要么都成功,要么都回滚。但要注意,如果异常被 catch 了没抛出去,事务不会回滚,这是血泪经验。另外,申请表里最好加一个audit_time和audit_remark字段,记录审核时间和备注,答辩时演示起来更有说服力。
4.2 图片上传与静态资源映射
宠物图片上传是另一个高频翻车点。前端用 Element Plus 的el-upload组件,后端用MultipartFile接收,存到本地磁盘或对象存储。存本地的话,要配静态资源映射,否则上传后的图片访问不到。
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/uploads/**") .addResourceLocations("file:" + System.getProperty("user.dir") + "/uploads/"); } }这段配置的意思是:浏览器访问/uploads/xxx.jpg时,去项目运行目录下的uploads文件夹找文件。上传接口里把文件写到这个目录,返回的 URL 拼成/uploads/文件名。注意路径分隔符在 Windows 和 Linux 下不一样,用File.separator或直接用/(Java 在 Windows 下也能识别)。
提示:如果图片上传后能存但访问 404,先检查
addResourceLocations的路径末尾有没有加/,这个斜杠漏了会导致映射失效。
4.3 后台管理页面的权限控制
后台管理页面不能谁都能进。简单做法是在前端路由守卫里判断 token 或用户角色,后端接口再加一层拦截器。前端router/index.js里:
router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') if (to.meta.requiresAuth && !token) { next('/login') } else { next() } })后端用 HandlerInterceptor 检查请求头里的 token,没带或无效就返回 401。两边都做,是因为前端守卫能被绕过,后端拦截才是最后一道门。毕设答辩时老师如果问“怎么保证安全”,这套组合拳足够应付。
5. 避坑与排查:部署前后最容易翻车的五件事
5.1 数据库连接报错:时区与驱动类
现象:启动后端时报The server time zone value 'xxx' is unrecognized或No suitable driver found。
原因:MySQL 8 的驱动类变成了com.mysql.cj.jdbc.Driver,老写法com.mysql.jdbc.Driver会警告甚至报错;时区没配导致服务器时区无法识别。
解决:URL 里加serverTimezone=Asia/Shanghai,驱动类改成com.mysql.cj.jdbc.Driver。如果还报错,检查 pom.xml 里 MySQL 连接器的版本,8.x 配 8.x 驱动,别混用。
5.2 前端打包后刷新 404
现象:npm run build后把 dist 放进 SpringBoot 的 static 目录,首页能打开,但刷新或直接访问某个路由就 404。
原因:Vue 是单页应用,路由由前端控制,服务器找不到对应的物理文件。
解决:在后端加一个配置,把所有未匹配的请求转发到index.html:
@Controller public class IndexController { @RequestMapping("/") public String index() { return "forward:/index.html"; } }或者用 Nginx 配try_files $uri $uri/ /index.html;。两种方式选一种,别同时用。
5.3 跨域配置与拦截器冲突
现象:明明配了 CORS,前端还是报Access-Control-Allow-Origin错误。
原因:拦截器在 CORS 配置之前执行,或者allowedOriginPatterns写成了allowedOrigins("*")同时开了allowCredentials(true),浏览器会拒绝。
解决:用allowedOriginPatterns("*")代替allowedOrigins("*");如果用了拦截器,确保拦截器放行 OPTIONS 预检请求:
if (HttpMethod.OPTIONS.equals(request.getMethod())) { return true; }5.4 逻辑删除导致唯一索引冲突
现象:删了一条记录后再插入相同用户名或宠物名,报唯一索引冲突。
原因:逻辑删除只是把deleted改成 1,记录还在表里,唯一索引依然生效。
解决:要么去掉唯一索引改在代码里查重,要么把唯一索引改成联合索引(username, deleted),但这样删除多次会冲突。更稳妥的做法是删除时把唯一字段改成一个带时间戳的临时值,或者干脆用物理删除加备份表。
5.5 端口占用与启动失败
现象:启动时报Port 8080 was already in use。
原因:上一个进程没关干净,或者别的软件占了端口。
解决:Windows 用netstat -ano | findstr 8080找到 PID,taskkill /PID xxx /F杀掉;Linux 用lsof -i:8080再kill -9。或者直接在application.yml里换端口,改成 8082、9090 都行,但记得前端代理地址也要同步改。
6. 二次开发与答辩加分:把系统改成你自己的
6.1 快速替换业务字段与页面文案
拿到源码后,最忌讳的是原封不动交上去。查重能过,但答辩时老师一眼就能看出你没动过。改的第一步是替换业务字段和页面文案。比如把“宠物领养”改成“校园流浪动物救助”,把“品种”改成“发现地点”,把“健康状况”改成“绝育情况”。改的时候注意三处同步:数据库表字段、后端实体类属性、前端页面绑定变量。漏一处就报错。
改完字段后,把前端views下的页面标题、按钮文字、提示语都过一遍。用全局搜索找“宠物”“领养”这些词,逐个替换。这一步花不了多少时间,但能让系统看起来像是你自己做的。
6.2 增加一个“领养回访”模块
想让答辩更有亮点,加一个回访记录模块。业务逻辑是:领养通过后,管理员可以定期添加回访记录,记录宠物的生活状况。这需要新建一张follow_up表,加对应的 Controller、Service、Mapper,前端加一个回访列表页和新增弹窗。
CREATE TABLE `follow_up` ( `id` bigint NOT NULL AUTO_INCREMENT, `application_id` bigint NOT NULL COMMENT '关联的领养申请', `content` varchar(500) DEFAULT NULL COMMENT '回访内容', `images` varchar(1000) DEFAULT NULL COMMENT '回访图片,逗号分隔', `follow_time` datetime DEFAULT NULL COMMENT '回访时间', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='领养回访记录';后端接口照着现有的申请模块抄,改改表名和字段就行。前端用 Element Plus 的表格和对话框组件,半天能搞定。答辩时演示这个功能,能体现你对业务有延伸思考,比只念代码强得多。
6.3 部署上线与打包注意事项
最后一步是打包部署。后端用mvn package生成 jar 包,前端用npm run build生成 dist 文件夹。把 dist 里的文件复制到后端src/main/resources/static下,重新打包,这样前后端就在一个 jar 里了。启动命令:
java -jar pet-adoption-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod生产环境的配置文件application-prod.yml里,数据库地址改成服务器 IP,端口改成 80 或 443,日志级别调到 warn 减少输出。如果部署到云服务器,记得开安全组端口,数据库别用 root 账号,新建一个只有增删改查权限的用户。
注意:打包前把前端
api里的 baseURL 改成/或实际域名,别留着localhost:8080,否则上线后接口全挂。
从那以后我每次交付这类项目,都会先跑一遍“改字段 → 加模块 → 打包部署”的完整流程,确认没有遗漏才敢交出去。希望这份拆解能帮你少走弯路,顺利把系统跑起来、改出来、讲清楚。
本文还有配套的精品资源,点击获取