尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

SpringBoot+Vue+MySQL失物招领平台:毕业设计全栈开发实战解析

SpringBoot+Vue+MySQL失物招领平台:毕业设计全栈开发实战解析 1. 项目概述与核心需求拆解1.1 失物招领平台是做什么的带过不少学生的毕设每年到三四月份就会有一批人拿着类似“SpringBootVueMySQL 失物招领平台”的题目来问我要不要换题或者问这个题能不能做、好不好做。我的回答一般很直接这个题非常稳技术上不炫技但该涉及的东西全都有——用户系统、信息流、搜索、状态流转、文件上传、权限控制、前后端分离部署完整的Web全栈链路都能覆盖到非常适合做本科毕业设计。失物招领平台本质上就是一个“信息撮合”系统。它在校园、社区、园区这种封闭场景里非常实用有人丢了东西发一条寻物启事有人捡到东西发一条招领信息两边通过平台匹配然后走认领流程。整个系统解决的痛点很明确——线下张贴启事信息覆盖范围小、容易过期、沟通成本高线上化之后丢失方和拾得方都能更快地碰上面。这个度拿捏得好其实有两个关键点。第一点是功能要做“全”但不做“多”把发布、搜索、认领、审核、留言这些主链路打通就足够撑起一篇论文的工作量了。第二点是技术选型要“稳”启动快、社区资料多、出问题能查得到对毕设阶段来说比什么都重要。1.2 毕业设计需求拆解拿到题目之后第一步不是急着写代码而是把需求拆开揉碎。失物招领平台从角色角度看主要有两类用户普通用户和管理员。普通用户可以注册登录、发布寻物启事、发布拾物招领、浏览所有物品信息、按关键词和分类搜索、对某条信息发起认领申请、在物品详情页留言。管理员后台负责审核用户发布的信息、处理认领申请、管理用户状态、统计分析平台数据。把需求再往细处拆就可以列出一个功能清单用户模块注册、登录、个人信息修改、头像上传、密码加密存储失物模块发布寻物启事标题、描述、物品分类、丢失地点、丢失时间、联系人、图片、我的发布列表、下架/删除招领模块发布拾物招领标题、描述、物品分类、拾到地点、拾到时间、联系人、图片、我的发布列表、标记已归还搜索模块基于关键词的标题搜索、按分类筛选、按状态筛选、分页展示认领模块用户提交认领申请含认领理由、失主查看申请并审核、审核结果通知留言模块物品详情页下留言互动管理后台登录、信息审核、认领审核、用户管理、数据统计这样拆完之后你会发现这个项目看起来简单但其实每个模块要做得完整都不轻松。不过对毕设来说恰恰是好事——每个功能点在论文里都能单独成一小节工作量看得见导师也挑不出“内容太少”的毛病。1.3 为什么这个选题一直很稳每年我都会看到有人选“校园二手交易平台”“在线考试系统”“博客系统”“失物招领平台”这类题被评为“万年长青题”不是没道理的。它们的共同特点是业务逻辑贴近真实生活好理解需求描述起来不需要复杂的行业背景技术实现覆盖主流的全栈开发模式能体现学生的工程能力系统规模适中一个人一学期能完成不会出现做不完或者太简单的极端情况。失物招领平台相比其他选题还有一个天然优势可以加创新点。比如微信小程序端、地图定位拾取位置、基于图片相似度的物品匹配、Excel导入导出统计报表等。如果你不想和隔壁同学的项目撞脸随便挑一个方向加上去工作量就能提升一个档次。但我的建议很明确先把主流程做扎实创新点作为锦上添花千万别为了加功能把基础系统做成半成品。2. 技术栈选型SpringBoot Vue MySQL为什么是黄金组合2.1 SpringBoot让后端开发“退烧”我记得几年前用SSHStruts2SpringHibernate做项目的时候光配置文件就能把人绕晕applicationContext.xml、struts.xml、hibernate.cfg.xml每个都要手动配稍不留神就启动报错。SpringBoot出来之后这种痛苦基本消失了。内嵌Tomcat、自动配置、starter机制一个注解就能把项目跑起来。对毕业设计来说SpringBoot最大的价值不是“赶上时代潮流”而是大幅度降低出错概率。这意味着你可以把精力放在业务逻辑上而不是和环境配置斗智斗勇。举个例子如果你想用MySQL数据库只要在pom.xml里引入spring-boot-starter-data-jpa或者mybatis-spring-boot-starter再在application.yml里配置数据源连接剩下的增删改查就能直接写了。这种开发体验对学生来说太友好了。另外SpringBoot全家桶的生态也很成熟。集成MyBatis-Plus做数据访问集成Spring Security或JWT做权限认证集成Redis做缓存都有大量现成案例可参考。说白了遇到问题百度一搜全是答案这和冷门框架完全不是一个学习成本。2.2 Vue前端开发效率的分水岭以前做后端的人最怕写前端用jQuery写页面是能写但代码管理困难逻辑一复杂就乱成一团。Vue出现之后前端开发变成了“数据驱动视图”的模式开发体验完全不同了。Vue的核心优势在于组件化开发。你可以把整个页面拆成一个个组件导航栏是一个组件物品卡片是一个组件分页器是一个组件弹窗是一个组件。每个组件只管自己那块逻辑互不干扰团队协作也方便。加上Vue Router做路由管理、Vuex或Pinia做全局状态管理、Element UI提供现成的页面组件搭一个管理后台或者C端页面都很快。对失物招领平台来说前端页面并不复杂主要就是首页信息流、发布页、详情页、个人中心、管理后台这几个模块。用Vue写的话工作量主要集中在前三四个页面路由配置理顺之后后面就是复制粘贴改改样式的事。很多同学对前端有畏难情绪觉得JavaScript不好学、CSS调样式很痛苦。我的建议是不需要成为前端专家只要会用Vue的基本语法会用Element UI的表格、表单、弹窗组件再会一个axios封装发请求就足够完成这个项目了。2.3 MySQL小体量项目的最佳数据底座MySQL可能是这个项目里争议最小的选型了。免费、轻量、资料多、面试常考对学生来说几乎没有学习成本。失物招领平台的数据量不会很大——最多几千条物品信息、几万条留言记录MySQL轻松就能扛住完全没必要上PostgreSQL或者MongoDB来给自己找麻烦。MySQL配合MyBatis-Plus写SQL的体验也很好。单表查询用LambdaQueryWrapper就能搞定多表关联、动态条件查询才有必要手写SQL。对毕设来说MyBatis-Plus真的是学习曲线最平缓的数据访问方案不用写一堆繁琐的XML映射文件也没有JPA那种“自动建表却不知道发生了什么”的黑盒感。你看见什么就知道它会执行什么。我记得有个学生刚开始用的是原生JDBC写着写着就后悔了代码里到处是try-catch-finally处理连接关闭写个分页查询要自己拼LIMIT。换成MyBatis-Plus之后效率提升不是一倍两倍。所以我的建议是如果还没写代码直接上MyBatis-Plus别自讨苦吃。2.4 还有哪些“加分项”值得加入基础技术栈是够用了但如果想在答辩时多几个亮点可以加这些JWT做登录鉴权比Session方案更适合前后端分离架构而且面试常问属于“低成本高回报”的知识点Redis缓存热门物品信息和验证码能讲出缓存穿透、缓存一致性这些概念论文里也能作为“系统优化”章节图片上传到云存储阿里云OSS或MinIO避免本地存储的部署麻烦也能展示你对文件处理的思考Logback日志框架记录操作日志和异常日志给系统加一层“可观测性”定时任务Spring Task定期下架超180天无人认领的物品体现你的工程化思维我个人不太建议加太多重量级组件比如引入消息队列、Elasticsearch这些。一个毕设项目把核心功能写扎实再有一到两个加分点就足够了。过度设计反而会在答辩时被老师追问到漏洞百出。3. 系统设计与数据库建模3.1 核心模块划分动手写代码之前建议先把系统架构画出来。前端项目负责页面展示和与后端交互后端项目按分层架构组织Controller层接收请求、Service层处理业务逻辑、Mapper层负责数据库操作。后端模块可以这样划分用户模块注册登录、JWT签发、个人信息物品模块失物/招领的发布、查询、修改、下架认领模块认领申请、审核处理评论模块物品详情页的留言文件模块图片上传与访问管理模块管理员身份的校验、信息审核、用户管理前端方面按照页面维度组织组件门户页面首页信息列表、详情页、发布页、搜索页用户中心我的发布、我的认领、个人资料管理后台物品审核列表、认领管理、用户管理前后端之间通过RESTful API通信统一返回格式为{ code: 200, message: success, data: {} }。这样前端处理逻辑会很清爽后端写起来也有章法而且论文里描述接口设计时特别清晰。3.2 数据库表结构设计数据库设计是论文里占大篇幅的部分也是答辩时容易被追问的点。失物招领平台的核心表我建议设计成以下六张表名说明关键字段user用户表user_id, username, password, nickname, phone, email, avatar, role, status, create_timecategory物品分类表category_id, name, sortitem物品信息表item_id, user_id, category_id, type(1失物/2招领), title, description, location, happen_time, contact, image, status, create_timeclaim_record认领记录表record_id, item_id, user_id, reason, proof_material, status, create_timecomment留言表comment_id, item_id, user_id, content, create_timeadmin_log管理员操作日志表log_id, admin_id, operation, target_id, create_time这六张表的逻辑关系重点说下。item表是整个系统的核心type字段区分是“寻物启事”还是“拾物招领”不需要拆成两张表这样查询统一信息流时写SQL更简单前端渲染也统一。claim_record表记录谁对哪条物品发起了认领申请status有0待审核、1已通过、2已拒绝三种状态。comment表挂在item_id下面实现详情页留言。关于字段类型有一些细节值得注意。password字段建议用varchar(100)而不是varchar(20)因为BCrypt加密后的字符串长度是60位左右留太短会报错。description用text类型因为物品描述可能比较长。happen_time用datetime方便后续按时间排序和筛选。image字段存图片URL地址多个图片可以用逗号分隔存储或者拆成附件表毕设阶段用逗号分隔就够用了。3.3 状态流转设计毕设里最容易忽略、但最容易被答辩老师一眼看穿的地方就是物品状态的处理。很多学生把状态设计成字段就完事了完全没考虑状态之间怎么流转、谁有权限改状态。失物招领平台的物品状态我建议这样定义状态码含义使用场景0待处理刚发布等待被认领/被联系1已完成失主找回物品或拾物已归还2已过期超过预设时间无人认领自动下架3已下架发布者主动下架状态流转的触发规则发布时状态为0失主在认领管理里把某条申请“标记为已归还”时状态变为1定时任务扫描超过180天的待处理物品改为2发布者主动操作“下架”时状态变为3有一点需要特别注意物品状态只能单向流转不能把已完成的状态改回待处理。否则会出现“明明东西已经还回去了系统里还能看到这条招领信息”的逻辑漏洞。在代码实现时后端接口要做判断只有状态为0的物品才能执行“标记完成”和“下架”操作。3.4 接口设计与统一返回格式接口设计建议遵循RESTful风格资源用名词复数动作用HTTP方法表达。以下是核心接口列表方法路径说明POST/api/user/register用户注册POST/api/user/login用户登录GET/api/user/info获取当前用户信息GET/api/item/list分页查询物品列表GET/api/item/{id}查询物品详情POST/api/item发布物品信息PUT/api/item/{id}修改物品信息PUT/api/item/{id}/status更新物品状态POST/api/claim提交认领申请GET/api/claim/listByItem查看某物品的认领申请PUT/api/claim/{id}/audit审核认领申请POST/api/comment发布留言GET/api/comment/listByItem查看某物品的留言列表统一返回格式我建议封装一个Result类public class ResultT { private Integer code; // 200成功500失败401未登录 private String message; // 提示信息 private T data; // 业务数据 public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(success); result.setData(data); return result; } public static T ResultT error(String message) { ResultT result new Result(); result.setCode(500); result.setMessage(message); return result; } }所有Controller接口都返回这个封装对象前端拿到code字段判断业务是否成功逻辑统一排查问题也方便。有的同学喜欢直接把数据裸返回前端还要层层判空建议不要这样干。4. 核心功能实现细节4.1 登录注册与JWT鉴权登录注册是几乎每个系统都有的功能但很多同学都是用最简单的方式实现登录成功后后端把用户ID放在Session里前端通过Cookie维持会话。这样做本身没错但我更推荐用JWT因为前后端分离架构下JWT更自然而且面试被问到的概率极高。JWT的思路是用户登录成功后后端生成一个包含用户ID、用户名、过期时间的Token字符串返回给前端。前端把Token存到localStorage里每次请求时放在请求头的Authorization字段中。后端通过拦截器解析Token就能识别当前登录的用户是谁不需要在服务端保存会话状态。SpringBoot里集成JWT很简单引入jjwt依赖写一个工具类负责生成和解析Token再写一个拦截器统一校验Component public class JwtInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 放行预检请求 if (OPTIONS.equals(request.getMethod())) { return true; } String token request.getHeader(Authorization); if (token ! null token.startsWith(Bearer )) { String jwt token.substring(7); try { Integer userId JwtUtil.parseToken(jwt); request.setAttribute(userId, userId); return true; } catch (Exception e) { // Token无效或过期 } } response.setStatus(401); return false; } }然后通过WebMvcConfigurer注册拦截器并且把登录、注册、公开的信息查询接口排除掉。这样需要登录才能操作的接口就统一保护起来了。密码存储方面一定不要用明文。用Spring Security自带的BCryptPasswordEncoder或者hutool里的BCrypt工具类把密码加密后再存数据库。校验的时候用matches方法比对。这样即使数据库泄露了用户的密码也不会直接暴露。4.2 发布失物/招领与文件上传发布功能是整个系统的核心入口。用户在发布页填写表单包含标题、分类、详情描述、地点、时间、联系方式、图片等信息。点击提交后前端先把图片传到服务器拿到返回的图片URL再把整个表单数据POST到后端接口。图片上传的处理逻辑值得展开说一下。千万要把图片保存到项目的源码目录下比如src/main/resources/static/upload/。这样做在本地开发时没问题但打包成jar部署之后就麻烦了——写入jar包内部的文件在重新打包时会丢失。更稳妥的做法是在application.yml里配置一个上传路径通常是服务器上的一个绝对路径比如/usr/local/upload/然后把静态资源映射配置成这个路径file: upload-path: /usr/local/upload/ spring: web: resources: static-locations: file:${file.upload-path}, classpath:/static/后端接收文件的接口这样写PostMapping(/api/upload) public ResultString upload(RequestParam(file) MultipartFile file) { if (file.isEmpty()) { return Result.error(请选择文件); } String originalFilename file.getOriginalFilename(); String ext originalFilename.substring(originalFilename.lastIndexOf(.)); String fileName UUID.randomUUID() ext; File dest new File(uploadPath, fileName); file.transferTo(dest); String url /files/ fileName; // 由静态资源映射提供访问 return Result.success(url); }用UUID重命名文件可以避免重名冲突。上传成功后返回的相对路径前端直接拼上服务器域名就能显示图片。4.3 多条件分页查询信息列表页是用户访问最多的页面需要支持按关键词、分类、类型失物/招领、状态等多个条件组合查询并且分页展示。用MyBatis-Plus实现的话可以这样写public PageItem queryItemList(ItemQuery query) { LambdaQueryWrapperItem wrapper new LambdaQueryWrapper(); // 关键词模糊搜索 if (StringUtils.hasText(query.getKeyword())) { wrapper.like(Item::getTitle, query.getKeyword()) .or() .like(Item::getDescription, query.getKeyword()); } // 分类筛选 if (query.getCategoryId() ! null) { wrapper.eq(Item::getCategoryId, query.getCategoryId()); } // 类型筛选失物 or 招领 if (query.getType() ! null) { wrapper.eq(Item::getType, query.getType()); } // 只显示待处理和已完成过期和下架的不显示 wrapper.in(Item::getStatus, 0, 1); // 按发布时间倒序 wrapper.orderByDesc(Item::getCreateTime); return itemMapper.selectPage(new Page(query.getPageNum(), query.getPageSize()), wrapper); }这样一个方法就覆盖了首页信息流、搜索页、分类筛选页的所有场景前端只需要传不同的参数组合。分页返回的数据结构用MyBatis-Plus自带的Page对象就行里面包含records列表、total总数、current当前页、size每页数量前端拿到之后构建分页器非常轻松。需要注意的是keyword为空的场景不能传空字符串去like否则会把所有数据都查出来还要排除已经下架和过期的物品避免用户看到无效信息。4.4 认领申请与审核流程认领功能是失物招领平台最有业务特色的部分。拾到物品的人发布招领信息后失主看到匹配的信息可以发起认领申请提交自己的认领理由和能够证明物品归属的凭证图片。而对应的发布寻物启事的失主在看到别人提交的“我有线索”或“我来认领”申请后需要审核并决定是否通过。认领申请的数据表是claim_record核心流程是用户在物品详情页点击“申请认领/提供线索”填写说明并提交后端校验该用户不是物品发布者本人且之前没有提交过重复申请物品发布者在个人中心“认领管理”列表中看到所有申请点击查看详情发布者根据描述和凭证选择“通过”或“拒绝”状态变化同步更新物品状态也随之变为“已完成”关键代码在提交申请时要先查一遍重复记录public ResultString submitClaim(ClaimRequest request) { Integer userId request.getUserId(); Integer itemId request.getItemId(); // 不能认领自己发布的物品 Item item itemService.getById(itemId); if (item.getUserId().equals(userId)) { return Result.error(不能认领自己发布的物品); } // 不能重复提交 long count claimRecordMapper.selectCount( new LambdaQueryWrapperClaimRecord() .eq(ClaimRecord::getItemId, itemId) .eq(ClaimRecord::getUserId, userId) ); if (count 0) { return Result.error(你已经提交过认领申请了); } itemService.updateStatus(itemId, 1); itemService.saveClaimRecord(request); return Result.success(认领申请提交成功); }在更新物品状态的地方要加一个乐观锁或者状态判断。你可以用update where status 0这种带条件的更新方式防止并发情况下两个人同时认领成功。4.5 前端页面与路由设计前端项目用Vue CLI或Vite创建推荐Vite启动速度快很多。路由模块用Vue Router的懒加载方式减少首屏加载体积const routes [ { path: /, name: Home, component: () import(/views/Home.vue) }, { path: /item/:id, name: ItemDetail, component: () import(/views/ItemDetail.vue) }, { path: /publish, name: Publish, component: () import(/views/Publish.vue), meta: { requiresAuth: true } }, { path: /user, component: () import(/layout/UserLayout.vue), meta: { requiresAuth: true }, children: [ { path: profile, component: () import(/views/user/Profile.vue) }, { path: myitems, component: () import(/views/user/MyItems.vue) }, { path: myclaims, component: () import(/views/user/MyClaims.vue) } ] }, { path: /admin, component: () import(/layout/AdminLayout.vue), meta: { requiresAuth: true, role: admin }, children: [ { path: audit, component: () import(/views/admin/Audit.vue) }, { path: users, component: () import(/views/admin/Users.vue) } ] } ]路由守卫里检查登录状态和角色router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.meta.requiresAuth !token) { next(/login) } else if (to.meta.role localStorage.getItem(role) ! to.meta.role) { next(/) } else { next() } })axios请求封装时加请求拦截器自动带Token加响应拦截器统一处理401状态跳转到登录页service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] Bearer token } return config }) service.interceptors.response.use( response { const res response.data if (res.code 401) { localStorage.removeItem(token) router.push(/login) } return res }, error { return Promise.reject(error) } )5. 部署流程与实操笔记5.1 环境准备部署是毕设里最容易被忽略却最容易出问题的一关。建议提前准备一份部署文档答辩时如果老师当场要求跑起来你可以照着文档5分钟搞定。开发环境需要准备JDK 1.8推荐8或11Maven 3.6Node.js 14推荐16 LTS版本MySQL 5.7 或 8.0部署前检查一下环境版本很多同学卡在“Maven打不了包”上多半是JDK版本和Maven版本不匹配导致的。JDK8建议配Maven 3.6.3JDK17建议配Maven 3.9。Node.js版本太高可能会导致npm install时报node-sass相关错误建议统一用16这个稳定版本。MySQL连接时application.yml里几个关键配置别写错spring: datasource: url: jdbc:mysql://localhost:3306/lost_found?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver记住一定要加characterEncodingutf8否则中文会乱码。MySQL 8.0需要用cj版的驱动用旧驱动会报“Loading class com.mysql.jdbc.Driver is deprecated”或者直接连不上。数据库初始化很简单用Navicat或者命令行执行项目里的sql脚本就行。注意先建库再导入脚本里一般已经包含建表和初始数据的语句。5.2 后端打包部署后端打包用Maven的package命令在项目根目录执行mvn clean package -DskipTests打包成功后在target目录下会生成一个jar文件比如lost-found-0.0.1.jar。用java -jar命令就能启动java -jar lost-found-0.0.1.jar --spring.profiles.activeprod生产环境的配置建议单独放一个application-prod.yml文件里面配置生产数据库地址、上传路径、日志路径等。用--spring.profiles.activeprod切换这样本地的开发配置和生产配置互不干扰。如果服务器内存不大可以给JVM限制一下内存java -Xms256m -Xmx512m -jar lost-found-0.0.1.jar另外饰品一下。有些同学喜欢用nohup和把后端进程挂到后台nohup java -jar lost-found-0.0.1.jar app.log 21 这种方式能用但服务器一旦重启进程就没了。更稳妥的方案是注册成systemd服务不过毕设阶段能真正用到服务器的人不多这里就不展开讲了。5.3 前端打包与Nginx配置前端开发调试阶段用npm run dev打包部署用npm install npm run build打包完成后会在项目根目录生成一个dist文件夹里面是纯静态文件HTML、CSS、JS。把这个文件夹放到服务器的任意目录就可以用Nginx托管。Nginx的配置是部署的重点我直接给一份可以落地用的server { listen 80; server_name localhost; # 前端静态文件 root /usr/share/nginx/html/dist; index index.html; # Vue Router history模式需要配置try_files location / { 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 /files/ { alias /usr/local/upload/; } }这一段配置里有三个关键点少一个都会出问题。try_files配置解决的是Vue Router使用history模式时刷新页面404的问题proxy_pass解决的是前端请求/api开头的接口如何转发到后端服务location /files/ 解决的是上传图片如何被外部访问到。5.4 部署踩坑实录把几次部署中遇到的坑整理出来给大家提个醒第一个坑是前端刷新页面直接404。这是因为Vue Router默认使用history模式地址栏变化后Nginx不知道去哪找对应的路由页面。解决办法就是上面配置里的try_files $uri $uri/ /index.html;所有未知路由都回退到index.html再由前端路由接管页面渲染。第二个坑是接口请求成功但图片显示不出来。多半是Nginx没有配/files/的location或者配了但路径不对。注意alias和root的区别alias /usr/local/upload/是精确映射访问/files/xxx直接对应/usr/local/upload/xxx如果用了root /usr/local/upload/实际访问路径会变成/usr/local/upload/files/xxx就错位了。第三个坑是服务器防火墙没开端口或者云服务商安全组没放行8080和80端口。后端服务启动成功前端也能打开但接口请求全部timeout这种情况我至少遇到过三次。排查思路很直接在服务器上curl一下本机接口地址通了说明端口问题直接在云控制台的安全组放行即可。6. 论文写作与答辩准备6.1 毕业论文结构怎么安排毕业论文虽然最后才写但实际上在系统设计阶段就要开始积累素材。我建议论文按下面的框架组织这个结构是大多数学校都能接受的规范模板第1章 绪论研究背景与意义、国内外研究现状、主要研究内容第2章 相关技术介绍SpringBoot、Vue、MySQL、前后端分离架构第3章 系统分析可行性分析、功能性需求、非功能性需求、用例分析第4章 系统设计系统总体架构、功能模块设计、数据库设计、接口设计第5章 系统实现结合核心功能模块展示关键代码和界面截图第6章 系统测试测试目的、测试环境、功能测试用例、测试结果分析第7章 总结与展望项目完成情况、不足与改进方向论文积累素材的方法是写代码时随手做笔记。每写完一个模块把核心逻辑、关键代码片段、页面截图保存下来同时在Word里建立一个“论文素材”文件夹按章节存放。这样最后写论文时你是把已有的素材组织起来而不是对着空白Word从头开始效率完全不一样。6.2 哪些图和表是“必画必放”毕业答辩时老师翻论文第一眼看的是图表是否规范、是否充足。信息量大的图表远比长篇文字更能体现工作量。建议这些图一定要有系统功能模块图树状结构展示系统有哪些功能模块系统总体架构图展示前端、后端、数据库三层架构以及它们之间的关系数据库E-R图六张核心表的实体关系用draw.io或ProcessOn画业务流程图发布物品、认领申请、管理员审核三个核心流程各画一张核心功能界面截图首页信息流、发布页、详情页、个人中心、管理后台关键接口时序图登录认证、认领审核这类跨模块操作表方面除了数据库表结构设计表之外测试用例表是论文的重要组成部分。一个功能测试用例表至少要有十个以上的用例覆盖正常流程、异常流程、边界条件。测试用例如下表所示要覆盖正常和异常情况编号测试项操作步骤预期结果实际结果是否通过TC01用户注册输入合法手机号和密码点击注册注册成功跳转登录页与预期一致通过TC02用户注册输入已存在用户名提示用户名已存在与预期一致通过TC03发布物品不填写图片上传提交表单提示请上传图片与预期一致通过TC04搜索功能输入不存在的关键词展示空列表并提示无结果与预期一致通过6.3 答辩高频问题应对答辩时老师问的问题看起来随机实际上八九不离十都围绕这几个方向。提前准备就能从容应对。第一个必问“你这个系统的核心功能是什么项目难点在哪里”建议回答时突出认领审核的状态设计讲清楚状态如何流转、如何防止重复认领、数据表之间怎么关联。第二个必问“数据库为什么这么设计有几张表表之间的关系是什么”要把六张核心表的字段作用、主外键关系、一对多关系讲清楚。建议画E-R图的时候就想好怎么用语言描述比如“一条物品信息下可以有多个认领申请记录所以claim_record表通过item_id外键关联item表”。第三个必问“JWT和Session有什么区别为什么选JWT”这题要能讲出JWT无状态、分布式系统友好、Token里携带信息这三个优点同时也不要回避JWT的局限比如无法主动失效的问题可以补一句“所以本项目对敏感操作还会在后台二次校验”。第四个必问“如果用户量变大系统哪里会成为瓶颈怎么优化”建议回答思路是数据库查询压力变大考虑加缓存Redis缓存热点数据、加索引、分库分表图片访问流量变大考虑上CDN。如果你系统里真的加了Redis那这个问题就是送分题。7. 常见问题与避坑指南7.1 常见异常速查表把开发过程中高频出现的报错整理成一个速查表遇到问题直接对号入座现象可能原因解决方案启动报错Port 8080 was already in use端口被占用改端口server.port8081或杀掉占用进程数据库中文乱码连接串没加characterEncodingutf8在JDBC URL中加入characterEncodingutf8前端npm install卡在node-sassNode版本过高或过低换Node 16版本或删除node_modules和package-lock重新安装接口请求返回CORS错误前后端跨域后端加CORS配置或用Nginx反向代理解决Vue页面刷新后404路由history模式未配置Nginx配置try_files $uri $uri/ /index.html;上传图片后访问404静态资源映射未配置后端加WebMvcConfigurer映射 /files/** 到上传目录打包时找不到主类Maven配置问题检查pom.xml中spring-boot-maven-plugin是否配置MySQL 8.0连接失败驱动版本不对使用mysql-connector-java 8.0以上的驱动登录后刷新页面又变未登录Token没持久化前端登录后把Token同时存到localStorage认领重复提交缺少唯一性校验submit接口前先查询用户是否已对该物品提交过申请这个表建议保存下来写代码过程中真能帮你省下不少时间。7.2 我自己踩过的几个坑先说图片上传这个坑。我第一次做这类项目时把上传的图片直接存到了项目的src/main/resources/static/upload目录下本地开发时一切正常但在服务器上部署时前端能打开页面图片却一直裂图。查了半天原因就是我把图片写进了jar包内部而jar包内部的资源是无法通过静态路径直接访问的。后来改成配置外部上传路径并使用file协议映射彻底解决了。再说Vue Router history模式和Nginx的配合问题。没有配try_files时你访问首页没问题但一旦点进详情页然后刷新Nginx返回404。排查这个问题的时候我还一度以为是后端接口或前端打包配置有问题。其实Nginx官方文档写得很清楚做前端路由接管时try_files必须带上这是一条经验但也是很多新手必踩的坑。第三点是关于分页的坑。MyBatis-Plus的分页插件必须要配置分页拦截器否则page方法只会查询数据但不会自动统计总数。很多学生第一次用MyBatis-Plus写分页发现total总是0或者页面压根不显示分页器就是因为少了MybatisPlusInterceptor的配置。记得要在配置类里注册Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; }7.3 时间规划与做毕设的节奏建议最后聊聊大家最关心的时间安排。一个失物招领平台按正常节奏来说数据库设计和项目初始化1周后端核心接口2周前端页面2周联调和部署1周剩余时间写论文和准备答辩。也就是说集中精力的话6周到8周能全部完成。如果你的进度落后了优先保证核心功能再加项目亮点。我个人在实际带项目中最深的体会是毕设最重要的不是“用了多少技术”而是“你讲得清楚自己做了什么”。项目再简单你能把表结构设计、状态流转、接口定义、部署流程讲得头头是道老师就会觉得这个学生是真做了功课的。反过来项目堆了一堆新技术结果一问三不知反而给人印象很差。最后分享一个小技巧开发过程中建立的“素材笔记”要勤更新每次遇到报错解决了、每次完成一个模块都记录一两句。写论文时把这些真实记录整理的整理润色的润色你会发现论文里的“系统实现”章节写得又快又真实。这比对着电脑憋一天没写出两段要舒服太多了。
返回列表