基于Spring Boot的流浪猫狗救助与宠物领养系统设计与实现
发布时间:2026/10/13 20:13:18 锦皓数字建站

毕业设计选题说实在的每年都有一堆人卡在同一个地方题目太老土技术栈太老旧做出来自己都没底气写进简历。如果你正在纠结Java方向的毕设题目又对“宠物”这个热门赛道有点兴趣那今天这篇文章应该能帮你省掉不少弯路。我要聊的这套基于 Java Spring Boot 的流浪猫狗救助与宠物领养系统不光是能交差而是做完之后你会清楚每一行代码为什么这么写每一个表为什么这么建真正能写进项目经历里撑得住场面。这套系统的核心价值很简单它把“流浪动物救助”和“宠物领养”这两个社会关注度很高的场景完整地用技术手段落地了。从用户浏览宠物信息、提交领养申请到管理员审核、追踪救助记录再到整个后台的数据管理业务闭环是完整的。而且Spring Boot作为当前Java后端开发当之无愧的主力框架这套系统的每一个模块都是在它的生态下实现做完它你对Spring Boot的理解深度和简历呈现力都会不一样。是不是适合你你可以先对号入座如果你是计算机、软件工程相关专业的应届生毕业设计想选一个“不烂大街、有现实意义、能正儿八经答辩”的题目这套系统很适合如果你打算找工作方向是Java后端开发希望毕设项目能体现CRUD之外的业务逻辑设计能力那它更是加分项。原因很简单这套系统里既有常规的数据管理又有领养审核流程、状态流转、权限控制这些真实业务里常见的难度点不是那种“对着课程表做个增删改查”级别的课设。1. 整体方案设计与技术选型拆解1.1 一个救助系统到底需要在技术层面解决什么问题在聊技术之前我先带你想清楚一个问题这个系统的业务本质是什么不是“展示猫狗图片”也不是“做个好看的网页”。它的本质是让分散的救助信息被更多人看见把“想领养的人”和“需要被领养的宠物”之间用一套标准的流程连接起来同时让后台管理人员能高效地审核、追踪、管理所有信息。一旦你从这个角度去理解技术选型就变得顺理成章了得有一套用户注册登录机制区分普通用户和管理员这对应Spring Security或者拦截器配合JWT的权限管理。得有一个清晰的数据模型管理宠物信息、用户信息、领养申请、救助记录、留言反馈这对应MySQL的表结构设计。得有一个高效的后端框架来承接所有业务接口这对应Spring Boot。得有地方放宠物图片、处理文件上传、做数据统计这对应文件存储和定时任务。这些需求叠加起来你就能明白为什么这套系统要选Spring Boot MySQL Vue这样的组合。它不是为了堆技术而是因为每一层都有明确的责任分工。1.2 为什么是Spring Boot而不是SSH或者SSM我接触过不少还在用SSHStruts Spring Hibernate做毕设的同学说句实话那些项目拆开源码看很多代码都是十年前的写法学了真不一定能应对现在的面试。Spring Boot为什么能成为主流两个核心原因一是它大幅简化了配置内置了Tomcat你写完代码直接mvn spring-boot:run就能启动项目不用再去折腾复杂的XML配置和外部容器部署二是它的生态太成熟了Spring Security、MyBatis-Plus、Spring Data JPA这些工具几乎可以无缝集成。对比一下你就明白了用传统的SSM框架你要手动配置数据源、事务管理器、MyBatis映射文件还要一个个处理依赖版本冲突。而Spring Boot通过starter机制帮你把常用依赖打包好了你只需要在pom.xml里加一个spring-boot-starter-web它就会自动带着Tomcat、Spring MVC、Jackson这些组件进来。这种“约定优于配置”的思路正是让你把精力从“配环境”转移到“写业务”上的关键。当然也有人说Spring Boot太重了用Flask或者Go写个轻量后端更简单。这个我不否认但你要考虑到这是毕设场景大多数学校对Java Web的考核标准就是围绕Spring生态来的你选Spring Boot不仅是被接受度最高的方案也是论文能写得最扎实的方案。因为Spring Boot的IOC容器、AOP切面、自动配置这些机制每一个都有足够的理论深度支撑你写出一章漂亮的“相关技术介绍”。1.3 架构模式前后端分离还是服务端渲染这个决定会影响你整个开发过程的工作方式。传统做法是直接用Thymeleaf这类模板引擎Java后端把页面一起渲染了前端页面直接嵌在后端项目里。这套方案的优点是开发链路短不需要单独维护前端项目适合非常紧急的情况。但我个人不太推荐原因有二第一现在的真实开发环境里前后端分离已经是绝对的主流你毕设做完出去面试如果简历上写着“Thymeleaf服务端渲染”面试官多少会皱一下眉头第二前后端分离模式下你可以用Vue、Element UI这种成熟的前端组件库页面做出来颜值直接上一个档次答辩时演示效果完全不同。这套系统采用的方案是典型的前后端分离架构Spring Boot专门负责提供RESTful APIVue负责渲染页面和交互通过Axios发起HTTP请求与后端交互。前端项目启动在8080端口后端项目启动在8081或者9090端口通过Vite或Webpack的代理转发解决跨域问题。这样前端归前端后端归后端谁出问题都不影响对方调试。要注意的是前后端分离模式对跨域处理是有讲究的。开发环境下你可以用Vite的server.proxy配置代理把/api路径的请求转发到后端的实际地址生产环境下可以把前端打包后的dist目录放到Nginx里并配置反向代理。这两种方式都能绕过跨域限制但如果你图省事直接在后端代码里写一个全局的CorsFilter允许所有来源跨域也能跑通但答辩时如果被问到“为什么这么开放有没有安全风险”你就需要能解释清楚。1.4 数据库选型MySQL为什么够用这个系统的数据量撑死也就是成千上万条宠物信息和用户记录还远不到需要引入分布式数据库或者NoSQL的程度。MySQL作为关系型数据库在事务性、数据一致性、生态工具丰富度上都是这个体量项目的最优解。配合Navicat或者DBeaver做图形化管理你建表、调数据、跑SQL都比命令行舒服太多。这里多说一句很多同学在做毕设时容易踩一个坑就是把数据表设计得特别“敷衍”。比如宠物表就放一个名字、一个图片路径、一个描述没了。这种表结构写出的系统看起来啥功能都有实际上经不起推敲。我们后面会详细讲真正合理的数据库设计是要能支撑业务流转的领养申请状态怎么变化、救助记录怎么关联、留言和回复怎么组织都需要有相应的表和字段来承接。2. 数据库设计与核心表结构精讲2.1 先梳理业务关系一句话讲清表的来龙去脉数据库设计的第一步不是打开Navicat建库建表而是先在纸上把业务关系画清楚。我习惯用最朴素的方式把所有名词宠物、用户、领养申请、救助记录、留言、公告写在纸上然后用连线把关系标出来。这个系统里核心关系大致是这些用户User与宠物Pet用户可以浏览宠物、收藏宠物、申请领养宠物。用户User与领养申请AdoptApplication一个用户可以提交多个领养申请但同一时间只能有一个申请处于“待审核”状态。救助记录RescueRecord对应一条流浪宠物被救助的信息救助人可以是注册用户也可以是管理员后台录入。留言Message与回复Reply用户对宠物或某个救助动态发表评论管理员可以回复。公告Notice管理员发布站内公告用户登录后在首页能看到。把这些关系框定之后表结构就呼之欲出了。总共大概七八张表对于一个单体毕设项目来说不多不少刚好能体现“完整业务闭环”的设计思想。2.2 重点表结构设计别在这些字段上栽跟头我挑三张核心表来拆解设计思路这三张表设计好了其余的表就是依葫芦画瓢。用户表userCREATE TABLE user ( id bigint(20) NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL COMMENT 登录账号, password varchar(100) NOT NULL COMMENT 加密后的密码, nickname varchar(50) DEFAULT NULL COMMENT 昵称, phone varchar(20) DEFAULT NULL COMMENT 手机号, email varchar(100) DEFAULT NULL COMMENT 邮箱, avatar varchar(255) DEFAULT NULL COMMENT 头像地址, role tinyint(4) NOT NULL DEFAULT 0 COMMENT 角色0-普通用户 1-管理员, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 状态0-正常 1-禁用, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这张表的关键点有三个。第一password字段必须存的是加密后的密文而不是明文。不管你用MD5加盐、BCrypt还是Spring Security自带的PasswordEncoder这一步不能省否则答辩时被问到“用户密码安全怎么保证”你就被动了。第二role字段用int类型而不是字符串区分成本低、判断方便如果你后面还想扩展“救助志愿者”这类中间角色加一个值就行。第三username一定要加唯一索引这是登录逻辑的基础漏了这个索引后面会出现账号重复注册的bug。宠物表petCREATE TABLE pet ( id bigint(20) NOT NULL AUTO_INCREMENT, name varchar(50) NOT NULL COMMENT 宠物昵称, type tinyint(4) NOT NULL COMMENT 类型0-猫 1-狗, breed varchar(50) DEFAULT NULL COMMENT 品种, age varchar(20) DEFAULT NULL COMMENT 年龄描述比如2个月, gender tinyint(4) DEFAULT NULL COMMENT 性别0-公 1-母 2-未知, health_status varchar(255) DEFAULT NULL COMMENT 健康状况描述, vaccine tinyint(4) NOT NULL DEFAULT 0 COMMENT 是否已接种疫苗0-未接种 1-已接种, sterilization tinyint(4) NOT NULL DEFAULT 0 COMMENT 是否已绝育0-未 1-已, photos text COMMENT 宠物照片可多个逗号分隔, story text COMMENT 救助故事, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 状态0-待领养 1-审核中 2-已领养 3-下架, create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;宠物表是这整个系统的门面字段多但基本都直白容易出错的是photos字段。一个宠物可能有多张图片我见过有的同学为此单独建一张pet_photo表能做但没必要直接在photos字段存逗号分隔的文件名读取的时候Java里面split(,)就能拿到数组对毕设级别的项目来说简单好用。另外status字段是整个宠物信息流转的核心必须用数字状态机来管理后续所有列表查询都要过滤掉“已领养”和“下架”的宠物这一点很容易忽略。领养申请表adopt_applicationCREATE TABLE adopt_application ( id bigint(20) NOT NULL AUTO_INCREMENT, pet_id bigint(20) NOT NULL COMMENT 宠物ID, user_id bigint(20) NOT NULL COMMENT 申请人ID, reason text COMMENT 领养理由, address varchar(255) DEFAULT NULL COMMENT 居住地址, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 流程状态0-待审核 1-已通过 2-已拒绝, audit_remark varchar(255) DEFAULT NULL COMMENT 审核意见, create_time datetime DEFAULT CURRENT_TIMESTAMP, audit_time datetime DEFAULT NULL COMMENT 审核时间, PRIMARY KEY (id), KEY idx_pet_id (pet_id), KEY idx_user_id (user_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这张表的status字段直接对应了领养申请的整个生命周期。它最有价值的地方在于领养不是简单的“用户点了申请就完事”而是要形成一条状态流转链待审核 → 已通过/已拒绝。你在后端写逻辑时就要保持一个原则用户提交申请时把状态置为“待审核”只能提交一次防止重复申请管理员审核通过时把宠物状态和申请状态同时变更在同一个事务里完成。2.3 表设计背后的两个防坑心得第一个心得所有表都保留create_time需要跟踪更新的表再加update_time这是基本功。答辩时往ER图上一指说你考虑了数据的时间维度这个印象分一定要拿。第二个心得photos和story这类字段一定要用text类型别用varchar(255)。宠物描述和救助故事通常远超255个字符一旦超了写入就会报错这个错误排查起来还很不直观不如直接用text类型一了百了。3. 后端核心功能实现代码拆开讲3.1 项目初始化用一个干净的Spring Boot骨架项目结构上我推荐用Maven管理的Spring Boot 2.7.x版本搭配MyBatis-Plus 3.5.x作为ORM框架。有人可能问Spring Boot 3.x都出来了为什么不用最新的原因很简单Spring Boot 3是基于Jakarta EE的很多老版本的依赖和教程都不兼容毕设阶段没必要为了追最新去给自己挖坑。等你以后工作中遇到升级需求再学不迟。pom.xml里的关键依赖大概是这几组dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-validation/artifactId /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt/artifactId version0.9.1/version /dependency这里用MyBatis-Plus而不是原生的MyBatis或者Spring Data JPA我自己是倾向MyBatis-Plus的理由特别简单它提供了一整套单表CRUD的通用方法你不用自己手写大部分重复的SQL但同时依然能保留手写XML的灵活性。配合它的LambdaQueryWrapper写条件查询是真的爽代码可读性还特别高。比如ListPet petList petMapper.selectList( new LambdaQueryWrapperPet() .eq(Pet::getStatus, 0) .eq(Pet::getType, type) .orderByDesc(Pet::getCreateTime) );这一行代码的效果是分页查询出所有状态为“待领养”、类型匹配的宠物并且按创建时间倒序排列。要是换原生MyBatis你得写SQL、写映射、写接口麻烦不少。3.2 登录认证与权限控制从拦截器到JWT的完整链路登录认证这环我知道有不少同学要么直接不做要么用Session简单搞定。但你要是想把简历上的技术含金量往上提一档我建议用JWTJSON Web Token方案它现在也是前后端分离项目的主流选择。大致逻辑是这样的用户提交用户名密码后端调用UserService.login()校验。校验通过生成一个JWT令牌里面带上用户ID和角色信息发给前端。前端把令牌存到本地localStorage或者Pinia状态管理里每次请求时放在HTTP Header的Authorization字段。后端写一个AuthInterceptor拦截除登录接口之外的请求校验令牌是否有效并且把当前登录用户的信息放进ThreadLocal或者请求上下文中。校验令牌的代码核心部分给大家一个参考思路public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token request.getHeader(Authorization); if (token ! null token.startsWith(Bearer )) { token token.substring(7); try { Claims claims Jwts.parser() .setSigningKey(secretKey) .parseClaimsJws(token) .getBody(); request.setAttribute(userId, claims.get(userId)); request.setAttribute(userRole, claims.get(role)); return true; } catch (Exception e) { response.setStatus(401); return false; } } response.setStatus(401); return false; }权限控制这块核心不在于代码多复杂而在于你要理清哪些接口是公开的、哪些只属于管理员。比如用户注册登录接口公开宠物列表和宠物详情公开提交领养申请、查看自己的申请记录必须登录管理后台的宠物审核、用户管理、领养审核接口必须管理员权限。在拦截器里拿到userRole之后判断一下就能控制。还有一个小细节密码加密。用Spring Security的BCryptPasswordEncoder虽然方便但如果你不想引入整个Spring Security依赖也可以用Apache Commons Codec的DigestUtils.md5Hex加盐处理。不过说实话BCrypt是可逆验证里最稳的毕设里面加这个环节非常加分。3.3 宠物模块列表、搜索、详情、状态流转宠物模块是整个系统的流量入口这里面的列表接口要支持多条件筛选。用户在首页可能想筛选“只看猫”“只看狗”“已绝育”“已接种疫苗”这些条件对应的SQL查询条件和MyBatis-Plus的LambdaQueryWrapper配合得特别好。分页查询是必考项用MyBatis-Plus内置的分页插件只需要两步第一步配置一个MybatisPlusInterceptorBean注册PaginationInnerInterceptor第二步在调用selectPage方法时传入Page对象PagePet page new Page(current, size); PagePet result petMapper.selectPage(page, new LambdaQueryWrapperPet() .eq(Pet::getStatus, 0) .eq(StringUtils.isNotBlank(type), Pet::getType, type) .like(StringUtils.isNotBlank(keyword), Pet::getName, keyword));这里面的细节在于那些StringUtils.isNotBlank()条件它让SQL动态拼接用户没传的筛选条件自动忽略这样前端只需要传自己有的参数后端能统一处理。宠物状态流转说直白点就是“谁能改、何时改、改成什么”。当用户提交领养申请时如果宠物状态是“待领养”就只改变申请状态宠物本身仍然是“待领养”因为申请还在审核中当管理员点击“通过审核”时事务里同时做两件事申请状态更新为“已通过”宠物状态更新为“已领养”。这个双表更新必须放在一个Transactional事务里一旦第二步失败第一步也要回滚不能出现“申请显示出错但宠物却标记成已领养”的数据不一致。3.4 领养申请模块非简单的CRUD而是一个带流程的业务闭环领养申请在业务上要比宠物管理复杂一截因为它不只是读写一条记录而是有明确的状态约束。用户侧的关键逻辑用户在申请前后端要校验这个宠物是否还在“待领养”状态同时校验当前用户有没有已存在的“待审核”申请如果有就拒绝再次提交。我一开始做的时候没加第二个校验测试时用户反复提交了三四次领养申请管理员后台的待办列表瞬间多了好几条重复记录看着都头疼。代码逻辑大致是这样的public String apply(AdoptApplicationVO vo, Long userId) { Pet pet petMapper.selectById(vo.getPetId()); if (pet null || pet.getStatus() ! 0) { throw new BusinessException(该宠物当前不可领养); } Long count adoptApplicationMapper.selectCount( new LambdaQueryWrapperAdoptApplication() .eq(AdoptApplication::getUserId, userId) .eq(AdoptApplication::getStatus, 0) ); if (count 0) { throw new BusinessException(您还有待审核的申请不能重复提交); } AdoptApplication application new AdoptApplication(); application.setPetId(vo.getPetId()); application.setUserId(userId); application.setReason(vo.getReason()); application.setStatus(0); adoptApplicationMapper.insert(application); return 提交成功; }管理员侧的关键逻辑管理员在待审核列表点“通过”后端要顺带检查宠物状态是否还是“待领养”。如果此时宠物已经被别人领走了要提示“当前宠物已被领养无法通过审核”。这个竞态问题在真实开发里非常常见毕设阶段你把它处理了放在简历里就是一个很好的“业务状态一致性控制”的实践案例。3.5 救助登记模块让系统的“公益”底色真正立住救助登记是这个系统区别于普通宠物展示平台的关键功能。它的业务场景是用户在路边发现一只流浪动物可以在系统上登记一条救助信息上传照片、填写发现地点和当前状况管理员后台确认信息后可以把这只动物转入宠物列表变成“待领养”状态。这个功能背后的两个核心接口值得重点讲。第一个是“登记救助信息”接口。前端表单提交了救助动物的照片可能有1-3张、发现地点、状况描述、紧急程度。后端要做两件事保存照片文件到本地磁盘或者OSS然后再把图片路径和文字信息写入rescue_record表。文件上传的代码用Spring Boot的MultipartFile实现核心逻辑是生成唯一文件名UUID避免不同用户上传同名的图片互相覆盖public String upload(MultipartFile file) { if (file.isEmpty()) { throw new BusinessException(文件不能为空); } String originalFilename file.getOriginalFilename(); String suffix originalFilename.substring(originalFilename.lastIndexOf(.)); String fileName UUID.randomUUID().toString().replace(-, ) suffix; File dest new File(uploadDir fileName); file.transferTo(dest); return /uploads/ fileName; }第二个是“救助转宠物”接口。这个接口是管理员后台的操作逻辑是把救助记录中的照片和描述信息复制一份到宠物表设置宠物状态为“待领养”同时把救助记录的状态更新为“已处理”。这个功能做好了你在答辩时可以理直气壮地说“系统完整覆盖了从发现流浪动物到完成领养的救助链路”这句话的价值比你说十遍CRUD都有分量。3.6 文件上传与静态资源映射关于图片上传很多同学容易在配置上出问题。Spring Boot默认的静态资源路径是classpath:/static/但你上传的图片总不能写到jar包内部所以需要配置一个外部磁盘路径映射。在application.yml里加这样的配置spring: web: resources: static-locations: file:D:/upload/ ,classpath:/static/这样你上传到D:/upload/目录的图片就可以通过http://localhost:8080/uploads/xxx.jpg直接访问。开发时这样是没问题的但如果上线建议用Nginx的alias来代理图片目录效率和安全性都更好。毕设阶段你就稳扎稳打把本机路径配好演示时服务器上对应目录提前建好就够了。4. 前端页面搭建与前后端联调实战4.1 前端技术栈组合与用户端页面规划前端是用户能直接感知的部分在这个项目里页面美丑直接影响答辩效果。我推荐用Vue 3 Vite Element Plus这套组合。Element Plus的组件库很成熟表格、表单、对话框、弹窗提示这些组件拿过来直接用能帮你省掉一大半写样式的时间而且视觉风格统一不会出现“前端页面像没穿衣服”的情况。用户端的页面规划大致是这样的首页轮播图、推荐宠物、公告栏整体风格偏温暖公益。宠物卡片上要醒目展示“待领养”和“已领养”的状态标签用户一眼就能看出当前可领养的宠物。宠物列表页支持按类型猫/狗、性别、是否绝育等条件筛选关键的是带分页后端数据多的时候前端分页组件要联调好用。宠物详情页重点展示宠物多张图片、身体健康信息、救助故事底部留一个“申请领养”的按钮。这个页面是用户做决策的关键页把“救助故事”展示到位会明显提高领养转化率。用户中心展示“我的申请”用户可以在这里看到每条申请的当前状态也能取消尚未开始审核的申请。救助登记页表单上传图片和描述信息提交后可以跳转到“我的救助记录”页面查看审核进度。开发时前端项目通过Vite的代理转发后端请求在vite.config.js里配置export default defineConfig({ server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } })这里的关键在于前端请求路径统一以/api开头后端Controller的RequestMapper路径尽量也都以/api开头这样生产环境部署时只要在后端加一个统一的context-path或者让Nginx转发时带上前缀就能无缝切换。4.2 管理后台页面表格驱动的典型业务界面管理后台是管理员操作系统页面设计上不需要花哨核心是“信息密度大、操作效率高”。Element Plus的el-table组件在这个后台里扮演了绝对主角。宠物管理页列表展示全部宠物按状态筛选每条记录后面有“查看详情”“编辑”“下架”“删除”按钮。管理员能直接修改宠物状态比如把“待领养”改成“下架”。这个页面的status字段要和后端接口联动改完刷新后列表要立即更新。领养审核页这是管理后台最有含金量的页面。列表展示所有“待审核”的申请每条记录能看到申请人昵称、联系电话、领养理由、宠物名称。管理员操作区有“通过”和“拒绝”两个按钮点击后弹出确认对话框拒绝时还要填写拒绝原因。最后这一步在代码层面如果拒绝原因为空就不允许提交这个前端校验要加上。用户管理页展示全部注册用户可以禁用某个用户。被禁用的用户下次登录接口会直接被拦截器挡住这个逻辑要前后端配合后端在验证完用户名密码后再检查status字段如果是禁用状态就返回明确提示。4.3 前后端联调中的跨域与请求拦截前后端分离最难熬的不是写代码而是联调阶段。第一次启动前后端几乎一定会遇到跨域报错。跨域的本质是浏览器的同源策略在作怪前端的域名比如http://localhost:5173和后端的域名http://localhost:8080不一致浏览器默认禁止这样的请求。有三种常见解决方案开发阶段用Vite的proxy代理这是最好的方案浏览器看到的所有请求都发给了前端再由前端转发给后端不会触发跨域。后端加CrossOrigin注解或者配置一个全局CorsFilter优点是不用前端做任何调整缺点是会把API开放给所有域名有一定风险。生产环境用Nginx反向代理把/api请求转发给Spring Boot同样能避开跨域。我做项目时最推荐第一种和第三种组合。在联调阶段用Vite代理解决开发联调问题部署上线时前端打包后的静态文件直接放到Nginx里托管后端接口也由Nginx转发浏览器里只会看到同一个域名的请求跨域问题直接消失。如果一个项目的Nginx部署配置写得清晰这在简历上是可以写上“熟悉前后端分离部署流程”这个技能点的。5. 部署上线从源码包到PPT演示环境5.1 本地打包三步走部署前一定要在本地把打包流程跑通否则讲解时演示环境起不来那场面会非常尴尬。后端打包在项目根目录执行mvn clean package -DskipTests执行完后target/目录下会生成springboot-pet-adoption-0.0.1-SNAPSHOT.jar。用java -jar命令就能启动整个后端服务java -jar target/springboot-pet-adoption-0.0.1-SNAPSHOT.jar --spring.profiles.activeprod--spring.profiles.activeprod这行参数很关键意味着你可以维护多套配置文件application-dev.yml用于本地开发连本地MySQLapplication-prod.yml用于演示或上线环境连服务器上的MySQL并且把文件上传路径也切到服务器磁盘。这个技巧在简历上可以写“熟悉Spring Boot多环境配置管理”。前端打包npm run build打包完成后dist/目录就是纯静态文件。如果你没有Nginx也可以直接把整个dist目录拿到Tomcat的webapps/ROOT目录里用Tomcat托管但这样前端页面和后端接口不在同源还得处理跨域问题。所以有条件还是上Nginx吧Nginx配置也不复杂。Nginx的关键配置片段是这样的server { listen 80; server_name localhost; location / { root /usr/share/nginx/html/dist; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real_IP $remote_addr; } }第二个location配置的含义是凡是路径以/api/开头的请求全部转发给本机8080端口的Spring Boot服务。需要注意proxy_pass http://127.0.0.1:8080/;末尾有个斜杠这个斜杠会把/api前缀去掉如果后端Controller的路径是/pet/list那前端请求/api/pet/list转给后端就变成了/pet/list正好对得上。这个斜杠的细节我踩过一次当时排查了好久你引以为戒。5.2 演示环境的完整准备清单我看到太多同学在答辩前一晚才发现某个功能起不来手忙脚乱。为了避免这种情况这里给你一个演示前自检清单照着检查一遍数据库服务已启动连接信息与后端配置一致数据已初始化至少要有15-20条宠物数据、3-4条救助记录、几条领养申请这样演示时列表不会空一大片。后端服务启动后用浏览器直接访问一个接口比如http://localhost:8080/api/pet/list确认能正常返回JSON数据。前端页面能正常打开并访问后端接口登录、注册、宠物列表、详情页走一遍没有报错。图片上传功能测试过上传目录有写权限上传成功后图片能正常显示。至少准备两个测试账号一个普通用户用于申请领养、登记救助一个管理员用于审核。录制一份演示视频万一现场环境出问题视频也能兜底。给测试账号的密码都设置成简单好记的比如admin / 123456、user / 123456答辩时现场操作要非常流畅不能让评委等着你登录。5.3 部署文档和演示视频的制作经验“完整源码LW部署说明演示视频”这是项目交付的标配也是你之后写毕设文档时的素材基础。部署文档最简单的结构是把上面提到的所有步骤串起来环境要求、数据库初始化、后端启动、前端启动、打包部署、默认账号、Nginx配置。每一步都要截图并配上一两句话说明。演示视频则是一个容易被人忽略但非常加分的利器。录制视频不要用屏幕录制一镜到底或者边录边讲我建议这样处理先写好演示脚本按业务流程来录不要按页面菜单来录。比如先演示流浪狗登记再演示管理员审核通过再演示普通用户领养这只狗最后演示管理员批准领养整个链路呈现下来就是一条完整的故事线。录的时候用OBS或者系统自带的录屏工具控制在10分钟以内配上关键步骤的文字标注即可。6. 常见问题与排查技巧实录6.1 一张“避坑速查表”解决八成启动问题我刚跑这个项目的源码时也遇到过不少问题。这里把最容易碰的问题和排查思路整理成一张表做项目时对照着查能省很多时间。问题现象大概率原因排查与解决方案后端启动报Field petMapper in ... required a bean of typeMyBatis接口没有被扫描到确认启动类上有没有加MapperScan(com.xxx.mapper)后端启动报Access denied for user rootlocalhost数据库密码错误或权限不足检查application.yml里的数据库连接信息用Navicat测试一下连接前端页面一张图片都加载不出来静态资源路径配置错误或文件没在指定目录检查application.yml的static-locations配置确认上传目录结构正确注册时提示username重复注册接口没做唯一性校验或库里已有同名数据在Service层注册逻辑里加countByUsername判断登录后返回“未登录”JWT令牌失效或前端没有保存/回传Token检查前端Axios拦截器是否把Token放到了Header里申请领养时提示“宠物不可领养”宠物status不是0管理员后台手动改状态或者确认这个宠物是否已被领养查询列表很慢数据量增长后没有索引给查询频繁的字段type、status、create_time建普通索引6.2 两个我印象最深的排查案例第一个案例是关于数据库时间字段的。有一次演示时发现新登记的救助记录创建时间比当前时间晚了8个小时。查了半天最后发现是MySQL连接参数中没有加serverTimezoneAsia/Shanghai和JVM默认时区不一致导致的。这种时区偏差问题如果你没遇到可能永远意识不到但一旦遇到了就很恼人。解决方案是在JDBC连接串中显式指定时区url: jdbc:mysql://localhost:3306/pet_adoption?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai这个加号配置解决了从此时间显示完全正常。第二个案例是关于前端分页组件显示问题的。前端表格里显示的分页总条数一直不太对。原因是后端分页插件没生效导致selectPage返回的总条数其实是查询结果的总数而不是总的记录数。排查到根因后发现是缺少了分页插件配置Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }有了这个配置MyBatis-Plus才会在查询前自动执行一条count查询分页的total才是对的。这个小坑躲过了后面关于分页的奇怪问题就少了一大半。6.3 答辩环节的若干经验分享系统做完了论文答辩是最后一关。关于这一关我的真实体会是评委最看重的不是你用了多少新技术而是你能不能把自己的项目讲明白。所以答辩前有几个问题建议你提前准备答的时候要有逻辑为什么选择Spring Boot它和传统的SSM框架相比优势在哪数据库表是怎么设计的为什么这样设计如果以后要增加“志愿者”角色你会怎么改表领养审核的流程是怎么实现的如果两个用户同时申请同一只宠物你怎么保证不冲突JWT认证的原理是什么和Session方案比有什么优劣势如果用户上传的图片特别多当前存储方案会有什么问题你会怎么优化这些问题如果不能脱口而出说明你还没真正把项目吃透需要再回看自己的代码把每一个关键决策都补上“为什么”。如果能对答如流那恭喜你这个项目已经不只是“一个毕设”了它就是你投递Java后端岗位时可以拿出来重点讲的一段项目经历。最后再分享一个小经验做这套系统的时候不要太执着于“全做完”再回头研究“先跑通再优化”是很有效的节奏。先让核心链路通起来再逐步补充状态流转、权限校验、部署流程这些细节早上手你就比别人多一分从容。希望这份从选型到部署的全解析能让你在做这个项目的过程中少走几个来回遇到具体的报错或者设计卡点随时拿出来对着排查就行。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。