尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

一套后端API驱动四端——织码在线教育系统多端统一学习体验设计

一套后端API驱动四端——织码在线教育系统多端统一学习体验设计
📅 发布时间:2026/7/1 9:35:18

引言

“培训视频手机上能看吗?”“下班路上能用平板学吗?”“微信里能直接打开吗?”——这是企业培训管理者每天都在被问到的问题。对学员而言,期望在任何设备、任何时间都能无缝进入学习状态;对开发团队而言,同时维护 Web、App、小程序、H5 四套独立前端代码是沉重的负担,功能迭代要同步四次、Bug 要修四处、接口要对四遍。

织码在线教育系统通过一套后端 API 驱动四端的架构设计,实现了真正意义上的多端统一——Web 端、App 端、微信小程序、H5 页面,四端数据同源、进度同步、体验一致。后端只需维护一套 RESTful API,前端各端按场景选型、按需适配,既保证了学员的无缝体验,又将研发维护成本降低了 60% 以上。

本文将从架构设计和工程实践两个维度,深入拆解这套多端统一方案的技术细节,涵盖四端覆盖矩阵、多端数据兼容设计、学习进度跨端同步、多端会话管理、Web SSR 方案以及 App 多端编译策略。


一、四端覆盖矩阵与统一架构

1.1 四端技术选型

系统覆盖的四端及其技术方案如下:

端技术方案适用场景核心特性
Web 学习端Nuxt 3 + Vue 3 SSRPC/移动浏览器SSR 首屏直出、SEO 友好、秒级加载
App 移动端UniApp(H5/小程序/Android/iOS)主力移动学习入口原生体验、推送通知、断点续学
微信小程序UniApp 小程序编译即用即走场景无需安装、微信生态内传播
H5 页面UniApp H5 编译分享链接直接访问零安装门槛、浏览器直接打开

四端共享同一套后端 RESTful API,差异仅体现在前端渲染层和特定能力(如推送通知、本地缓存策略)。核心原则是:业务逻辑在后端收口,前端只负责展示和交互。

1.2 统一 API 网关设计

所有端的请求统一经过 API 网关,网关负责鉴权、限流、日志和请求路由,后端微服务对各端透明:

# Spring Cloud Gateway 路由配置(application.yml)spring:cloud:gateway:routes:-id:course-serviceuri:lb://course-servicepredicates:-Path=/api/course/**filters:-name:RequestRateLimiter# 限流:每端独立计数args:redis-rate-limiter.replenishRate:50redis-rate-limiter.burstCapacity:100-name:JwtAuthFilter# 统一 JWT 鉴权

网关层通过X-Client-Type请求头识别来源端(WEB/APP/MINIPROGRAM/H5),后端服务可据此做差异化处理(如小程序端返回精简字段),但绝大多数接口逻辑对各端完全一致。

二、多端数据兼容设计

2.1 标准化数据结构

不同端对数据的消费方式存在差异:Web 端和 App 端的视频播放器 SDK 不同,所需播放凭证格式不同;小程序端受限于包体积,图片需要按需加载缩略图;分页场景下,小程序下拉加载更多和 PC 端分页器的交互模式也不同。

解法:后端 API 返回标准化数据结构,各端按需取用字段,避免后端针对不同端出多套接口。视频播放凭证由各端客户端在播放时按需请求,不在列表接口中预取。

// 统一课程详情响应结构publicclassCourseDetailVO{privateLongcourseId;privateStringtitle;privateStringcoverUrl;// 封面图(各端自行按需缩放)privateStringdescription;privateList<ChapterVO>chapters;// 章节列表(各端按需展开)privateCourseStatVOstats;// 统计数据// 不在此处返回视频播放凭证,由播放时按需请求}

2.2 分页统一与端适配

分页是各端差异最大的交互之一。后端统一返回分页元数据,各端自行决定展示方式——PC 端渲染分页器,移动端渲染"加载更多"按钮,小程序用onReachBottom触发下拉加载:

// 统一分页响应结构publicclassPageResult<T>{privateList<T>list;// 当前页数据privateLongtotal;// 总记录数privateIntegerpageNum;// 当前页码privateIntegerpageSize;// 每页条数privateIntegertotalPages;// 总页数privateBooleanhasNext;// 是否有下一页(移动端下拉加载用)}// 课程列表接口(各端通用)@GetMapping("/api/course/list")publicResult<PageResult<CourseListVO>>listCourses(@RequestParam(defaultValue="1")IntegerpageNum,@RequestParam(defaultValue="10")IntegerpageSize,@RequestHeader(value="X-Client-Type",defaultValue="WEB")StringclientType){// 小程序端默认每页返回 20 条,减少请求频次if("MINIPROGRAM".equals(clientType)&&pageSize==10){pageSize=20;}PageResult<CourseListVO>result=courseService.listCourses(pageNum,pageSize);returnResult.success(result);}

通过hasNext字段,移动端无需计算总页数即可判断是否继续加载,简化了前端逻辑。


三、学习进度跨端同步

3.1 进度数据模型

学员在 Web 端看了 30% 的课程,切换到 App 端应该从 30% 处继续,而不是从头开始。这要求学习进度以服务端为主,客户端本地缓存为辅。

进度持久化的数据表设计:

-- 学习进度记录表CREATETABLE`edu_learn_progress`(`id`bigintNOTNULLAUTO_INCREMENTCOMMENT'主键ID',`user_id`bigintNOTNULLCOMMENT'学员ID',`course_id`bigintNOTNULLCOMMENT'课程ID',`chapter_id`bigintNOTNULLCOMMENT'章节ID',`watched_seconds`intNOTNULLDEFAULT0COMMENT'已观看秒数',`total_seconds`intNOTNULLDEFAULT0COMMENT'视频总秒数',`progress_percent`decimal(5,2)NOTNULLDEFAULT0.00COMMENT'进度百分比',`last_position`intNOTNULLDEFAULT0COMMENT'最后播放位置(秒)',`last_client_type`varchar(20)DEFAULTNULLCOMMENT'最后上报的端类型',`last_report_time`datetimeDEFAULTNULLCOMMENT'最后上报时间',`completed`tinyintNOTNULLDEFAULT0COMMENT'是否完成: 0未完成 1已完成',`create_time`datetimeNOTNULLDEFAULTCURRENT_TIMESTAMP,`update_time`datetimeNOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMP,PRIMARYKEY(`id`),UNIQUEKEY`uk_user_chapter`(`user_id`,`chapter_id`),KEY`idx_user_course`(`user_id`,`course_id`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4COMMENT='学习进度记录表';

关键设计:last_position字段精确记录到秒,last_client_type记录最后上报的端类型,便于排查跨端同步异常。唯一索引uk_user_chapter保证同一学员同一章节只有一条进度记录,避免多端并发写入产生脏数据。

3.2 进度上报与断点续学

客户端每隔固定间隔(如每 15 秒)上报一次观看进度,切换端时直接从服务端拉取最新进度继续播放:

// 视频学习进度上报(各端通用接口)@PostMapping("/api/course/progress/report")publicResult<Void>reportProgress(@RequestBodyProgressReportDTOdto){// dto 包含:courseId, chapterId, watchedSeconds, totalSeconds, clientTypeLonguserId=getCurrentUserId();// 防回退:只更新比当前更大的进度位置LearnProgressexisting=progressService.getProgress(userId,dto.getChapterId());if(existing!=null&&dto.getWatchedSeconds()<existing.getLastPosition()){// 客户端回退(如拖动进度条),不覆盖已有进度returnResult.success();}// 更新进度progressService.updateWatchProgress(userId,dto.getCourseId(),dto.getChapterId(),dto.getWatchedSeconds(),dto.getTotalSeconds(),dto.getClientType());returnResult.success();}// 获取学习进度(各端通用接口,返回服务端最新进度)@GetMapping("/api/course/{courseId}/progress")publicResult<CourseProgressVO>getProgress(@PathVariableLongcourseId){returnResult.success(progressService.getCourseProgress(getCurrentUserId(),courseId));}

CourseProgressVO返回课程下所有章节的进度汇总,客户端据此显示整体进度条和各章节完成状态:

// 课程进度汇总响应publicclassCourseProgressVO{privateLongcourseId;privateIntegertotalChapters;// 总章节数privateIntegercompletedChapters;// 已完成章节数privateBigDecimaloverallPercent;// 整体进度百分比privateList<ChapterProgressVO>chapters;// 各章节进度详情}publicclassChapterProgressVO{privateLongchapterId;privateIntegerlastPosition;// 上次播放位置(秒)privateBigDecimalpercent;// 本章进度百分比privateBooleancompleted;// 是否完成}


四、多端会话统一管理

4.1 JWT + Redis 多端会话

学员在四端使用同一账号,需要支持多端同时在线,同时要保证会话安全。方案采用JWT Token + Redis 会话存储,按userId + clientType维度管理会话:

@PostMapping("/api/auth/login")publicResult<LoginVO>login(@RequestBodyLoginDTOdto){// 1. 校验账号密码 / 手机验证码Useruser=authService.authenticate(dto);// 2. 签发 JWT Token(统一格式,四端通用)Stringtoken=jwtUtil.generateToken(user.getId(),user.getRole());// 3. 写入 Redis 会话(支持多端同时在线)StringsessionKey="session:"+user.getId()+":"+dto.getClientType();redisTemplate.opsForValue().set(sessionKey,token,7,TimeUnit.DAYS);returnResult.success(newLoginVO(token,user));}

clientType枚举值包括WEB、APP、MINIPROGRAM、H5,各端会话独立管理,互不干扰。学员可以同时在 PC 端学习视频、在手机上做题,不会因为一端登录而踢出另一端。

4.2 会话安全设计

Redis 中的会话存储结构如下:

# Redis Key 结构 session:{userId}:{clientType} → JWT Token(TTL 7天) # 示例 session:10001:WEB → "eyJhbGciOiJIUzI1NiJ9..."(PC 端会话) session:10001:APP → "eyJhbGciOiJIUzI1NiJ9..."(手机端会话) session:10001:MINIPROGRAM → "eyJhbGciOiJIUzI1NiJ9..."(小程序会话) session:10001:H5 → "eyJhbGciOiJIUzI1NiJ9..."(H5 会话)
// 统一鉴权过滤器:校验 Token 有效性@ComponentpublicclassJwtAuthFilterimplementsGlobalFilter{@OverridepublicMono<Void>filter(ServerWebExchangeexchange,GatewayFilterChainchain){Stringtoken=extractToken(exchange.getRequest());StringclientType=exchange.getRequest().getHeaders().getFirst("X-Client-Type");if(token==null){returnunauthorized(exchange,"未登录");}// 1. 校验 JWT 签名和过期时间Claimsclaims=jwtUtil.parseToken(token);if(claims==null){returnunauthorized(exchange,"Token无效或已过期");}// 2. 校验 Redis 会话是否存在(防止 Token 被撤销后仍可用)StringsessionKey="session:"+claims.getUserId()+":"+clientType;StringstoredToken=redisTemplate.opsForValue().get(sessionKey);if(!token.equals(storedToken)){returnunauthorized(exchange,"会话已失效,请重新登录");}// 3. 续期会话(活跃用户自动延长)redisTemplate.expire(sessionKey,7,TimeUnit.DAYS);returnchain.filter(exchange);}}

双层校验机制:JWT 签名校验保证 Token 未被篡改,Redis 会话校验保证 Token 未被主动撤销(如用户修改密码后全端登出)。通过遍历session:{userId}:*删除所有端的会话即可实现全端登出。


五、Web 学习端 SSR 方案

Web 学习端选择 Nuxt 3 做 SSR,出发点有两个:

SEO 需求:课程详情页、资讯文章等需要被搜索引擎收录,SSR 确保首屏 HTML 完整直出,爬虫无需执行 JS 即可获取全部内容。

首屏性能:服务端渲染减少客户端在 hydration 前的白屏时间,学员打开课程页面直接看到完整内容,而非先看到骨架屏再等待数据加载。

// Nuxt 3 课程详情页 SSR 数据获取// pages/course/[id].vue<script setup>constroute=useRoute()// useAsyncData 在服务端执行,数据随 HTML 一同下发const{data:course}=awaituseAsyncData(`course-${route.params.id}`,()=>$fetch(`/api/course/${route.params.id}`))// 设置 SEO meta(服务端渲染时生效,爬虫可读取)useSeoMeta({title:course.value?.title,description:course.value?.description,ogImage:course.value?.coverUrl})</script>

SSR 方案下,后端 API 的响应速度直接影响首屏渲染时间。系统对课程详情等高频接口做了Redis 缓存 + 降级策略:

// 课程详情接口(SSR 友好,支持缓存)@GetMapping("/api/course/{courseId}")publicResult<CourseDetailVO>getCourseDetail(@PathVariableLongcourseId){StringcacheKey="course:detail:"+courseId;// 1. 先查 Redis 缓存CourseDetailVOcached=(CourseDetailVO)redisTemplate.opsForValue().get(cacheKey);if(cached!=null){returnResult.success(cached);}// 2. 缓存未命中,查数据库并回填缓存CourseDetailVOdetail=courseService.getCourseDetail(courseId);redisTemplate.opsForValue().set(cacheKey,detail,30,TimeUnit.MINUTES);returnResult.success(detail);}

缓存 TTL 设为 30 分钟,课程上下架时通过事件主动清除缓存,保证数据一致性。


六、App 多端编译与差异化处理

6.1 UniApp 条件编译

App 移动端基于 UniApp 开发,一套 Vue 3 代码可编译为 H5、微信小程序、Android App、iOS App 四个目标。针对不同端的差异,通过条件编译处理:

<template> <view> <!-- 通用内容 --> <video-player :src="videoUrl" /> <!-- #ifdef MP-WEIXIN --> <!-- 微信小程序特有:分享按钮 --> <button open-type="share">分享给朋友</button> <!-- #endif --> <!-- #ifdef APP-PLUS --> <!-- 原生App特有:画中画浮窗学习 --> <pip-button @click="enablePip" /> <!-- #endif --> </view> </template>

6.2 多端视频播放器适配

视频播放是多端差异最大的场景。不同端使用不同的播放器 SDK,但播放凭证(PlayAuth)通过统一的后端接口获取,实现"同源凭证、各端播放":

// 统一播放凭证获取接口(各端通用)@GetMapping("/api/course/chapter/{chapterId}/playauth")publicResult<PlayAuthVO>getPlayAuth(@PathVariableLongchapterId,@RequestHeader("X-Client-Type")StringclientType){LonguserId=getCurrentUserId();// 1. 校验学习权限courseService.checkAccess(userId,chapterId);// 2. 获取阿里云 VOD 播放凭证StringplayAuth=vodService.getPlayAuth(chapterId);// 3. 记录播放日志(含端类型)learnLogService.logPlay(userId,chapterId,clientType);returnResult.success(newPlayAuthVO(playAuth,videoId));}

各端的播放器适配策略:

端播放器方案凭证使用特有能力
Web 端Aliplayer Web SDKPlayAuth倍速播放、清晰度切换
H5 端Aliplayer H5PlayAuth适配移动浏览器
小程序端<video>组件 + VOD 小程序插件PlayAuth微信内分享
原生 AppVOD iOS/Android SDKPlayAuth + STS画中画、后台播放、下载离线

6.3 进度同步实测效果

多端进度同步的实际表现:

场景:学员在 PC 端 Web 学习端观看《Python 入门》第 3 章,看到 00:28:45 操作:关闭 PC 端,打开手机 App 端进入同一课程 结果: - App 端显示:"上次看到 00:28:45,是否从此处继续?" - 学员点击"继续观看",从 28 分 45 秒精确续播 - 学习进度条显示同步后的状态 数据流: PC 端每 15s 上报进度 → 写入 MySQL edu_learn_progress 表 App 端打开课程 → 查询 edu_learn_progress 表获取 last_position → 精确定位播放位置 → 继续上报进度

七、多端覆盖带来的实际价值

用户角色典型场景多端带来的价值
出差中的销售人员高铁上用手机 App 看产品培训不受地点限制,碎片时间利用
倒班制一线员工休息时间微信小程序学习无需安装 App,即用即走
需要备考的员工通勤路上 H5 端刷题分享链接直接打开,零门槛
管理者手机端查看各部门培训进度随时掌握团队学习数据

对运营团队而言,一套内容录制一次、上架一次,自动覆盖全渠道,维护成本相比多套独立系统降低 60% 以上。


八、总结

织码在线教育系统的多端统一方案在技术实现上重点解决了以下问题:

  1. 后端 API 统一:一套 RESTful API + 标准化数据结构,四端按需取用字段,避免多套接口的维护灾难
  2. 会话管理统一:JWT + Redis 按userId + clientType维度管理,支持多端同时在线与全端登出
  3. 进度数据统一:服务端 MySQL 持久化为主,客户端定期上报,防回退机制保证进度不丢失,切端无缝衔接
  4. 前端按场景选型:Nuxt 3 SSR 服务 SEO 与首屏性能需求,UniApp 一套代码覆盖移动四端,各端用最合适的技术

"多端覆盖"在今天的企业培训场景下已经不是加分项,而是基本要求。学员的学习时间碎片化、设备多样化是既成现实,培训系统若只能在电脑上运行,就等于自动放弃了大量的学习时机。如果你对多端架构设计的某个技术点有疑问,欢迎评论区交流。

如需私有化部署报价、远程产品演示,可访问官网https://www.weavecodes.com/,私信作者领取企业落地案例。

相关新闻

  • 别再手动数氢键了!用Materials Studio脚本一键搞定周期性体系统计(附完整Perl代码)
  • 手把手教你用STC89C52单片机读取MPU6050数据,并在LCD1602上实时显示(附完整代码)
  • 别再死磕SPWM了!手把手教你用STM32实现SVPWM驱动PMSM电机(附代码)

最新新闻

  • 3步解锁高级功能:Cursor Pro激活工具的深度应用指南
  • Figma到Unity一键转换:5分钟实现设计到游戏界面的完美迁移
  • 从入门到进阶:Kiran Desktop用户账户管理与权限控制详解
  • openEuler/bigdata故障排除:常见问题诊断与解决方法大全
  • openEuler/bigdata监控与管理:Ambari与Ranger集成方案终极指南
  • iTrustee Client高级API使用:从TEEC_InitializeContext到TEEC_InvokeCommand的完整流程指南

日新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号