kizumi_header_banner_img

Learn. Build. Share.

加载中

文章导读

基于脚手架微服务的视频点播系统-客户端业务逻辑处理部分(二)


avatar
xiu114514 2025年10月23日 88
基于脚手架微服务的视频点播系统-客户端业务逻辑处理部分(二)

@TOC 写这部分代码的时候碰到了两次bug,耗时很久就解决了一个,所以才鸽了一个月再来更新。这里先提前说一下本文结束时代码的bug。当然不是代码的问题经排查,是ffmpeg我最开时时版本使用的有问题。导致mpv通过url播放远端服务器上的m3u8文件时不能通过调整进度条正确设置播放位置。为什么这里不解决了呢,是因为这个问题仅出现在本地环回测试上,而博主在写服务端时搁服务端弄了个m3u8文件让我这个“有问题”的客户端去播放,发现可以正常播放了。所以如果读者发现本地测试无法正常播放,不用担心,等我们服务端也写好之后一联调就没有这问题了。ok,废话不多说,我们继续客户端代码的编写。 还需要说明的一点是,因为我目前的代码量已经比上篇文章多很多了,我不会再像之前那样给出每一步的具体实现代码,因为每个人的大致逻辑虽然相同,但细节实现上大有不同,给出我自己细节部分的实现反而会造成干扰。所以只给出关键部分和主要逻辑在文章中,如有更详细的代码需要可以参考我前文给的源码连接。

一.播放m3u8文件

__前⾯实现视频播放时,播放的视频是从本地加载的,正常情况下,当⽤⼾点击⾸⻚的视频封⾯或标题时,应该从服务器获取要播放的视频⽂件,然后交给mpv库进⾏播放。要想播放服务器上视频⽂件,实现⼀个从服务器获取视频⽂件的接口即可。但问题是,⼀个视频⽂件可能⽐较⼤,如果直接从服务器获取完成视频⽂件后再播放,则客⼾端等待的时间太⻓了,可以尝试将原视频进⾏分⽚进⾏传输播放。  m3u8是⼀种⽤于流媒体播放的索引⽂件格式,包含了多个媒体⽂件的路径或URL,本质上是基于⽂本的播放列表,⽤于指定视频或⾳频的分段⽂件以及播放顺序,使播放器能够按需加载和播放内容,是苹果公司为HLS(HTTP Live Streaming 流媒体⽹络传输协议)流媒体设计的标准格式,⼴泛⽤于在线视频和直播场景。  当⽤⼾将视频⽂件上传服务器后,服务器会将视频⽂件切割成多个⼩⽂件(通常是.ts后缀的分⽚),M3U8⽂件记录这些分⽚的URL和顺序,播放器拿到M3U8⽂件后,根据内部管理的视频URL,下载并拼接播放,⼤⼤提升了流畅性。注意:mpv库⽀持M3U8⽂件播放。  ffmpeg大家可以自己去网上搜索教程进行下载安装,如果不想安装可以用我在gitee中提交的样例视频。  因为mpv播放器支持直接通过url播放远端服务器上的m3u8文件。所以客户端我们只需要改变startplay方法即可。 我们这里规定下请求的url格式:

我们在本地服务端的视频文件摆放路径如下: 在这里插入图片描述 所以假服务端需要新增两个路由:

而我们之前播放视频时是通过playTime去检测是否播放完毕的,不够严谨,所以我们这里需要通过mpv去获取播放时间,同时根据当前播放的是那个分片与总分片个数进行对比来判断视频是否播放完毕:

上面代码中在mpvPlayer类中新增currentTime 成员变量。剩余部分与playTime相关的修改部分不再给出。

二.下载弹幕

视频在播放时,需要同步加载各播放时间的弹幕数据,并显示在视频界⾯上。弹幕数据存储在服务器上,在视频播放前获取到弹幕数据后,再播放视频。 获取弹幕的接口定义如下: 请求URL

请求参数:

字段名称字段类型字段说明
requestIdstring请求ID
sessionIdstring客户端会话ID
videoIdstring视频ID

返回响应:200 OK

响应参数

字段名称字段类型字段说明
requestIdstring请求ID
errorCodeinteger错误码;0-成功
errorMsgstring错误信息
resultobject返回结果
barrageListarray弹幕列表
barrageIdstring弹幕ID
userIdstring发送用户
barrageContentstring弹幕内容
barrageTimeinteger弹幕时间-相对秒数

接下来就是经典步骤了dataCenter定义异步方法与完成信号,服务端接收请求返回响应。

那么当客户端成功收到服务端传过来的json报文后,则需要进行解析并加载到当前播放器的弹幕列表中。同时我们需要在弹幕数据加载完毕之后再去播放视频,所以添加新函数去处理响应信号的同时还需要将原来的播放逻辑修改为一下形式:

ok,播放视频与弹幕加载部分到这里也就完成了。对了,这里我们需要改一下原来playerpage时的关闭逻辑,具体逻辑是关闭时直接释放播放器对象以及mpv对象,当用户重新播放视频时再去new一个playerpage与mpv播放器对象。这样子改能显著降低我们播放器的内存消耗(同时存在一堆播放器内存占用肯定大啊,之前设计时没考虑到这一点)。大家根据自己的代码按照上面的逻辑进行修改即可。

三.播放界面数据更新

因为播放界面的上层videoBox已经存储有视频的相关信息了,所以我们直接在播放器的类中新增一个VideoInfo类型的成员变量并让Videobox在初始构造时传入视频信息即可。

当然用户头像需要在videoBox界面获取到用户头像之后再进行获取。

四.更新播放数

播放次数的更新通常与实际播放⾏为相关,例如当⽤⼾点击播放按钮并开始播放视频时,播放次数就会增加;如果⽤⼾只是打开视频但没有点击播放按钮,则播放次数通常不会更新,这是因为播放次数通常指⽤⼾实际观看了内容,⽽不是打开了⽂件。因此在PlayerPage的播放按钮槽函数中,可以增加⽂件的播放次数。 请求Url:

请求参数

字段名称字段类型字段说明
requestIdstring请求ID
sessionIdstring客户端会话ID
videoIdstring视频ID

返回响应:200 OK

响应参数

字段名称字段类型字段说明
requestIdstring请求ID
errorCodeinteger错误码;0-成功
errorMsgstring错误信息

那我们播放次数的增加就按照用户开始播放当前视频几次来计算吧,也就是说用户每触发一次startplayer我们给当前视频增加一次播放量(当然也可以视频结束时去增加播放量,无非就是把发送播放量改变的请求放到mpvplayer里面而已)。

假服务端逻辑如下:

因为我们这里是假服务器,就不再进行详细的播放数更新操作了,到服务端部分再。

五.检测视频是否点赞过

打开播放页面后,点赞按钮上图⽚应该根据用户是否对该视频点赞过合理显⽰,因此需要知道⽤⼾是否对该视频点赞过。 请求url:

请求参数

字段名称字段类型字段说明
requestIdstring请求ID
sessionIdstring客户端会话ID
videoIdstring视频ID

返回响应:200 OK 响应参数

字段名称字段类型字段说明
requestIdstring请求ID
errorCodeinteger错误码;0-成功
errorMsgstring错误信息
resultobject结果信息
isLikeboolean是否点赞结果

假服务端处理:

老逻辑走完之后,我们需要根据服务端传回来的响应数据去改变点赞情况显示:

六.更新点赞数

用户在观看视频时有可能会进行点赞操作表达对视频的喜爱。所以这里我们需要处理下,因为用户可能在观看视频是多次点击点赞按钮,所以我们最后播放窗口关闭时再去进行点赞情况的更新。 请求url:

请求参数

字段名称字段类型字段说明
requestIdstring请求ID
sessionIdstring客户端会话ID
videoIdstring视频ID

返回响应:200 OK

响应参数

字段名称字段类型字段说明
requestIdstring请求ID
errorCodeinteger错误码;0-成功
errorMsgstring错误信息

注意到我们上面判断用户是否对当前视频点赞过的添加的一个bool类型的成员变量likeCount了吗,最后如果该值不等于刚开始videobox传给我的videoinfo中的likecount时我们再更新:

假服务端的处理逻辑:

七.发送弹幕

⽤⼾在观看视频的过程中,如果⽤⼾有社交互动需求,或者视频内容引起⽤⼾的情感共鸣等,⽤⼾可能会发送弹幕,表达⾃⼰的情感或观点。发送弹幕前⽤⼾必须先登录,发送弹幕成功后,弹幕信息需同步到服务器。 请求url:

请求参数

字段名称字段类型字段说明
requestIdstring请求ID
sessionIdstring客户端会话ID
videoIdstring视频ID
barrageInfoobject弹幕信息
barrageContentstring弹幕内容
barrageTimeinteger弹幕时间-相对秒数

返回响应:200 OK

响应参数

字段名称字段类型字段说明
requestIdstring请求ID
errorCodeinteger错误码;0-成功
errorMsgstring错误信息

假服务端的处理逻辑:

八.我的界面部分-用户信息结构的设定

当⽤⼾点击主界⾯左侧栏我的⻚⾯切换按钮时,假设⽤⼾已经登录,此时该⻚⾯会加载当前登录⽤⼾的个⼈信息,并在界⾯上进⾏展⽰,包含⽤⼾头像、⽤⼾昵称、关注数、粉丝数、获赞数、播放数,以及⽤⼾之前上传的视频等信息,如下图所⽰: 在这里插入图片描述 注意:如果⽤⼾在播放⻚⾯观看视频时,想要查看视频上传者的信息,通过点击⽤⼾头像可以跳转到上传视频⽤⼾界⾯,此时就要获取视频上传者的个⼈信息,即获取其他⽤⼾信息。 在这里插入图片描述 为了⽅便对⽤⼾信息进⾏管理,定义如下描述⽤⼾信息结构:

让dataCenter持有⼀份⽤⼾信息的指针:

九.获取当前用户信息

请求url:

请求参数

字段名称字段类型字段说明
requestIdstring请求ID
sessionIdstring客户端会话ID
userIdstring用户ID

返回响应:200 OK

响应参数

字段名称字段类型字段说明
requestIdstring请求ID
errorCodeinteger错误码;0-成功
errorMsgstring错误信息
resultobject响应结果
userInfoobject用户信息
userIdstring用户ID
phoneNumstring绑定手机号
nicknamestring用户昵称
roleTypearray角色类型
identityTypearray身份类型
likeCountinteger点赞量
playCountinteger播放量
followedCountinteger关注量
followerCountinteger粉丝量
userStatusinteger用户状态
isFollowinginteger是否已关注
userMemostring用户备注信息
userCTimestring用户创建时间
avatarFileIdstring头像文件ID

如果是⽤⼾获取⾃⼰的个⼈信息, 则在 json 中不填写 userId 属性, 服务器通过会话 id 来获取当前⽤⼾信息. 获取其他⽤⼾信息时,需要传递该⽤⼾的userId。服务器可以通过userId是否为空确认获取⾃⼰的个⼈信息还是其他⽤⼾的个⼈信息。 客⼾端添加获取⾃⼰和他⼈个⼈信息请求接⼝:

假服务端的处理逻辑:

此时我们在客户端的界面处理相关逻辑即可:

十.上传与修改用户头像

⽤⼾登录之后,可以通过点击⽤⼾头像按钮来修改头像,修改图像需要: • 从磁盘获取新图⽚作为⽤⼾头像 • 上传⽤⼾图像到服务器 • 图⽚上传成功后,⽤返回的图⽚id修改服务器中⽤⼾信息中头像id • ⽤⼾头像修改成功后,⽤新头像id重新下载图⽚,并将图⽚设置到控件中 其中从磁盘获取⽤⼾图像的操作已经在uploadAvatarBtnClicked函数中完成完成 请求URL: POST /HttpService/uploadPhoto?requestId=xxx&sessionId=xxx 请求参数

Content-Type: application/octet-stream

字段名称字段类型字段说明
requestIdstring请求ID
sessionIdstring客户端会话ID
bodybinary文件数据

返回响应:200 OK

响应参数

字段名称字段类型字段说明
requestIdstring请求ID
errorCodeinteger错误码;0-成功
errorMsgstring错误信息
resultobject响应结果
fileIdstring文件ID

客⼾端新增上传图⽚请求:

假服务端处理逻辑:

客户端收到新头像文件的id时,再根据此id向服务端获取新的头像: 请求URL: POST /HttpService/setAvatar 请求参数

字段名称字段类型字段说明
requestIdstring请求ID
sessionIdstring客户端会话ID
fileIdstring文件ID

返回响应:200 OK

响应参数

字段名称字段类型字段说明
requestIdstring请求ID
errorCodeinteger错误码;0-成功
errorMsgstring错误信息

假服务端处理逻辑:

十一.获取用户视频列表

其实逻辑与之前获取首页视频列表差不多,不过因为考虑到管理界面的原因,我们需要新增几个字段:

前面的代码不需要修改,因为首页视频列表也不需要新增的这几个字段。 那么接下来我们的思路就是,在datacenter中新增一个用户视频列表。跟获取用户信息部分一样,传入的userId为空则标识获取当前登录用户的视频列表,不为空则是获取其他用户视频列表。 请求url:POST /HttpService/userVideoList 请求参数

字段名称字段类型字段说明
requestIdstring请求ID
sessionIdstring客户端会话ID
userIdstring用户ID
pageIndexinteger页码
pageCountinteger每页条目数量

返回响应:200 OK 按时间排序

响应参数

字段名称字段类型字段说明
requestIdstring请求ID
errorCodeinteger错误码;0-成功
errorMsgstring错误信息
resultobject响应结果
totalCountinteger总数量
videoListarray视频列表
videoIdstring视频ID
userIdstring所属用户ID
userAvatarIdstring用户头像ID
nicknamestring所属用户名称
checkerIdstring审核者用户ID
checkerAvatarstring审核者用户头像ID
checkerNamestring审核者用户名称
videoFileIdstring视频文件ID
photoFileIdstring封面文件ID
likeCountinteger点赞数量
playCountinteger播放数量
videoSizeinteger视频大小
videoDescstring视频简介
videoTitlestring视频标题
videoDurationinteger视频时长
videoUpTimestring视频上架时间
videoStatusinteger视频状态

假服务端的处理逻辑:

客户端对收到的用户视频列表进行展示:

十二.删除视频

我的⻚⾯中,当前登录⽤⼾可以通过点击视频框中的 … 按钮,删除之前上传的视频。 注意,… 按钮只有在我的⻚⾯中使⽤的VideoBox中才显⽰,⾸⻚和其他⽤⼾⻚⾯中的VideoBox中…都是隐藏的,即⾸⻚和其他⻚⾯中的视频是不能删除的。 在VideoBox中,设置删除按钮的隐藏和显式⽅式,并给该按钮绑定槽函数,当按钮点击时发射信号通过我的⻚⾯,删除列表中的视频。

接下来便需要告诉服务端我要删除视频,需要注意的时删除视频时,传⼊的是视频ID,⽽不是视频⽂件ID,因为需要删除数据库的视频元信息。 请求url:POST /HttpService/removeVideo 请求参数

字段名称字段类型字段说明
requestIdstring请求ID
sessionIdstring客户端会话ID
videoIdstring视频ID

返回响应:200 OK

响应参数

字段名称字段类型字段说明
requestIdstring请求ID
errorCodeinteger错误码;0-成功
errorMsgstring错误信息

假服务端的处理逻辑:

十三.获取其他用户信息

目前我们只有一个地方就是播放器界面的头像按钮,需要点击之后跳转到其他用户信息界面:

接下来不需要新的请求,直接使用我们前面写好的请求即可获取其他用户信息:

十四.关注与取消关注

当发布视频⽤⼾的关注状态为被关注或者被取消关注时,关注按钮上⽂本和样式是不⼀样的,将来需要根据按钮的点击设置关注或取消关注,为简单起⻅,下⾯对关注按钮简单进⾏封装。

将关注按钮类型提升为AttentionButton,就能看到按钮的效果。 在其他⽤⼾界⾯显⽰时,关注按钮上的⽂本刚开始并不⼀定是"关注",此处需要根据当前⽤⼾对视频上传⽤的实际关注情况来进⾏设置。

完成之后,给关注按钮绑定槽函数,根据⽤⼾的点击发送关注或取消关注请求。 新增关注请求url:POST /HttpService/newAttention 请求参数

字段名称字段类型字段说明
requestIdstring请求ID
sessionIdstring客户端会话ID
userIdstring用户ID

返回响应:200 OK

响应参数

字段名称字段类型字段说明
requestIdstring请求ID
errorCodeinteger错误码;0-成功
errorMsgstring错误信息

取消关注请求url:POST /HttpService/delAttention 请求参数

字段名称字段类型字段说明
requestIdstring请求ID
sessionIdstring客户端会话ID
userIdstring用户ID

返回响应:200 OK

响应参数

字段名称字段类型字段说明
requestIdstring请求ID
errorCodeinteger错误码;0-成功
errorMsgstring错误信息

假服务端的处理逻辑:

 



评论(已关闭)

评论已关闭

日历

2025 年 10 月
 123456
78910111213
14151617181920
21222324252627
282930