
1. 项目由来与核心痛点做毕业设计选题目这件事很多人会卡在“既要有点技术含量又不能太冷门”的平衡点上。我当初选“基于SpringBootVue的宠物领养系统”这个方向说白了就两个理由一是宠物公益在当下社会关注度极高做出来的东西有真实的应用场景答辩时老师不会觉得你在空中楼阁二是这套技术栈组合是当前Java后端和前端开发岗位最主流的需求SpringBoot负责业务逻辑和接口Vue负责用户交互前后端分离的开发模式本身也是企业级项目的标配。说句实在话如果只是做一个简单的CRUD系统用JSP加Servlet也能搞定但那样做出来的东西离现代软件开发的方式差得太远。SpringBoot Vue的组合能让你在毕设里同时展示清楚后端接口设计能力、数据库建模能力、前端组件化开发能力还有前后端联调的经验这些都是面试官真正看重的点。这个系统能做什么简单说它把“流浪动物救助”和“领养匹配”两个环节做成了线上化流程救助站或爱心人士可以在平台上登记需要被领养的动物信息包括照片、品种、健康状况、性格描述想领养的人可以浏览动物列表通过筛选条件找到合眼缘的宠物提交领养申请救助方可以审核申请人的资质和领养意向决定是否同意。同时系统里还配套了寻宠启示、宠物百科、志愿者招募这些辅助模块让整个平台更贴近真实的公益运转模式。适合谁来参考如果你正在做Java方向的毕业设计或者你刚学完SpringBoot和Vue想做一个小项目练手这篇文章都很值得你看完。我会把从数据库设计到接口开发再到前端页面实现的完整链路都拆开讲重点讲那些文档里不写、但实际开发中一定会踩的坑。2. 整体架构设计与技术选型思路2.1 前后端分离的核心逻辑先聊一个关键问题为什么一定要用前后端分离而不是传统的服务端渲染传统的单体应用里JSP页面在后端动态渲染前端和后端代码混在一起改一个页面的样式可能要重启整个应用。而前后端分离架构下后端只负责提供JSON格式的接口数据前端通过HTTP请求去调用接口拿到数据后渲染页面。这种模式有几个实际好处后端开发和前端开发可以并行互不阻塞同一个后端接口可以被PC端网页、手机H5、小程序等多端复用部署时前端静态文件扔到Nginx即可后端单独部署排障时定位问题也更快。具体到我们这个宠物领养系统技术选型是层级技术选型说明后端框架SpringBoot 2.7.x快速搭建RESTful API服务持久层MyBatis-Plus简化单表CRUD条件构造器很实用数据库MySQL 8.0存储用户、动物、申请等核心数据权限认证Spring Security JWT无状态登录RESTful API的标准方案前端框架Vue 2.7 Element UI组件化开发后台管理界面HTTP请求Axios统一封装请求和拦截器构建工具Maven npm后端依赖管理和前端打包管理文件存储本地磁盘 配置映射保存宠物照片上传文件2.2 数据库建模的几个重点坑系统涉及的实体不少用户、角色、动物信息、领养申请、寻宠启示、收藏、评论通知。我在建模时踩了不少坑这里直接给出我认为最合理的核心表结构设计思路基础的五张核心表是用户表、动物表、领养申请表、寻宠启示表、志愿者申请表。用户表要区分登录账号和用户详细信息建议拆成user表和user_profile表前者管登录凭证后者管真实姓名、手机号、居住地这些。动物表是核心中的核心字段建议包含动物名称、种类猫/狗/其他、品种、性别、年龄用月份存储更精确、是否绝育、是否驱虫、疫苗状态、所在城市、救助站关联ID、详细描述、健康状态、封面图片URL、状态字段待领养/已领养/审核中。这里有几个特别注意的地方状态字段不要用字符串随意填一定要用数字枚举比如0表示待审核1表示待领养2表示已领养3表示已下架。这样在后端做条件查询时会非常方便而且不会因为手滑输入了不一致的中文导致Bug。时间字段建议用MySQL的DATETIME而不是字符串排序和统计会很轻松。所有表都加上create_time和update_time两个字段用MyBatis-Plus的自动填充功能统一维护别在业务代码里动不动手动set时间。领养申请表的关联关系是最容易出错的地方。一张申请记录要同时关联申请用户ID、动物ID还要记录申请时的表单内容申请理由、居住条件、养宠经验、工作收入情况。这里强烈建议用逻辑外键而不是数据库物理外键也就是说在Java实体里定义字段但不真的在MySQL里建立FOREIGN KEY约束。原因很简单物理外键在删除关联数据时会非常麻烦而且大多数公司开发规范也是禁用的毕业设计千万别在这上面炫技。2.3 后端接口设计的RESTful规范接口设计上我遵循了最基础的RESTful风格但也做了一些实际开发中的妥协。用户模块的接口POST /api/user/register注册、POST /api/user/loging登录、GET /api/user/info获取当前用户信息、PUT /api/user/info修改个人资料。动物模块GET /api/animals分页查询动物列表、GET /api/animals/{id}获取详情、POST /api/animals发布新动物、PUT /api/animals/{id}修改信息、DELETE /api/animals/{id}下架删除。领养模块POST /api/adoptions/submit提交申请、GET /api/adoptions/my查看我的申请、PUT /api/adoptions/{id}/approve同意、PUT /api/adoptions/{id}/reject拒绝。说一个实际的注意点领养的审批流程在状态流转上一定要做校验。比如你只能从“待审核”流转到“已通过”或“已拒绝”不能直接从“已通过”再变回“待审核”。这种校验虽然写的代码有点繁琐但能避免很多逻辑混乱。我的做法是在Service层写一个专门的状态流转判断方法每次更新前先检查前置状态不符合就抛自定义异常。3. SpringBoot后端核心模块实现3.1 项目初始化与统一返回格式新建SpringBoot项目的步骤就不一步步截图了说几个关键的配置。pom.xml里依赖版本锁定的建议spring-boot-starter-parent用2.7.18MyBatis-Plus用3.5.3.xjjwt用0.9.1。别小看版本锁定这件事SpringBoot 3.x和SpringBoot 2.x的javax迁移到jakarta命名空间很多教程混着用就会直接启动报错。如果你看的教程用的是2.x就老老实实全套2.x。后端接口最好统一返回格式我定义了一个Result类包含code、msg、data三个字段。code为200时表示成功400表示参数错误401表示未登录500表示服务器异常。所有Controller的方法返回值都写成Result这样前端Axios拦截器只需要判断code是否为200极大简化了错误处理逻辑。SpringBoot的全局异常处理用RestControllerAdvice注解实现配合ExceptionHandler可以捕获业务异常和系统异常。这里我建议自定义一个BizException凡是业务校验不通过的地方就throw new BizException(xxx)全局处理器把msg返回给前端。这样代码里就不会到处是if-else的返回错误分支逻辑会干净很多。application.yml配置里数据库连接建议加上serverTimezoneAsia/Shanghai避免时区问题导致时间字段歇菜。mybatis-plus的配置里开启map-underscore-to-camel-case: true这样数据库的下划线字段能自动映射到Java的驼峰属性省去大量手工映射代码。3.2 JWT登录认证与权限控制登录认证我选了JWT方案。核心流程是用户提交用户名和密码后端校验成功后生成一个token字符串返回给前端前端把token存在localStorage里每次请求在请求头里带上Authorization: Bearer token后端写一个拦截器或过滤器解析token确认用户身份并把用户ID放到请求上下文里。Spring Security在这里的使用要把握好尺度毕设不需要把整个过滤器链搞得太复杂。我的做法是自定义一个JwtAuthenticationFilter继承OncePerRequestFilter在里面做token的校验和用户信息的加载。然后把这个过滤器放到Spring Security的过滤器链中同时用SecurityConfig配置哪些路径需要认证、哪些路径放行。放行的路径包括登录注册接口、动物列表查询接口、图片访问接口这些公共资源需要认证的包括提交领养申请、修改个人资料、管理后台操作等。这里有个容易踩的坑JWT的密钥一定要配置在application.yml里不要硬编码。过期时间建议设置成24小时太短了用户用着突然就退出登录太长了安全性受影响。token的生成用jjwt库解析时如果抛了ExpiredJwtException说明过期了返回401并提示前端跳转到登录页。另外一个细节是同一个用户在不同的端比如PC和手机登录可能会生成不同的token如果想做到一处登录另一处被踢下线那就需要把有效的token存到Redis里维护。但毕设一般不需要做到这种程度只要每次请求都能正确解析出用户ID即可。3.3 动物信息管理与图片上传宠物照片上传是整个系统用户体验的关键。文件上传我用的是SpringBoot自带的MultipartFile接收前端传过来的file字段然后保存到本地磁盘的上传目录。这里有几个必须处理好的细节上传目录必须配置成绝对路径不能用相对路径否则在不同操作系统下很容易出现找不到文件的问题。保存的文件名就不能直接用用户原始文件名要加时间戳或UUID前缀避免重名覆盖。图片上传成功后返回给前端的是一个可访问的URL如果图片存储在本地可以配置一个静态资源映射把磁盘目录映射到URL路径上这样前端img标签直接引用URL就能展示图片。文件大小限制要注意SpringBoot默认单文件最大1MB这个对于宠物照片来说很可能不够。建议在配置里设置max-file-size为5MBmax-request-size为10MB。前端上传前也要做校验同时检查文件类型和后缀限制只能上传jpg、png、gif这些格式防止非图片文件被故意传上来。动物发布时还有个细节救助站人员填写的动物信息里封面图和详情图是分开的封面图只传一张详情图可以多张。存储上最好把详情图的URL拼接成逗号分隔的字符串存在一个字段里查询时用split拆成列表。虽然这不太符合严格的数据库范式但对于宠物这种图片数量不固定的场景来说实际编码会方便得多。3.4 领养申请的审批流程逻辑领养申请模块是整个系统的核心业务。申请人从动物详情页点击“申请领养”弹出表单填写申请理由、居住情况、养宠经验等信息。提交后这条申请记录的状态变成待审核同时向动物所属的救助站管理员发送一条站内通知。管理员端在审批列表里能看到所有待审核的记录点击详情能看到申请人的完整信息和动物信息。审批的核心是判断申请人的条件是否适合养这只宠物。技术上我实现了一个简单的条件积分逻辑如果用户填写了自有住房加10分租房加3分养宠经验超过3年加10分1-3年加6分没有经验0分家庭成员中没有对宠物过敏的加5分。系统并不用积分直接判定结果只是作为管理员的参考最终决策还是人工判断这样更符合公益救助的实际情况。审批通过后还有一个联动操作动物表里对应记录的状态自动改成“已领养”同时如果这只动物之前挂在寻宠启示下要同步下架寻宠启示。审批拒绝时一定要填写拒绝理由否则申请人不知道问题出在哪里下次还会重复申请。这块最容易出的Bug是并发问题同一个动物被多个用户同时提交领养申请而动物当前状态是待领养理论上只应该有一个申请能通过。解决办法是在审批通过的方法上加事务并在更新动物状态时使用乐观锁或者先执行UPDATE语句判断影响行数如果影响行数为0说明状态已被修改就不能再通过审批这样能有效防止超领。4. Vue前端页面与交互实现4.1 项目搭建和环境配置前端的搭建用的是Vue CLI版本建议用Vue 2.7配Element UI这组合的社区资料最多、组件最齐全遇到问题搜一下就有一堆答案。如果你学校要求用Vue 3的话也可以但Element UI不支持Vue 3要用Element PlusAPI上有一些差异自己注意适配。创建项目的命令很简单vue create pet-front。创建时选择手动配置功能勾选Router、VuexCSS预处理器看个人习惯我选的是Sass。node版本建议16.xVue CLI对Node 18以上的版本兼容性偶尔会有问题如果你装了新版本Node导致构建报错不一定要换Node版本可以用npx升级Vue CLI到最新版试试。依赖除了vue-router和vuex之外重点要装axios和element-uinpm install axios element-ui。Element UI全量引入虽然打包体积大一点但毕设项目压根不在乎这点体积全量引入省事不会因为按需引入配置出错导致组件样式丢失。4.2 路由配置与页面结构前台用户端的路由结构我设计成首页路由/animals对应动物列表页/animals/:id对应动物详情页/user/info对应个人中心/user/myApplications对应我的申请/adopt/add对应发布动物信息/found/add对应发布寻宠启示/login和/register对应登录注册页。路由守卫很重要。在router.beforeEach的全局前置守卫里判断要跳转的路径是否需要登录权限如果需要在meta里标记requiresAuth: true然后检查当前登录状态是否存在。未登录就跳转到登录页同时带着redirect参数登录成功后跳回原来的页面这个体验细节做得好会让用户觉得系统很贴心。导航栏的设计上顶部放系统名称和一级导航入口用户登录后右上角显示头像和用户名点击下拉菜单可以进入个人中心和退出登录。前端根据用户角色来显示不同的导航项普通用户能看到领养入口管理员能看到后台管理入口。角色的区分在登录返回的userinfo接口里带上一个role字段前端用Vuex存储起来渲染时做v-if判断。4.3 Axios封装与接口联调要点Axios封装是前端开发中绝对不能偷懒的部分。我单独建一个request.js文件创建axios实例并设置baseURL和timeout。请求拦截器里从localStorage取出token在请求头加上Authorization响应拦截器里统一处理HTTP响应码code为200时直接返回data未登录或token过期时清空本地存储并跳转登录页。baseURL在本地开发时可以直接写http://localhost:8080但考虑到部署时前后端可能是不同域名的一定要在vite或vue-cli的devServer配置里设置proxy代理把/api前缀请求转发到后端地址。这样前后端联调时不需要处理跨域问题生产部署时也能通过Nginx再做一层反向代理。很多人在这里卡住是因为直接在前端代码里写死了后端地址换成服务器环境就改一堆地方。接口模块化的做法是把不同业务的API按文件拆开user.js放注册登录和用户信息接口animals.js放动物相关接口adoption.js放领养申请相关接口。每个接口函数用箭头函数导出内部调用axios实例的get或post方法。这样的好处是页面组件里不用关心具体URL后续接口地址有变动时只需要改一个文件。4.4 核心页面实现与组件复用宠物列表页是整个系统最关键的页面我拆了几个子组件AnimalCard作为单只宠物的卡片组件FilterSidebar作为筛选栏组件PaginationBar作为分页组件。AnimalCard放在列表里循环渲染展示宠物图片、名称、品种、性别和健康标签点击卡片跳转详情页。筛选功能包括按种类筛选、按城市筛选、按状态筛选。传参方式我用了路由query参数因为这样好处是筛选条件可以通过URL分享给朋友刷新页面后条件也不会丢失。筛选条件变化时触发一个watch重新调用列表接口。后端接口支持这些条件参数的组合查询通过MyBatis-Plus的LambdaQueryWrapper构建动态条件。动物详情页展示大图画廊、基本信息表格、性格描述和救助站信息。最核心的是底部两个按钮“申请领养”和“收藏”。申请领养按钮点击后如果未登录则跳转登录页已登录则弹出申请表单Dialog表单里默认带入用户的基本信息申请人只需要补填申请理由和养宠经验。提交成功后弹出成功提示并关闭Dialog详情页上的动物状态如果变为已领养按钮要自动变为禁用状态。后台管理页面用Element UI的卡片布局每张卡展示一个申请记录点击审批按钮弹出确认框根据管理员的选择调用approve或reject接口。管理页面的表格列表和数据加载做成了一组可复用的mixin新的后台模块只需要复用mixin里的数据加载、分页处理、状态刷新逻辑开发效率会提升非常明显。5. 联调部署、测试与常见问题排查5.1 前后端联调的标准流程联调的第一步是先把后端跑起来然后用一段健康检查脚本验证连通性。我习惯先从头到尾把注册、登录、获取用户信息这条链路走通因为这条链路涉及了JWT拦截器和全局异常处理链路通说明核心认证机制没问题。然后再测试单个业务模块比如动物列表查询从最简单的无参数查询到带筛选条件、分页参数的组合查询。之前有个朋友联调时遇到一个经典问题前端请求发送了后端日志也显示接收到了但响应时间非常长最后超时了。排查了半天发现是数据库连接池的连接配置有问题默认连接数太小加上没有空闲连接回收并发稍微高一点就导致获取连接等待。解决办法是在配置里调大initial-size和max-active同时连接空闲超时时间设置成合适值。联调过程中建议把后端的日志级别调到DEBUG在Controller层和Service层打一些关键日志记录请求参数和返回结果。这样联调时随时可以通过日志定位问题是出在参数接收、业务逻辑还是数据库查询。debug日志定位问题很快但线上部署一定要关闭否则日志量大会拖垮性能。5.2 多少都会遇到的数据库问题实录数据类型映射。MySQL的datetime类型映射到Java的LocalDateTime是没有问题的但如果你返回给前端的数据里有LocalDateTime字段序列化后是带T的ISO格式前端的日期组件很可能解析不了。建议在application.yml里配置Jackson的全局时间格式yyyy-MM-dd HH:mm:ss这样接口就返回标准格式。前端的日期选择器绑定的输入值也尽量用字符串避免来回转Date对象。模糊搜索。动物列表页有按名称搜索功能MyBatis-Plus的like条件要用在动物名称字段上但需要注意的是如果搜索关键字里有百分号或下划线这类SQL通配符需要做转义处理否则搜索行为会不符合预期。实际用下来搜索功能和筛选条件组合在一起时要特别关注WHERE条件的拼接顺序MyBatis-Plus的条件构造器要保持同一个Wrapper对象传参不要复制多个条件拼接。分页数量不准确。MyBatis-Plus分页需要配置PaginationInterceptor不配置的话传入分页参数不会真正拿到LIMIT分页结果而是一次性查全表再内存分页。如果你发现接口返回的total字段是总数、但前几页的数据不对大概率就是分页插件没有生效。5.3 前端常见的渲染与样式问题Element UI的组件样式在打包后有时会丢失大概率是引入了组件库但没有引入样式文件。全量引入时需要在main.js里import元素ui的css按需引入时要配置babel-plugin-component。样式失效的排查方向先看浏览器控制台有没有样式请求404再看node_modules里对应组件的样式路径是否能找得到。图片加载失败在宠物系统里格外显眼。前端列表页组件里图片URL用接口返回的路径但路径可能是相对路径导致图片请求到了前端服务器而不是后端图片服务器。解决办法是后端返回的图片URL直接拼接完整地址或者前端写一个全局过滤器统一拼接图片域名。如果图片404按F12看网络请求路径就知道是哪里拼错了。Vuex刷新数据丢失也是一个经典坑。Vuex的state是存在内存里的页面一刷新就全部清空。用户登录后虽然设置了token和用户信息在Vuex中但刷新后状态丢失页面又会显示未登录。解决方案是初始化时从localStorage读取初始状态或者刷新接口重新获取用户信息。我的做法是main.js里在应用启动时调一次userInfo接口如果token有效就把用户信息重新放进Vuex。5.4 部署到云服务器的打包指南后端打包用Maven的package命令生成可执行的jar包。部署命令是nohup java -jar pet-server.jar --spring.profiles.activeprod 这样即使你关闭SSH窗口服务也会在后台继续运行。但如果你的服务器内存不高建议加上JVM参数限制内存使用-Xms256m -Xmx512m防止默认堆内存过小导致频繁GC。前端打包用npm run build生成dist目录整个目录放到服务器的Nginx的html目录下。Nginx的配置里需要做两件事一是将根路径指向dist目录并配置try_files参数配合前端路由的history模式否则刷新页面会404二是配置反向代理把/api路径代理到后端的SpringBoot服务的地址。有一点要想清楚前端部署的域名和后端服务不在同一个端口用户从浏览器访问时如果出现跨域报错严格说是两个端口之间的问题。正确做法是Nginx统一做代理转发让浏览器只访问80端口所有后端请求通过后端代理路径转发这样一来前端根本不会有跨域问题。我曾经见过同学不解这种做法非要在前端给 axios 配置跨域设置反而制造出一堆莫名其妙的问题后来改成 Nginx 代理之后很快就解决了。所以先明确一点跨域问题最好放到部署层的Nginx去解决而不是改前端代码。另外上传的宠物图片目录一定要记得做好访问映射。我用的方案是Nginx把一个/images/路径直接指向磁盘的上传目录这样前端的图片URL就是http://域名/images/xxx.jpg由Nginx直接处理静态文件不会走到后端应用层的接口。5.5 常见问题速查表我把整个开发过程中真实遇到过的问题整理成一张速查表遇到类似的可以直接先查一下问题现象排查方向解决方案后端启动报java版本错误检查JAVA_HOME和pom.xml版本统一使用JDK 1.8或11SpringBoot 2.x配JDK 8最稳前端npm install报错检查node版本和网络源切换到淘宝镜像源Node 16.x配Vue CLI兼容最好登录接口报401检查token是否传入前端请求拦截器确认加Authorization头后端确认过滤器注册图片上传后访问404检查静态资源映射确认Nginx或SpringBoot资源映射路径和保存路径一致分页total正确但列表页为空检查分页插件配置确认MyBatis-Plus分页Interceptor已注册前端样式刷新后丢失检查Element UI样式引入全量引入或在babel配置中引入按需样式路由刷新后404检查Nginx try_files配置配置fallback到index.html时间字段显示带T检查Jackson配置配置全局日期格式为yyyy-MM-dd HH:mm:ss列表接口慢检查数据库索引给动物表status、城市字段加普通索引并发提交申请导致状态错乱检查事务和乐观锁更新状态时使用条件UPDATE影响行数判断6. 答辩演示准备与项目亮点提炼过了开发这道关其实还有一道隐藏关卡答辩现场演示。很多同学做出来的系统功能是完整的但一旦现场演示就暴露问题最大的问题不是代码Bug而是演示节奏和思路不清楚。建议准备一份演示脚本按这个顺序走先讲项目背景和价值强调流浪动物救助的社会意义再展示系统整体架构图说清楚前后端分离、技术选型的理由然后按业务链路从前到后演示注册登录、浏览宠物列表、查看详情、提交领养申请、管理员审批、动物状态变化。关键节点停下来讲解一下数据库表设计和接口设计让老师看到你的技术深度。答辩提问环节经常会被问到的问题是为什么选择MyBatis-Plus而不是原生的MyBatis为什么用JWT而不用Session系统的并发量背景和如何优化这几个问题的答案要提前准备好每一个都要能往项目实际设计上靠。比如JWT和Session的区别不要只背概念要结合你项目中如何部署、如何存储token、如何做拦截来回答。项目的亮点可以从这几个方向提炼一是完整的角色权限体系普通用户和管理员的权限差异是通过Spring Security JWT实现的二是宠物图片上传和访问这套完整链路涵盖了静态资源映射、文件类型校验、大小限制等细节三是领养审批的状态机设计状态流转清晰且防止了并发问题四是前端组件化复用AnimalCard、分页组件、上传组件在多处复用代码结构清晰。如果时间允许还可以录制一段演示视频万一现场服务器出了问题也有后手。视频里录好主要流程的操作过程和核心代码讲解视频时间控制在5分钟以内作为答辩的补充材料。这个准备工作看着小但真到关键时候能救命。7. 写在最后做这个宠物领养系统最大的收获不在于用了多少新技术而在于把一条完整的业务链路从零到一做了出来。从最初的数据库表设计到后端接口开发再到前端页面联调最后部署上线每一步都在解决问题每一步都在加深对技术栈的理解。如果你正准备做类似的毕设我建议你先别急着写代码花三天时间把数据库表结构和接口定义想清楚画清楚一张流程图想清楚每一张表之间的关系理清楚每个页面需要调用哪些接口。建模阶段想得越细写代码阶段就越不用返工。代码敲累了就去看看真实领养平台是怎么设计的多参考一下人家信息架构和交互流程比闷头造轮子有用得多。最后再分享一个小技巧整个项目过程中一定要随手截图、随手记录开发日志。不仅是需求分析、数据库设计、时序图这些文档你踩过的坑也可以顺手记在一个md文件里。答辩时把开发过程文档和在项目里解决的问题列出来内容一充实老师的印象分直接上一个台阶。遇到报错时的排查思路这些都是实打实的学习成果展示。预祝你能顺利把这个系统做出来答辩的时候能自信地把整个项目的设计思路和实现细节讲清楚。有问题欢迎随时交流这个方向可以聊的东西还有很多。