资讯动态

校园失物招领系统全栈实战:基于Spring Boot 3与Vue 3

发布时间:2026/9/7 21:37:39 来源:尧图企业网站定制
这周抽时间做了一套校园失物招领系统。起因很简单校园里丢东西太常见了校园卡、耳机、书本、雨伞失物招领信息散落在各个群里没人统一管理要么刷屏被淹没要么贴了纸质公告没人看。这类需求做一个小型全栈系统非常合适既能真实落地使用也能作为课程设计、期末项目或者毕业设计的完整案例。本套系统覆盖了失物招领业务的核心闭环用户注册登录、失物发布、图片上传、分类浏览、关键词匹配、认领申请、管理员审核、认领确认、统计看板以及定时清理过期失物。后端使用 Spring Boot 3 MyBatis-Plus MySQL前端使用 Vue 3 Element Plus部署支持传统前后端分离启动和 Docker Compose 一键启动同时也预留了简洁的 RESTful 接口方便后续接入钉钉、企业微信通知或者改造成校园服务大厅的一个子模块。文章会从核心能力、适用场景、环境准备、部署启动、功能测试、接口批量任务、资源占用、常见问题排查、最佳实践这几个维度展开。想要跑通这套系统或者准备交期末作业、毕业设计的同学可以直接按文中的步骤操作。1. 核心能力速览能力项说明系统类型校园失物招领全栈 Web 系统前端技术栈Vue 3 Element Plus Pinia Axios Vite后端技术栈Spring Boot 3 MyBatis-Plus MySQL 8.0 JWT核心功能失物发布、寻物启事、图片上传、分类检索、关键词匹配、认领申请、管理员审核、统计看板文件存储本地磁盘存储或 MinIO 对象存储配置项切换部署方式前后端分离部署 / Docker Compose 一键启动接口能力RESTful API支持 JSON 交互预留鉴权接口批量任务定时清理过期失物、定时生成失物周报、Excel 批量导入推荐配置2 核 4G 服务器或普通开发机即可本项目不涉及重型计算适合场景高校后勤、学生会、图书馆、食堂、教学楼值班室等场景从技术难度来看这个项目处于中等偏应用层。没有复杂的 AI 推理、没有 GPU 依赖主要的工作量集中在业务表设计、状态流转、权限校验和前后端联调。2. 适用场景与使用边界校园失物招领系统适合三类人使用。第一类是学生或老师需要发布捡到的物品或者发布自己丢失物品的寻物启事第二类是后勤、图书馆、食堂、教学楼的管理员需要审核失物信息、管理认领流程、定期清理物品第三类是开发学习者需要一套包含登录鉴权、文件上传、流程审核、数据统计的全栈项目作为课设或毕设基础。系统能解决的问题很明确把碎片化失物信息统一入库通过分类和关键词快速检索让“物品在哪里、状态是什么”一目了然。管理员和用户的操作记录有迹可循比微信群接龙规范得多。但使用边界也要说清楚。这套系统面向校园内部场景不涉及跨校、跨平台的复杂协同如果你们学校有多个校区建议按校区字段过滤或者在部署时拆成多个实例不要在一个库里混着跑。另外系统不处理二手交易、不处理贵重物品快递寄送等衍生业务职责边界保持简单。合规方面需要注意几点失物信息中的人脸、证件号码、联系方式等敏感信息要在发布时脱敏捡到物品拍照时尽量避免拍到他人面部和隐私认领时必须提供有效凭证不允许仅凭描述就放行系统部署后管理员账号需要专人保管不建议让普通学生直接拿管理员权限。如果是作为毕业设计或者课程设计公开发布所有测试数据都要替换成脱敏后的模拟数据。3. 环境准备与前置条件开始之前先确认本机环境。我用的是标准前后端分离环境具体版本可以按自己习惯调整但建议尽量靠近下列版本。依赖版本建议说明JDK17Spring Boot 3 要求 JDK 17 起步Maven3.8用于后端依赖管理和打包Node.js18用于前端依赖安装和构建MySQL8.0业务数据库Docker可选如果不想手动配数据库直接用 ComposeNginx可选生产环境反向代理开发环境不需要先检查基础环境java -version mvn -version node -v npm -v mysql --version如果没有装 MySQL又不想手动安装可以直接用 Docker 起一个 MySQL 容器。开发阶段还可以把spring.datasource.url指向远程数据库但本地跑全栈项目更推荐本机 MySQL调试方便日志查询也直观。磁盘方面这个项目很小系统本身占不到多少空间主要空间消耗在图片上传目录建议单独分一个uploads目录后续备份和清理都方便。内存方面后端 Spring Boot 应用加上前端 Node 开发服务开发机 8G 内存完全够用生产环境 2 核 4G 服务器也可以跑得很舒服。4. 安装部署与启动方式4.1 数据库初始化在 MySQL 中创建数据库并导入初始化脚本。CREATE DATABASE IF NOT EXISTS campus_lost_found DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE campus_lost_found;项目的sql目录下通常包含init.sql导入命令如下mysql -u root -p campus_lost_found init.sql初始化脚本包含 4 张核心表用户表user、失物信息表item、认领记录表claim_record、管理员操作日志表audit_log。状态字段使用数字枚举例如item.status中 0 表示待审核、1 表示已发布、2 表示待认领、3 表示已完成、4 表示已过期。4.2 后端启动后端是标准的 Spring Boot 项目修改数据库连接配置后即可启动。application.yml关键配置server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/campus_lost_found?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 10MB max-request-size: 30MB mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0 jwt: secret: your-jwt-secret-key expire-hours: 24 upload: dir: ./uploads url-prefix: /uploads启动后端mvn clean package -DskipTests java -jar target/campus-lost-found-0.0.1-SNAPSHOT.jar看到日志中出现Started CampusLostFoundApplication就说明启动成功服务默认监听 8080 端口。图片上传目录会自动创建不需要手动干预。4.3 前端启动与构建前端使用 Vite Vue 3开发模式直接跑 Node 服务生产模式先构建静态文件再交给 Nginx 或后端静态资源目录。cd frontend npm install npm run dev开发服务默认启动在 5173 端口。如果修改了后端地址需要在.env.development中配置代理。VITE_APP_API_BASE_URL/api VITE_APP_UPLOAD_BASE_URLhttp://localhost:8080Vite 代理配置在vite.config.js中import { defineConfig } from vite import vue from vitejs/plugin-vue export default defineConfig({ plugins: [vue()], server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true, rewrite: (path) path.replace(/^\/api/, ) }, /uploads: { target: http://localhost:8080, changeOrigin: true } } } })生产构建npm run build构建产物在dist目录发布时把dist目录扔给 Nginx 即可。Nginx 同时负责反向代理/api和后端文件上传目录这样前后端同域避免跨域问题。4.4 Docker Compose 一键启动不想手动安装 MySQL 和 Node 环境的话直接使用 Docker Compose。docker-compose.yml示例version: 3.8 services: mysql: image: mysql:8.0 container_name: campus-mysql restart: always environment: MYSQL_ROOT_PASSWORD: root123456 MYSQL_DATABASE: campus_lost_found ports: - 3306:3306 volumes: - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql - mysql-data:/var/lib/mysql backend: build: context: . dockerfile: Dockerfile container_name: campus-backend restart: always depends_on: - mysql environment: SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/campus_lost_found?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai SPRING_DATASOURCE_USERNAME: root SPRING_DATASOURCE_PASSWORD: root123456 JWT_SECRET: docker-compose-secret ports: - 8080:8080 volumes: - ./uploads:/app/uploads frontend: build: context: ./frontend dockerfile: Dockerfile container_name: campus-frontend restart: always ports: - 80:80 depends_on: - backend volumes: mysql-data:启动docker compose up -d --build启动后访问http://localhost前端页面和接口都是同域Nginx 内部会把/api代理到后端的8080端口。这种方式特别适合部署到服务器一条命令完成整个环境的搭建。5. 核心功能测试与效果验证系统启动之后可以从用户视角和管理员视角分别过一遍核心流程。5.1 用户注册与登录访问前端页面进入注册页填写用户名、手机号、密码。注册成功后系统自动登录并返回 JWT Token后续所有请求都在Authorization请求头中带Bearer Token。预期结果注册后可以退出再登录登录成功后跳转到失物列表页。判断标准如果注册时用户名重复后端会返回“用户名已存在”登录时密码错误返回“用户名或密码错误”。接口返回的 JSON 结构统一为{ code: 200, data: ..., message: success }。5.2 发布失物与图片上传登录后点击“发布失物”填写标题、物品分类、丢失地点、详细描述上传一张或者多张图片。提交后系统会把物品状态设为“待审核”同时给管理员产生一条审核任务。图片上传走的是独立的/api/upload接口前端使用 Element Plus 的el-upload组件上传成功后拿到图片 URL再随表单一起提交。预期结果表单提交成功列表页出现这条数据但状态是“待审核”图片可以正常打开URL 指向/uploads/xxx.jpg。常见问题如果图片太大后端会拒绝默认单文件 10MB。测试时建议用手机随手拍的图片一般都在 2MB 到 5MB 之间。5.3 关键词匹配与列表检索失物列表页支持按分类、状态、地点、关键词筛选。关键词匹配这里用的是 MySQL 的LIKE模糊查询例如搜索“校园卡”会匹配标题和描述中包含“校园卡”的记录。如果发布会时物品名称不够规范管理员可以在审核时补充标准化关键词例如把用户填写的“一卡通”“饭卡”统一改成“校园卡”。SELECT * FROM item WHERE title LIKE CONCAT(%, #{keyword}, %) OR description LIKE CONCAT(%, #{keyword}, %) OR category LIKE CONCAT(%, #{keyword}, %) ORDER BY create_time DESC;这种方案在数据量不大的情况下完全够用。如果后续失物数据量到几十万条再考虑引入 Elasticsearch 或者 MySQL 全文索引。预期结果搜索“校园卡”能同时匹配到标题包含“校园卡”“一卡通”“饭卡”的失物前提是管理员在审核时补充了足够的关键词。5.4 管理员审核与认领流程管理员登录后台可以看到所有待审核的失物信息。审核操作有两类通过、驳回。通过后失物状态变为“已发布”普通用户可以在列表页看到。用户看到某个失物与自己丢失的物品相似可以发起“认领申请”填写物品细节和联系方式。管理员在后台对比申请信息和失物描述如果匹配则同意认领系统会向失主和认领人展示联系电话。整个状态流转待审核 - 已发布 - 认领中 - 已归还 - 已驳回 - 已过期预期结果普通用户无法直接将失物状态修改为“已认领”只有管理员可以操作认领记录在数据库中留痕全部写入claim_record表。判断标准测试时可以分别使用普通用户账号和 admin 账号登录确认权限控制生效。普通用户调用管理接口时后端返回 403。5.5 统计看板统计页展示三类数据每日新增失物数量、失物分类占比、各状态数量。数据来自item表的分组聚合查询。SELECT category, COUNT(*) AS num FROM item WHERE deleted 0 GROUP BY category ORDER BY num DESC;前端使用 ECharts 渲染柱状图和饼图。这个模块是课设和毕设的加分项能从业务数据角度展示系统的使用效果。6. 接口 API 调用与批量任务6.1 RESTful 接口清单接口路径方法功能鉴权/api/auth/registerPOST用户注册否/api/auth/loginPOST用户登录否/api/itemsGET分页查询失物列表否/api/items/{id}GET查询失物详情否/api/itemsPOST发布失物是/api/items/{id}PUT更新失物信息管理员/api/items/{id}/statusPUT修改失物状态管理员/api/uploadPOST上传图片是/api/claimsPOST发起认领申请是/api/claims/{id}/approvePUT同意认领管理员/api/stats/dailyGET统计每日新增管理员/api/stats/categoryGET统计分类占比管理员6.2 curl 调用示例登录并获取 Tokencurl -X POST http://localhost:8080/api/auth/login \ -H Content-Type: application/json \ -d {username:admin,password:123456}使用 Token 发布失物curl -X POST http://localhost:8080/api/items \ -H Content-Type: application/json \ -H Authorization: Bearer TOKEN \ -d { title: 蓝色雨伞, category: 雨伞, location: 第三食堂一楼, description: 伞柄有白色标签写着李明的名字, imgUrl: /uploads/umbrella.jpg }查询失物列表并带关键词curl -G http://localhost:8080/api/items \ --data-urlencode keyword校园卡 \ --data-urlencode page1 \ --data-urlencode pageSize106.3 Python 批量导入脚本如果线下已经登记了一批失物信息可以整理成 Excel 后通过脚本批量导入。import requests API_URL http://localhost:8080/api/items TOKEN 粘贴登录后的 token HEADERS { Authorization: fBearer {TOKEN}, Content-Type: application/json } items [ { title: 黑色保温杯, category: 水杯, location: 图书馆三楼, description: 杯身有卡通贴纸, imgUrl: }, { title: 《数据结构》教材, category: 书籍, location: 教学楼 A201, description: 封面有笔记扉页写着专业班级, imgUrl: } ] for item in items: response requests.post(API_URL, jsonitem, headersHEADERS, timeout10) print(item[title], response.status_code, response.json())注意批量导入时必须确保当前账号是管理员否则接口会返回 403。实际使用中可以把 Excel 读取和接口提交拆成两个脚本先本地生成 JSON再逐条导入避免一条失败导致全部重来。6.4 定时清理与周报任务系统里内置了简单的定时任务使用 Spring 的Scheduled注解实现。一个典型的任务是每天凌晨清理创建超过 180 天且仍处于“已发布”状态的失物信息把这些数据标记为“已过期”而不是物理删除。Component public class ItemExpireTask { Scheduled(cron 0 0 2 * * ?) public void expireOldItems() { LocalDateTime threshold LocalDateTime.now().minusDays(180); itemMapper.expireByTime(threshold); } }另一个任务是每周生成失物招领周报统计本周新增、已归还、待处理数量并把统计结果写入日志表。后续如果接入企业微信或钉钉机器人可以直接改成 HTTP 推送。7. 资源占用与性能观察这个项目没有 AI 推理、没有大模型计算资源占用非常可控。后端 Spring Boot 应用启动后JVM 默认堆内存会根据本机内存自动调整通常会在 256MB 到 1GB 之间波动。前端构建后的静态资源大约几 MBNginx 承载静态文件几乎没有压力。MySQL 在数据量几千条时连接数和 CPU 占用都很低。整体来看2 核 4G 的服务器跑这套系统绰绰有余。观察资源占用的常用方法# 查看 Java 进程占用 top -p $(pgrep -f campus-lost-found) # 查看内存明细 ps aux | grep java # 查看 MySQL 慢查询日志 tail -f /var/log/mysql/slow-query.log接口性能方面需要注意几个位置图片上传接口。如果用户一次上传 5 张 5MB 图片请求体就有 25MB后端虽然会限制总大小但大图压缩依然是性能关键。项目里可以在上传接口做一次简单压缩把超过 2MB 的图片等比缩小到 1200px 宽度能显著降低存储和加载压力。列表查询接口。随着数据量增长item表的create_time、category、status字段要加索引。初始化脚本里已经建议添加联合索引CREATE INDEX idx_item_status_time ON item(status, create_time); CREATE INDEX idx_item_category ON item(category);并发场景。校园失物招领系统的并发量不会很高按一个 2 万人的学校估算一天新增失物可能只有几十条QPS 峰值远达不到瓶颈。但如果做毕设答辩演示需要注意页面同时刷新时前端不要发起大量重复请求加上防抖即可。8. 常见问题与排查方法问题现象可能原因排查方式解决方案前端页面打不开Node 服务未启动或端口被占用检查终端日志检查 5173 端口重启前端服务或更换端口登录接口报 502后端未启动或代理地址不对直接访问后端接口看返回确认 8080 端口可用检查 Vite 代理注册时提示数据库连接失败MySQL 未启动或密码配置错误查看后端日志中的异常堆栈修改 application.yml 中的数据库配置图片上传失败上传目录无写权限查看后端日志检查 uploads 目录权限执行 chmod -R 755 uploads或修改目录路径列表页数据不显示接口返回异常或字段名不一致打开浏览器开发者工具看 Network对比后端实体字段和前端字段名管理员接口返回 403当前登录用户不是管理员查看用户表的 role 字段手动将测试账号的 role 改为 admin发布失物后列表没有数据前端可能过滤了“待审核”状态用管理员账号进后台查看审核通过后数据才会出现在公示列表页面样式错乱Element Plus 版本不一致查看 package.json 中的依赖版本统一安装指定版本并重新构建上传大图页面卡住图片压缩逻辑未生效查看网络面板中的请求大小在前端上传前做一次图片压缩Docker Compose 起不起来端口冲突或镜像拉取失败docker compose logs 查看日志释放端口或更换镜像源重新拉取第一跑不顺利是正常的最有效的排查路径是先看后端日志再看前端开发者工具的 Network 面板绝大多数问题都出在接口地址、Token 未携带、数据库配置这三处。9. 最佳实践与使用建议项目能跑通只是第一步要做到真正可用、好维护下面这些优化方向建议重视。失物信息的发布格式要尽量统一。用户在发布物品时标题和描述往往是口语化的例如“我的卡掉了”“捡到一个壳子”这对后续检索很不友好。管理员在审核时应该补充标准化关键词把物品归类为校园卡、耳机、书籍、证件、雨伞等固定分类。认领环节要多做一层交叉验证。失物招领系统最大的风险不是技术问题而是冒领。建议在认领申请中要求用户提供物品的细节特征例如校园卡号后四位、笔记本的封面样式、耳机的颜色和品牌管理员核对通过后再展示联系方式。涉及身份证、学生证、银行卡等重要证件时最好要求线下核对原件。后台的权限要细分。目前系统只有普通用户和管理员两种角色后续如果接入多个场景例如图书馆管理员只能管图书馆的失物食堂管理员只能管食堂的失物可以引入角色和部门的概念把item表增加location归属字段并让不同管理员只看到自己负责区域的数据。生产环境部署时不要把数据库密码和 JWT 密钥写死在代码里。建议通过环境变量注入例如使用SPRING_DATASOURCE_PASSWORD和JWT_SECRET环境变量。后端日志不要打印登录密码和 Token 明文使用脱敏组件替代。每周固定做一次数据备份备份最少包含两个内容MySQL 数据库导出文件和uploads目录。数据库导出命令示例mysqldump -u root -p campus_lost_found campus_lost_found_$(date %Y%m%d).sql备份策略不用太复杂保留最近 30 天即可。10. 总结与下一步校园失物招领系统从业务模型上看是一套非常典型的 CRUD 权限 文件上传 简单统计的全栈系统。它不像 AI 项目那样依赖显卡和模型核心价值在于把一张失物信息表从“群里刷屏”变成“可查询、可追踪、可管理的在线服务”。对于想练手全栈开发、准备课程设计或者需要给校园部门做个实用工具的同学这套代码和部署流程可以直接复用。最先应该验证的功能是完整认领链路用户发布失物、管理员审核、用户认领申请、管理员分配、状态更新。这条链路跑通系统的主干就没有问题。最容易踩的坑有三个第一是数据库编码没有配置为 utf8mb4导致中文乱码第二是图片上传目录没有写权限第三是前后端联调时 Token 没有正确携带。这三个问题排查掉整个系统就稳定了。后续可以扩展的方向也很多接入钉钉或企业微信机器人新失物发布后自动通知管理员搭建微信公众号或小程序端方便学生直接在手机上发布和查询使用向量化或关键词库优化物品匹配准确率进一步提升“自动匹配”的体验。如果想长期使用建议把认证方式从 JWT 升级为成熟的权限框架例如 Sa-Token 或者 Spring Security加上操作审计日志和更细粒度的菜单权限系统的安全性和完整性会再上一个台阶。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价