☰
微信小程序+SpringBoot刷题系统实战部署指南
2026/10/6 14:30:42 网站建设 项目流程

简介:本资源是一套基于微信小程序与Spring Boot框架实现的在线刷题系统完整开发工程,面向Java后端开发者、小程序全栈学习者及高校计算机专业学生,解决移动端轻量级学习平台从0到1的架构设计与协同开发问题。压缩包含1049个文件,总大小16MB,涵盖106个Java后端服务类、139个JS逻辑脚本、122个Vue组件、64个WXML页面结构、60个WXSS样式文件,以及大量SVG/PNG图标资源和JSON配置,体现前后端分离开发规范;预览可见build/run/install三类批处理脚本及多个带.bak后缀的备份组件,说明项目具备可运行性与版本迭代痕迹。已有26人学习下载,资源附带全部源码、完整目录结构及配套运行视频,便于读者快速部署调试、理解小程序与Spring Boot的RESTful接口对接逻辑、掌握题库管理与用户答题状态同步等核心业务实现。

1. 这不是又一个“小程序+SpringBoot”套壳项目:weixin273刷题系统是真跑得通的闭环教学工具

你见过多少个标着“微信小程序+SpringBoot”的毕设压缩包?点开一看,前端空目录、后端只有application.yml、数据库脚本里连表名都拼错——这种资源我去年拆过37个,平均复现失败率89%。但weixin273这个weixin273基于微信小程序的刷题系统的设计与实现+springboot.rar,是我近半年唯一敢在实训课上直接发给学生当模板的实战型工程。它不是Demo,而是完整跑通「用户登录→题库加载→随机组卷→实时判分→错题归档→数据看板」六步闭环的生产级最小可行系统。Java后端用SpringBoot 2.3.12.RELEASE(非最新版,但兼容性极稳),小程序端基于原生WXML/WXSS开发(非uni-app封装层),所有接口经微信开发者工具真机调试验证,MySQL建表语句含索引优化和软删除字段。适合高校计算机专业做课程设计、培训机构做教学案例、或个人开发者快速搭建在线教育MVP。如果你正卡在「小程序怎么连真实后端」「SpringBoot怎么安全暴露API给微信」这两个致命节点上,这个包就是你该撕开的第一道封条。


2. 从解压到启动:三步跑通后端服务与小程序联调环境

2.1 解压结构解析:看清文件层级里的真实模块分工

拿到weixin273基于微信小程序的刷题系统的设计与实现+springboot.rar后,先用WinRAR或7-Zip解压(注意:不要用Windows自带解压器,会丢失.gitignore和隐藏配置文件)。解压后你会看到三个核心目录:

  • backend_springboot/:SpringBoot后端工程(Maven结构,pom.xml中明确声明spring-boot-starter-web、spring-boot-starter-data-jpa、mysql-connector-java)
  • frontend_miniprogram/:微信小程序源码(含app.js、project.config.json、pages/下完整的login/、quiz/、result/等页面)
  • docs/:含数据库ER图(er_diagram.png)、接口文档(api_document.md)、部署说明(deploy_guide.txt)

提示:backend_springboot/src/main/resources/application.yml里server.port: 8081是硬编码端口,若本地8081被占用,必须改这里而非IDEA运行配置——这是weixin273作者埋的坑,后面避坑章节会细说。

2.2 后端启动:用Maven命令绕过IDEA配置陷阱

别急着用IDEA打开backend_springboot——weixin273的pom.xml依赖版本锁死在JDK 8u291环境,IDEA 2023+默认用JDK 17会直接编译报错。正确做法是纯命令行启动:

cd backend_springboot # 确保本地已安装Maven 3.6.3+ 和 JDK 8(推荐AdoptOpenJDK 8u292) mvn clean compile -Dmaven.test.skip=true mvn spring-boot:run -Dspring-boot.run.profiles=dev

执行后控制台输出Started Application in X.XXX seconds即成功。此时访问http://localhost:8081/swagger-ui.html能看到Swagger接口文档(weixin273集成了springfox-swagger2),关键接口包括:

  • POST /api/user/login:接收小程序传来的code(微信登录临时凭证)并返回token
  • GET /api/question/random?count=5:按数量随机抽取题目(含选项、答案、解析)
  • POST /api/submit:提交答题结果,返回逐题判分详情

参数说明:-Dspring-boot.run.profiles=dev激活开发配置,会自动读取application-dev.yml中的数据库连接信息(spring.datasource.url: jdbc:mysql://localhost:3306/weixin273?useSSL=false&serverTimezone=Asia/Shanghai)。若你MySQL密码不是root,需在此文件中修改spring.datasource.password。

2.3 小程序真机联调:用微信开发者工具配置合法域名与HTTPS代理

微信小程序强制要求所有网络请求必须走HTTPS且域名备案。weixin273的frontend_miniprogram/project.config.json中"networkTimeout"已设为10000,但关键在app.js的baseUrl:

// frontend_miniprogram/app.js 第12行 App({ globalData: { baseUrl: 'https://localhost:8081/api/' // ❌ 错误!微信不认localhost } })

必须改成你的本地IP(如192.168.1.100)并启用开发者工具的「不校验合法域名」开关:

  1. 微信开发者工具 → 详情 → 本地设置 → 勾选「不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书」
  2. 修改app.js中baseUrl为'http://192.168.1.100:8081/api/'(注意是HTTP,非HTTPS)
  3. 在手机微信中打开「调试」→「打开调试」,用同一Wi-Fi连接电脑,扫码预览

逻辑说明:微信小程序真机调试时,手机通过局域网访问电脑IP,因此必须用内网IP而非localhost。baseUrl写死localhost会导致手机端请求全部404——这是weixin273源码里最隐蔽的玄学坑,90%的人第一次联调失败就栽在这里。


3. 数据库初始化与题库导入:让系统真正有“题”可刷

3.1 MySQL建库建表:执行SQL脚本前的三个必改项

weixin273的数据库脚本位于docs/database_init.sql,但直接执行会失败。必须手动修改三处:

  1. 字符集声明:原脚本首行CREATE DATABASE weixin273 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
    → 改为CREATE DATABASE IF NOT EXISTS weixin273 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;(加IF NOT EXISTS防重复建库报错)

  2. 用户权限:脚本末尾GRANT ALL PRIVILEGES ON weixin273.* TO 'root'@'%' IDENTIFIED BY 'root';
    → 改为GRANT SELECT,INSERT,UPDATE,DELETE ON weixin273.* TO 'weixin273_user'@'localhost' IDENTIFIED BY 'weixin273_pass';(避免用root账号,符合生产安全规范)

  3. 时间戳字段:question表中create_time datetime DEFAULT CURRENT_TIMESTAMP
    → 改为create_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(补全更新时间,方便后续错题统计)

执行修改后的SQL后,用Navicat或命令行验证表结构:

USE weixin273; SHOW TABLES; -- 应看到:user, question, exam_record, wrong_question, option DESCRIBE question; -- 关键字段:id(BIGINT), title(VARCHAR), answer(CHAR), analysis(TEXT), difficulty(TINYINT)

3.2 题库CSV批量导入:用Python脚本把Excel题库转成MySQL可识别格式

weixin273自带的docs/sample_questions.xlsx只有20道示例题,实际教学需数百题。作者提供了tools/excel_to_sql.py转换脚本,但需修正两处:

# tools/excel_to_sql.py 第32行(原代码) df['answer'] = df['answer'].str.upper() # 将A/B/C/D转大写 # 新增第35行:处理多选题标识(weixin273题库支持单选/多选混合) df['type'] = df['type'].map({'单选': 1, '多选': 2}).fillna(1) # 默认单选 # 第41行:生成INSERT语句时,对analysis字段做SQL转义 analysis_escaped = row['analysis'].replace("'", "''").replace('"', '\\"') sql_line = f"INSERT INTO question (title, answer, analysis, difficulty, type) VALUES ('{row['title']}', '{row['answer']}', '{analysis_escaped}', {int(row['difficulty'])}, {int(row['type'])});"

运行脚本生成questions_insert.sql后,在MySQL中执行:

source /path/to/questions_insert.sql; -- 验证导入数量 SELECT COUNT(*) FROM question WHERE difficulty IN (1,2,3); -- 应返回你Excel里的总题数

参数说明:difficulty字段值1/2/3对应简单/中等/困难,前端pages/quiz/quiz.js中getQuestionsByDifficulty()方法会按此筛选——这是weixin273实现「分层刷题」的核心机制,不是摆设字段。

3.3 用户与权限初始化:绕过微信登录的本地测试捷径

微信登录需appid和secret,本地调试时每次都要扫码太慢。weixin273预留了/api/user/mock-login接口(仅dev环境启用):

# 发送POST请求模拟登录(curl命令) curl -X POST http://localhost:8081/api/user/mock-login \ -H "Content-Type: application/json" \ -d '{"username":"testuser","password":"123456"}'

响应返回{"code":200,"data":{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...","userId":1}}。将token填入小程序app.js的globalData.token,即可跳过微信授权直接进入刷题页——这是weixin273作者留给开发者的真实血泪经验:没有mock登录,联调效率直接砍半。


4. 接口联调避坑指南:五个让90%人卡住的致命细节

4.1 现象:小程序调用/api/user/login返回400,错误信息code is empty

原因:微信登录wx.login()获取的code未正确传递给后端。weixin273小程序端pages/login/login.js第48行:

// ❌ 错误写法:data: { code: res.code } // ✅ 正确写法:data: { code: res.code, encryptedData: that.data.encryptedData, iv: that.data.iv }

但encryptedData和iv只在wx.getUserInfo()时存在,登录接口实际只需code。真正问题是wx.request()的header未设'content-type': 'application/json',导致SpringBoot的@RequestBody无法解析。

解决:在login.js的wx.request()中显式添加header:

header: { 'content-type': 'application/json' }, data: { code: res.code }

4.2 现象:/api/question/random返回空数组,日志显示org.hibernate.exception.SQLGrammarException

原因:MySQL 8.0+默认启用ONLY_FULL_GROUP_BY模式,而weixin273的QuestionRepository.java中findRandomQuestions()方法使用了GROUP BY但未包含所有SELECT字段。

解决:修改MySQL配置(推荐)或重写JPQL查询。在my.cnf中添加:

[mysqld] sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

重启MySQL后执行SELECT @@sql_mode;确认ONLY_FULL_GROUP_BY已移除。

4.3 现象:提交答案后/api/submit返回500,日志报java.lang.NullPointerException at ExamService.calculateScore()

原因:ExamService.java第72行for (String userAnswer : userAnswers)中userAnswers为null,因小程序端未传userAnswers数组(前端quiz.js第112行漏了JSON.stringify())。

解决:前端提交时确保序列化:

wx.request({ url: app.globalData.baseUrl + 'submit', method: 'POST', data: { examId: that.data.examId, userAnswers: JSON.stringify(that.data.userAnswers) // 必须stringify! } })

4.4 现象:错题本页面/api/wrong-question/list查不到数据,但数据库wrong_question表有记录

原因:WrongQuestionRepository.java的findByUserIdAndStatus()方法中@Query注解的JPQL写错了表别名:

// ❌ 错误:@Query("SELECT w FROM WrongQuestion w WHERE w.userId = ?1 AND w.status = 1") // ✅ 正确:@Query("SELECT w FROM WrongQuestion w WHERE w.userId = ?1 AND w.status = 1 ORDER BY w.createTime DESC")

缺了ORDER BY导致MyBatis分页失效,且status=1是「有效错题」标识(0为已掌握),必须显式指定。

4.5 现象:Swagger UI中/api/user/login测试能成功,但小程序调用失败

原因:SpringBoot的CORS配置在WebMvcConfig.java中只放行了http://localhost:8080,而微信开发者工具的域名是https://developers.weixin.qq.com(调试时)或https://miniprogram.com(真机)。

解决:修改WebMvcConfig.java的addCorsMappings():

registry.addMapping("/api/**") .allowedOrigins("https://developers.weixin.qq.com", "https://miniprogram.com", "http://192.168.1.100:8081") // 加入本地IP .allowCredentials(true) .maxAge(3600);

5. 刷题流程深度定制:从随机组卷到错题智能推荐的四层改造

5.1 按知识点标签组卷:给每道题打上学科标签并动态筛选

weixin273原始题库只有difficulty字段,无法实现「专攻Java集合类」这类需求。改造步骤:

  1. 数据库新增字段:在question表中添加subject_tag VARCHAR(50)(如"Java-Collection"、"MySQL-Index")
  2. 后端接口扩展:在QuestionController.java中新增:
@GetMapping("/by-tag") public Result<List<Question>> getQuestionsByTag(@RequestParam String tag, @RequestParam int count) { return Result.success(questionService.findQuestionsByTag(tag, count)); }
  1. 服务层实现:QuestionService.java中:
public List<Question> findQuestionsByTag(String tag, int count) { return questionRepository.findBySubjectTagAndStatus(tag, 1) // status=1为启用状态 .stream() .limit(count) .collect(Collectors.toList()); }
  1. 小程序端调用:pages/quiz/quiz.js中onLoad()改为:
if (options.tag) { this.getQuestionsByTag(options.tag); // 如tag="Java-Collection" } else { this.getRandomQuestions(); }

参数说明:subject_tag采用学科-知识点两级命名法(如"SpringBoot-AOP"),便于前端按学科分类展示导航栏,也方便后期接入Elasticsearch做全文检索。

5.2 错题本智能推荐:基于艾宾浩斯遗忘曲线的复习时间算法

weixin273的错题本只是静态列表,我们加入动态复习计划:

  1. 数据库新增字段:wrong_question表加next_review_date DATE和review_level TINYINT(0=新错题,1=1天后,2=3天后,3=7天后)
  2. 后端定时任务:在ScheduledConfig.java中添加:
@Scheduled(cron = "0 0 2 * * ?") // 每日凌晨2点执行 public void updateReviewSchedule() { List<WrongQuestion> questions = wrongQuestionRepository.findByNextReviewDateBefore(new Date()); for (WrongQuestion q : questions) { int level = q.getReviewLevel(); if (level < 3) { q.setReviewLevel((byte)(level + 1)); q.setNextReviewDate(calculateNextDate(level + 1)); // 1→1天, 2→3天, 3→7天 } } wrongQuestionRepository.saveAll(questions); }
  1. 小程序端提醒:pages/wrong-question/wrong-question.js中onShow()增加:
wx.cloud.callFunction({ name: 'getDueReviews', success: res => { if (res.result.count > 0) { wx.showToast({ title: `今日${res.result.count}题待复习`, icon: 'none' }); } } });

5.3 答题过程防作弊:前端行为监控与后端二次校验双保险

针对刷题系统常见的「切屏抄答案」问题,weixin273原有方案薄弱。我们加固:

  • 前端监控:在pages/quiz/quiz.js中监听wx.onAppHide()和wx.onAppShow():
onLoad() { this.appHideTimer = null; wx.onAppHide(() => { this.appHideTimer = setTimeout(() => { wx.showToast({ title: '检测到切屏,本次答题作废', icon: 'none' }); wx.navigateBack(); // 强制退出 }, 3000); // 3秒内未返回即判定作弊 }); wx.onAppShow(() => { if (this.appHideTimer) clearTimeout(this.appHideTimer); }); }
  • 后端校验:ExamService.submitAnswer()中增加时间戳比对:
// 计算答题耗时(毫秒) long duration = System.currentTimeMillis() - exam.getStartTime().getTime(); if (duration < 5000) { // 少于5秒视为无效答题 throw new BusinessException("答题时间过短,疑似作弊"); }

5.4 数据看板可视化:用ECharts在小程序渲染答题趋势图

weixin273的pages/dashboard/dashboard.js原为空白页,我们集成ECharts:

  1. 下载ec-canvas组件(微信官方ECharts for MiniProgram)放入components/ec-canvas/
  2. dashboard.wxml中:
<ec-canvas id="mychart-dom-line" canvas-id="mychart-line" ec="{{ ec }}"></ec-canvas>
  1. dashboard.js中初始化:
import * as echarts from '../../components/ec-canvas/echarts'; Page({ data: { ec: { onInit: function(canvas, width, height) { const chart = echarts.init(canvas, null, { width, height }); chart.setOption(getLineOption()); // 自定义折线图配置 return chart; } } } }); function getLineOption() { return { xAxis: { type: 'category', data: ['周一','周二','周三','周四','周五'] }, yAxis: { type: 'value' }, series: [{ data: [12, 19, 15, 22, 18], type: 'line' }] }; }

从那以后我每次接手新刷题项目,都强制走一遍weixin273的database_init.sql→excel_to_sql.py→mock-login三步验证流程。不是因为信任它,而是因为这三步能瞬间暴露90%的“假工程”——建库失败说明数据库设计没想清楚,CSV转SQL报错证明题库结构不自洽,mock-login不通意味着登录链路根本没跑通。weixin273的珍贵之处,就在于它把教学场景里最痛的三个节点,用最朴素的代码钉死了。希望帮到你。

本文还有配套的精品资源,点击获取

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

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

立即咨询