资讯详情

SpringBoot+Vue宠物领养系统实战:业务建模、状态机与答辩避坑指南

📅 2026/10/15 21:41:07 | 华诺云谱 👁 阅读
SpringBoot+Vue宠物领养系统实战:业务建模、状态机与答辩避坑指南
简介这份资源是面向计算机专业毕业生与答辩准备的宠物领养系统答辩PPT配套SpringBootVue.js技术栈的毕业设计项目适合需要完成开题、答辩或参考同类Web系统开发的学生使用。压缩包内共1个pptx文件大小约2.65MB内容涵盖选题背景与意义、开发环境说明、管理员与用户双角色功能结构设计、系统操作流程及结论致谢等答辩核心模块可直接用于答辩演示或作为PPT排版与内容组织参考。目前已有1484人学习下载说明该选题与技术方案在毕业设计中具有较高关注度。通过这份PPT读者能快速梳理SpringBoot后端与Vue.js前端结合的B/S架构项目脉络理解宠物领养、认领审核、教学视频与感谢信等模块的设计思路并借鉴其功能结构图与流程图的呈现方式为自身答辩材料撰写和项目讲解提供实用参考。1. 从一份答辩 PPT 反推宠物领养系统到底该怎么落地很多同学做毕业设计选题定了“宠物领养系统”技术栈选了 SpringBoot Vue代码吭哧吭哧写完最后卡在答辩 PPT 上——不是不会做 PPT而是讲不清楚这套系统到底解决了什么问题、技术选型为什么这么定、数据表为什么这么设计。答辩老师问一句“你这个领养流程怎么防止一只宠物被重复领养”当场就懵了。这篇笔记不聊 PPT 排版聊的是这套系统本身。把 SpringBoot Vue 宠物领养系统从业务建模、接口设计、状态机流转到部署验证整条链路拆开讲一遍。适合正在做类似选题的在校开发者、需要快速搭一套前后端分离管理系统的初中级工程师以及想搞清楚“一个真实业务系统该长什么样”的 Vue 后端入门者。读完你至少能自己把领养主流程跑通并且知道答辩时哪些点最容易被追问。2. 领养业务建模为什么不能只有一张宠物表2.1 领养系统的核心实体与关系很多人第一版设计就是三张表用户表、宠物表、领养记录表。跑起来没问题但一答辩就露馅。真实领养业务里宠物有“待领养 / 审核中 / 已领养 / 下架”多个状态领养申请有“待审核 / 通过 / 拒绝 / 已取消”多个状态而且申请和宠物之间是一对多关系——同一只宠物可能同时收到多个申请但最终只能有一个通过。所以最小可用的实体至少是五个用户user、宠物pet、领养申请adoption_apply、宠物分类category、操作日志operation_log。操作日志这张表很多人会忽略但答辩时老师特别爱问“你怎么追踪一只宠物从发布到被领养的全过程”有这张表你就能答上来。关系上用户和宠物是一对多一个用户能发布多只宠物用户和领养申请是一对多一个用户能提交多个申请宠物和领养申请也是一对多一只宠物能被多次申请。最终“通过”的那条申请会把宠物状态锁死为“已领养”。2.2 数据表字段设计与状态枚举下面这张表是我一般会用的宠物表核心字段直接抄就行字段名类型说明idbigint主键自增namevarchar(50)宠物昵称category_idint分类外键age_monthint月龄比直接存年龄好算gendertinyint0 未知 1 公 2 母health_statustinyint0 健康 1 观察中 2 治疗中adopt_statustinyint0 待领养 1 审核中 2 已领养 3 下架publisher_idbigint发布人create_timedatetime发布时间领养申请表的关键字段是 pet_id、applicant_id、apply_status0 待审核 1 通过 2 拒绝 3 取消、apply_reason、audit_time、auditor_id。注意 apply_status 和 pet 的 adopt_status 是两套状态不要混用这是答辩高频追问点。2.3 状态流转图与并发控制思路领养主流程的状态流转是这样的宠物发布后 adopt_status0有人提交申请后变成 1审核中管理员审核通过后变成 2已领养同时该宠物的其他待审核申请全部置为 2拒绝。如果审核拒绝宠物回到 0。这里有个坑两个人同时点“申请领养”如果代码里只是先查再改会出现两只申请都通过的情况。常见做法是在更新宠物状态时加乐观锁用update pet set adopt_status2 where id? and adopt_status1看影响行数是否为 1为 0 就说明被别人抢先了直接回滚事务并提示“该宠物已被领养”。-- 审核通过时的核心更新利用 where 条件做乐观锁 UPDATE pet SET adopt_status 2, update_time NOW() WHERE id #{petId} AND adopt_status 1; -- 同时把该宠物其他待审核申请批量拒绝 UPDATE adoption_apply SET apply_status 2, audit_time NOW() WHERE pet_id #{petId} AND apply_status 0 AND id ! #{applyId};这两条 SQL 必须放在同一个Transactional方法里任何一条影响行数为 0 都要抛异常回滚。参数说明petId 是宠物主键applyId 是本次通过的申请主键audit_time 记录审核时间用于后续追溯。3. 后端接口分层SpringBoot 里怎么把领养流程写干净3.1 Controller-Service-Mapper 三层职责划分SpringBoot 项目最容易写乱的地方就是 Controller 里塞业务逻辑。我的习惯是 Controller 只做参数校验和结果封装Service 写业务规则和事务Mapper 只做单表 CRUD。以“提交领养申请”为例Controller 收到请求后先校验用户是否登录、宠物是否存在然后调 Service 的 apply 方法。RestController RequestMapping(/api/adoption) public class AdoptionController { Autowired private AdoptionService adoptionService; PostMapping(/apply) public Result apply(RequestBody Valid ApplyDTO dto, HttpServletRequest request) { // 从拦截器塞进 request 的 userId 取当前登录用户 Long userId (Long) request.getAttribute(userId); adoptionService.apply(dto.getPetId(), userId, dto.getReason()); return Result.success(); } }逻辑说明Valid触发 DTO 上的注解校验比如 petId 不能为空、reason 长度限制。userId 不从请求体取而是从登录态取防止前端伪造。参数说明ApplyDTO 至少包含 petId 和 reason 两个字段。3.2 领养申请接口的参数校验与幂等处理幂等这块很多人不做答辩时被问到“用户手抖点了两次申请怎么办”就答不上来。简单做法是在 adoption_apply 表上加唯一索引(pet_id, applicant_id, apply_status)不行因为拒绝后还能再申请。更稳的做法是提交前先查该用户对该宠物是否有“待审核”的申请有就直接返回“请勿重复提交”。public void apply(Long petId, Long userId, String reason) { Pet pet petMapper.selectById(petId); if (pet null || pet.getAdoptStatus() ! 0) { throw new BizException(该宠物当前不可申请); } // 幂等同一用户对同一宠物不能有进行中的申请 int count applyMapper.countPending(petId, userId); if (count 0) { throw new BizException(你已提交过申请请等待审核); } AdoptionApply apply new AdoptionApply(); apply.setPetId(petId); apply.setApplicantId(userId); apply.setApplyReason(reason); apply.setApplyStatus(0); applyMapper.insert(apply); // 宠物进入审核中 petMapper.updateStatus(petId, 1); }参数说明countPending 对应 SQL 是select count(*) from adoption_apply where pet_id? and applicant_id? and apply_status0。注意这里没有加锁因为唯一性由业务查询保证高并发下仍可能穿透生产环境建议再加分布式锁或数据库唯一约束兜底。3.3 审核接口的事务边界与回滚条件审核接口是整个系统最需要事务的地方。通过时要同时做三件事更新申请状态、更新宠物状态、拒绝其他申请。任何一步失败都必须整体回滚。Transactional(rollbackFor Exception.class) public void audit(Long applyId, Long auditorId, boolean pass) { AdoptionApply apply applyMapper.selectById(applyId); if (apply null || apply.getApplyStatus() ! 0) { throw new BizException(申请不存在或已处理); } if (pass) { int rows petMapper.lockAdopted(apply.getPetId()); if (rows 0) { throw new BizException(该宠物已被其他人领养); } applyMapper.updateStatus(applyId, 1, auditorId); applyMapper.rejectOthers(apply.getPetId(), applyId); } else { applyMapper.updateStatus(applyId, 2, auditorId); // 拒绝后宠物回到待领养但仅当没有其他待审核申请时 int pending applyMapper.countPendingByPet(apply.getPetId()); if (pending 0) { petMapper.updateStatus(apply.getPetId(), 0); } } }逻辑说明rollbackFor Exception.class保证受检异常也回滚。lockAdopted 就是前面那条乐观锁 SQL。rejectOthers 批量拒绝同宠物其他待审核申请。参数说明pass 为 true 表示通过false 表示拒绝auditorId 记录审核人。4. 前端 Vue 页面领养列表与申请表单怎么串起来4.1 宠物列表页的数据请求与分页Vue 这边我用 Vue3 Element Plus 的组合居多列表页核心就是调后端分页接口。请求参数带上 pageNum、pageSize、categoryId、adoptStatus 四个后端用 PageHelper 或 MyBatis-Plus 的分页插件返回。// 宠物列表页的请求封装 import request from /utils/request export function fetchPetList(params) { return request({ url: /api/pet/list, method: get, params: { pageNum: params.pageNum || 1, pageSize: params.pageSize || 10, categoryId: params.categoryId || null, adoptStatus: params.adoptStatus ! undefined ? params.adoptStatus : null } }) }逻辑说明adoptStatus 用! undefined判断而不是直接||因为 0 是有效状态待领养用||会被当成 falsy 丢掉。参数说明pageNum 从 1 开始pageSize 默认 10categoryId 和 adoptStatus 为 null 时后端不拼查询条件。4.2 申请弹窗的表单校验规则申请领养是个弹窗里面一个 textarea 填理由加一个提交按钮。校验规则至少两条理由不能为空、长度不超过 200 字。用 Element Plus 的 Form 组件自带规则就行。const rules { reason: [ { required: true, message: 请填写领养理由, trigger: blur }, { min: 10, max: 200, message: 理由长度在 10 到 200 字之间, trigger: blur } ] } const submitApply async () { await formRef.value.validate() await applyAdoption({ petId: currentPetId.value, reason: form.reason }) ElMessage.success(申请已提交请等待审核) dialogVisible.value false refreshList() }逻辑说明validate 不通过会抛异常后面的代码不执行。提交成功后关闭弹窗并刷新列表让用户看到宠物状态变成“审核中”。参数说明currentPetId 是当前操作的宠物 idform.reason 绑定 textarea。4.3 审核状态在前端的展示与轮询刷新用户提交申请后怎么知道审核结果简单做法是在“我的申请”页面加一个手动刷新按钮进阶做法是轮询。我一般用setInterval每 30 秒拉一次申请列表页面卸载时清掉定时器。onMounted(() { loadMyApplies() timer setInterval(loadMyApplies, 30000) }) onUnmounted(() { clearInterval(timer) })逻辑说明定时器必须清理否则页面切走后还在请求属于典型内存泄漏。参数说明30000 毫秒即 30 秒太短会给后端压力太长用户觉得卡。5. 避坑与排查答辩前一定要自己跑一遍的 5 个点5.1 跨域配置写了但 OPTIONS 请求 403现象前端调接口浏览器报 CORS 错误后端日志显示 OPTIONS 请求被拦截。原因SpringBoot 的拦截器把 OPTIONS 预检请求也拦了没放行。解决在拦截器的 preHandle 里判断if (HttpMethod.OPTIONS.matches(request.getMethod())) return true;或者在 WebMvcConfigurer 里配 addCorsMappings 时允许所有方法和头。5.2 领养状态更新了但列表没变现象审核通过后数据库里宠物状态是 2但前端列表还显示“待领养”。原因前端用了缓存或者没重新请求也可能是后端返回的是旧对象。解决审核成功后前端主动调一次列表接口后端在更新后重新 select 一次再返回别直接返回更新前的实体。5.3 时间字段前后端差 8 小时现象数据库存的是正确时间前端显示少了 8 小时。原因后端返回的是 Date 对象Jackson 默认按 UTC 序列化。解决在 application.yml 里配spring.jackson.time-zoneGMT8和date-formatyyyy-MM-dd HH:mm:ss或者实体字段上加JsonFormat注解。5.4 图片上传后访问 404现象宠物图片上传成功但前端 img 标签加载不出来。原因上传目录不在静态资源映射路径下。解决在 WebMvcConfigurer 里加addResourceHandlers把上传目录映射到/upload/**前端用/upload/xxx.jpg访问。注意路径结尾要带斜杠这是血泪经验。5.5 答辩时被问“为什么用 Vue 不用 Thymeleaf”现象老师觉得前后端分离没必要。原因这是选型问题不是技术问题。解决从三个角度答——前后端分离便于分工、Vue 的组件化适合管理后台、接口可复用给小程序或 App。别硬说 Thymeleaf 不好说场景不同就行。6. 答辩前最后一公里用 Postman 把主流程串一遍代码写完不等于系统能跑。我一般会在答辩前一天用 Postman 把“注册 → 登录 → 发布宠物 → 提交申请 → 审核通过 → 查询结果”整条链路手动跑一遍确认每个接口的返回结构和状态码都对。这一步能提前暴露 80% 的演示翻车风险。具体做法是建一个 Collection把六个接口按顺序排好用环境变量存 token 和 petId。登录接口的返回里取 token 存到环境变量后续接口在 Header 里带Authorization: Bearer {{token}}。发布宠物接口的返回里取 id 存成 petId申请接口直接引用。这样点一次 Run 就能全链路跑通。// Postman 登录接口的 Tests 脚本自动提取 token const res pm.response.json() if (res.code 200) { pm.environment.set(token, res.data.token) pm.test(登录成功, () pm.expect(res.code).to.eql(200)) } else { pm.test(登录失败, () pm.expect.fail(res.msg)) }逻辑说明这段脚本在登录请求返回后执行把 token 写进环境变量供后续请求使用。参数说明res.code 是后端统一返回结构的业务码200 表示成功res.data.token 是 JWT 令牌。跑通之后把每个接口的请求参数和返回示例截图放进 PPT 的“系统测试”章节比放一堆代码截图有说服力得多。老师问“你怎么证明系统能用”你直接翻到这一页说“这是完整链路的接口测试记录”比任何解释都管用。最后一个习惯答辩前把数据库清空重新造一批演示数据别用开发时乱七八糟的测试数据。宠物名字起得像样点别叫“测试1”“aaa”老师看到这种数据会默认你系统没认真做。这个细节我踩过坑后来每次演示前都花十分钟重新造数据效果立竿见影。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑