校园资源共享毕设项目实战:从需求分析到高可用架构落地
2026/8/9 5:07:46 网站建设 项目流程


校园资源共享毕设项目实战:从需求分析到高可用架构落地

写在前面
去年指导学弟做毕设,题目是“校园资源共享平台”。原以为两周能收尾,结果从需求撕逼到上线演示,足足熬了两个月。踩坑无数,也攒下一套可直接套用的“轻量级高可用”模板。今天全部摊开,能 copy 的代码直接拿走,不能 copy 的思路至少让你少掉 200 根头发。


一、需求澄清:把“伪需求”拍死在黑板

  1. 资源冲突
    同一把“西门子示波器”被 3 个人预约到同一时段,老师却只看演示结果——冲突现场=翻车现场。
    → 必须引入“时段独占锁”。

  2. 用户权限混乱
    学生、教师、管理员都能登录,但看到的功能完全不同。
    → RBAC 模型(Role-Based Access Control)+ JWT 无状态鉴权,省掉 Session 共享烦恼。

  3. 文件存储随意
    早期把图片直接扔在project/upload,Git 一提交,仓库 2 GB,CI 直接爆炸。
    → 对象存储(MinIO)+ 统一 CDN 域名,仓库只存代码。


二、技术选型:别让“过度设计”拖垮进度

维度候选方案结论理由
主数据库MySQL vs SQLiteMySQL并发写>20 时 SQLite 锁整个文件,演示现场必卡
缓存Redis vs 本地 MapRedis预约锁需进程级共享,本地 Map 在多实例下失效
文件存储本地磁盘 vs MinIOMinIO本地盘在 Docker 重启后路径漂移,MinIO 兼容 S3,迁云零改造
前端框架Vue2 vs Vue3Vue3组合式 API 让表格分页逻辑更清爽,build 体积降 30%
部署包jar 单文件 vs DockerDocker机房服务器只有 Ubuntu 18.04,Dockerfile 一把梭,环境差异归零

三、架构总览:一张图先建立“上帝视角”

  • 网关层:Nginx 反向代理 + HTTPS(Let's Encrypt 免费证书)
  • 业务层:Spring Boot 3.x,内嵌 Tomcat,端口 8080
  • 数据层:MySQL 8.0 主库 + Redis 7.0 缓存
  • 存储层:MinIO 单节点(生产可扩 MinIO 集群)
  • 前端:Vue3 静态文件托管在 Nginx,与后端同域,避免 CORS 额外配置

四、核心模块拆解与代码级实现

4.1 资源发布:统一 DTO + 参数校验

// ResourceDTO.java public record ResourceDTO( @NotBlank(message = "名称不能为空") @Length(max = 50) String name, @NotNull @Min(1) Integer totalQty, MultipartFile image ) {}
  • record省掉 Getter/Setter,DTO 只负责“穿数据”,不做业务。
  • 文件字段单独放 DTO,否则@RequestBody无法解析multipart/form-data

4.2 预约锁机制:Redis 分布式锁 + 幂等 Token

  1. 用户点击“预约”→前端带uuid作为幂等键
  2. 后端执行 Lua 脚本,保证“查询-占坑-写记录”原子性
// ReservationService.java public String reserve(ReserveCommand cmd) { String key = "lock:res:" + cmd.getResourceId() + ":" + cmd.getStartTime(); String val = Thread.currentThread().getName() + ":" + System.nanoTime(); Boolean ok = redisTemplate.execute( RedisScript.of("if redis.call('exists',KEYS[1])==0 then " + "redis.call('set',KEYS[1],ARGV[1],'ex',ARGV[2]); return 1; else return 0; end"), List.of(key), val, "30"); if (!Boolean.TRUE.equals(ok)) { throw new BizException("时段已被抢占"); } try { reservationMapper.insert(cmd); return cmd.getId(); } finally { if (val.equals(redisTemplate.opsForValue().get(key))) { redisTemplate.delete(key); // 仅自己删自己的锁 } } }
  • 过期时间 30 秒,防止业务宕机留下死锁。
  • finally块做“谁加锁谁释放”,避免 A 用户释放 B 用户的锁。

4.3 JWT 无状态鉴权:双 Token(Access + Refresh)

# application.yml jwt: access-expire: 15 # 分钟 refresh-expire: 1440 # 分钟 = 1 天
// JwtFilter.java if (token != null && jwtUtil.validate(token)) { UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken( jwtUtil.getUserId(token), null, List.of(new SimpleGrantedAuthority("ROLE_" + role))); SecurityContextHolder.getContext().setAuthentication(auth); }
  • Access Token 存内存,Refresh Token 存 HttpOnly Cookie,XSS 偷不走。
  • 用户角色放在Authentication里,方法级安全直接用@PreAuthorize("hasRole('ADMIN')")

4.4 文件上传:MinIO 客户端封装

// MinioService.java public String upload(MultipartFile file) { String bucket = "resource"; String objName = UUIDUUID() + "-" + file.getOriginalFilename(); try { minioClient.putObject( PutObjectArgs.builder() .bucket(bucket) .object(objName) .stream(file.getInputStream(), file.getSize(), -1) .contentType(file.getContentType()) .build()); return "https://cdn.example.com/" + bucket + "/" + objName; } catch (Exception e) { throw new BizException("上传失败"); } }
  • 返回 CDN 地址,前端直接<img :src="url">,后端磁盘零压力。
  • 上传前检查 ContentType,禁止text/html,防止 XSS 挂马。

五、性能 & 安全:把“万一”当“一定”来防

  1. 重复提交
    前端按钮置灰 + 后端幂等 Token(见 4.2),30 秒内同一uuid只能成功一次。

  2. XSS 过滤
    使用jsoupWhitelist.basic()清洗富文本,JSON 返回统一Content-Type: application/json,杜绝“意外解析”。

  3. 冷启动优化
    Spring Boot 3 原生 AOT 编译后启动 1.8 s → 0.9 s;把 MinIO、MySQL 连接预热放在CommandLineRunner,演示现场不尴尬。

  4. 接口防刷
    基于 Redis 的令牌桶,每秒 10 次,超限返回 429,IP+用户双维度。


六、生产环境踩坑实录

现象根因解决
CORS 配置遗漏前端 404 不报错,但数据拿不到Nginx 与后端端口不同,浏览器预检失败application.yml打开spring.web.cors.allowed-origin-patterns=https://*example.com
静态资源 404打包后图标空白Vue 默认baseUrl="/",部署到子目录/share/设置vite.config.tsbase: '/share/',并同步修改 Nginxlocation
数据库连接池耗尽压测 50 并发直接 500Hikari 默认最大 10,演示当天忘记改生产配置maximum-pool-size=cpu*2+1,并打开leak-detection-threshold=5000

七、部署脚本:一条命令跑起来

# 克隆即运行 git clone https://github.com/yourname/campus-share.git cd campus-share cp .env.example .env docker-compose up -d # 访问 https://localhost:8443
  • docker-compose.yml里已经把 MySQL、Redis、MinIO、Spring Boot 编排好,端口无冲突。
  • 首次启动自动执行flyway migrate,建表+初始数据,毕设演示零手动。

八、可继续折腾的脑洞

  1. 多校区共享网络
    把 MinIO 升级成“多站点纠删码”,MySQL 用 Group Replication,Redis 上 Cluster,不同校区就近访问最近节点,流量用 DNS 分地域解析。

  2. 微信小程序接入
    后端接口无需改动,只新增wx.login获取openid,把openid与本地user_id做绑定即可。前端用 Taro 或 uni-app 一套代码同时发 H5 + 小程序,毕设加分项到手。


九、小结

整套代码从 0 到 1 大概 3k 行,核心就三句话:
“锁”用 Redis,“文件”用 MinIO,“权限”用 JWT。
剩下的都是体力活——把异常打印清楚、把日志切成文件、把 Docker 镜像压到 100 MB 以内。

如果你已经跑通本文的docker-compose,不妨试着把“多校区”或“小程序”任选一个做下去,下次站在答辩 PPT 前,你会感谢今天多写的这一行注释。


需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询