ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

小程序+Java后端马拉松报名系统毕业设计实战指南

小程序+Java后端马拉松报名系统毕业设计实战指南 简介这份资源是面向高校计算机相关专业学生与Java初学者的一套马拉松报名系统毕业设计完整方案采用微信小程序前端搭配Java后端与MySQL数据库适合作为毕业设计、课程设计或全栈入门练手项目。压缩包共1220个文件约41.42MB包含127个Java后端源码、135个Vue组件、172个JavaScript脚本、86个WXSS与84个WXML小程序页面文件以及94个JSON配置、2个SQL数据库脚本和2个MP4演示视频另附说明文档与项目构建脚本覆盖前后端与数据库各层。系统功能上管理员可管理用户、赛事信息、赛事报名、活动商场、留言板、订单与系统设置用户端支持注册登录、浏览赛事、在线报名及购买商城商品业务闭环较为完整。目前已有300人学习下载读者可据此掌握小程序与Java后端联调思路、数据库表结构设计及项目部署流程快速搭建可运行的参考系统。1. 马拉松报名系统为什么“小程序 Java 后端”是毕业设计里最稳的选题每年毕业设计选题总有一批同学在“做点什么”上卡住。太简单的怕被答辩老师怼太复杂的又怕做不完。马拉松报名系统这个题目恰好卡在一个很舒服的位置业务逻辑清晰、用户角色分明、技术栈主流而且能同时展示前端交互和后端工程能力。用微信小程序做用户端Java 做后端前后端分离这套组合在近几年的计算机毕业设计里出现频率极高原因很直接——小程序免安装、传播方便Java 生态成熟、资料多遇到问题能搜到答案。这个系统解决的核心问题其实就三件事赛事发布、选手报名、数据管理。但真动手做你会发现每一件都能拆出一堆细节。比如报名时怎么防止重复提交名额满了怎么自动关闭通道支付状态怎么同步这些才是答辩时老师爱问的地方。适合谁做适合已经学过 Java 基础、了解 Spring Boot 和 MyBatis、对微信小程序开发有一点接触的本科生。如果你连数据库增删改查都没写过建议先补一补再上手否则中期会很痛苦。2. 技术选型与架构为什么不是 Vue Spring Boot而是小程序 Java2.1 小程序端选型原生开发还是 uniapp微信小程序开发目前主流两条路原生 WXML/WXSS/JS 和 uniapp。原生开发的好处是离微信官方能力最近比如获取手机号、顶部导航栏高度适配、登录态维护这些在原生里都有直接 API。uniapp 的优势是一套代码多端发布但如果你只做微信小程序原生反而更省心不用处理编译层的兼容问题。我一般会建议毕业设计用原生原因有三点。第一答辩时老师问“你这个登录怎么做的”你可以直接说调用wx.login拿 code后端换 openid流程清晰。第二原生小程序的目录结构简单pages下每个页面四个文件新手不容易迷路。第三遇到问题搜“微信小程序 获取手机号”原生方案的答案最多。顶部导航栏高度是个经典坑。不同机型状态栏高度不一样直接用固定像素会翻车。正确做法是用wx.getSystemInfoSync()拿到statusBarHeight再结合胶囊按钮位置计算。代码大概长这样// 获取状态栏高度和胶囊位置计算自定义导航栏总高度 const systemInfo wx.getSystemInfoSync(); const menuButton wx.getMenuButtonBoundingClientRect(); const navBarHeight (menuButton.top - systemInfo.statusBarHeight) * 2 menuButton.height; // 最终导航栏总高度 状态栏 导航栏内容区 const totalHeight systemInfo.statusBarHeight navBarHeight;这段逻辑说明statusBarHeight是手机状态栏高度menuButton是右上角胶囊的位置信息。导航栏内容区高度等于胶囊上下间距之和加胶囊自身高度。参数不需要手动设全部动态计算适配所有机型。2.2 后端选型Spring Boot MyBatis-Plus 的取舍Java 后端做毕业设计Spring Boot 几乎是默认选项。但持久层用 MyBatis 还是 MyBatis-Plus很多人纠结。我的建议是直接用 MyBatis-Plus因为毕业设计的时间要花在业务逻辑上不是写重复的 CRUD SQL。MyBatis-Plus 的BaseMapper自带增删改查分页插件配一下就能用省下来的时间可以去做报名状态机、名额扣减这些真正有含量的东西。数据库选 MySQL 8版本不用太新5.7 也够。表设计上核心就几张用户表、赛事表、报名记录表、支付流水表。报名记录表里一定要有唯一索引比如(user_id, event_id)联合唯一这是防止重复报名的最后一道防线。别指望前端按钮置灰能拦住所有情况网络重试、多端登录都会绕过前端校验。跨域问题在前后端分离里必现。小程序请求 Java 后端虽然小程序不算严格意义的浏览器跨域但如果你用浏览器调试工具或者 H5 预览就会遇到。后端加一个全局 CORS 配置就行Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) // 允许所有来源生产环境要收紧 .allowedMethods(GET, POST, PUT, DELETE) .allowCredentials(true) .maxAge(3600); } }逻辑说明allowedOriginPatterns用通配符匹配来源allowCredentials允许携带凭证。注意生产环境不能这么写要指定具体域名。参数maxAge是预检请求缓存时间单位秒。2.3 前后端分离的接口约定前后端分离最怕接口对不上。我的习惯是先定接口文档再写代码用 Swagger 或者简单的 Markdown 都行。统一返回格式比如{code, msg, data}前端只认code判断成功失败。登录态用 token小程序端存wx.setStorageSync每次请求带在 header 里。后端用拦截器校验 token放行登录和赛事列表这类公开接口。3. 数据库设计与核心表结构从报名防重到名额扣减3.1 五张核心表与字段说明毕业设计的数据库不用太复杂但关键字段不能省。下面是我一般会用的表结构字段名和类型可以直接抄。表名关键字段说明userid, openid, nickname, phone, create_timeopenid 唯一phone 可空eventid, title, quota, signed_count, status, start_timequota 总名额signed_count 已报人数registrationid, user_id, event_id, status, create_time联合唯一索引 user_idevent_idpaymentid, registration_id, trade_no, amount, statustrade_no 唯一adminid, username, password后台管理用event表的signed_count是冗余字段用的时候要小心。每次报名成功就1取消报名就-1。但并发下直接update event set signed_count signed_count 1是原子操作MySQL 行锁能保证不超卖。别先查再改那是经典翻车写法。3.2 报名防重的三层校验第一层前端按钮点击后置灰防止用户狂点。第二层后端接口先查registration表有没有记录有就返回“已报名”。第三层数据库唯一索引兜底插入冲突就捕获异常返回友好提示。三层缺一不可尤其是第三层很多同学觉得前两层够了结果压测时出现两条重复记录答辩被问住。-- 联合唯一索引防止同一用户重复报名同一赛事 ALTER TABLE registration ADD UNIQUE KEY uk_user_event (user_id, event_id);这条 SQL 执行后任何重复插入都会抛DuplicateKeyException后端捕获后返回“请勿重复报名”。3.3 名额扣减的原子操作名额扣减必须用数据库原子操作不能先select再update。正确写法UPDATE event SET signed_count signed_count 1 WHERE id #{eventId} AND signed_count quota AND status 1;执行后看影响行数如果是 0说明名额满了或赛事已关闭直接返回失败。这个where条件里的signed_count quota就是防超卖的关键。参数eventId是赛事 IDquota是总名额。别用 Java 代码去判断数据库层判断才可靠。4. 小程序端关键页面实现登录、赛事列表与报名表单4.1 微信登录获取手机号的完整链路微信小程序登录分两步先wx.login拿 code 换 openid再getPhoneNumber拿加密数据换手机号。第一步后端用 code 调微信接口换 openid 和 session_key。第二步前端按钮触发getPhoneNumber拿到encryptedData和iv传给后端解密。// 小程序端获取手机号按钮回调 onGetPhoneNumber(e) { if (e.detail.errMsg ! getPhoneNumber:ok) { wx.showToast({ title: 需要授权才能报名, icon: none }); return; } wx.login({ success: (res) { // 把 code、encryptedData、iv 一起传给后端 wx.request({ url: https://your-domain.com/api/login/phone, method: POST, data: { code: res.code, encryptedData: e.detail.encryptedData, iv: e.detail.iv }, success: (resp) { wx.setStorageSync(token, resp.data.data.token); } }); } }); }逻辑说明e.detail.errMsg判断用户是否同意授权。wx.login的 code 每次不同用来换 openid。encryptedData和iv是加密手机号数据必须一起传。后端解密用 session_key所以 code 和加密数据要同时传不能分两次请求。参数说明encryptedData是 Base64 编码的加密串iv是初始向量。后端用 AES-128-CBC 解密密钥是 session_key。注意 session_key 有时效解密失败要重新登录。4.2 赛事列表的分页与下拉刷新赛事列表用scroll-view或者页面级下拉刷新都行。分页参数page和size后端用 MyBatis-Plus 的分页插件返回total和records。前端判断records.length size就不再加载。// 赛事列表分页加载 loadEvents() { if (this.data.loading || !this.data.hasMore) return; this.setData({ loading: true }); wx.request({ url: https://your-domain.com/api/event/list, data: { page: this.data.page, size: 10 }, success: (res) { const list res.data.data.records; this.setData({ events: this.data.events.concat(list), page: this.data.page 1, hasMore: list.length 10, loading: false }); } }); }逻辑说明loading防止重复请求hasMore控制是否还有下一页。每次成功返回后page 1列表拼接。参数size设 10 比较合适太小加载次数多太大首屏慢。4.3 报名表单的字段校验与提交报名表单一般收集姓名、身份证号、手机号、紧急联系人。身份证号要做格式校验手机号用正则。提交前先本地校验减少无效请求。提交接口要带 token后端从 token 解析 user_id不要前端传 user_id否则可以伪造。// 身份证号简单校验 const idCardRegex /(^\d{15}$)|(^\d{17}(\d|X|x)$)/; if (!idCardRegex.test(this.data.idCard)) { wx.showToast({ title: 身份证号格式不对, icon: none }); return; }正则说明15 位纯数字或 18 位数字最后一位可以是 X。这个校验不验证校验位但毕业设计够用。真要严格校验需要写加权因子计算代码量不小看时间取舍。5. 避坑与排查那些答辩前夜让我睡不着的问题5.1 小程序请求域名未配置现象开发者工具里请求正常真机预览报“不在以下 request 合法域名列表中”。原因微信小程序要求所有请求域名在后台配置白名单开发者工具可以勾选“不校验合法域名”绕过真机不行。解决登录微信公众平台在开发设置里添加 request 合法域名。注意必须是 HTTPS且不能带端口号。毕业设计如果没买域名可以用测试号或者本地调试但答辩演示建议提前配好。5.2 后端返回时间格式前端显示异常现象数据库datetime类型返回给小程序显示成2024-01-01T00:00:00.00000:00带 T 和时区。原因Spring Boot 默认用 Jackson 序列化Date类型转成 ISO 格式。解决在application.yml里配置spring.jackson.date-format和time-zone或者在实体类字段上加JsonFormat。spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8配置后所有Date字段按指定格式输出。注意time-zone要设对否则时间差 8 小时。5.3 报名成功但支付状态不同步现象用户支付了但报名记录还是“待支付”。原因支付回调没处理或者处理失败。微信支付回调是异步的后端要提供一个接口接收回调验签后更新payment和registration状态。常见错误是回调接口被拦截器拦了没放行。解决把回调接口加入白名单不校验 token。另外回调可能重复要做幂等用trade_no唯一索引兜底。5.4 MyBatis-Plus 分页插件没生效现象传了page和size返回的还是全部数据。原因没配分页插件。解决加一个配置类。Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }逻辑说明PaginationInnerInterceptor是分页拦截器DbType.MYSQL指定数据库类型。不加这个Page对象不会自动拼limit。5.5 小程序顶部导航栏标题不居中现象自定义导航栏后标题偏左或偏右。原因没考虑胶囊按钮占位。解决标题区域宽度设为screenWidth - 胶囊宽度 - 两边间距用 flex 居中。或者直接用微信默认导航栏省事。毕业设计如果时间紧默认导航栏完全够用别在样式上耗太久。6. 进阶技巧用状态机管理报名流程与答辩演示建议报名流程看起来简单但状态不少待支付、已支付、已取消、已退款、已完成。如果到处写if (status 1)代码会乱成一团。我一般会用一个简单的状态机把状态和允许的操作列出来代码里只做查表和判断。当前状态允许操作目标状态待支付支付已支付待支付取消已取消已支付退款已退款已支付完赛已完成实现上可以用枚举加 Map或者直接一个switch。关键是把状态流转集中在一个方法里别散落在各个 Service。答辩时老师问“你这个状态怎么管理的”你能说清楚流转规则比堆代码更有说服力。演示视频录制有个小技巧提前把数据准备好别现场注册。赛事列表放 3 到 5 条报名记录放几条不同状态的。演示顺序按“登录 → 看赛事 → 报名 → 支付 → 查看报名记录 → 后台管理”走控制在 3 分钟内。后台管理用若依或者自己写个简单页面都行能展示赛事增删改和报名名单导出就够。最后说个血泪经验数据库脚本一定要单独存一份.sql文件别只存在 Navicat 里。答辩前换电脑或者重装系统没有脚本就得重头建表。源码打包时把README.md写好环境要求、启动步骤、默认账号密码列清楚。别小看这个老师拿到你的压缩包第一件事就是看能不能跑起来。希望帮到你。本文还有配套的精品资源点击获取
返回列表