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倒序查询

获取收藏的视频列表

  • 按照收藏时间倒序

分类管理

获取分类分页

保存分类

删除分类

修改分类顺序

相关推荐
howard200537 分钟前
3.2.2.2 Spring Boot配置视图控制器
spring boot·自定义spring mvc配置·配置视图控制器
西门吹雪分身37 分钟前
Redis之RedLock算法以及底层原理
数据库·redis·算法
一代...37 分钟前
【redis】初识redis
数据库·redis·缓存
·云扬·1 小时前
【BUG】Redis RDB快照持久化及写操作禁止问题排查与解决
数据库·redis·bug
橘猫云计算机设计1 小时前
基于django云平台的求职智能分析系统(源码+lw+部署文档+讲解),源码可白嫖!
数据库·spring boot·后端·python·django·毕业设计
MrWho不迷糊2 小时前
Spring Boot 怎么打印日志
spring boot·后端·微服务
Java_SuSheng4 小时前
关于SQLite轻量数据库的研究
java·数据库·spring boot·sqlite·mybatis
Warren984 小时前
Springboot项目正常启动,访问资源却出现404错误如何解决?
java·spring boot·spring
风象南4 小时前
Redis中5种BitMap应用场景及实现
redis·后端
老李不敲代码8 小时前
榕壹云无人共享系统:基于SpringBoot+MySQL+UniApp的物联网共享解决方案
spring boot·物联网·mysql·微信小程序·uni-app·软件需求