Easyliev在线视频分享平台项目总结——SpringBoot、Mybatis、Redis、ElasticSearch、FFmpeg

EasyLive项目总结

登陆注册

获取图片验证码

  • captchat插件

    • base编码(图片,用于前端展示)

    • checkCodeKey验证码标识(用于匹配redis缓存,校验验证码)

  • redis缓存

    • 保存验证码缓存用于登录注册校验(checkCodeKey为标识)

注册

  • 校验验证码

    • 根据前端传递的checkCodeKey,在Redis缓存中查找验证码并进行比较
  • 注册

    • 昵称是否被使用

    • 邮箱是否被使用

  • 清除Redis中的验证码缓存

登录

  • 校验验证码

  • 保存token到redis

    • 逻辑过期

      • 即存放在redis中的token对象包含一个过期时间字段

        • expireAt,表示该token将在哪个时间过期,存放其时间戳
      • 在自动登录时,进行比较,如果小于某个指定时间(如1天)访问,就重置token的过期时间

  • 保存token到cookie

    • 清除原先Redis中的token缓存(基于request)

      • request获取cookies数组,for循环遍历获取对应token信息(根据cookie的name标识判断)
    • 将token写入cookie中(基于response)

      • 设置过期时间(7天)

      • 设置有效路径(所有路径)

      • 往response中添加cookie

  • 清除Redis中的验证码缓存

自动登录

  • 判断token信息是否为空

    • 不为空

      • 判断过期时间(小于1天)

        • 更新Redis缓存

        • 更新cooklie过期时间

登出

  • 清理cookie

区别admin端与web端

  • Redis的key标识前缀不同

  • Cookie的name不同

视频投稿

客户端

  • 发布视频

    • 判断投稿视频合集数量是否超过系统限制

    • 对修改视频操作进行额外校验

      • 数据库是否存在

      • 视频状态是否处于不能修改的状态(转码中 / 待审核)

    • 创建新增视频文件集合(addFileList)和待删除视频文件集合(deleteFileList)

    • 判断 新增 or 修改

      • 新增

      • 修改

        • 获取当前视频投稿的视频文件集合

        • 采用stream流,将视频文件集合转化为Map集合

          • 用于判断新上传的集合中是否有文件被删除or是否有新增的视频文件
        • 判断是否修改视频的文件名

          • 遍历上传的视频文件集合

            • for循环遍历视频文件集合判断是否数据库存在

                • 表示视频文件已经被删除

                  • 将数据库的视频文件信息添加到待删除视频文件集合
                • 表示视频文件没有被删除

                  • 检查是否修改文件名称
        • 判断是否修改文件基础信息

        • 获取新增视频集合

          • 采用stream流,上传的视频文件集合中,没有id的就是新增的,直接过滤出来
        • 更新状态

          • 是否需要新增视频

              • 修改状态为转码中
              • 视频基础信息发送改变

                • 修改状态为待审核
    • 删除待删除文件

      • 删除视频文件发布表中的对应信息

      • 将待删除文件路径集合添加到Redis消息队列

    • 批量插入 / 更新 视频文件发布表信息

      • 注意:新增的视频文件需要设置状态为转码中
    • 将新增文件集合添加到消息队列

      • 后台开启异步线程执行转码视频操作

        • 将临时目录中的分片文件移动到真正的视频文件目录

          • 从Redis中获取临时视频文件发布目录(之前存的uploadFileDto)

          • 获取真正的视频文件目录(不存在就创建)

          • 复制文件

            • FileUtils.copyDirectory(tempFile, targetFile)
        • 删除临时文件夹的相关信息

          • 删除文件目录

          • 删除文件缓存

        • 合并分片文件为完整的视频文件(temp.mp4)

          • 合并分片为temp.mp4

          • 删除原始目录中的分片文件

        • ffmepg获取播放时长,封装文件发布对象

        • ffmpeg将视频文件转码为ts文件

          • 判断视频文件的编码格式

            • 使用ffmpeg将hevc格式的将其转化为mp4格式
          • ffmpeg转码视频文件

            • ts文件

            • m3u8文件

          • 删除temp.mp4文件

        • 更新视频文件发布状态

          • 成功

          • 失败

        • finally操作

          • 判断是否有转码失败的文件

              • 修改视频文件发布状态为转码失败
          • 判断是否有转码中的文件

              • 修改视频文件发布状态为待审核
  • 加载视频投稿列表

    • 判断查询的视频投稿状态(status)

      • 全部

      • 进行中

      • 审核成功

      • 审核失败

    • 设置需要查询视频的Count数据(点赞、收藏、投币等)

  • 获取视频投稿不同状态的数量信息

    • 状态分类

      • 已通过

      • 未通过

      • 进行中

    • 封装VO

  • 获取视频投稿详细信息

    • 判断数据库是否存在

    • 获取视频合集分P

      • 按照fileIndex字段从小到大排序
    • 封装VO

      • 用于修改视频投稿信息功能
  • 保存视频互动设置

    • 评论设置

    • 弹幕设置

  • 删除视频投稿信息

    • 判断合理性

      • 视频是否存在

      • 当前用户id是否为视频发布者id

      • 当前用户是否为管理员

    • 删除视频信息(数据库)

    • 删除ES信息

    • 扣减用户硬币

    • 开启异步线程处理其他内容(没删除变成数据库的脏数据,对于应用基础性能关系不大),防止事务超时

      • 删除视频文件合集

      • 删除视频弹幕

      • 删除视频评论

      • 删除服务器文件

管理端

  • 获取所有视频投稿

    • 设置需要查询count信息

    • 设置需要查询user信息

  • 审核视频

    • 合法性校验

      • 判断status(视频状态)是否合法

      • 视频是否存在

    • 更新视频审核状态

      • 构建查询条件

        • 视频id

        • status为待审核状态

      • 构建更新内容

        • 设置前端传递来的status
      • 更新

        • 更新成功

          • 审核失败

            • return
          • 审核成功

            • 将视频发布信息拷贝到视频表中

            • 将视频文件发布信息拷贝到视频文件表中

              • 先清理视频文件表中该videoId对应的文件信息

                • 因为是已经通过了重新修改提交审核,所以数据库可能存在对应文件信息
              • 查询视频文件发布表中对应该videoId的数据

              • 将数据批量插入视频文件表

            • 根据Redis缓存中保存的待删除文件路径,删除服务器上对应的文件

              • 待删除文件集合不为空

              • for循环遍历

                • 如果存在目录,则删除
              • 清理Redis中的待删除文件缓存

            • 保存视频信息到es中

        • 更新失败

          • 报错
  • 删除视频投稿信息

    • 判断合理性

      • 视频是否存在

      • 当前用户id是否为视频发布者id

      • 当前用户是否为管理员

    • 删除视频信息(数据库)

    • 删除ES信息

    • 扣减用户硬币

    • 开启异步线程处理其他内容(没删除变成数据库的脏数据,对于应用基础性能关系不大),防止事务超时

      • 删除视频文件合集

      • 删除视频弹幕

      • 删除视频评论

      • 删除服务器文件

  • 加载视频分P合集

    • 按照file_index倒序

视频管理

客户端

  • 获取推荐视频列表

  • 获取视频普通列表

  • 视频主页详情

    • 获取视频基础信息

      • 点赞

      • 收藏

      • 投币

    • 获取视频合集

    • 获取视频在线观看人数

      • 采用Redis存储在线播放信息

        • 某个用户在线观看某个视频

        • 某个视频在线观看总人数

      • 前端轮询访问当前视频的实时在线观看人数

        • 判断某个用户是否已经在观看该视频

            • 创建对应key(视频文件id + 用户观看设备id共同标识)

            • 对Redis缓存中的在线观看人数执行increase操作

            • 延长两个key对应数据的过期时间

            • 从Redis中获取实时在线观看人数

              • 是否为null

                • 是:返回1

                • 否:返回count

      • 如何监听用户退出视频观看页面?

        • 使用Redis监听器监听对应key过期

          (KeyExpirationEventMessageListener)

          • 实现onMessage方法,监听key过期(代表用户已经退出视频观看页面)

          • 获取key并判断是不是在线观看人数的key

              • 获取视频文件id,构建查询对应缓存的key

              • 对Redis中的在线观看人数执行decrease操作

            • 否:return

    • ElasticSearch相关

      • 搜索相关视频

        • 对搜索关键字执行increase操作(搜索热词)

        • es搜索

      • 获取相关推荐视频

  • 获取搜索热词

    • 从Redis中获取
  • 加载24小时热门视频

    • mysql层面进行约束,只查询近24小时内的热门视频

管理端

  • 推荐视频

    • 视频是否存在

    • 更新推荐状态

视频合集管理

操作合集

  • 加载所有视频合集

    • MySQL层面连表查询
  • 保存视频合集

    • 新增

      • 判断视频列表是否为空

        • 是:报错
      • 检查上传的视频是否是自己投稿发布的视频

        • 否:报错
      • 保存合集

      • 保存合集视频

        • 判断合集是否存在

        • 获取合集中最大的视频排序sort

        • 处理视频的videoIds为对象集合

          • 切割字符串

          • for循环创建对象(sort自增)

          • 添加到集合中

        • 批量插入数据库

    • 修改

  • 删除视频合集

    • 删除合集

    • 删除合集中的视频

  • 修改视频合集排列顺序

    • 分割seriesIds字符串获取id数组

    • 重新创建一个排序sort(从0开始)

    • for循环遍历id数组

      • 创建对象并设置sort排序字段
    • 入库

操作合集视频

  • 获取指定合集中的所有视频

    • 根据合集id查询该合集下的视频信息

    • 使用stream流将查询结果转化为这些视频的id集合

    • 在查询条件中带上这个id数组,查询的结果需要排除掉这些id对应的视频

    • 查询数据库(VideoInfo)

  • 保存视频到指定合集中

    • 判断合集是否存在

    • 获取合集中最大的视频排序sort

    • 处理视频的videoIds为对象集合

      • 切割字符串

      • for循环创建对象(sort自增)

      • 添加到集合中

    • 批量插入数据库

  • 删除指定合集中的视频

    • 是否存在该合集

    • 获取合集视频列表(按照sort排序)

    • 封装VO返回

      • 合集对象

      • 合集视频列表

    • 获取携带视频的合集(所有合集)

获取指定视频合集详细信息

(包括合集中的视频)

互动管理

评论

  • 发布评论

    • 视频是否存在

    • 评论区是否关闭

    • 评论分类

      • 一级评论

        • 父级id为0
      • 二级评论

        • 回复的评论合法性校验

          • 是否存在

          • 是否属于当前视频

        • 判断回复的是一级评论还是二级评论

          • 回复一级评论

            • 设置父级id

              • 为被回复的评论id
          • 回复二级评论

            • 设置父级id

              • 为被回复评论的父级id
            • 设置被回复的用户id

        • 给评论添加被回复用户的昵称和头像

    • 入库

      • 评论入库

      • 更新视频的评论数

  • 加载评论区

    • 合法性校验

      • 视频是否存在

      • 评论区是否关闭

    • 获取评论区数据(commentData)

      • 设置分页

      • 设置排序方式

        • 最新

        • 最热

      • 设置需要查询子集合(即二级评论,因为评论呈树形展示)

    • 置顶评论

      • 剔除commentData中的待置顶评论

      • 将待置顶评论添加到commentData头部

    • 查询用户对评论的点赞 / 讨厌 操作数据(user Action List)

    • 封装VO返回

      • commentData

      • userActionList

  • 取消置顶评论

    • 合法性校验

      • 评论是否存在

      • 视频是否存在

      • 判断当前用户是否有取消置顶的权限

        • 即当前视频是不是归属于当前用户
    • 修改置顶评论type

      • 采用mysql层面的乐观锁:修改top_type为置顶的数据
  • 置顶评论

    • 取消置顶

    • 置顶

  • 删除评论

    • 合法性校验

      • 评论是否存在

      • 视频是否存在

      • 当前用户是否具备删除权限

        • 评论发布者

        • up主

        • 管理员

    • 是否为一级评论

        • 更新评论数

        • 删除其下的二级评论

弹幕

  • 合法性校验

    • 视频是否存在

    • 弹幕是否关闭

  • 发布弹幕

  • 修改视频弹幕数量

  • 更新es数据

用户行为

  • 合法性校验

    • 视频是否存在

    • 用户操作类型是否存在

    • 评论是否存在

  • 从数据库中获取对应的数据用户行为(dbAction)

  • 记录用户行为

    • 点赞、收藏

      • 判断dbAction是否为空

          • 点赞收藏------插入操作
        • 非空

          • 取消点赞收藏------删除操作
      • 更新视频数据信息(like_count、collect_count)

      • 更新es信息

    • 投币

      • 合法性校验

        • 判断是否自己给自己投币

        • 判断是否已经投过币

        • 判断硬币是否足够扣减

      • 添加up硬币

      • 记录投币行为

      • 更新视频数据细信息(coin_count)

    • 评论点赞、讨厌

      • 获取用户行为的对立面

      • 查询数据库中是否存在当前用户行为的对立面数据

        • 存在:表示取消点赞or取消讨厌

          • 删除对立面
        • 不存在:表示点赞or讨厌

          • 记录用户行为
      • 更新评论的count相关数据

历史记录

加载历史记录

  • 根据更新时间倒序排

删除历史记录

清空历史记录

  • 批量删除

文件管理

上传图片

  • 构建图片上传目录

    • 按照YYYYMMDD格式创建每日目录,便于查找
  • 创建图片文件

    • 随机文件名称
  • 将图片写出到指定目录

    • file.transferTo()
  • 是否生成缩略图

    • 是则采用Ffmpeg生成
  • 返回图片保存目录,用于前端实时展示

获取图片资源

  • http请求,使用response的OutStream写出图片

    • 设置Header,保存过期时间

    • 设置ContentType为image

预处理视频上传

  • 长度为15的随机字符串作为UploadId

  • 创建文件上传Dto

    • 文件上传id

      • 标识分片上传临时目录
    • 视频文件名称name

    • 文件分片数量chunks

      • 分片index不会超过这个值
    • 当前分片标识index

      • 确保分片按顺序且全部上传
    • 视频总大小size

    • 视频分片路径path

  • 创建视频分片上传的临时目录

    • 基础文件信息 + userId + uploadId
  • 保存Dto到Reids缓存,以UploadId作为Key标识,用于视频分片上传

  • 返回UploadId到前端

视频上传(分片上传)

  • 视频文件视频存在

  • 分片文件是否超出大小限制

  • 文件上传内容是否有误(根据index和chunks来判断)

    • 漏了某些分片

    • 超出分片最大数量

  • 创建分片目录,保存分片文件

  • 更新Redis中的分片Dto信息

    • index

    • size

删除视频上传

  • 获取Redis缓存的文件上传Dto,判断是否存在

      • 删除缓存

      • 删除服务器的temp临时目录下的视频分片文件夹

      • 报错

获取视频播放流媒体资源

  • 获取视频文件路径path

  • response读取写出m3u8流媒体文件

  • 封装视频播放Dto

  • 将视频播放Dto存放到Redis消息队列中(异步处理)

获取视频ts文件

  • 获取视频分片ts文件路径path

  • response写出ts文件,使视频完整播放

用户管理

加载所有用户

修改用户状态

  • 判断用户是否存在

  • 修改状态

管理端登录拦截器

拦截的是否为HandelMethod方法

  • 否:return放行

是否为account登录操作

  • 是:return放行

获取token信息

  • request获取Header中的token信息

  • 是否为获取图片资源操作

    • 是:从cookie中获取token(因为前端请求问题无法从Header中获取token信息)

token是否为空

  • 是:报错拦截

Redis中的token信息是否存在

  • 否:报错拦截

放行

AOP切面

登录校验切面

  • 前置通知

    • 获取方法

    • 获取注解

    • 注解是否为空

      • 是:return

      • 否:放行

    • 注解是否设置需要校验登录

      • 是:校验登录

        • 获取HttpServletRequest对象

        • request中获取header中的token信息

        • 合法性校验

          • token是否为空

            • 是:报错

            • 否:放行

          • token是否匹配Redis保存的信息

            • 否:报错

            • 是:放行

消息发送切面

  • 自定义静态变量(参数名)

    • 审核视频

      • videoId

      • reason

    • 用户操作

      • videoId

      • actionType

    • 发布评论

      • videoId

      • content

      • replayCommentId

  • 环绕通知

    • 获取方法返回值result

    • 获取方法

    • 获取RecordUserMessage注解

    • 判断注解是否为空

        • 保存消息

          • 方法参数

            • 注解recordUserMessage

            • 参数列表parameters

            • 参数变量值列表args

          • 准备基础变量(videoId,reason等)

          • for循环遍历参数列表,为对应变量赋值

          • 如果是用户操作,判断用户操作类型

            (controller层默认传递的是like点赞操作)

            • 是否为like

              • 修改为对应消息类型
          • 获取当前用户信息

          • 在消息管理中保存消息

    • 返回result

ElasticEsearch

Es配置类

  • 创建RestHighLevelClient的Bean对象

  • 销毁时,关闭RestHighLevelClient对象

创建索引

  • initRun类中使用,用于程序初始化es

  • 声明文档的数据格式(maapping),对应VideoInfoEsDto类

    • 视频id

    • 视频封面

    • 视频名称

    • 用户id

    • 创建时间

    • 标签

    • 播放数量

    • 弹幕数量

    • 收藏数量

保存文档

  • 新增

    • 创建VideoInfoEsDto,并配置数量

    • 使用RestHighLevelClient创建文档

      • IndexRquest
  • 更新

    • 通过反射配置属性

      • 通过反射获取VideoInfo的属性名数组

      • for循环遍历fields数组

        • 获取该属性的get方法

        • 通过invoke获取属性值

        • 判断属性值是否为空

            • 为String类型,且不为空

            • 不为String类型,且不为null

          • 将数据put到提前准备好的Map中

            • key为属性名,value为属性值
      • 根据Map,使用RestHighLevelClient来执行文档的更新操作

        • UpdateRequest

更新文档数量

  • 根据指定的视频id和属性名,更新数量信息

    • 使用RestHighLevelClient更新文档

      • UpdateRequest

        • script脚本

删除文档

  • 使用RestHighLevelClient删除文档

    • DeleteRequest

根据id判断文档是否存在

  • 使用RestHighLevelClient获取文档

    • GetRequest

搜索

  • 创建搜索条件(SearchSourceBuilder)

    • 查询关键字

      • 映射匹配视频名称or视频标签(含分词)
    • 高亮

    • 排序方式

    • 分页

  • 构建Http查询请求(SearchRequest)

    • new时指定文档name

    • 添加查询条件SearchSourceBuilder

  • 使用RestHighLevelClient查询文档数据

    • 调用search方法返回response(SearchResponse)

    • response获取命中数hits

    • 操作hits

      • 获取总数据量

      • 遍历hits

        • 命中的是否为videoName(可能为tags)

            • 为videoInfo设置videoName
        • 添加到视频集合

        • 添加到用户id集合

    • 根据用户id集合查询用户集合

    • 将用户集合转化为Map

    • forEach为视频集合中的各个视频设置用户nickName

    • 封装返回

系统设置管理

获取系统设置

保存系统设置

数据统计中心

客户端

  • 获取实时数据

    • 获取昨天的日期(String)

      • Calendar类
    • 获取昨天的数据

      • 设置日期------昨天

      • 设置用户id------当前用户

    • 将数据转化为map

      • 按照数据类型type进行分组
    • 获取各项总数据

      • 针对粉丝数

        • 携带用户id

          • 获取粉丝数
    • 封装返回

      • 昨天的数据Map

      • 各项总数据info

  • 获取近一周数据

    • 获取前七天的日期集合(String)

    • 查询前七天的数据

      • 设置用户id

      • 设置查询的数据类型

      • 设置查询的日期集合

      • 按照日期倒序排

    • 将数据转化为Map

      • 按照日期进行分组
    • 遍历字符串,装填返回结果集result

      • 对Map采用get命令获取对应的数据对象

        • 为空:重新new一个,并设置日期
      • 及那个数据对象添加到结果集result中

管理端

  • 获取实时数据

    • 获取昨天的日期(String)

      • Calendar类
    • 获取全站昨天的数据

      • 设置日期------昨天
    • 遍历数据集合

      • 修改粉丝数为全站的总用户数
    • 将数据转化为map

      • 按照数据类型type进行分组
    • 获取各项总数据

      • 针对粉丝数

        • 不携带用户id

          • 获取实时全站用户总数
    • 封装返回

      • 昨天的数据Map

      • 各项总数据info

  • 获取近一周数据

    • 获取前七天的日期集合(String)

    • 查询前七天的数据

      • 设置查询条件

        • 设置查询的数据类型

        • 设置查询的日期集合

        • 按照日期倒序排

      • 判断是否查询用户数

          • 查询全站的用户总数
          • 查询对应类型的全站总数
    • 将数据转化为Map

      • 按照日期进行分组
    • 遍历字符串,装填返回结果集result

      • 对Map采用get命令获取对应的数据对象

        • 为空:重新new一个,并设置日期
      • 及那个数据对象添加到结果集result中

消息管理

获取未读消息总数

获取未读消息数,并按照类型分组

  • 数据库层面实现分组

读取对应消息类型的未读消息

  • 本质上是Update操作,将未读状态修改为已读

    • 设置条件

      • 用户id

      • 消息类型

    • 更新内容

      • 已读

加载对应消息类型的消息分页

  • 按照message_id倒序排序

删除消息

保存消息(用于消息发送切面)

  • 合法性校验

    • 视频是否存在

    • 是否自己操作自己

      • 是:直接return
  • 创建消息额外扩展内容对象UserMessageExtendDto

  • 已经点赞/收藏(即使取消)的视频不再发送消息

    • 查询数据库

    • 判断count>0

      • return
  • 封装消息对象userMessage

  • 特殊处理

    • 特殊处理评论消息

      • 被回复评论是否存在

          • UserMessageExtendDto设置messageContentReply
    • 特殊处理系统消息

      • 视频是否存在

          • UserMessageExtendDto设置auditStatus
  • userMessage设置扩展内容UserMessageExtendDto

  • 入库

用户主页

获取用户信息

  • 判断数据库是否存在当前被访问的用户

  • 获取被访问用户的粉丝数、关注数

    • 同一张表,查询条件不同

      • 粉丝数条件为focus_user_id

      • 关注数条件为user_id

  • 获取播放量和点赞数

    • 数据库层面使用sum()函数统计

      • 因为统计的是该用户的所有视频数据
  • 判断当前用户是否关注了被访问用户

    • 访问自己

    • 访问他人

更新用户信息

保存主题

关注

  • 合理性校验

    • 是否关注自己

    • 是否已经关注该用户

    • 被关注用户是否存在

  • 执行关注操作

取关

  • 删除关注记录

获取关注列表

获取粉丝列表

获取视频列表

  • 是否有查询的type条件

      • 按照type对应的字段倒序查询
      • 设置为按照create_time倒序查询

获取收藏的视频列表

  • 按照收藏时间倒序

分类管理

获取分类分页

保存分类

删除分类

修改分类顺序

相关推荐
欢乐少年19042 小时前
SpringBoot集成Sentry日志收集-3 (Spring Boot集成)
spring boot·后端·sentry
笑远4 小时前
MySQL 主主复制与 Redis 环境安装部署
redis·mysql·adb
曹天骄5 小时前
使用 MyBatis XML 和 QueryWrapper 实现动态查询
xml·mybatis
小斌的Debug日记6 小时前
框架基本知识总结 Day16
redis·spring
随风九天6 小时前
Spring Boot + MyBatis + MySQL:快速搭建CRUD应用
spring boot·mysql·mybatis
计算机-秋大田7 小时前
基于Spring Boot的宠物健康顾问系统的设计与实现(LW+源码+讲解)
java·vue.js·spring boot·后端·课程设计
曹天骄7 小时前
mybatis-plus+springboot3项目实现分页
mybatis
morris1317 小时前
【redis】布隆过滤器的Java实现
java·redis·布隆过滤器
椰椰椰耶7 小时前
【redis】全局命令set、get、keys
数据库·redis·缓存
月落星还在8 小时前
Redis 内存淘汰策略深度解析
数据库·redis·缓存