跳到主要内容

视频数据的记录

首先先来介绍记录服务(record-service) 的功能,这里包含了视频本身的相关数据,以及用户观看的相关数据。

数据中台其实是要从记录服务中进行收集数据,在真实的场景中,这个记录服务是由别的部门开发完成的,并不是由数据中台服务开发。就像有的项目中去调用第三方接口调用数据,这个接口肯定是别人来完成,我们直接调用既可以了。

在学习数据中台项目时,我也完成了记录服务的功能,本章节就来详细介绍此服务的功能

表结构

CREATE TABLE `d_video` (
`id` bigint NOT NULL COMMENT 'id',
`video_name` varchar(256) DEFAULT NULL COMMENT '视频名字',
`video_type_id` bigint NOT NULL COMMENT '视频类型id',
`parent_video_type_id` bigint DEFAULT NULL COMMENT '父级的视频分类id',
`video_duration` bigint NOT NULL COMMENT '视频时长,单位:秒',
`status` int DEFAULT '1' COMMENT '状态 1:启用 0:禁用',
`edit_time` datetime DEFAULT NULL COMMENT '编辑时间',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='视频表';
CREATE TABLE `d_video_type` (
`id` bigint NOT NULL COMMENT 'id',
`parent_id` bigint NOT NULL DEFAULT '0' COMMENT '父视频分类id',
`name` varchar(256) DEFAULT NULL COMMENT '视频分类名字',
`category_level` int NOT NULL DEFAULT '2' COMMENT '1:1级分类 2:2级分类',
`status` int DEFAULT '1' COMMENT '状态 1:启用 0:禁用',
`edit_time` datetime DEFAULT NULL COMMENT '编辑时间',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='视频分类表';
CREATE TABLE `d_video_react` (
`id` bigint NOT NULL COMMENT 'id',
`user_id` bigint NOT NULL COMMENT '用户id',
`user_name` varchar(256) DEFAULT NULL COMMENT '用户名字',
`video_id` bigint DEFAULT NULL COMMENT '视频id',
`video_name` varchar(256) DEFAULT NULL COMMENT '视频名字',
`video_type_id` bigint NOT NULL COMMENT '视频分类id',
`parent_video_type_id` bigint DEFAULT NULL COMMENT '父级的视频分类id',
`react_type` tinyint NOT NULL DEFAULT '0' COMMENT '反应类型 0无反应 1点赞 2点踩',
`enter_watch_time` datetime DEFAULT NULL COMMENT '进入观看视频的时间',
`watch_duration` bigint NOT NULL COMMENT '视频观看时长,单位:秒',
`watch_complete` int DEFAULT '0' COMMENT '是否将视频全部看完 0:否 1:是',
`status` int DEFAULT '1' COMMENT '状态 1:启用 0:禁用',
`edit_time` datetime DEFAULT NULL COMMENT '编辑时间',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='视频观看反应表';

表结构的设计非常的简单,只有三张表,分别是:视频表视频分类表视频观看反应表

  • 视频表: 记录了视频本身的信息,包括:视频名字、视频类型id、父级的视频分类id、视频时长
  • 视频分类表: 记录了视频所属的分类,包括:视频分类id、父视频分类id、视频分类名字、分类的级别

关于这三张表的查询逻辑也是非常的简单,就是从表中查看然后做一些简单的处理,返回给即可,这里就直接贴上代码了

视频数据的查询

相关流程

@RestController
@RequestMapping("/video")
@Tag(name = "video", description = "视频")
public class VideoController {

@Autowired
private VideoService videoService;

@Autowired
public VideoReactService videoReactService;

@Operation(summary = "查询所有视频数据")
@RequestMapping(value = "/query/list")
public ApiResponse<List<VideoVo>> queryList() {
return ApiResponse.ok(videoService.queryList());
}

@Operation(summary = "分页查询所有视频数据")
@RequestMapping(value = "/page/list")
public ApiResponse<PageVo<VideoVo>> pageList(@Valid @RequestBody PageDto pageDto) {
return ApiResponse.ok(videoService.pageList(pageDto));
}

@Operation(summary = "通过类型查询所有视频数据")
@RequestMapping(value = "/queryVideoListByCategoryLevel")
public ApiResponse<List<VideoVo>> queryVideoListByCategoryLevel(@Valid @RequestBody VideoByVideoTypeListDto videoReactListDto) {
return ApiResponse.ok(videoService.queryVideoListByCategoryLevel(videoReactListDto));
}
}
@Service
public class VideoService extends ServiceImpl<VideoMapper, Video> {

@Autowired
private VideoMapper videoMapper;

@Autowired
private VideoTypeMapper videoTypeMapper;

public PageVo<VideoVo> pageList(PageDto pageDto) {
//分页查询视频数据
IPage<Video> videoPage = videoMapper.selectPage(PageUtil.getPageParams(pageDto.getPageNum(),
pageDto.getPageSize()), Wrappers.emptyWrapper());
if (CollectionUtil.isEmpty(videoPage.getRecords())) {
return new PageVo<>(videoPage.getCurrent(), videoPage.getSize(), videoPage.getTotal(), new ArrayList<>());
}
//获取所有视频类型
List<VideoType> videoTypeList = videoTypeMapper.selectList(Wrappers.emptyWrapper());
if (CollectionUtil.isEmpty(videoTypeList)) {
return new PageVo<>(videoPage.getCurrent(), videoPage.getSize(), videoPage.getTotal(), new ArrayList<>());
}
//将视频类型转换为map,key为id,value为视频类型对象
Map<Long, VideoType> videoTypeMap = videoTypeList.stream().collect(Collectors.toMap(VideoType::getId,
videoType -> videoType, (v1, v2) -> v1));
//转换为vo对象
return PageUtil.convertPage(videoPage, video -> {
VideoVo videoVo = new VideoVo();
BeanUtil.copyProperties(video, videoVo);
videoVo.setVideoTypeName(videoTypeMap.get(videoVo.getVideoTypeId()).getName());
VideoType videoType = videoTypeMap.get(videoVo.getVideoTypeId());
if (Objects.nonNull(videoType)) {
videoVo.setVideoTypeName(videoType.getName());
videoVo.setParentVideoTypeName(Optional.ofNullable(videoTypeMap.get(videoType.getParentId()))
.map(VideoType::getName).orElse(""));
}
return videoVo;
});
}

public List<VideoVo> queryList() {
//
List<Video> videoList = videoMapper.selectList(Wrappers.emptyWrapper());
if (CollectionUtil.isEmpty(videoList)) {
return new ArrayList<>();
}
//获取所有视频类型
List<VideoType> videoTypeList = videoTypeMapper.selectList(Wrappers.emptyWrapper());
if (CollectionUtil.isEmpty(videoTypeList)) {
return new ArrayList<>();
}
//将视频类型转换为map,key为id,value为视频类型对象
Map<Long, VideoType> videoTypeMap = videoTypeList.stream().collect(Collectors.toMap(VideoType::getId,
videoType -> videoType, (v1, v2) -> v1));
//转换为vo对象
return videoList.stream().map(video -> {
VideoVo videoVo = new VideoVo();
BeanUtil.copyProperties(video, videoVo);
//设置视频类型名称
VideoType videoType = videoTypeMap.get(videoVo.getVideoTypeId());
if (Objects.nonNull(videoType)) {
videoVo.setVideoTypeName(videoType.getName());
videoVo.setParentVideoTypeName(Optional.ofNullable(videoTypeMap.get(videoType.getParentId()))
.map(VideoType::getName).orElse(""));
}
return videoVo;
}).collect(Collectors.toList());
}

public List<VideoVo> queryVideoListByCategoryLevel(VideoByVideoTypeListDto videoReactListDto) {
//根据视频类型查询视频数据
List<Video> videoList = videoMapper.selectList(Wrappers.lambdaQuery(Video.class)
.eq(Video::getVideoTypeId, videoReactListDto.getCategoryLevelId()));
if (CollectionUtil.isEmpty(videoList)) {
return new ArrayList<>();
}
//获取所有视频类型
List<VideoType> videoTypeList = videoTypeMapper.selectList(Wrappers.emptyWrapper());
if (CollectionUtil.isEmpty(videoTypeList)) {
return new ArrayList<>();
}
//将视频类型转换为map,key为id,value为视频类型对象
Map<Long, VideoType> videoTypeMap = videoTypeList.stream().collect(Collectors.toMap(VideoType::getId,
videoType -> videoType, (v1, v2) -> v1));
//转换为vo对象
return videoList.stream().map(video -> {
VideoVo videoVo = new VideoVo();
BeanUtil.copyProperties(video, videoVo);
//设置视频类型名称
VideoType videoType = videoTypeMap.get(videoVo.getVideoTypeId());
if (Objects.nonNull(videoType)) {
videoVo.setVideoTypeName(videoType.getName());
videoVo.setParentVideoTypeName(Optional.ofNullable(videoTypeMap.get(videoType.getParentId()))
.map(VideoType::getName).orElse(""));
}
return videoVo;
}).collect(Collectors.toList());
}
}

视频类型数据的查询

相关流程

@RestController
@RequestMapping("/video/type")
@Tag(name = "/video/type", description = "视频类型")
public class VideoTypeController {

@Autowired
private VideoTypeService videoTypeService;

@Operation(summary = "查询所有视频类型")
@RequestMapping(value = "queryAll")
public ApiResponse<List<VideoTypeVo>> queryAll() {
return ApiResponse.ok(videoTypeService.queryAll());
}

@Operation(summary = "根据分类等级查询视频类型")
@PostMapping(value = "queryListByCategoryLevel")
public ApiResponse<List<VideoTypeVo>> queryListByCategoryLevel(@Valid @RequestBody CategoryLevelDto categoryLevelDto) {
return ApiResponse.ok(videoTypeService.queryListByCategoryLevel(categoryLevelDto));
}


@Operation(summary = "根据父级id查询视频类型")
@PostMapping(value = "queryListByParentId")
public ApiResponse<List<VideoTypeVo>> queryListByParentId(@Valid @RequestBody VideoTypeDto videoTypeDto) {
return ApiResponse.ok(videoTypeService.queryListByParentId(videoTypeDto));
}

}
@Service
public class VideoTypeService extends ServiceImpl<VideoTypeMapper, VideoType> {

@Autowired
private VideoTypeMapper videoTypeMapper;

public List<VideoTypeVo> queryAll() {
//获取所有视频类型
List<VideoType> videoTypeList = videoTypeMapper.selectList(Wrappers.emptyWrapper());
if (CollectionUtil.isEmpty(videoTypeList)) {
return new ArrayList<>();
}
//转换为vo对象
return videoTypeList.stream().map(videoType -> {
VideoTypeVo videoTypeVo = new VideoTypeVo();
BeanUtils.copyProperties(videoType, videoTypeVo);
return videoTypeVo;
}).toList();
}

public List<VideoTypeVo> queryListByParentId(VideoTypeDto videoTypeDto) {
//根据父级id查询视频类型
List<VideoType> videoTypeList = videoTypeMapper.selectList(Wrappers.lambdaQuery(VideoType.class)
.eq(VideoType::getParentId, videoTypeDto.getParentId()));
if (CollectionUtil.isEmpty(videoTypeList)) {
return new ArrayList<>();
}
//转换为vo对象
return videoTypeList.stream().map(videoType -> {
VideoTypeVo videoTypeVo = new VideoTypeVo();
BeanUtils.copyProperties(videoType, videoTypeVo);
return videoTypeVo;
}).toList();
}

public List<VideoTypeVo> queryListByCategoryLevel(CategoryLevelDto categoryLevelDto) {
//根据分类等级查询视频类型
List<VideoType> videoTypeList = videoTypeMapper.selectList(Wrappers.lambdaQuery(VideoType.class)
.eq(VideoType::getCategoryLevel, categoryLevelDto.getCategoryLevel()));
if (CollectionUtil.isEmpty(videoTypeList)) {
return new ArrayList<>();
}
//转换为vo对象
return videoTypeList.stream().map(videoType -> {
VideoTypeVo videoTypeVo = new VideoTypeVo();
BeanUtils.copyProperties(videoType, videoTypeVo);
return videoTypeVo;
}).toList();
}
}

视频观看记录数据的查询

相关流程

@RestController
@RequestMapping("/video/reactor")
@Tag(name = "video/reactor", description = "视频反应")
public class VideoReactorController {

@Autowired
public VideoReactService videoReactService;


@Operation(summary = "查询所有视频反应数据")
@RequestMapping(value = "/query/list")
public ApiResponse<List<VideoReactVo>> reactorQueryList(@Valid @RequestBody VideoReactListDto videoReactListDto) {
return ApiResponse.ok(videoReactService.reactorQueryList(videoReactListDto));
}

@Operation(summary = "分页查询所有视频反应数据")
@RequestMapping(value = "/page/list")
public ApiResponse<PageVo<VideoReactVo>> reactorPageList(@Valid @RequestBody VideoReactPageDto videoReactPageDto) {
return ApiResponse.ok(videoReactService.reactorPageList(videoReactPageDto));
}
}
package org.javaup.service;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baidu.fsg.uid.UidGenerator;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.javaup.dto.VideoReactListDto;
import org.javaup.dto.VideoReactPageDto;
import org.javaup.entity.Video;
import org.javaup.entity.VideoReact;
import org.javaup.entity.VideoType;
import org.javaup.enums.BusinessStatus;
import org.javaup.enums.ReactorType;
import org.javaup.mapper.VideoMapper;
import org.javaup.mapper.VideoReactMapper;
import org.javaup.mapper.VideoTypeMapper;
import org.javaup.page.PageUtil;
import org.javaup.page.PageVo;
import org.javaup.util.DateUtils;
import org.javaup.vo.VideoReactVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;

/**
* @program: 数据中台实战项目。 添加 阿星不是程序员 微信,添加时备注 中台 来获取项目的完整资料
* @description: service实现层
* @author: 阿星不是程序员
**/
@Service
public class VideoReactService extends ServiceImpl<VideoReactMapper, VideoReact> {

@Autowired
private VideoReactMapper videoReactMapper;

@Autowired
private VideoMapper videoMapper;

@Autowired
private VideoTypeMapper videoTypeMapper;

@Autowired
private UidGenerator uidGenerator;

@Autowired
public VideoReactService proxyVideoReactService;

public List<VideoReactVo> reactorQueryList(VideoReactListDto videoReactListDto) {
//查询所有视频反应数据
List<VideoReact> videoReactList = videoReactMapper.selectList(Wrappers.lambdaQuery(VideoReact.class)
.eq(VideoReact::getVideoId, videoReactListDto.getVideoId()));
if (CollectionUtil.isEmpty(videoReactList)) {
return new ArrayList<>();
}
//获取所有视频类型
List<VideoType> videoTypeList = videoTypeMapper.selectList(Wrappers.emptyWrapper());
if (CollectionUtil.isEmpty(videoTypeList)) {
return new ArrayList<>();
}
//将视频类型转换为map,key为id,value为视频类型对象
Map<Long, VideoType> videoTypeMap = videoTypeList.stream().collect(Collectors.toMap(VideoType::getId,
videoType -> videoType, (v1, v2) -> v1));
return videoReactList.stream().map(videoReact -> {
VideoReactVo videoReactVo = new VideoReactVo();
BeanUtil.copyProperties(videoReact, videoReactVo);
videoReactVo.setVideoTypeName(videoTypeMap.get(videoReactVo.getVideoTypeId()).getName());
videoReactVo.setParentVideoTypeName(videoTypeMap.get(videoReactVo.getParentVideoTypeId()).getName());
videoReactVo.setReactTypeName(ReactorType.getMsg(videoReactVo.getReactType()));
videoReactVo.setWatchCompleteName(BusinessStatus.getMsg(videoReactVo.getWatchComplete()));
return videoReactVo;
}).toList();
}


public PageVo<VideoReactVo> reactorPageList(VideoReactPageDto videoReactPageDto) {
//分页查询视频反应数据
IPage<VideoReact> videoReactPage = videoReactMapper.selectPage(PageUtil.getPageParams(videoReactPageDto.getPageNum(),
videoReactPageDto.getPageSize()), Wrappers.lambdaQuery(VideoReact.class)
.eq(VideoReact::getVideoId, videoReactPageDto.getVideoId()));
if (CollectionUtil.isEmpty(videoReactPage.getRecords())) {
return new PageVo<>(videoReactPage.getCurrent(), videoReactPage.getSize(), videoReactPage.getTotal(), new ArrayList<>());
}
//获取所有视频类型
List<VideoType> videoTypeList = videoTypeMapper.selectList(Wrappers.emptyWrapper());
if (CollectionUtil.isEmpty(videoTypeList)) {
return new PageVo<>(videoReactPage.getCurrent(), videoReactPage.getSize(), videoReactPage.getTotal(), new ArrayList<>());
}
//将视频类型转换为map,key为id,value为视频类型对象
Map<Long, VideoType> videoTypeMap = videoTypeList.stream().collect(Collectors.toMap(VideoType::getId,
videoType -> videoType, (v1, v2) -> v1));
//转换为vo对象
return PageUtil.convertPage(videoReactPage, videoReact -> {
VideoReactVo videoReactVo = new VideoReactVo();
BeanUtil.copyProperties(videoReact, videoReactVo);
videoReactVo.setVideoTypeName(videoTypeMap.get(videoReactVo.getVideoTypeId()).getName());
videoReactVo.setParentVideoTypeName(videoTypeMap.get(videoReactVo.getParentVideoTypeId()).getName());
videoReactVo.setReactTypeName(ReactorType.getMsg(videoReactVo.getReactType()));
videoReactVo.setWatchCompleteName(BusinessStatus.getMsg(videoReactVo.getWatchComplete()));
return videoReactVo;
});
}
}

以上的这些数据查看其实大部分都是给前端页面使用的,而数据中台 既可以支持这种API方式的调用获取数据,也直接连接数据源执行SQL的方法来获取。