仿b站微服务项目需求分析、实现思路和解决单表增删改查需求模版

需求分析与实现之前先给出解决大部分单表增删改查需求模版:

以个人主页权限查看为例:

确定请求参数和返回值,编写控制器接口定义

@RestController  ResponseBody+Controller注解二合一,既注册了该类到容器且标识是个
controller又使响应json化
@Api(tags = "用户个人主页各模块权限开放状态查看与编辑")                          
@RequestMapping("/selfCenter")   请求大路径
@CrossOrigin(value = "*")   最简单解决跨域注解
@Slf4j
public class SelfCenterController {
    @Resource
    注意注入抽象接口即可,会自动映射到实现了该接口的实现service类
    SelfCenterService selfCenterService;
    @ApiOperation("获取用户个人主页各模块权限开放状态")
    @PostMapping("/getUserPrivilege/{userId}")    请求小路径和请求方法类型post
    public Result<PrivilegeResponse> getUserPrivilege(@PathVariable Integer userId){
                                                        ↑截取路径中的参数,注意该路径中的参数需要
        return selfCenterService.getUserPrivilege(userId);  是封装类型比如Integer或String否则截取
                                                            不到
    }
}

编写service接口,固定方法传参返回值名称

public interface SelfCenterService {
    Result<PrivilegeResponse> getUserPrivilege(Integer userId);
}

编写mybatis-plus对应操作表的实体类

@Data
@TableName("privilege")
@Accessors(chain = true)
public class Privilege {
    @TableId(type = IdType.AUTO)
    Integer id;
    @TableField("user_id")
    Integer userId;
    @TableField("collect_group")
    Integer collectGroup;
    @TableField("remotely_like")
    Integer remotelyLike;
    @TableField("fans_list")
    Integer fansList;
    @TableField("idol_list")
    Integer idolList;
}

创建操作该实体类的mapper

package ljl.bilibili.mapper.user_center.user_info;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import ljl.bilibili.entity.user_center.user_info.Privilege;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface PrivilegeMapper extends BaseMapper<Privilege> {
}

写service接口的具体实现,在其中将传入参数(如果是自定义请求类则先将其转换为实体类)并入mybatis-plus特有单表增删改查语法,注入并调用对应mapper完成单表增删改查(若是查询往往需要将查出来的实体类转换为

响应类),最后泛型封装返回值,在原有返回值基础上提供额外描述字段code、msg辅助前端查看调用接口情况

public class SelfCenterServiceImpl implements SelfCenterService {
    注入该mapper
    @Resource
    PrivilegeMapper privilegeMapper;
    @Override
    public Result<PrivilegeResponse> getUserPrivilege(Integer userId){
        LambdaQueryWrapper<Privilege> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(Privilege::getUserId,userId);
        Privilege privilege=privilegeMapper.selectById(userId);
        return Result.data(new PrivilegeResponse().setCollectGroup(privilege.getCollectGroup()).setFansList(privilege.getFansList()).setIdolList(privilege.getIdolList()).setRemotelyLike(privilege.getRemotelyLike()));
    }
}


多表则是手写sql,注解形式写在mapper文件中或者xml文件中,然后调用mapper完成数据库层增删改查。

需求分析与实现思路

视频服务

收藏:

1.右上角看到收藏夹列表和每个收藏夹下的视频:根据传入的用户id查询得到收藏夹列表并返回收藏夹,将选定的收藏夹id传入查询得到收藏夹下的视频并返回收藏的视频

2.可以看到标注了视频是否被收藏的收藏夹列表:根据传入的用户id和视频id对收藏夹进行标记并返回有标记的收藏夹

3.可以同时收藏和取消多个视频:选定被某个收藏夹收藏和取消被某个收藏夹收藏后根据传入的对象的type字段来决定是新增收藏还是取消收藏并同时执行,并返回操作结果

4.可以创建、修改、删除收藏夹:根据传入的收藏夹对象信息来进行新增修改删除

评论:

1.获取视频下的评论:将视频id传入并返回对视频的评论和对评论的评论的合二为一评论

2.新增评论:将不同的评论对象传入并返回操作结果

弹幕:

1.获取弹幕:将视频id传入并返回各种特性如不同颜色不同方位等的弹幕

2.新增弹幕:将各种特性弹幕对象传入并返回操作结果

点赞:

对视频或评论的点赞和取消点赞:传入统一对象新增或删除点赞记录,并由于用户可以对视频点赞也可以对视频下的评论点赞,根据是否有评论id决定是删除该用户对该视频的点赞还是删除对该视频下评论的点赞,返回操作结果

播放:

1.新增播放记录:传入播放记录对象并查询之前是否有过播放记录,若无则新增播放记录

2.获取视频详情信息和自己相对视频状态:传入视频id、用户id和收藏夹id获取视频相关信息,并根据视频id和用户id查询是否自己已收藏和点赞过该视频

3.视频详情页获取推荐视频:传入视频id远程调用搜索服务的近似视频接口并返回推荐视频

4.首页中获取首页推荐视频:传入之前已刷新数获取首页视频,并在前端加值实现刷新不重复

5.右上角获取历史视频:未登录状态下从客户端缓存中查看,登录后传入用户id获取历史视频

上传视频:

1.分片上传视频文件自动截取封面示例图和视频存储位置:前端将完整文件切片并传输到后端,后端记录已上传分片数和总共需要上传片数,当已上传片数达到总数后执行合并,并返回自动截取的视频封面给前端

2.断点续传:前端每次将切片上传时会先发送查询是否已上传过的请求,每次上传分片时会缓存一份该分片的记录,只有合并了才会删除记录,如果因为网络波动等原因导致上传失败后端缓存仍在,发送请求查询该分片已上传过则不会再上传,只会上传未上传的分片。

3.提交视频相关信息:将分片上传结束后获取到的视频存储在minio中的路径和视频标题等赋到视频相关信息对象里传给后端,后端只需要将视频相关信息插入数据库无需再次上传一次文件

弹幕、收藏同理,但收藏需求因为操作时会有多个收藏夹可以选择,因此多出一个可以同时收藏和取消收藏一个视频于不同的收藏夹,因此请求参数加了额外的type字段做区分

上传视频的思路是将视频文件、视频相关信息如名字简介、封面一起传给后端,先检查视频头几个二进制位看是否符合MP4格式,不符合则说明上传的恶意文件,再看是否封面为空,是的话就标记一下后续发异步转码任务时会顺带截取封面,不是就直接上传封面,然后将视频文件上到minio后将视频相关信息插入数据库,并发送异步转码任务,在异步任务中获取视频时长和如果没有封面的话自动截取封面。

同时上传视频后会调用接口获取视频的第一帧图片。

用户服务

关注

1.关注和取关:将关注和取关对象传入后端插入和删除记录,同时若未登录状态后端鉴权后返回401跳转登录页面。

2.获取关注列表和粉丝列表:传入用户id和类型,根据类型确定是查询关注列表还是粉丝列表,根据用户id查询并返回对应的列表

个人中心

1.获取个人主页权限:传入用户id获取对应的个人主页向外权限,如收藏夹公开还是私有

2.编辑个人主页权限:传入各项个人主页权限开放状态后修改数据库中对应记录,返回操作结果

3.获取个人主页内容:根据传入的自己的id和要访问的人的id判断是否是查看他人个人主页,若查看的是他人个人主页则根据该用户开放的模块查询对应的内容返回前端,若查看的是自己的个人主页则不用查询开放的权限直接返回所有模块的内容

个人信息

1.获取个人信息:传入自己的id和要被获取个人信息的用户id,根据要被获取个人信息的用户id查询该用户对应的信息,根据传入自己的id和要被获取个人信息的用户id判断该用户是否已被自己关注被封装值到响应中,未登录状态下查看默认是设置为未关注的

2.编辑个人信息:将传入的编辑对象值修改到数据库,同时根据值是否为空动态修改,只有实际有修改值的属性才会在数据库中更新

搜索服务

1.近似关键字、关键字匹配搜索结果:将关键字传入后使用springboot集成es的查询写法获得默认结果

2.搜索结果重排序:根据传入的排序类型将查询结果重新排序后返回

3.定时同步mysql到es数据:对视频和用户数据有影响的操作执行时会异步发送消息,消费者生成对应的redis缓存,同时es中执行定时任务,将mysql中的数据插入es中,若未全量同步过则先全量同步,已全量同步则先获取redis中缓存的各类操作的值并用集合装载,先执行增删同步操作再执行更新操作已防止更新的文档还未插入或已删除,同时使用布隆过滤器保证查询id是否存在百分百正确,批量执行操作并收集失败操作递归调用减少失败操作次数,并设置递归上限防止堆栈溢出

消息服务

1.异步发送点赞、评论、动态视频、数据同步、转码消息:把传递的自定义消息对象用springboot集成rocketmq写法发送出去

2.消费点赞、评论、动态视频、数据同步、转码:评论是将监听方法的参数转换成与数据库交互的实体并插入数据库,而点赞多了根据属性type确定是生成点赞还是取消点赞,同时设置顺序消费防止出现点赞消息通知还未生成就已被删除的情况,动态视频则是插入动态视频后查询该视频作者的所有粉丝统一插入新数据,转码是远程调用视频服务编写的获取文件流接口获取到视频的文件流并判断是否需要截取封面,若需要则调用jave的api截取,并调用jave的api截取出秒数形式时长后转换成00:00的格式,同时判断若视频编码不为h264时转码成h264编码防止视频在浏览器中只有声音没有图像。

网关服务:

1.统一鉴权与授权:配置放行接口路径和需鉴权接口路径,并使用自定义过滤器取代security默认过滤器通过截取token进行鉴权,登录成功后返回token来授权

2.账号密码、手机号、邮箱号多种登录注册方式:账号密码登录下先获取图像验证码并缓存字符串值到redis中,将传入的登录对象值进行提取查询,若用户存在且用户的密码解密后和请求的密码一致且验证码与缓存到redis中的值一致则登录成功返回用户id和长短token,注册时用户名唯一,若用户名已存在需要重新输入值注册,手机号登录下

根据传递的手机号发送验证码到手机并缓存到redis,将手机号和获取的手机上的验证码构造对象传递给后端后查询请求验证码是否和缓存验证码一致,若一致且该手机号在数据库中有记录则直接返回对应用户id和长短token,若无则新创建一个用户,邮箱号登录同手机号登录

3.双token实现无感刷新token:登录通过后返回短token和长token,短token过期时长30min,长token过期时长7天,每25min携带长token发送一次刷新token请求获取以当前时间为起点来过期的长短token,同时每次打开页面会查询是否缓存用户id,若有缓存则发送一次刷新token请求,避免了还未到刷新token的时间点就已退出页面导致定时刷新token流程中断,也防止未登录状态下仍旧发送刷新token请求,从而实现未退出登录情况下七天内登录网站一次即可续token

4.防xss攻击和csrf攻击:将长token放到http-only-cookie里防止被恶意js操纵,自定义过滤器提取请求头鉴定是否有网站特有请求头拒绝非网站源发起的请求防止csrf攻击

聊天服务:

创建临时会话、聊天会话、发送消息、获取聊天会话和消息:发起临时会话时根据传入的userid获取接收消息方的相关信息,若发送出去了消息则生成聊天会话,页面刷新时传递用户id获取聊天会话和聊天会话的会话信息和未读消息数、是否已读的状态,选定聊天会话传递会话id获取聊天记录

一对一实时私聊:客户端和服务端建立连接后服务端将该客户端的sessionId和websocket对象的组合存储到map中,同时客户端会发送websocket消息将客户端的用户id和sessionid传递给服务端并存储到map中,每次发送消息时根据发送方的id和接收方的id在map中查询到websocket对象,利用该对象发送websocket实时消息,以此实现仅知道接收消息的人的用户id即可转发消息给接收方,同时若该会话之前未有过且双方均处于在线状态则会在接收方实时生成新会话,若接收方不在线则转为消息插入数据库。

讯飞星火大模型使用:

1.文生文:传递提问到后端,调用讯飞星火大模型获取流式响应并将每次响应的结果websocket方式传递回客户端

2.文生图:传递提问到后端,调用讯飞星火大模型获取图片的文件流并转换成Base64编码返回给客户端

3.文生ppt:传递主题到后端,调用讯飞星火大模型获取ppt大纲,再将大纲作为提问调用讯飞星火大模型得到大纲的详述,封装大纲和大纲详述集合返回给客户端

最后,宣传一下自己的仿b站前后端分离微服务项目,依赖版本号也在该项目的父pom.xml

实现了以下功能:

视频的上传、查看与上传时获取封面

视频的点赞、评论、可同时新增和删除多个收藏记录的收藏、多功能的弹幕

用户的个人信息查看编辑、用户之间的关注

用户的个人主页权限修改、查看、由个人主页权限动态决定的用户个人主页内容的获取

手机号、邮箱、图形验证码的多种方式登录

支持临时会话的服务器为代理的一对一实时私聊

基于讯飞星火的文生文、文生图、(全网首发)智能PPT

关注up动态视频、评论、点赞、私聊消息的生成与推送

基于es实现的视频和用户的聚合搜索、推荐视频

网关的路由和统一鉴权与授权

基于双token的七天内无感刷新token

防csrf、xss、抓包、恶意上传脚本攻击

统一处理异常和泛型封装响应体、自定义修改响应序列化值

简易的仿redis缓存读取与数据过期剔除实现

xxl-job+ redis+ rocketmq+ es+ 布隆过滤器的自定义es与mysql数据同步

slueth+zipkin的多服务间请求链路追踪

集中多服务日志到一个文件目录下与按需添加特定内容入日志

多服务的详细接口文档

项目地址LABiliBili,github地址GitHub - aigcbilibili/aigcbilibili: 仿bilibili前后端实现,演示地址https://labilibili.com/video/演示.mp4,如果大家觉得有帮助的话可以去github点个小星星♪(・ω・)ノ

该专栏存放前后端分离仿b站微服务项目相关教程

全部评论
牛的老哥
点赞 回复 分享
发布于 07-27 21:26 江苏
博主,阅读了需求分析后,大致看了下源代码,如果写入简历的话,请问以下学习顺序是否合理~ 1. 基础模块 网关服务:如何通过 token 进行用户身份验证,以及如何实现多种登录方式。 用户服务:用户的注册、登录、关注/取关。 2. 视频基础功能 视频上传功能 播放功能 推荐系统 3. 用户互动模块 点赞功能 评论功能 弹幕功能 4. 收藏功能 收藏夹和收藏功能 5. 扩展 消息服务:消息服务的异步处理和顺序消费 6. 实时聊天和大模型服务 聊天服务:学习 WebSocket 讯飞星火大模型:学习如何调用外部 AI 模型服务
点赞 回复 分享
发布于 09-19 21:36 澳大利亚
佬,我前后端联调完成后,挺多功能都不能正常使用头像能够上传到minio里但是显示不出来,点击提交有一个404错误,也找不到对应的controller。搜索功能好像是es索引的问题,我目前只按照前面帖子的操作创建了两个索引。佬能给个大概思路吗?就是怎么调试这个项目,我现在能正常使用的有视频上传和评论区
点赞 回复 分享
发布于 10-29 13:21 江西
佬,抱歉啊,这段时间又是答辩又是毕设的,摆了一段时间,这是之前学习过程中总结的部分问题,大佬有时间可以看看,能给出些建议的话万谢了其实问题主要就是评论回复在前端的显示、搜索(es)、还有大模型调用、点赞评论几个方面。问题最大的就是前端调试方面,佬的源码我这里有两个dist目录,然后其中一个乱码一个正常,相同点是修改了没影响到前端展示,我猜是和nginx相关,但是我刷新缓存也没有用(本项目nginx好像没开启缓存?),佬能教下怎么改这个项目的前端吗?不瞒佬,我学习这个项目是打算作为毕设和春招找工作,前端的内容我不太懂,单独做一个够呛,就打算在这个项目的基础上改下
点赞 回复 分享
发布于 11-12 08:28 江西

相关推荐

评论
4
6
分享
牛客网
牛客企业服务