又到了一年毕设季周围好几个学弟学妹都在问同一个问题微信小程序 Spring Boot 这个组合到底能不能撑起一个合格的毕设我的看法是能而且非常适合。尤其是公考、刷题、题库类的小程序业务逻辑清晰、功能边界明确、用户角色简单后端有东西可写前端有页面可做数据库也有足够的表去支撑论文里的系统设计章节。我平时接到的毕设咨询里这类项目的占比一直很高所以这次拿基于 Spring Boot 微信小程序的公考宝典小程序当例子把从需求拆解、技术选型、核心实现到部署答辩的完整链路讲透。这篇文的目标读者就是正在选题、已经开题但没动手、或者写了一半卡住的计算机专业同学内容会偏实战废话不多每一条都是我自己实践过的经验。1. 公考宝典小程序到底是做什么的从标题读出隐藏需求1.1 一个公考刷题类项目天然包含哪些功能先别急着写代码把公考宝典这四个字拆开看。公考指的是公务员考试相关的学习备考场景宝典意味着一个集中的知识库和练习工具。把这个需求落到软件系统上就自然引出四个核心模块刷题练习、试卷模拟、错题整理、学习记录。很多同学拿到题目后第一反应是去想办法找源码其实更值钱的是你自己能把这个需求讲清楚。我问过好几个同学你们做的是公考宝典那公考和普通考试有什么区别答案是题量大、知识点散、需要长期反复练习。这意味着系统必须支持按知识点和题型分类刷题要有随机组卷能力还要有错题重练和刷题统计功能。如果只做一个简单的出题-答题-判分循环论文里连系统的创新点都写不出来答辩时导师一问就露馅。在这类系统中角色通常分两种普通考生用户和管理员。考生用户注册登录后可以浏览题库、选择题型分类练习、参加模拟考试、查看历史成绩、维护自己的错题本。管理员则在后台维护题库数据包括题目的增删改查、分类管理、试卷配置还可以查看用户统计数据。这个角色划分直接决定了后端 API 的权限设计——考生接口和管理端接口必须分开这也是答辩时值得讲的一个点。1.2 从完整源码LW部署说明演示视频反推交付物边界标题里最扎眼的其实是后面那串词完整源码、LW、部署说明、演示视频。我理解很多同学看到全套一条龙就以为是买回来直接交但这里有个认知误区。完整源码解决的是起步难的问题LW也就是论文/设计文档解决的是不知道怎么写系统设计章节的问题部署说明解决的是把项目跑起来的问题演示视频解决的是答辩时候怎么展示的问题。它们合在一起本质是给你做毕设的全过程提供参考坐标系。但你心里要清楚这些交付物的正确用法是当脚手架不是当成品。所谓全包一条龙听起来省事实际上最稳的路径是把自己变成这个项目的第二作者——源码拿来做对照、文档用来搭框架、演示视频用来学表达然后亲手把项目里头每个模块的逻辑走一遍改一改、加一加、减一减。就拿我熟悉的一个案例来说某同学拿到一套类似源码包后把里面的科目分类从行测/申论扩展成了行测-言语理解、行测-数量关系、行测-判断推理、申论-归纳概括等更细致的分类就这么一个小改动论文的创新点和答辩时的个人工作全都有了。所以交付物全不全不是核心你把项目消化到几成才是核心。2. 技术选型不是拍脑袋Spring Boot 和小程序为什么是最稳的组合2.1 后端选 Spring Boot 的真实理由后台框架可以选的太多SSM、Spring Boot、Spring Cloud 甚至 Python 系的 Django 都能做。但如果你做的是毕设我的建议是首选 Spring Boot尤其对于这种中小规模的管理系统加小程序后端。原因很直接第一生态成熟遇到报错时搜索引擎一搜就能找到一堆同类问题的解决方案第二内置的自动配置让你摆脱繁琐的 XML 配置开发和调试速度明显快毕设有硬性 deadline时间是稀缺资源第三它默认自带 Tomcat打包一个 jar 直接能跑部署成本低到几乎可以忽略。实际开发中我习惯用 Spring Boot 2.7.x配合 MyBatis-Plus 操作数据库。MyBatis-Plus 这个选型对新手尤其友好它不是让你绕过 SQL而是把单表操作的通用 CRUD 封装好了——分页查询用selectPage就行条件查询用QueryWrapper就能拼比手写大量 XML 映射文件少很多重复劳动。当然项目里复杂一点的联表查询我还是会写自定义 SQL毕竟答辩时被问到你有没有写过复杂 SQL你得有东西能答。2.2 小程序端的选型约束与开发姿势微信小程序端的开发语言是 WXML、WXSS 和 JavaScript跟传统网页前端有差异但基本概念是相通的。为什么选微信小程序而不是普通 Web 网页作为前端两点一是微信生态自带传播属性公考学习这个场景天然适合在微信里使用备考的人每天打开微信的次数远远多于打开浏览器的次数二是微信小程序有一套完整的前后端通信机制调接口、传 JSON、处理登录态都是标准流程做进毕设里技术叙事非常完整。小程序的开发姿势我建议直接用微信开发者工具新建项目的时候选不使用云开发——这里多说一句虽然云开发能帮你省掉服务器但毕设最好还是自己部署后端否则论文里的系统部署和服务器环境配置章节会变得很难写。前端目录结构一般就是 pages页面、components自定义组件、utils公共工具、config全局配置这几个目录清爽不臃肿。2.3 数据库表结构设计一次设计好的表能省一半开发时间数据库是整个系统最值得花时间的部分因为表结构一旦定下来后面改起来非常伤筋动骨。公考宝典小程序的表我一般这样拆用户表user、题库分类表category、题目表question、试卷表exam、试卷题目关联表exam_question、刷题记录表pick_record、错题本表wrong_book、收藏表favorite。用户表重点字段包括 openid微信用户唯一标识、昵称、头像、角色考生/管理员。题目表是核心字段要覆盖题干、选项 A/B/C/D、正确答案、题目解析、所属分类 ID、题型单选/多选/判断、难度等级、是否启用。这里有个我踩过多次的坑题目表的正确答案字段不要存成字符串再在代码里做映射直接设计成固定字段 result_char 或 result_int后端判定对错时只需要一次字段比较逻辑简单还不会出错。试卷表记录模拟考试的基本信息和总时长试卷题目关联表存的是某张试卷包含哪些题目、顺序是什么这种多对多关联表也叫中间表是论文里实体关系图的重要组成部分。刷题记录表则记录用户每次答题的试卷/题目、选择答案、判定结果、答题时间是用户学习统计的数据来源。数据库引擎和字符集也提醒一下引擎用 InnoDB字符集用 utf8mb4。utf8mb4 不是可选项因为用户昵称里可能包含特殊符号和生僻字utf8mb4 才能完整存储。3. 后端核心逻辑拆解登录鉴权、刷题引擎和错题回捞3.1 微信登录与 Token 鉴权链路是怎么串起来的微信小程序登录的流程是一个固定套路很多同学第一次接触时会被绕晕其实拆开就三步。前端调用wx.login()拿到临时凭证 code后端拿着 code 向微信接口jscode2session换取用户的 openid 和 session_key拿到 openid 后执行查库或入库逻辑并签发自己的登录凭证返回给前端。我这里用的是 JWTJSON Web Token方案后端签发 token 返回给前端前端后续请求在请求头Authorization字段里带上它。为什么不用 session因为小程序端和后端是拆开的JWT 无状态服务端不用存 session 记录分布式的坑也少。很多教程喜欢把 openid 直接当前缀拼接成 token 返回这个能跑通但不严谨我习惯的做法是登录后查询用户表拿到 userId把 userId 塞进 token 的 payload 里后续业务请求都从 token 里解析 userId这样写出来的代码语义更干净。// JwtUtil 核心方法根据 userId 生成 token public String generateToken(Integer userId) { Date now new Date(); Date expiryDate new Date(now.getTime() EXPIRATION_TIME); return Jwts.builder() .setSubject(userId.toString()) .setIssuedAt(now) .setExpiration(expiryDate) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); }鉴权这件事还有一个隐藏考点小程序端并不是所有页面都需要登录但刷题、模拟考试、错题本这些核心业务必须登录。所以我在后端写了一个拦截器放行用户登录注册相关的接口和题目列表查询接口其他接口全部校验 token。这个设计在论文里可以直接对应系统安全性与权限控制一节答辩被问到时你还能顺势讲一下拦截器实现这属于典型加分项。3.2 刷题模块的核心随机抽题、分页查询与对错判定刷题模块是所有功能的中心。小程序端的专项练习按分类选题目后端接口设计上支持两个参数categoryId分类 ID和 page页码用 MyBatis-Plus 的分页插件实现。// 题目分页查询 Service 核心代码 public PageQuestion getQuestionPage(Integer categoryId, Integer page, Integer size) { PageQuestion pageParam new Page(page, size); QueryWrapperQuestion wrapper new QueryWrapper(); if (categoryId ! null) { wrapper.eq(category_id, categoryId); } // 只查询启用的题目 wrapper.eq(status, 1); wrapper.orderByAsc(id); return questionMapper.selectPage(pageParam, wrapper); }同类题目最好不要每次都是同样的顺序出现用户刷到第三次答案都背下来了学习体验很差。所以我额外加了一个随机刷题模式用ORDER BY RAND()实现完全随机当数据量较大时这条 SQL 会有一点性能开销但公考刷题的题目量级在毕设里根本到不了那种瓶颈完全够用。这也算是一个可以写进论文的性能权衡考量。对错判定的逻辑在答题提交接口里。前端把一整套答题结果传过来包括题目 ID 列表和用户选择的答案列表后端批量查询题目后用正确答案字段逐一比对把每道题的判定结果、得分、耗时组装好返回。有几个同学会在这个环节选择把正确答案下发到前端让前端判断我坚决不推荐——这样相当于把题目答案暴露给了前端想用抓包工具的话所有正确答案全透明了答辩时导师问一句你考虑过接口安全性吗就非常尴尬。3.3 错题本与学习统计把用户留下的行为数据沉淀下来错题本模块的价值在于二次学习。用户答错一道题后后端在判分的同时会往错题本表写一条记录包括题目 ID、用户 ID、错误答案、错误次数。但这里要处理一个逻辑细节同一道题用户错了三次错题本里应该显示几条记录经验做法是不要重复插入而是做存在则更新错误次数的 upsert 逻辑这样列表展示和移出错题功能都好实现。-- 错题本 upsert 核心 SQL 逻辑简化示意 INSERT INTO wrong_book (user_id, question_id, wrong_count, create_time) VALUES (#{userId}, #{questionId}, 1, NOW()) ON DUPLICATE KEY UPDATE wrong_count wrong_count 1;学习统计模块相对独立也算是一个可扩展点。用户每次交卷后端记录成绩到刷题记录表学习统计页面就可以按天展示刷题数量、正确率、累计做题量。这些数据用一条GROUP BY的 SQL 就能查出来工作量不大但非常能撑场面——论文里的数据可视化章节和个人主页的展示素材全靠它。我见过不少同学这个模块做得很有亮点比如按科目维度统计正确率并用小程序端的图表库画柱状图效率和美观度一下就上来了。4. 小程序端核心页面与开发细节从请求封装到答题交卷4.1 页面结构想清楚再动 WXML效率翻倍小程序端看起来页面多归纳起来就四类用户体系页面登录、个人中心、内容浏览页面首页、题库列表、题目详情、练习交互页面刷题答题页、模拟考试页、数据展示页面成绩单、错题本、学习统计。我建议你在创建第一个页面之前先在纸上把页面跳转图画一遍搞清楚哪个页面会调用哪个接口哪个接口的数据会被多个页面复用。首页建议做成信息聚合型顶部放一个轮播图或者醒目的学习入口下面是分类入口言语理解、数量关系、判断推理等再往下是每日一练入口和最近学习统计卡片。题库页就是一个可搜索的题目列表支持按分类筛选。答题页是整个前端最复杂的页面顶部要显示进度条中间是题目内容与选项底部是上一题/下一题和交卷按钮还要抽出一块区域做答题卡弹层方便用户快速跳题和检查未答题目。这里有个交互设计的细节值得单独说单选题默认四个选项展示为 A/B/C/D 四个标签用户点了之后要高亮已选项多选题的选项用复选框样式需要明确提示多选判断题只有对/错两个按钮。不同题型如果 UI 不区分用户在答题时很容易误操作这种体验问题虽然不影响核心功能但演示视频里被导师看到就会留下不够细心的印象。4.2 请求封装与登录态的全局维护小程序的wx.request是底层 API直接在每个页面里调用会有三个副作用代码重复、错误处理各写各的、token 携带逻辑散落各处。正确做法是在 utils 目录里封装一个 request 方法统一设置 baseUrl、统一拼接请求头、统一处理 HTTP 状态码和业务状态码。// utils/request.js 封装核心逻辑简化 const request (url, method, data) { return new Promise((resolve, reject) { wx.request({ url: BASE_URL url, method: method, data: data, header: { Authorization: wx.getStorageSync(token) }, success(res) { if (res.data.code 200) { resolve(res.data.data); } else if (res.data.code 401) { // token 失效跳转登录 wx.navigateTo({ url: /pages/login/login }); reject(res.data); } else { wx.showToast({ title: res.data.msg || 请求失败, icon: none }); reject(res.data); } }, fail(err) { wx.showToast({ title: 网络异常, icon: none }); reject(err); } }); }); };登录态维护我认为是前端最容易出 bug 的地方。小程序不像浏览器有完整的 cookie 机制token 要手动存到wx.setStorageSync而且wx.login()的 code 是一次性的后端返回的 token 有有效期。所以我建议做一个统一的登录判断用户进入小程序时先看本地有没有 token有就直接用没有就跳转登录页登录页拿到 token 后存本地并跳回原页面。不要在每个页面的onLoad里反复写登录判断逻辑抽成一个公共函数或全局拦截整洁很多。小程序里还有一个天然的坑就是wx.login()时机问题——如果你在app.js的onLaunch里就调wx.login()这时用户还没有授权手机号或头像后端只能拿到 code所以更稳妥的形式是用户触发某个需要登录的操作时再去换取 token而不是一进来就登录。4.3 答题卡、计时器与交卷判定三个高频翻车点逐个说答题卡弹层在模拟考试场景中几乎必做。它的本质是一个九宫格或者试卷网格每一格代表一道题的状态——待做、已答、当前题。实现思路是用一个全局的对象数组或者当前试卷的状态数组来驱动每个选项被点击时同步更新这个数组答题卡组件通过监听数组变化刷新样式。这里要注意小程序里setData的性能问题如果一组试卷有 100 道题不建议每次点击都把整个题目列表重新 setData而是只更新当前题目相关的那几个字段。计时器在模拟考试里是必备功能。小程序端可以用setInterval做倒计时每一分钟更新一次剩余时间显示。交卷判定有两条逻辑一是时间到了系统自动交卷二是用户主动点击交卷。自动交卷要做得机智一点倒计时归零时立刻禁用答题界面的所有交互并触发交卷接口同时清掉setInterval避免用户卡到最后一秒交卷导致重复提交主动交卷前弹一个自定义模态框确认还有 X 道未答确定交卷吗防止用户误触。我自己见过不少同学在交卷流程里没做防重复提交用户在微信小程序里快速点两次交卷按钮后端就生成了两条成绩记录演示的时候特别难看这个一定要防。5. 部署与交付资源包的正确打开方式5.1 后端打包部署从本地 IDE 到云服务器的完整路径开发阶段在本地跑 Spring BootIDEA 里点运行就能启动真正考验人的是部署上线。毕设答辩时导师不一定会现场连接你的服务器验证功能但部署说明是会被认真翻看的所以你必须自己走通这条路径。大致流程是准备一台云服务器装好 JDK版本要和项目里一致我用的是 JDK 8稳定且兼容性好、MySQL、Maven可选如果直接在服务器上拉代码构建的话。本地把项目打包成 jar通过文件传输工具传到服务器然后用nohup java -jar 项目名.jar启动或用systemd写成一个服务单元文件实现开机自启。后端还需要配置 MySQL 的远程访问权限并且在项目的application.yml里把数据库地址、账号、密码改成服务器的实际配置。这里有一个新手极其容易踩的坑配置文件里的数据库密码硬编码。不要觉得无所谓答辩时导师可能会问如果你的源码传到公开平台数据库密码不就泄露了这种问题。接受度较高的做法是把敏感配置放到application-prod.yml里并且在部署说明文档中写明该文件不入库、不上传只放在服务器上。哪怕你只是做做样子也体现出了安全意识。另外后端服务启动后默认端口可能是 8080小程序端的合法域名配置要求 HTTPS所以还建议在服务器上部署 Nginx 做反向代理把/api/路径的请求转发到本机的 8080 端口这样前端请求地址就变成了https://你的域名/api/...。# 后端 jar 启动示例部署说明核心命令 nohup java -jar gongkao-server.jar --spring.profiles.activeprod gongkao.log 21 5.2 微信小程序端发布合法域名与体验版本的细节小程序端部署流程分两步。第一步是在微信公众平台注册小程序账号获取 AppID开发者工具里用这个 AppID 创建项目本地预览正常后点击上传按钮把代码传到微信后台生成体验版二维码。第二步是配置合法域名。在小程序后台的开发管理-服务器域名里把后端的域名填到 request 合法域名列表中。这个过程最容易卡住的是域名校验。微信要求域名必须是 HTTPS 且 ICP 备案完成所以如果你的服务器在国内域名备案是绕不开的一步。还没备案的时候怎么办有一个临时方案在微信开发者工具里勾选不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书这样本地开发调试没问题但手机上打开体验版就会全部请求失败。我见过太多同学栽在这上面调试时一片绿一分享给导师就是白屏。所以最稳妥的路径是开发期就用内网穿透或者调试工具做联调发布前一周搞定备案和 HTTPS给证书部署留出缓冲时间。演示视频录制也顺带提一下因为它是交付物里最容易被轻视的一环。录制前把小程序窗口调成手机模拟器的大小确保录出来没有侧边栏录制时按用户注册-刷题-模拟考试-查看错题-后台管理的顺序走一遍每个功能操作两秒后停一下再继续方便后期剪辑加字幕。不要用录屏软件直接录整个电脑屏幕画面太小、重点不突出导师看着累。5.3 拿到完整资源包之后按什么顺序消化才不会翻车如果你手上已经有了一套完整源码、文档和演示视频我建议的消化顺序是这样的第一步先跑通。按照部署说明把项目在本地运行起来数据库脚本导入小程序端导入开发者工具前后端联通亲眼看到数据从数据库流转到页面。第二步读文档。LW 文档和源码对照着看理解每一个章节对应项目的哪个模块而不是把文档当小说读。第三步做标记。找出你自己完全没搞懂的部分这些就是答辩时最可能被追问的地方。第四步动手改。哪怕只是把首页标语换掉、把题库增加一个分类都是你做了工作的证明。这个顺序的核心原则是一句话让项目从别人的变成你的。全包式资源看起来是捷径实际上直接提交反而风险最大——因为导师一眼就能看出你对项目的熟悉程度。真正聪明的做法是把它当作一个高质量参考实现在它的基础上做增量改动。比如把某个普通列表页改成搜索筛选模式把后端接口从简单查询改成缓存查询甚至只是把界面主题色换了这些都能成为你的个人工作内容。这也是为什么我一直强调交付物齐全不可怕怕的是你连代码里controller和service的区别都说不清就敢把名字写进毕业论文。6. 毕设过程中的高频翻车点与答辩自检清单6.1 开发阶段最容易卡住的三个位置翻车点一数据库连接不上。百分之八十的环境问题出在这一般是密码不对、MySQL 服务没启动、端口被占用这三个原因。我的排查顺序是先ping服务器/本机地址再telnet ip 3306看端口通不通最后在项目日志里看具体报错信息。翻车点二wx.login返回 code 后后端调微信接口时网络不通。到这一步基本可以排除代码逻辑问题直接检查服务器能不能访问微信接口的域名。部分云服务器厂商默认有安全组规则需要在控制台放行 443 端口。翻车点三分页查询的数据总是不对。这类问题九成出在 MyBatis-Plus 的Page对象参数写法上current传的是页码不是偏移量。我当时就在这个坑里蹲了一下午页面换到下一页数据却一直重复第一页的。认真看一眼官方文档的分页示例会比反复改 SQL 管用得多。6.2 答辩现场的演示策略与提问应对答辩演示环节我习惯给一条先主干后分支的演示路径。不要上来就展示登录而是先打开小程序简单说一句话这是一个基于微信小程序的公考刷题平台用户端负责刷题与学习管理管理端负责题库维护然后直接进入刷题流程。刷题流程走完展示成绩单和错题本这个时候导师自然会想看到管理端你再切到后台管理页面演示一道题目从修改到生效的完整过程。被提问时有一个通用法则回答要落到具体代码和数据流上。比如导师问你项目里的登录是怎么做的别回答用了 JWT要说前端调 wx.login 拿到 code后端请求微信接口换 openid查用户表后签发 JWT token前端存 storage后续请求带在 header 里。这个回答里包含了流程、技术点、实现位置一听就知道是你亲手写的。要是问到你觉得项目哪里还可以改进不要慌提前准备两个点缓存比如用缓存存放热点题目、减少重复查库和消息队列比如题库大批量导入时的异步处理这两个是经典且安全的扩展点。6.3 学术规范与自我负责最后说一个不太中听但必须想清楚的问题。毕设资源包再全也不能替你上台答辩、不能替你把项目讲明白、更不能代替你完成学习过程。我看过太多反面案例源码跑通了、文档装订好了结果答辩时导师问了一句这个模块的思路是什么整个教室安静了十几秒。所以我的建议非常直白参考源码和文档完全没有问题但一定要有一个消化-重构-验证的过程。你至少要做到能用一句话说清系统架构能指出每个模块的入口代码在哪能现场改动一个小功能并重新运行。如果你能做到这些那么无论这份资源包是全包还是基础包都不重要了——因为此刻你已经真正掌握了这个项目而毕设的意义也恰恰在于此。拿我自己的实操经验来说做完这个公考宝典项目后最有满足感的其实不是最终答辩过了而是某一次自己动手加每日一练推荐算法时感受到代码逻辑在你脑中被彻底打通的过程。希望这篇文章能让你少走几个弯路也祝你顺利搞定这个项目。