目录

视频上传

接口一:检查该视频/媒资文件是否已经上传完成

接口二:检查视频分块是否已经在minio中已经存在

接口三:上传分块文件到minio中(已经上传的分块会在接口二进行校验)

接口四:合并上传的分块文件保存文件合并后的文件信息


视频上传

视频上传流程图

接口一:检查该视频/媒资文件是否已经上传完成

首先:前端计算上传视频的MD5传递给后端,后端接收到MD5值之后,通过MD5到媒资管理表中查询是否存在该文件信息,如果存在并且从媒资管理表中获取这个文件存放在minio的位置,通过位置到minio分布式文件系统中查询文件是否存在,如果mysql媒资信息表和minio中的媒资文件都存在返回true,无需进行后续上传,如果不存在返回前端false用来。

controller层

    @ApiOperation(value = "文件上传前检查文件")@PostMapping("/upload/checkfile")public RestResponse<Boolean> checkfile(@RequestParam("fileMd5") String fileMd5) throws Exception {RestResponse<Boolean> booleanRestResponse = mediaFilesService.checkFile(fileMd5);return booleanRestResponse;}

service层

接口:

    public RestResponse<Boolean> checkFile(String fileMd5);

实现类:

    /*** 通过md5值在数据库判断该文件是否存在* @param fileMd5 文件的md5* @return*/@Overridepublic RestResponse<Boolean> checkFile(String fileMd5) {MediaFiles mediaFiles = baseMapper.selectById(fileMd5);//说明在数据库中已经存在if (mediaFiles!=null){//检查在minio中是否存在//桶String bucket = mediaFiles.getBucket();//存储目录String filePath = mediaFiles.getFilePath();//文件流InputStream stream = null;try {stream = minioClient.getObject(GetObjectArgs.builder().bucket(bucket).object(filePath).build());if (stream!=null){//return 文件已经存在return RestResponse.success(true);}} catch (Exception e) {e.printStackTrace();}}return RestResponse.success(false);}

接口二:检查视频分块是否已经在minio中已经存在

首先接收前端上传媒资文件所生成的md5和分块序号,通过文件的md5值和文件每一块的序号组成在minio中存储分块文件的位置,获取该位置的分块文件是否存在,如果存在返回true(说明该分块文件已经在此前完成过上传,无需再次上传),如果不存在返回false,说明该分块文件还未上传,重新上传这一块文件。

controller层(控制层)

    @ApiOperation(value = "分块文件上传前的检测")@PostMapping("/upload/checkchunk")public RestResponse<Boolean> checkchunk(@RequestParam("fileMd5") String fileMd5, @RequestParam("chunk") int chunk) throws Exception {RestResponse<Boolean> booleanRestResponse = mediaFilesService.checkChunk(fileMd5,chunk);return booleanRestResponse;}

service层(业务逻辑层)

接口:

    public RestResponse<Boolean> checkChunk(String fileMd5, int chunkIndex);

接口实现类:

 /*** 检查分块是否已经存在* @param fileMd5  文件的md5* @param chunkIndex  分块序号* @return*/@Overridepublic RestResponse<Boolean> checkChunk(String fileMd5, int chunkIndex) {//获取所在的桶String bucket = BUCKET_VIDEO;//分块文件的路径String chunkFileFolderPath = getChunkFileFolderPath(fileMd5) + chunkIndex;//文件流InputStream inputStream = null;try {inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(bucket).object(chunkFileFolderPath).build());} catch (Exception e) {e.printStackTrace();log.debug("分块不存在");}if (inputStream !=null){return RestResponse.success(true);}return RestResponse.success(false);}

接口三:上传分块文件到minio中(已经上传的分块会在接口二进行校验)

接收前端传来的分割好的5M文件和这个文件的分割序号以及完整文件的md5值,将文件在本地转储一下,进行上传,如果是用户原先上传一半停止了上传或者由于网络波动导致上传中断,下一次上传原先文件时会在接口二中判断原先文件的哪几块已经存在minio中,存在的分块无需再次上传,不存在的分块走上传分块文件接口进行上传分块文件。

controller层(控制层)

    @ApiOperation(value = "上传分块文件")@PostMapping("/upload/uploadchunk")public RestResponse uploadchunk(@RequestParam("file") MultipartFile file, @RequestParam("fileMd5") String fileMd5, @RequestParam("chunk") int chunk) throws Exception {System.out.println(fileMd5);System.out.println("分块文件序号:"+chunk);//创建临时文件File tempFile = File.createTempFile("minio", "temp");//上传的文件拷贝到临时文件file.transferTo(tempFile);//文件路径String absolutePath = tempFile.getAbsolutePath();RestResponse restResponse = mediaFilesService.uploadChunk(fileMd5, chunk, absolutePath);return restResponse;}

service(业务逻辑层)

接口:

    /*** @description 上传分块* @param fileMd5  文件md5* @param chunk  分块序号* @param  localfChunkFilePath 本地文件路径*/public RestResponse uploadChunk(String fileMd5,int chunk,String localfChunkFilePath);

实现类:

@Overridepublic RestResponse uploadChunk(String fileMd5, int chunk, String localfChunkFilePath) {//得到分块文件的路径String chunkFileFolderPath = getChunkFileFolderPath(fileMd5);//String chunkFilePath = chunkFileFolderPath + chunk;//得到文件类型String mimeType = getMimeType(null);//上传分块文件到minioboolean flag = false;try {flag = addMediaFilesToMinIO(localfChunkFilePath, mimeType, BUCKET_VIDEO, chunkFilePath);} catch (Exception e) {log.debug("上传分块文件:{},失败:{}",chunkFilePath,e.getMessage());}if (!flag){return RestResponse.validfail(false,"上传分块文件失败");}return RestResponse.success(true);}

上传文件的方法

    /*** @description 将文件写入minIO* @param localFilePath  文件地址* @param bucket  桶* @param objectName 对象名称*/public boolean addMediaFilesToMinIO(String localFilePath,String mimeType,String bucket, String objectName) {try {UploadObjectArgs testbucket = UploadObjectArgs.builder().bucket(bucket).object(objectName).filename(localFilePath).contentType(mimeType).build();minioClient.uploadObject(testbucket);log.info("上传文件到minio成功,bucket:{},objectName:{}",bucket,objectName);System.out.println("上传成功");return true;} catch (Exception e) {e.printStackTrace();log.error("上传文件到minio出错,bucket:{},objectName:{},错误原因:{}",bucket,objectName,e.getMessage(),e);XueChengPlusException.cast("上传文件到文件系统失败");}return false;}

接口四:合并上传的分块文件保存文件合并后的文件信息

当前端按照5M将文件切分好依次上传所有之后,会请求接口四(合并文件),后端接收原文件的md5值和上传文件的名称和分块总数,在业务层进行处理,

1:首先会通过md5值获取在minio中存储该文件的分块位置目录

2:通过接收到分块总数和存储分块的位置得到所有分块文件的存储的具体位置存放到集合中

3:通过位置路径调用minio的合并api,将文件合并。

4:将合并好的文件临时下载到本地获得合并文件的md5值和前端上传文件的md5进行比较

5:删除临时本地的临时文件,如果校验通过存储该文件的相关信息到mysql媒资表中

6:就是将minio中存储的分块文件给删除。

controller层

    @ApiOperation(value = "合并文件")@PostMapping("/upload/mergechunks")public RestResponse mergechunks(@RequestParam("fileMd5") String fileMd5, @RequestParam("fileName") String fileName, @RequestParam("chunkTotal") int chunkTotal) throws Exception {System.out.println(fileMd5);System.out.println(chunkTotal);Long companyId = 1232141425L;UploadFileParamsDto uploadFileParamsDto = new UploadFileParamsDto();uploadFileParamsDto.setFileType("001002");uploadFileParamsDto.setTags("课程视频");uploadFileParamsDto.setRemark("");uploadFileParamsDto.setFilename(fileName);return mediaFilesService.mergechunks(companyId,fileMd5,chunkTotal,uploadFileParamsDto);}

业务层

接口

    /*** @description 合并分块* @param companyId  机构id* @param fileMd5  文件md5* @param chunkTotal 分块总和* @param uploadFileParamsDto 文件信息*/public RestResponse mergechunks(Long companyId,String fileMd5,int chunkTotal,UploadFileParamsDto uploadFileParamsDto);

实现类:

    @Overridepublic RestResponse mergechunks(Long companyId, String fileMd5, int chunkTotal, UploadFileParamsDto uploadFileParamsDto) {//=====获取分块文件路径=====String chunkFileFolderPath = getChunkFileFolderPath(fileMd5);//组成将分块文件路径组成 List<ComposeSource>List<ComposeSource> sourceObjectList = Stream.iterate(0, i -> ++i).limit(chunkTotal).map(i -> ComposeSource.builder().bucket(BUCKET_VIDEO).object(chunkFileFolderPath.concat(Integer.toString(i))).build()).collect(Collectors.toList());//=====合并=====//文件名称String fileName = uploadFileParamsDto.getFilename();//文件扩展名String extName = fileName.substring(fileName.lastIndexOf("."));//合并文件路径String mergeFilePath = getFilePathByMd5(fileMd5, extName);try {//合并文件ObjectWriteResponse response = minioClient.composeObject(ComposeObjectArgs.builder().bucket(BUCKET_VIDEO).object(mergeFilePath).sources(sourceObjectList).build());log.info("合并文件成功:{}",mergeFilePath);} catch (Exception e) {log.info("合并文件失败,fileMd5:{},异常:{}",fileMd5,e.getMessage(),e);return RestResponse.validfail(false, "合并文件失败。");}// ====验证md5====File minioFile = downloadFileFromMinIO(BUCKET_VIDEO,mergeFilePath);if(minioFile == null){log.debug("下载合并后文件失败,mergeFilePath:{}",mergeFilePath);return RestResponse.validfail(false, "下载合并后文件失败。");}try (InputStream newFileInputStream = new FileInputStream(minioFile)) {//minio上文件的md5值String md5Hex = DigestUtils.md5Hex(newFileInputStream);//比较md5值,不一致则说明文件不完整if(!fileMd5.equals(md5Hex)){return RestResponse.validfail(false, "文件合并校验失败,最终上传失败。");}//文件大小uploadFileParamsDto.setFileSize(minioFile.length());}catch (Exception e){log.debug("校验文件失败,fileMd5:{},异常:{}",fileMd5,e.getMessage(),e);return RestResponse.validfail(false, "文件合并校验失败,最终上传失败。");}finally {if(minioFile!=null){minioFile.delete();}}//文件入库currentProxy.addMediaFilesToDb(companyId,fileMd5,uploadFileParamsDto,BUCKET_VIDEO,mergeFilePath);//=====清除分块文件=====clearChunkFiles(chunkFileFolderPath,chunkTotal);return RestResponse.success(true);}

下载合并文件的方法

    /*** 从minio下载文件* @param bucket 桶* @param objectName 对象名称* @return 下载后的文件*/public File downloadFileFromMinIO(String bucket,String objectName){//临时文件File minioFile = null;FileOutputStream outputStream = null;try{InputStream stream = minioClient.getObject(GetObjectArgs.builder().bucket(bucket).object(objectName).build());//创建临时文件minioFile=File.createTempFile("minio", ".merge");outputStream = new FileOutputStream(minioFile);IOUtils.copy(stream,outputStream);return minioFile;} catch (Exception e) {e.printStackTrace();}finally {if(outputStream!=null){try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}}return null;}

清楚分块文件的方法

 /*** 清除分块文件* @param chunkFileFolderPath 分块文件路径* @param chunkTotal 分块文件总数*//*** 清除分块文件* @param chunkFileFolderPath 分块文件路径* @param chunkTotal 分块文件总数*/private void clearChunkFiles(String chunkFileFolderPath,int chunkTotal){try {List<DeleteObject> deleteObjects = Stream.iterate(0, i -> ++i).limit(chunkTotal).map(i -> new DeleteObject(chunkFileFolderPath.concat(Integer.toString(i)))).collect(Collectors.toList());RemoveObjectsArgs removeObjectsArgs = RemoveObjectsArgs.builder().bucket(BUCKET_VIDEO).objects(deleteObjects).build();Iterable<Result<DeleteError>> results = minioClient.removeObjects(removeObjectsArgs);results.forEach(r->{DeleteError deleteError = null;try {deleteError = r.get();} catch (Exception e) {e.printStackTrace();log.error("清楚分块文件失败,objectname:{}",deleteError.objectName(),e);}});} catch (Exception e) {e.printStackTrace();log.error("清楚分块文件失败,chunkFileFolderPath:{}",chunkFileFolderPath,e);}}

使用MinIO文件存储系统【完成视频断点续传】业务逻辑相关推荐

  1. Day134-136.尚品汇:平台属性接口、SPU、跨域问题、配置持久化、MinIO 分布式文件存储系统

    目录 Day 02 商品后台管理系统 1. 商品基本知识 2. 回顾Mybatis 3. 添加平台属性接口 (多表查询) Day 03 完成后台平台属性管理.SPU 1. 修改平台属性 2. gate ...

  2. 分布式文件存储系统Minio使用总结

    分布式文件存储系统Minio使用总结 1.分布式文件系统应用: 1.1.Minlo 介绍: Minlo 是一个基于Apache License v2.0开源协议的对象存储服务.它兼容亚马逊S3云存储服 ...

  3. 分布式文件存储系统MinIO笔记

    文章目录 一.MinIO介绍 1.文件系统应用场景 2.MinIO介绍 3.MinIO优点 4.MinIO的基础概念 5.纠删码EC(Erasure Code) 6.存储形式 7.存储方案 二.Min ...

  4. fastdfs 吗 支持windows_主流开源文件存储系统-fastdfs是否支持windows?你可以选择minio...

    首先答案是肯定的,fastdfs不支持windows. 其次建议你使用Minio 一.引言 一般来说文件存储花钱就选择阿里云oss.七牛云等产品,开源的话,目前开源的分布式文件存储系统非常多,上网一搜 ...

  5. minio实现大文件分片上传+断点续传+预览

    minio实现大文件分片上传+断点续传+预览 只提供后端java代码 思路: 前端分片 校验文件md5是否已经存在 --不存在创建临时桶存分片 校验分块是否已经上传 分块上传 合并分块 校验合成后md ...

  6. java实现MinIO文件上传,并将视频文件截图,将视频封面及视频通过MinIo上传到服务器中

    java实现MinIO文件上传,并将视频文件截图,将视频封面及视频通过MinIo上传到服务器中 配置完毕,接下来开始代码编写. 说明 总过程分为两步. 1.配置MinIO的环境. 2.代码编写. 下面 ...

  7. 盘点分布式文件存储系统____分布式文件存储系统简介

    盘点分布式文件存储系统 在项目的数据存储中,结构化数据通常采用关系型数据库,非结构化数据(文件)的存储就有很多种方式,服务器本地存储.Nas挂载.ftp等等,今天就来盘点一下,分布式文件存储系统. 一 ...

  8. 分布式文件存储系统调研

    分布式文件存储系统调研 主流分布式文件存储系统 分布式文件系统 适合类型 文件分布 系统性能 复杂度 备份机制 接口类型 开发语言 使用 FastDFS 4KB~500MB 小文件合并存储,不分片处理 ...

  9. 小滴课堂-项目大课学习笔记(2)海量数据存储-分布式文件存储系统

    在了解分布式文件存储之前,我们可以先来了解一下什么是分布式存储,分布式存储的系统又分为哪些 什么是分布式存储 在近些年来,随着各大的互联网公司的大数据应用的崛起,分布式系统被广泛的投入到实践当中.互联 ...

最新文章

  1. 如何用虚幻引擎4和C++开发游戏?斯坦福相关课程上线
  2. 我眼中的Linux设备树(三 属性)
  3. 低成本运行 Spark 数据计算
  4. MySQL 命令行导出、导入Select 查询结果
  5. Bulk批量操作API的介绍
  6. 深入理解linux网络技术内幕读书笔记(十)--帧的接收
  7. LeetCode50. Pow(x, n)(二进制位运算)
  8. L1-042 日期格式化 (5 分)—团体程序设计天梯赛
  9. 《游戏设计师修炼之道:数据驱动的游戏设计》一1.1 风险管理的作用
  10. Atitit mybatis 配置 redis 集成 attilax总结 艾提拉总结 1.1. setting name=cacheEnabled v 1 1.2. Mapper文件 1 1.
  11. python所有第三方库_自动更新Python所有第三方库
  12. SQL存储过程、存储函数
  13. php5.3.3 xhprof,给CentOS6.3 + PHP5.3 安装PHP性能测试工具 XHProf-0.9.2
  14. 【专家独推】全网最全Matlab常用函数(包括按首字母进行分类)
  15. LM75温度传感器数据采集实验
  16. 任务栏文件资源管理器打开特别卡
  17. 维控plc解密 维控程序文件密码 工程密码 子程序密码搞定
  18. VM的三种网络连接方式
  19. 上山能养鸡,下海能养鲍鱼,他如何依靠养殖成为富翁
  20. missingno错误不显示图片,pycharm

热门文章

  1. nextTick的原理以及为什么nextTick优先promise
  2. 嵌入式Linux开发24——Linux 按键输入实验
  3. 28-Vue之ECharts-折线图
  4. 开放式社交网络(OSN网络)之二:一个不甘被时代淘汰的中年父亲
  5. 企业品牌营销从何做起
  6. 华为将设研发机构在日本“进军物联网”
  7. matlab仿真分形树,MATLAB生成分形树
  8. 51单片机定时器频率计算
  9. 关于开源项目「基于ZigBee和STM32的智能家居控制系统」的使用说明
  10. cookie,sessionStorage 和 localStorage 的区别 cookie弊端