当前位置:首页 > 编程笔记 > 正文
已解决

spring boot 实现Minio分片上传

来自网友在路上 177877提问 提问时间:2023-10-14 16:19:02阅读次数: 77

最佳答案 问答题库778位专家为你答疑解惑

应用场景

分片上传,就是将所要上传的文件,按照一定的大小,将整个文件分隔成多个数据块(我们称之为Part)来进行分别上传,上传完之后再由服务端对所有上传的文件进行汇总整合成原始的文件。

分片上传的场景

  • 大文件上传

  • 网络环境环境不好,存在需要重传风险的场景

分片上传的步骤

<style>#mermaid-svg-D41OI2JGH7Ta7Qoz {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-D41OI2JGH7Ta7Qoz .error-icon{fill:#552222;}#mermaid-svg-D41OI2JGH7Ta7Qoz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-D41OI2JGH7Ta7Qoz .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-D41OI2JGH7Ta7Qoz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-D41OI2JGH7Ta7Qoz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-D41OI2JGH7Ta7Qoz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-D41OI2JGH7Ta7Qoz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-D41OI2JGH7Ta7Qoz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-D41OI2JGH7Ta7Qoz .marker.cross{stroke:#333333;}#mermaid-svg-D41OI2JGH7Ta7Qoz svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-D41OI2JGH7Ta7Qoz .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-D41OI2JGH7Ta7Qoz .cluster-label text{fill:#333;}#mermaid-svg-D41OI2JGH7Ta7Qoz .cluster-label span{color:#333;}#mermaid-svg-D41OI2JGH7Ta7Qoz .label text,#mermaid-svg-D41OI2JGH7Ta7Qoz span{fill:#333;color:#333;}#mermaid-svg-D41OI2JGH7Ta7Qoz .node rect,#mermaid-svg-D41OI2JGH7Ta7Qoz .node circle,#mermaid-svg-D41OI2JGH7Ta7Qoz .node ellipse,#mermaid-svg-D41OI2JGH7Ta7Qoz .node polygon,#mermaid-svg-D41OI2JGH7Ta7Qoz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-D41OI2JGH7Ta7Qoz .node .label{text-align:center;}#mermaid-svg-D41OI2JGH7Ta7Qoz .node.clickable{cursor:pointer;}#mermaid-svg-D41OI2JGH7Ta7Qoz .arrowheadPath{fill:#333333;}#mermaid-svg-D41OI2JGH7Ta7Qoz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-D41OI2JGH7Ta7Qoz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-D41OI2JGH7Ta7Qoz .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-D41OI2JGH7Ta7Qoz .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-D41OI2JGH7Ta7Qoz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-D41OI2JGH7Ta7Qoz .cluster text{fill:#333;}#mermaid-svg-D41OI2JGH7Ta7Qoz .cluster span{color:#333;}#mermaid-svg-D41OI2JGH7Ta7Qoz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-D41OI2JGH7Ta7Qoz :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style>
没有
前端上传文件的MD5值
判断是否上传过文件
创建文件存储用于存储分块
前端上传文件的MD5值和分块文件的序号
通过序号判断是否包含该分块
前端上传分块
存储分块
是否是最后一块
合并分块
返回文件的存储路径

检查文件的代码

在文件第一次上传时,上传文件的md5值,从而判断文件是否存在minio中

public Result<Boolean> checkFile(String fileMd5) {//正常做业务时应该先从数据库中查询//如果数据库存在再查询 minioGetObjectArgs getObjectArgs = GetObjectArgs.builder().bucket(bucketName)//                    todo 这里固定了文件的后缀,实际情况下应该从数据库开始查询,得到文件的路径.object(getFilePathByMd5(fileMd5,"png")).build();//查询远程服务获取到一个流对象try {FilterInputStream inputStream = minioClient.getObject(getObjectArgs);if(inputStream!=null){//文件已存在return Result.success(true);}} catch (Exception e) {e.printStackTrace();}//文件不存在return Result.success(false);}

检查分块的代码

检查分块是前端把需要上传的文件经过大小计算后,算出分块的数量,然后把循环发送文件的md5值和分块序号,然后在minio中检查对应文件夹下是否有对应的分块,如果检查到某一处没有对应的分块,便知道传输中断的位置。

 public Result<Boolean> checkChunk(String fileMd5, int chunkIndex) {//根据md5得到分块文件所在目录的路径String chunkFileFolderPath = getChunkFileFolderPath(fileMd5);//如果数据库存在再查询 minioGetObjectArgs getObjectArgs = GetObjectArgs.builder().bucket(bucketName).object(chunkFileFolderPath+chunkIndex).build();//查询远程服务获取到一个流对象try {FilterInputStream inputStream = minioClient.getObject(getObjectArgs);if(inputStream!=null){//文件已存在return Result.success(true);}} catch (Exception e) {e.printStackTrace();}//文件不存在return Result.success(false);}

上传分块的代码

    public Result uploadChunk(String fileMd5, int chunk, String localChunkFilePath) {//分块文件的路径String chunkFilePath = getChunkFileFolderPath(fileMd5) + chunk;//获取mimeTypeString mimeType = localChunkFilePath.substring(localChunkFilePath.lastIndexOf("."));//将分块文件上传到minioboolean b = addMediaFilesToMinIO(localChunkFilePath, mimeType, bucketName, chunkFilePath);if(!b){return Result.error("上传分块文件失败");}//上传成功return Result.success(true);}

合并分块的代码

合并分块文件之前,需要检查文件是否和源文件相同,我们通过把分块合并后取文件的md5值和传输过来的MD5值作比较,如果相同则证明传输正确,把合并后的文件存入minio中,并清除分块文件

public Result mergechunks(String fileMd5, int chunkTotal) {//分块文件所在目录String chunkFileFolderPath = getChunkFileFolderPath(fileMd5);//找到所有的分块文件List<ComposeSource> sources = Stream.iterate(0, i -> ++i).limit(chunkTotal).map(i -> ComposeSource.builder().bucket(bucketName).object(chunkFileFolderPath + i).build()).collect(Collectors.toList());//合并后文件的objectnameString objectName = getFilePathByMd5(fileMd5, "png");//指定合并后的objectName等信息ComposeObjectArgs composeObjectArgs = ComposeObjectArgs.builder().bucket(bucketName).object(objectName)//合并后的文件的objectname.sources(sources)//指定源文件.build();//===========合并文件============//报错size 1048576 must be greater than 5242880,minio默认的分块文件大小为5Mtry {minioClient.composeObject(composeObjectArgs);} catch (Exception e) {e.printStackTrace();log.error("合并文件出错,bucket:{},objectName:{},错误信息:{}",bucketName,objectName,e.getMessage());return Result.error("合并文件异常");}//===========校验合并后的和源文件是否一致,视频上传才成功===========//先下载合并后的文件File file = downloadFileFromMinIO(bucketName, objectName);try(FileInputStream fileInputStream = new FileInputStream(file)){//计算合并后文件的md5String mergeFile_md5 = DigestUtils.md5Hex(fileInputStream);//比较原始md5和合并后文件的md5if(!fileMd5.equals(mergeFile_md5)){log.error("校验合并文件md5值不一致,原始文件:{},合并文件:{}",fileMd5,mergeFile_md5);return Result.error("文件校验失败");}}catch (Exception e) {return Result.error("文件校验失败");}//==============将文件信息入库============
//        在做业务时要将得到的路径存入数据库//==========清理分块文件=========clearChunkFiles(chunkFileFolderPath,chunkTotal);return Result.success(true);}/*** 清除分块文件* @param chunkFileFolderPath 分块文件路径* @param chunkTotal 分块文件总数*/private void clearChunkFiles(String chunkFileFolderPath,int chunkTotal){Iterable<DeleteObject> objects =  Stream.iterate(0, i -> ++i).limit(chunkTotal).map(i -> new DeleteObject(chunkFileFolderPath+ i)).collect(Collectors.toList());;RemoveObjectsArgs removeObjectsArgs = RemoveObjectsArgs.builder().bucket(bucketName).objects(objects).build();Iterable<io.minio.Result<DeleteError>> results = minioClient.removeObjects(removeObjectsArgs);//要想真正删除results.forEach(f->{try {DeleteError deleteError = f.get();} catch (Exception e) {e.printStackTrace();}});}
查看全文

99%的人还看了

猜你感兴趣

版权申明

本文"spring boot 实现Minio分片上传":http://eshow365.cn/6-19466-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!