ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于微信小程序与Spring Boot的在线学习系统开发实战指南

基于微信小程序与Spring Boot的在线学习系统开发实战指南 看到“基于微信小程序的在线学习系统springboot(文档源码)”这种命名大概率是正在做毕业设计、课程设计或者想快速接手一个前后端分离实战项目的朋友。这类项目的价值不在于那一堆能跑的代码而在于把一套在线学习产品从页面交互、后端接口到数据库设计完整串起来的能力。这篇我打算换个讲法不只带你跑通demo而是把我在实际开发、部署、演示过程中反复用到的东西都拆开说小程序端的列表加载更多、顶部导航栏适配、登录态怎么保持后端Spring Boot的接口分层和JWT认证以及拿到源码后从建库到真机预览的完整路线。适合正在忙毕设的学生也适合想用小程序加Spring Boot快速搭学习类产品的开发者做参考。1. 先看懂这个项目一套在线学习系统的功能地图1.1 项目命名里的信息量“weixin222基于微信小程序的在线学习系统springboot(文档源码)_kaic”这个文件名看起来像随机拼凑实际上信息量不小weixin222指向微信小程序端“222”一般是发布者或仓库内部的项目编号和功能无关。在线学习系统核心业务领域说明系统围绕课程展示、学习行为、进度记录这类场景展开。springboot后端技术栈对应的是Java生态。文档源码交付物形式意味着不只是代码还配套了数据库脚本、说明文档、部署步骤之类的内容我经手的同类项目里文档一般还会包含需求说明和接口清单。这个命名方式在毕设项目和源码交易平台里很常见。对我这种常年看各种项目的人来说翻译成人话就是这是一个前后端分离系统小程序负责展示和交互Spring Boot负责业务逻辑与数据存取两者通过HTTP接口通信。只要你把这条主链路想清楚后面看代码会快很多。1.2 核心角色与业务链路在线学习系统和电商系统不一样它没有太复杂的订单和库存核心逻辑可以压缩成一条链学生登录浏览课程列表点进课程详情看章节内容视频、文档系统记录学习进度学生可以收藏、评论、选课后台由老师或管理员维护课程内容。从角色维度看这类系统一般都拆成三类学生浏览课程、选课、学习、提交进度、收藏、评论。教师或内容提供者后台上传课程、管理章节偶尔回复评论很多毕设项目里教师角色会合并到管理员里。管理员用户管理、课程上下架、数据统计。拿到项目源码后我习惯先看三张东西SQL脚本里的表结构、后端Controller的接口列表、小程序端的页面目录。只要把这三样对应起来整个系统的功能边界就清楚了。很多同学一上来就埋头看某个类的源码反而会陷入细节出不来。1.3 动手前必须想清楚的三个问题在写任何代码之前我会先回答三个问题这三个问题也决定了后面所有表结构和接口的设计第一课程资源是什么形态。视频是放在本地服务器还是用腾讯云、阿里云的视频服务还是直接引用第三方视频链接这决定了资源表怎么设计小程序播放器怎么接入。常见做法是视频转成MP4格式放服务器或对象存储课程表里存视频URL。第二游客能不能看内容。如果允许游客看课程简介和目录但不允许看视频那课程列表和课程详情的接口就要区分是否需要登录如果所有内容都要登录才能看那接口统一加上鉴权即可。学习类系统通常选择后者体验也更合理。第三部署环境在哪。本地用localhost调试和部署到云服务器后通过域名访问两者的配置差别很大主要影响小程序的合法域名和HTTPS证书配置。很多项目卡在这一步不是代码问题而是环境问题。2. 技术选型微信小程序和Spring Boot为什么是绝配2.1 小程序端的优势与边界为什么大量在线教育、知识付费、在线学习项目都选择微信小程序而不是原生App或者H5核心原因有几点第一微信生态天然带了流量入口分享到群里点开就能用不需要下载安装用户心理门槛低。第二小程序开发语法接近前端上手快微信开发者工具做调试很顺手。第三微信官方审核体系成熟发布时走一遍审核就行。但小程序也有很明显的边界做在线学习系统时尤其要留意包体限制。微信小程序主包默认有大小限制资源一多很容易超限这是做视频课程类小程序最常见的坑。网络环境。小程序的请求域名必须是HTTPS而且要在小程序后台配置合法域名这在本地开发时可以关掉校验但一上线就绕不开。页面栈限制。小程序页面层级最多十层随便跳来跳去会顶到上限后面我会讲怎么处理。2.2 Spring Boot在后端扮演的角色Spring Boot能成为这类系统的默认选择我理解是三个原因叠在一起一是开箱即用内嵌Tomcat不用单独装容器一个java -jar命令就能跑起来对毕设和中小型项目非常友好。二是生态太丰富官方Starter和第三方库覆盖了数据库、缓存、安全、文件上传这些常见需求写代码量大大减少。三是分层结构清晰Controller负责接口Service写业务逻辑Mapper操作数据库和前端按接口对接时天然顺滑。从答辩和找工作的角度来说Java技术栈也是最容易讲清楚的面试官一问“系统怎么设计的”你可以从后端分层讲到数据库设计再讲到前端交互整个链路非常完整。2.3 配套组件选型表这类在线学习系统的常见组合我按主流做法列一下你可以根据项目实际情况调整组件推荐方案用途说明数据库MySQL 5.7或8.0存用户、课程、章节、学习记录等核心数据ORMMyBatis-Plus简化CRUD自带分页插件和逻辑删除鉴权方案JWT 拦截器前后端分离场景下保持登录态文件存储本地目录 / 对象存储存放课程视频、封面图、课件接口调试Apifox / Postman本地启动后端后快速验证接口接口文档Knife4j可选生成Swagger风格接口文档需要注意这些组件不是标题里直接写出来的而是在我处理过的多个同类项目里最常用的搭配。拿到具体项目后先看它的pom.xml和application.yml里面写了什么就用什么不要上来就换版本。3. 数据库设计用表结构还原整个学习业务3.1 用户表与openid的来龙去脉在线学习系统既然依托微信小程序用户表的设计有一个关键字段绕不开openid。openid是微信生态里每个用户在某个小程序下的唯一标识小程序端通过wx.login()拿到临时code后端拿着code调用微信接口换回openid。所以用户表的设计通常是id主键、openid、昵称、头像、角色、手机号可选、创建时间。这里有一个我反复强调的点前端不要直接把openid当用户主键用也不要随意传给后端接口。正确做法是后端拿到openid后映射成自己系统里的userId后续所有接口都围绕userId来做JWT令牌里放userId就行了。这样即使openid泄露也不会被伪造身份。角色字段我建议用int类型存比如0学生、1教师、2管理员不要用字符串。原因是后续做权限判断时整型比较比字符串高效也方便扩展。3.2 课程、章节与资源的三层结构在线学习系统的内容部分我习惯拆成三层课程表courseid、标题、封面图、课程简介、难度、分类id、价格0表示免费、状态上架/下架、教师id、创建时间。章节表chapterid、课程id、章节标题、排序字段、视频地址、视频时长。一个课程对应多个章节这是经典的父子关系。资源表resourceid、章节id、文件名、文件URL、资源类型视频/PPT/PDF。一个章节可以挂多个资源方便做课件下载和视频播放。为什么一定要把章节和资源分开因为课程学习进度通常要精确到章节如果只有课程没有章节用户学到第几分钟、看到第几节课都没有办法记录。把粒度拆到章节后面做学习进度、续播、完成状态都非常好处理。3.3 学习行为表进度、选课与评论用户的实际学习行为比内容表更复杂我主要讲三张行为表选课/收藏表user_courseid、用户id、课程id、类型0选课、1收藏、创建时间。这张表同时承载“我选的课”和“我收藏的课”用类型字段区分。为了避免重复选课或重复收藏建议在用户id和课程id上加唯一索引。学习进度表study_progressid、用户id、章节id、视频播放位置、总时长、更新时间。用户在视频播放中暂停或退出时把当前播放位置上报给后端下次打开时调接口拿到position从断点续播。这里唯一索引要建立在user_id加chapter_id上幂等更新防止产生重复记录。评论表commentid、用户id、课程id或章节id、评论内容、回复的目标评论id、创建时间。评论适合挂在课程粒度回复可以通过目标评论id形成评论树。还有一点容易被忽略如果系统要做打卡、考试或答题还需要对应的打卡表、试卷表和答题记录表粒度自己控制即可。核心原则是所有用户主动产生的数据都要记录是谁操作的、操作的对象是谁、操作时间是什么这三要素缺一不可。3.4 建表时容易踩的坑我在看别人的毕设项目时数据库这块问题最多说几个高频坑视频时长字段用varchar存字符串。不要这样存建议用int类型存秒数比如“12分30秒”存成750前端展示时再转成“12:30”计算进度和剩余时长都方便。价格字段用float。价格建议用decimal(10,2)浮点数做金额计算会丢失精度在线付费课程尤其要注意。所有表没有逻辑删除字段。用MyBatis-Plus时加一个deleted字段并配合TableLogic注解默认0正常1删除查询自动过滤。管理端“删除课程”时实际上做的是隐藏不会真删数据这对内容审核类系统很重要。时间字段类型不统一。建议全部用datetimeJava实体对应LocalDateTime前端拿到后统一做格式化避免时区转换问题。4. 小程序前端那些反复被搜索的实现细节4.1 课程列表分页与“加载更多”“微信小程序页面列表加载更多”这个搜索词我太有共鸣了做在线学习系统的人几乎都会遇到。课程列表页最合理的交互方式就是滚动到底部自动加载下一页核心实现逻辑其实不复杂页面数据里维护page、pageSize、hasMore、list四个字段。滚动到底部时触发onReachBottom方法判断hasMore为true且当前没有请求正在进行才发起请求。后端返回当前页数据和总条数前端把返回的新数据append到list里同时page加1。底部显示状态根据hasMore切换为“上拉加载更多”或“没有更多了”。这里有两个细节一定要处理好。一是防重复请求在请求过程中用一个loading标志位防止手指连续滑动时发出多次请求二是onReachBottom触发频率实际上比想象高如果不加标志位很容易出现数据重复或乱序。实测下来用标志位加page判断分页基本就稳了。另外如果课程有封面图列表页图片建议用lazy-load属性做懒加载课程数量一多图片加载对滚动性能的影响非常明显。4.2 自定义导航栏高度适配在线学习系统的课程详情页和播放页很多设计师喜欢用自定义导航栏实现沉浸式效果但自定义导航栏有一个老生常谈的问题不同机型的状态栏高度和胶囊按钮位置不一样写死44px在全面屏手机上一定翻车。我的标准做法是在页面的onLoad里调用wx.getSystemInfoSync()拿到statusBarHeight再调用wx.getMenuButtonBoundingClientRect()拿到胶囊按钮的top和height。导航栏高度用这个公式计算(capsule.top - statusBarHeight) * 2 capsule.height。这个公式不是我发明的是微信生态里验证过很多次的通用方案。算出导航栏高度后整个页面的顶部占位区域也就确定了下边内容可以放心往下排。要注意的是不同基础库版本对getSystemInfoSync的支持略有差异建议做一个公共的工具函数全局统一调用。4.3 登录流程与请求封装在线学习系统几乎都要登录尤其是要记录学习进度、收藏、选课这些功能。我推荐的登录流程是进入小程序后先检查本地storage里有没有token没有就调wx.login()拿code把code发到后端接口后端拿code换openid并注册或登录用户返回token和用户信息小程序把这个token存下来之后每次请求都在请求头带上token。这套流程看起来简单但有几个细节值得注意。第一wx.login()拿到的code有效期很短必须在后端及时换取登录态不要存到本地留着以后用。第二后端返回的token要设置过期时间小程序端要主动处理401状态出现401时清掉本地token并重新执行登录流程。第三请求封装建议用一个公共的request方法统一拼baseURL、统一处理错误码、统一展示错误提示避免每个页面各自处理。我在项目里通常会把baseURL单独放在一个config.js里切换环境时只改一处。这样做有一个直接的好处本地调试用http://localhost:8080上线前改成正式HTTPS域名只需要动一个文件。4.4 表单、单选与离开监听的细节学习类小程序里表单交互看起来不难实际坑不少。比如选课、支付方式、答题选项这些场景经常用到单选框微信原生的radio-group和radio样式比较朴素而且默认样式在不同机型上有差异。我的做法是数据量少的交互尽量用自定义样式点击整行触发选中选中的状态通过data里的字段控制时机合适时也可以用picker替代单选交互更接近微信原生习惯选择题答案也可以用这种方式。还有两个高频搜索词值得一起说。“微信小程序如何监听用户离开小程序”做视频课程时非常关键用户播放视频中切到后台或退出小程序必须在onHide生命周期里暂停视频并上报播放位置。如果只在onUnload里上报很多用户是直接左滑退出的根本不会触发卸载事件进度就会丢。“微信小程序顶部导航栏高度”前面已经讲了这里再提醒一句沉浸式页面如果要适配“灵动岛”和不同状态栏高度最好在页面可见性变化时重新计算一次不要只算一次就缓存固定值。5. Spring Boot后端从接口定义到代码落地5.1 分层架构与统一返回体后端代码如果没分层写到后面一定乱。我处理这类在线学习系统时用的是几乎成了行业标准的四层结构Controller接收请求参数Service处理业务逻辑Mapper操作数据库实体类对应表结构。以课程列表接口为例请求链路是前端传pageNum和pageSizeController接收后转给ServiceService调用MyBatis-Plus的分页插件查询数据库最终把列表数据和总数封装成统一返回体返回。统一返回体我用一个ResultT类来实现字段就三个code、message、data。成功时code为200业务异常时code为其他值前端根据code决定是正常渲染还是弹错误提示。这个设计在前后端分离项目里非常关键否则每个接口返回格式都不一样小程序端解析逻辑会写得想骂人。5.2 JWT登录态与拦截器设计在线学习系统后端最核心的鉴权环节我用的是JWT加拦截器的组合。登录成功后后端把用户id放进JWT的payload里设置过期时间用密钥签名后返回给小程序。小程序每次请求都在header里带token后端拦截器统一解析。拦截器的落地步骤大概是定义一个JwtInterceptor实现HandlerInterceptor在preHandle里从请求头取出token调用JWT工具类解析。解析失败或过期就直接返回401结果解析成功就把token里的userId放到ThreadLocal或请求属性里供后续Controller使用。还需要在WebMvcConfigurer里注册拦截器并配置哪些路径放行比如登录接口、公开课程列表接口哪些路径需要拦截。这里有一个细节学习进度上报接口必须带登录态但课程列表首页如果想允许游客浏览就可以放行。权限设计要看产品需求不是所有接口都要锁死。5.3 核心接口示例分页列表与学习进度上报课程分页接口的逻辑很标准核心代码如下GetMapping(/api/course/page) public ResultPageResultCourseVO page(RequestParam Integer pageNum, RequestParam Integer pageSize) { PageCourse page new Page(pageNum, pageSize); LambdaQueryWrapperCourse wrapper new LambdaQueryWrapper(); wrapper.eq(Course::getStatus, 1); // 只查上架课程 wrapper.orderByDesc(Course::getCreateTime); courseMapper.selectPage(page, wrapper); PageResultCourseVO result new PageResult(); result.setList(...); // 转为前端需要的VO result.setTotal(page.getTotal()); result.setPageNum(pageNum); result.setPageSize(pageSize); return Result.success(result); }学习进度上报的接口则要强调幂等PostMapping(/api/progress/report) public ResultProgressVO report(RequestBody ProgressReportDTO dto) { // 从ThreadLocal里取当前用户id Long userId UserContext.getUserId(); StudyProgress progress progressMapper.selectOne( new LambdaQueryWrapperStudyProgress() .eq(StudyProgress::getUserId, userId) .eq(StudyProgress::getChapterId, dto.getChapterId())); if (progress null) { // 不存在则插入 } else { // 存在则更新播放位置 } return Result.success(progressVO); }为什么一定要做幂等因为小程序端在视频暂停、切后台、退出页面等多个时机都可能触发上报后端如果不处理重复请求数据库里会攒下一堆脏数据。5.4 全局异常、参数校验与安全防护后端还有一个环节经常被忽略就是全局异常处理。用RestControllerAdvice加ExceptionHandler统一捕获异常把异常信息转成标准返回体前端就不会看到默认的错误堆栈页面。业务异常可以自定义一个BusinessException在Service层主动抛出给全局处理器。参数校验用javax.validation的注解就好比如NotNull、Min、Size。Controller的方法参数加上Valid注解后参数不合法会被框架拦截并抛异常统一异常处理器会返回格式一致的错误信息。安全这块MyBatis-Plus的#{}参数处理已经天然防住了大部分SQL注入管理端接口建议加上角色校验可以在拦截器里判断该用户的role是否允许访问也可以自定义权限注解。在线学习系统里老师和管理员能调用的接口远多于学生这个权限边界一定要在接口层控制住。6. 拿到“文档源码”后的快速启动路线6.1 交付包里通常装了哪些东西这类“文档源码”的项目交付物的构成大同小异我拆给你看database目录SQL脚本一般是用数据库管理工具导出的包含建库建表语句和初始数据。server或backend目录Spring Boot后端源码Maven工程结构。miniapp或weixin目录微信小程序前端源码。文档需求说明、数据库设计、部署手册、使用说明有些还会带答辩PPT。README简短的项目介绍和启动步骤。拿到项目后我强烈建议先看文档里的数据库说明和部署手册再打开SQL脚本确认表结构最后再让后端跑起来。不要一上来就双击导入IDE代码是跑不起来的必须先建库。6.2 环境版本怎么对齐Spring Boot项目的版本兼容问题是最常见的启动失败原因我这里列一个常用对照表给你参考Spring Boot版本JDK版本MyBatis-Plus建议版本说明2.3.xJDK83.3.x老项目常见稳定2.7.xJDK8 / JDK113.5.x市面上大量毕设项目使用3.0.x及以上JDK173.5.3.1及以上javax换成了jakarta包注意如果项目用的是Spring Boot 3.x代码里原来的javax.servlet都会变成jakarta.servlet自定义拦截器或过滤器可能会编译报错。遇到这种问题先检查pom.xml里声明的Spring Boot版本不要盲目升级依赖。MySQL版本也要和驱动对应Spring Boot 2.7.x配mysql-connector-java 8.0即可Spring Boot 3.x建议用新版驱动。这些看似小的问题实际排查起来会耗掉半天时间提前对齐是最好的办法。6.3 最小化启动流程新手最容易卡住的点是不知道先做什么。我按正常人能理解的最小路径写一遍第一步用Navicat或命令行执行SQL脚本把数据库建好。修改后端application.yml里的数据库用户名和密码确保能连上库。第二步用IDEA打开后端目录右下角等Maven把依赖下载完。不要急着点运行先执行mvn compile看能不能编译通过。编译报错就先解决版本问题。第三步启动后端主类看到Spring Boot的启动日志里出现Tomcat started后就说明后端起来了。用Apifox或Postman先测一个公开接口比如课程列表接口确认能返回JSON数据。第四步用微信开发者工具导入小程序目录在config.js或utils/request.js里把baseURL改成http://localhost:8080/api并在开发者工具右上角“详情”里勾选“不校验合法域名、web-view业务域名、TLS版本以及HTTPS证书”这是本地联调的标配操作。第五步编译小程序看首页数据能不能加载出来。如果数据正常整个链路就通了后续再去调登录、选课、进度上报这些功能。6.4 把小程序发给别人试用的正确姿势很多人急着给导师或朋友看demo但不知道小程序怎么分享。这里有两种方式第一种是体验版。登录微信公众平台把对方微信号加为项目成员体验者权限然后在微信开发者工具里点击“上传”把代码传到后台再到后台“版本管理”里把该版本设为体验版生成体验版二维码。扫描后对方就能用了。第二种是预览模式。开发者工具直接点“预览”会生成一个预览二维码但二维码有效期很短而且需要扫码的人是开发者或体验成员才能打开。临时演示够用长期试用还是体验版更稳。这里有一个常见卡点如果后端跑在你本地电脑扫码的人手机上是不可能访问到localhost的所以外部试用必须把后端部署到一台公网服务器上或者用其他联网方案把本地服务暴露出去。项目文档里如果写了云服务器部署步骤就按文档来。7. 实测踩坑记录这些问题真的会让你卡住7.1 Spring Boot版本太高导致的兼容性连锁反应“springboot版本太高”这个搜索词能上榜我是完全不意外的。很多同学从Maven仓库直接拉最新的Spring Boot版本比如3.2.x结果项目里其他依赖全是按2.x写的启动直接报一堆错。我遇到过的典型报错链是这样的Spring Boot 3.2.x要求JDK17但本机只装了JDK8项目启动就报UnsupportedClassVersionError把JDK升上去之后发现原来代码里import javax.servlet.http.HttpServletRequest编译不过去了因为3.x换成了jakarta包再去改MyBatis-Plus版本又发现分页插件配置类的位置变了方法签名也不同。解决思路不是一味升级而是先看项目文档里标注的版本。如果项目基于2.7.x就固定用2.7.x不要动。如果非要升级那就一次性把所有依赖都对齐到3.x相当于做一次全面的技术栈迁移工作量比想象中的大。7.2 微信小程序2MB包体限制与uniapp打包超限“uniapp 微信小程序打包 source size 2612kb exceed max limit 2mb”这个报错信息我闭着眼都能背出来。用uni-app开发的在线学习系统打包成微信小程序时超过2MB限制是常态因为uni-app自身运行时库就占了不少体积。处理办法按优先级排序第一把课程详情页、视频播放页这类不常访问的页面拆到分包里主包只留下首页、列表页、登录页这些核心页面。微信官方对分包总大小的限制比单包宽松很多正常拆包后压力会大幅下降。第二压缩图片资源课程封面图不要放本地尽量用线上URL。第三检查项目里有没有误引入的大型第三方组件库按需引入是基本原则。如果项目是原生小程序情况会好一些但课程视频、PPT资源同样不要放在包内必须服务器存储加URL访问。7.3 小程序HTTPS调试证书与抓包姿势小程序上线要求request的URL必须是HTTPS且域名备案不过开发阶段大家基本都是走本地HTTP。本地调试没问题后联调阶段会遇到一个痛点有些问题只在真机出现但你又看不到请求细节。这时候就需要抓包工具。Charles是开发调试里非常常用的工具可以用来查看小程序发出的HTTPS请求内容包括请求头、参数和响应结果。基本节奏是手机和电脑连同一个局域网手机设置HTTP代理指向电脑IP和Charles监听端口安装Charles根证书并开启SSL解密然后就能在电脑上看到小程序的所有请求了。这里我要特意提醒一句抓包只用于调试自己开发的小程序是一种常规开发手段。联调完成后记得把手机代理关掉否则手机会一直走代理导致网络异常。在实际操作中如果小程序开启了证书校验或者用的是较新的基础库版本抓包可能会遇到握手失败常见解法是更新Charles版本并重新安装根证书同时保证手机和电脑时间一致。7.4 细碎但致命的几个小问题除了上面三个大坑我再把开发过程中容易忽略的小问题列成一张表问题现象常见原因处理建议小程序请求返回10002或request fail合法域名未配置或本地关校验后仍报网络错误检查域名配置、HTTP还是HTTPS、证书是否有效发布体验版后打开白屏代码上传后域名校验生效在公众平台配置合法域名确认后端已部署到公网视频播放退出后声音仍在页面卸载时未销毁播放器在onHide和onUnload里调用播放器stop进度条不准确从0开始未断点续播用户离开时进度未上报上报播放位置进入时读取并seek到对应位置自定义导航栏在全面屏上错位导航栏高度写死44px用胶囊按钮位置加状态栏高度动态计算微信开发者工具能跑真机不行网络环境差异本地关校验导致上线前部署公网域名配HTTPS关闭本地校验这些问题的共同点是代码层面不难但是没有人提醒就很容易被卡住。我每做一个类似项目都会把这些问题记进文档里后面接手的人会省掉大量排查时间。最后再说一点体会做这种前后端分离的在线学习系统最有价值的不是把某个页面做得多炫而是把“登录到学习到记录进度”这条主链路完整跑通。你只要把用户、课程、章节、进度这四类核心表设计清楚了再围绕它们把接口补齐整个项目就立住了。后续如果想扩展无非是加支付、打卡、试卷、多端等模块核心骨架不会变。
返回列表