恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

微信小程序+SpringBoot竞赛管理系统毕设实战:从架构设计到避坑指南

  • 首页
  • 资讯中心
  • /
  • 微信小程序+SpringBoot竞赛管理系统毕设实战:从架构设计到避坑指南

相关资讯

Java Web空气质量监测系统:从源码部署到AQI算法实现全解析 2026/10/8 23:22:41
嵌入式功耗优化必读:Linux内核Runtime PM机制全解析 2026/10/8 23:22:41
Java课设超市订单管理系统源码解析与答辩避坑指南 2026/10/8 23:22:41

最新资讯

飞书CLI开源后,Claude Code办公自动化实战大纲:从Base URL改到TaoToken开始
Claude Fable 5 正式发布,TaoToken 统一 Key 接入 Anthropic 新模型
headcount 16部门选型完全指南:CFO、CTO、CISO等角色该装哪些技能
Hermes Desktop多Profile多Agent协作指南:多主机AI工作流如何搭建
端侧部署Qwen3.8的三大硬核优化:Chunked Prefill、MTP与CUDA Graph
苏州工业废料回收靠谱服务商测评排名,捷盛发环保科技价格公道不玩套路

今日推荐

AI编程智能体实战:从写代码到指挥代码的架构与落地
多模态大模型全栈能力拆解:从数据对齐到弹性推理
大模型Agent开发入门:从工具调用循环到落地避坑指南

本周热门

MR25H40CDF + PIC18F65K40:工业记录仪高可靠存储实战
基于STM32的数控恒压恒流电源设计:从硬件到PID调参全解析
LT9211 MIPI重定时器原理与双路扇出实战指南

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

微信小程序+SpringBoot竞赛管理系统毕设实战:从架构设计到避坑指南

发布时间:2026/10/8 23:22:41
微信小程序+SpringBoot竞赛管理系统毕设实战:从架构设计到避坑指南 简介这份资源面向计算机相关专业做毕业设计的学生提供一套基于微信小程序的大学生科技竞赛管理系统完整实现方案后台采用Spring Boot框架搭配Vue管理页面数据库为MySQL开发环境兼容Eclipse、MyEclipse、STS与IDEAJDK版本为1.8。系统功能覆盖个人中心、主办方管理、竞赛分类与公告栏管理、竞赛信息与报名管理、竞赛成绩管理及系统管理等模块学生端支持注册、在线报名、查询成绩与收藏管理主办方端可进行报名与成绩维护管理员则统筹竞赛与系统配置。压缩包共1338个文件以png图片、js脚本、svg图标、vue组件、java源码、json配置、wxss与wxml小程序页面为主另含sql脚本、doc文档与mp4演示视频整体约77.3MB。资源内含源码、数据库脚本、论文、开题报告、环境工具包及同框架项目安装教程已有132人学习适合需要完整赛题方案与排错参考的毕业生。1. 从一份“能跑起来”的毕设说起微信小程序 SpringBoot 竞赛管理系统到底在做什么每年到了毕设季计算机专业的学生最头疼的不是写不出代码而是不知道写什么、怎么写才能既像样又能过答辩。我见过太多人从网上抄一份源码改个名字就交上去结果答辩时老师问一句“你这个登录鉴权怎么做的”就当场翻车。今天要聊的这个题目——基于微信小程序的大学生科技竞赛管理系统配合 SpringBoot 后端——其实是一个非常适合本科毕业设计的选题因为它同时覆盖了移动端开发、后端接口设计、数据库建模和权限管理这几个核心考点而且业务逻辑足够清晰不会让你陷进某个冷门算法里出不来。这个系统解决的核心问题是高校里科技竞赛的报名、审核、通知、成绩管理往往靠 Excel 和微信群完成信息散落、统计困难。做成小程序之后学生可以在手机上直接浏览竞赛列表、提交报名材料、查看审核进度管理员在后台发布竞赛、审核报名、导出成绩。技术栈上前端用微信小程序原生开发或 uni-app 打包后端用 SpringBoot 提供 RESTful 接口数据库用 MySQL整体是一个典型的前后端分离架构。适合正在做毕设的本科生也适合想拿一个完整项目练手 SpringBoot 和微信小程序的初级开发者。2. 技术选型与架构拆解为什么是 SpringBoot 微信小程序而不是别的2.1 后端为什么选 SpringBoot 而不是 SSM 或 Node.js很多学校的课程还在教 SSMSpring SpringMVC MyBatis但如果你现在做毕设还用 SSM光是 XML 配置就能耗掉你三分之一的时间。SpringBoot 的核心优势是自动装配和起步依赖你只需要在pom.xml里引入spring-boot-starter-web和mybatis-plus-boot-starter一个可运行的 Web 服务就搭好了。对于毕设这种周期短、功能明确的项目SpringBoot 能让你把精力放在业务逻辑上而不是环境配置上。另一个常见的选择是 Node.js Express优点是前后端都是 JavaScript学习成本低。但问题在于国内高校答辩老师对 Java 技术栈的认可度普遍更高而且 SpringBoot 生态里的 Spring Security、MyBatis-Plus、Redis 缓存这些组件能让你的系统在“技术含量”上看起来更扎实。如果你的毕设还想顺便练一下 Java 面试题里常问的 IOC、AOP、事务管理那 SpringBoot 就是不二之选。版本选择上我一般会建议用 SpringBoot 2.7.x 而不是 3.x。原因很实际3.x 要求 JDK 17而很多学校机房的 JDK 还是 8 或 11另外 3.x 对 Jakarta EE 的迁移会让一些老教程里的代码直接报错你搜到的很多“SpringBoot 整合 XX”的文章可能还没更新。用 2.7.x 可以避开这些玄学问题保证你的项目在答辩现场能稳定跑起来。2.2 微信小程序端的技术决策原生开发还是 uni-app微信小程序开发有两条路一是用微信官方的小程序原生框架二是用 uni-app 这类跨端框架。原生开发的好处是文档齐全、API 调用直接、调试工具成熟缺点是只能跑在微信里。uni-app 的好处是一套代码可以打包到微信小程序、H5 甚至 App但代价是引入了额外的抽象层遇到一些微信特有的 API 时反而更麻烦。对于毕设来说我建议直接用微信小程序原生开发。原因很简单你的题目就是“基于微信小程序”用原生框架更贴合题意而且微信开发者工具自带模拟器和真机调试你不需要额外配置 HBuilderX 的打包环境。小程序端的核心页面包括竞赛列表页、竞赛详情页、报名表单页、个人中心页、消息通知页。其中竞赛列表页需要处理分页加载这是微信小程序页面列表加载更多的典型场景后面会专门讲。2.3 数据库表设计五张核心表撑起整个系统数据库设计是毕设里最容易体现你功底的部分。这个系统最少需要五张表用户表user、竞赛表competition、报名表registration、成绩表score、通知表notice。用户表里要区分角色一般用role字段标记student和admin。竞赛表里要有报名开始时间、截止时间、最大人数这些字段方便后端做校验。报名表是核心业务表关联用户 ID 和竞赛 ID还要有审核状态字段pending、approved、rejected。这里有一个血泪经验报名表一定要加唯一索引约束同一个用户不能重复报名同一场竞赛。我见过有人没加这个约束结果测试时狂点提交按钮数据库里插入了十几条重复记录答辩演示时直接翻车。唯一索引的 SQL 如下ALTER TABLE registration ADD UNIQUE KEY uk_user_competition (user_id, competition_id);这条语句的含义是在registration表的user_id和competition_id两列上建立联合唯一索引数据库层面保证同一用户对同一竞赛只能有一条报名记录。参数说明uk_user_competition是索引名可以自定义但建议见名知意。加上之后即使前端没做防重复提交后端插入时也会抛异常你在 Service 层捕获这个异常并返回友好提示即可。3. 后端接口实现从登录鉴权到竞赛 CRUD 的完整链路3.1 微信登录与 JWT 鉴权的落地步骤微信小程序的登录流程和传统 Web 不一样。用户在小程序里点击登录前端调用wx.login()拿到一个临时code然后把code发给后端。后端拿着code加上你的小程序appid和secret去请求微信的code2Session接口换取用户的openid和session_key。拿到openid之后你在自己的用户表里查一下有没有这个用户没有就自动注册一个有就直接登录。最后后端生成一个 JWT token 返回给前端后续请求都带着这个 token。这里有一个关键点session_key不要返回给前端它应该留在后端用来解密用户信息。很多教程会把session_key一起返回这是不安全的。JWT 的生成可以用jjwt库设置一个合理的过期时间比如 7 天。下面是一个简化的登录接口代码PostMapping(/login) public Result login(RequestBody LoginDTO loginDTO) { // 1. 调用微信接口换取 openid String url https://api.weixin.qq.com/sns/jscode2session ?appid appid secret secret js_code loginDTO.getCode() grant_typeauthorization_code; String response restTemplate.getForObject(url, String.class); JSONObject json JSON.parseObject(response); String openid json.getString(openid); // 2. 查库或自动注册 User user userService.findByOpenid(openid); if (user null) { user new User(); user.setOpenid(openid); user.setRole(student); userService.save(user); } // 3. 生成 JWT String token JwtUtil.generateToken(user.getId(), user.getRole()); return Result.success(token); }逻辑说明这段代码先通过restTemplate请求微信的jscode2session接口拿到openid。然后查库判断用户是否存在不存在则自动注册。最后用JwtUtil生成 token 返回。参数说明appid和secret建议放在application.yml里不要硬编码在代码中LoginDTO里只有一个code字段Result是统一返回体包含code、msg、data三个字段。3.2 竞赛列表接口的分页与条件查询竞赛列表是使用频率最高的接口需要支持分页、按状态筛选、按关键字搜索。用 MyBatis-Plus 的话分页只需要配置一个PaginationInnerInterceptor然后调用page()方法即可。下面是一个典型的列表查询GetMapping(/list) public Result list(RequestParam(defaultValue 1) Integer page, RequestParam(defaultValue 10) Integer size, RequestParam(required false) String keyword, RequestParam(required false) String status) { LambdaQueryWrapperCompetition wrapper new LambdaQueryWrapper(); if (StringUtils.hasText(keyword)) { wrapper.like(Competition::getTitle, keyword); } if (StringUtils.hasText(status)) { wrapper.eq(Competition::getStatus, status); } wrapper.orderByDesc(Competition::getCreateTime); PageCompetition result competitionService.page(new Page(page, size), wrapper); return Result.success(result); }逻辑说明LambdaQueryWrapper是 MyBatis-Plus 提供的条件构造器like方法对应 SQL 的LIKE %keyword%eq对应。orderByDesc按创建时间倒序保证最新的竞赛排在前面。参数说明page和size有默认值前端不传也不会报错keyword和status是可选参数用required false标记。注意Page对象返回的records是当前页数据total是总记录数前端需要这两个字段来实现分页加载。3.3 报名审核的状态流转与并发控制报名审核涉及状态流转学生提交报名后状态是pending管理员审核通过变成approved拒绝变成rejected。这里有一个容易被忽略的问题如果两个管理员同时审核同一条报名记录可能会产生覆盖。解决办法是用乐观锁在registration表加一个version字段每次更新时带上版本号。Transactional public boolean audit(Long registrationId, String status, Long adminId) { Registration reg registrationService.getById(registrationId); if (reg null || !pending.equals(reg.getStatus())) { throw new BusinessException(报名记录不存在或已审核); } reg.setStatus(status); reg.setAuditTime(new Date()); reg.setAuditBy(adminId); // updateById 会自动带上 version 条件 return registrationService.updateById(reg); }逻辑说明先查记录判断状态是否为pending只有待审核的记录才能被审核。然后设置新状态、审核时间、审核人调用updateById。如果配置了乐观锁插件MyBatis-Plus 会自动在WHERE条件里加上version 旧值更新失败说明有人抢先改了返回false。参数说明status只允许传approved或rejected建议在 Controller 层做校验adminId从 JWT 里解析不要从前端传。4. 微信小程序端关键页面列表加载更多与表单提交的避坑写法4.1 竞赛列表页的下拉刷新与上拉加载微信小程序的列表加载更多是一个经典场景但很多人写出来的效果是上拉之后重复加载同一页数据或者加载完了还在触发请求。正确的做法是维护page、hasMore、loading三个状态变量。page记录当前页码hasMore标记是否还有数据loading防止重复请求。Page({ data: { list: [], page: 1, hasMore: true, loading: false }, onReachBottom() { if (!this.data.hasMore || this.data.loading) return; this.loadData(); }, loadData() { this.setData({ loading: true }); wx.request({ url: ${baseUrl}/competition/list, data: { page: this.data.page, size: 10 }, success: (res) { const records res.data.data.records; this.setData({ list: this.data.list.concat(records), page: this.data.page 1, hasMore: records.length 10, loading: false }); }, fail: () { this.setData({ loading: false }); wx.showToast({ title: 加载失败, icon: none }); } }); } });逻辑说明onReachBottom是小程序页面的生命周期函数用户上拉到底部时触发。先判断hasMore和loading避免无效请求。请求成功后把新数据拼接到list后面页码加一。hasMore的判断逻辑是如果本次返回的记录数等于size说明可能还有下一页小于size则说明已经到底了。参数说明baseUrl建议放在单独的配置文件里方便切换开发和生产环境size设为 10 是经验值太大首屏加载慢太小请求次数多。4.2 报名表单的校验与防重复提交报名表单通常包含姓名、学号、联系方式、参赛项目描述等字段。前端校验只能防君子后端校验才是底线。但前端校验能提升用户体验所以两边都要做。前端在提交前检查必填项是否为空后端在接口里再次校验并且利用数据库唯一索引防止重复报名。submitForm() { const { name, studentId, phone } this.data.form; if (!name || !studentId || !phone) { wx.showToast({ title: 请填写完整信息, icon: none }); return; } if (this.data.submitting) return; this.setData({ submitting: true }); wx.request({ url: ${baseUrl}/registration/submit, method: POST, header: { Authorization: wx.getStorageSync(token) }, data: this.data.form, success: (res) { if (res.data.code 200) { wx.showToast({ title: 报名成功 }); wx.navigateBack(); } else { wx.showToast({ title: res.data.msg, icon: none }); } }, complete: () { this.setData({ submitting: false }); } }); }逻辑说明先做前端必填校验然后用submitting标记防止用户狂点按钮。请求头里带上 JWT token后端从 token 里解析用户 ID。complete回调里重置submitting无论成功失败都要重置否则按钮会一直处于禁用状态。参数说明wx.getStorageSync(token)是从本地缓存读取登录时存的 token注意 token 过期时要引导用户重新登录。4.3 消息通知页的未读标记与跳转逻辑消息通知页需要展示管理员发布的通知并且区分已读和未读。实现方式是在notice表里加一个read字段或者单独建一张user_notice关联表记录每个用户的已读状态。简单起见毕设里可以直接在notice表加read字段但这样只能支持全体通知不能针对特定用户。如果要做定向通知就需要关联表。小程序端的展示逻辑是未读通知加一个红点或加粗字体点击后调用标记已读接口然后跳转到详情页。这里要注意的是标记已读的接口应该在跳转前调用而不是在详情页的onLoad里调用否则用户快速返回时可能状态还没更新。5. 避坑与排查毕设答辩前最容易翻车的五个问题5.1 跨域问题导致小程序请求全部失败现象微信开发者工具里请求后端接口控制台报request:fail或者net::ERR_CONNECTION_REFUSED。原因小程序的请求域名需要在微信公众平台配置合法域名开发阶段可以在开发者工具里勾选“不校验合法域名”。但即使勾选了如果后端没开跨域浏览器环境下的 H5 调试也会失败。解决在后端加一个全局跨域配置用WebMvcConfigurer实现addCorsMappings允许所有来源、所有方法。注意生产环境要收紧来源但毕设演示阶段可以放开。5.2 SpringBoot 版本太高导致依赖冲突现象项目启动时报ClassNotFoundException或NoSuchMethodError通常出现在javax.servlet和jakarta.servlet之间。原因SpringBoot 3.x 把javax包名改成了jakarta而你引入的某些第三方库还在用旧包名。解决把 SpringBoot 版本降到 2.7.x或者把所有相关依赖升级到兼容 3.x 的版本。对于毕设降版本是最省事的做法。5.3 数据库时区不对导致时间差八小时现象前端显示的比赛开始时间比实际时间少了八小时。原因MySQL 的时区配置和 JVM 的时区不一致或者 JDBC 连接串没指定时区。解决在application.yml的 JDBC URL 里加上serverTimezoneAsia/Shanghai同时在 MySQL 配置文件里设置default-time-zone08:00。另外实体类里的时间字段建议用LocalDateTime而不是Date避免一些历史遗留问题。5.4 小程序真机调试时请求超时现象开发者工具里一切正常真机预览时接口请求超时。原因真机访问的是你电脑的局域网 IP如果电脑防火墙没关或者手机和电脑不在同一个 WiFi 下就会连不上。解决确保手机和电脑在同一局域网关闭电脑防火墙后端启动时绑定0.0.0.0而不是127.0.0.1。如果还是不行可以用内网穿透工具临时映射一个公网地址但注意不要用于生产环境。5.5 答辩现场数据库连不上现象答辩时换了一台电脑项目启动报数据库连接失败。原因数据库密码、端口、库名和开发环境不一致。解决提前把数据库导出成 SQL 文件答辩前在演示电脑上重新导入并且把application.yml里的数据库配置改成演示电脑的配置。更稳妥的做法是准备一个 Docker Compose 文件一键启动 MySQL 和 Redis但这对毕设来说可能有点超纲量力而行。6. 进阶技巧用 AOP 做操作日志和接口耗时统计毕设如果只做 CRUD答辩时很难拿到高分。加一个 AOP 切面做操作日志和接口耗时统计既能体现你对 Spring 核心概念的理解又能让系统看起来更完整。具体做法是自定义一个Log注解然后在切面里拦截所有标注了该注解的方法记录方法名、参数、执行时间、操作人写入日志表。Aspect Component public class LogAspect { Around(annotation(logAnnotation)) public Object around(ProceedingJoinPoint joinPoint, Log logAnnotation) throws Throwable { long start System.currentTimeMillis(); Object result joinPoint.proceed(); long cost System.currentTimeMillis() - start; // 从 JWT 里解析当前用户 String username SecurityUtil.getCurrentUsername(); String methodName joinPoint.getSignature().getName(); logService.save(new SysLog(username, methodName, cost, new Date())); return result; } }逻辑说明Around环绕通知可以在方法执行前后插入逻辑。joinPoint.proceed()执行原方法返回结果。System.currentTimeMillis()计算耗时。SecurityUtil是一个工具类从ThreadLocal里拿当前请求的用户信息。参数说明annotation(logAnnotation)表示只拦截标注了Log的方法SysLog是日志实体类包含用户名、方法名、耗时、时间四个字段。这个切面加上之后你可以在管理后台加一个日志查询页面管理员能看到谁在什么时候调用了什么接口、耗时多少。答辩时老师问“你这个系统有没有做性能监控”你就可以把这个拿出来讲。另外接口耗时统计还能帮你发现慢查询比如某个列表接口耗时超过 500 毫秒你就知道该加索引了。还有一个实用技巧用Transactional注解时注意默认只对RuntimeException回滚。如果你在 Service 里抛的是Exception事务不会回滚。我一般会写成Transactional(rollbackFor Exception.class)避免这个坑。这个细节在答辩时如果被问到能加分不少。做毕设这件事我的习惯是先把最小可运行版本跑通再往上加功能。不要一上来就设计十几张表、几十个接口那样很容易卡在某个细节里出不来。先让登录、列表、报名这三个核心流程跑通再去加审核、通知、日志这些锦上添花的东西。希望帮到你。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号