spring boot 實現(xiàn)Minio分片上傳的步驟
應(yīng)用場景
分片上傳,就是將所要上傳的文件,按照一定的大小,將整個文件分隔成多個數(shù)據(jù)塊(我們稱之為Part)來進行分別上傳,上傳完之后再由服務(wù)端對所有上傳的文件進行匯總整合成原始的文件。
分片上傳的場景
- 大文件上傳
- 網(wǎng)絡(luò)環(huán)境環(huán)境不好,存在需要重傳風(fēng)險的場景
分片上傳的步驟
檢查文件的代碼
在文件第一次上傳時,上傳文件的md5值,從而判斷文件是否存在minio中
public Result<Boolean> checkFile(String fileMd5) { //正常做業(yè)務(wù)時應(yīng)該先從數(shù)據(jù)庫中查詢 //如果數(shù)據(jù)庫存在再查詢 minio GetObjectArgs getObjectArgs = GetObjectArgs.builder() .bucket(bucketName) // todo 這里固定了文件的后綴,實際情況下應(yīng)該從數(shù)據(jù)庫開始查詢,得到文件的路徑 .object(getFilePathByMd5(fileMd5,"png")) .build(); //查詢遠程服務(wù)獲取到一個流對象 try { FilterInputStream inputStream = minioClient.getObject(getObjectArgs); if(inputStream!=null){ //文件已存在 return Result.success(true); } } catch (Exception e) { e.printStackTrace(); } //文件不存在 return Result.success(false); }
檢查分塊的代碼
檢查分塊是前端把需要上傳的文件經(jīng)過大小計算后,算出分塊的數(shù)量,然后把循環(huán)發(fā)送文件的md5值和分塊序號,然后在minio中檢查對應(yīng)文件夾下是否有對應(yīng)的分塊,如果檢查到某一處沒有對應(yīng)的分塊,便知道傳輸中斷的位置。
public Result<Boolean> checkChunk(String fileMd5, int chunkIndex) { //根據(jù)md5得到分塊文件所在目錄的路徑 String chunkFileFolderPath = getChunkFileFolderPath(fileMd5); //如果數(shù)據(jù)庫存在再查詢 minio GetObjectArgs getObjectArgs = GetObjectArgs.builder() .bucket(bucketName) .object(chunkFileFolderPath+chunkIndex) .build(); //查詢遠程服務(wù)獲取到一個流對象 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; //獲取mimeType String mimeType = localChunkFilePath.substring(localChunkFilePath.lastIndexOf(".")); //將分塊文件上傳到minio boolean 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()); //合并后文件的objectname String 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默認的分塊文件大小為5M try { 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)){ //計算合并后文件的md5 String mergeFile_md5 = DigestUtils.md5Hex(fileInputStream); //比較原始md5和合并后文件的md5 if(!fileMd5.equals(mergeFile_md5)){ log.error("校驗合并文件md5值不一致,原始文件:{},合并文件:{}",fileMd5,mergeFile_md5); return Result.error("文件校驗失敗"); } }catch (Exception e) { return Result.error("文件校驗失敗"); } //==============將文件信息入庫============ // 在做業(yè)務(wù)時要將得到的路徑存入數(shù)據(jù)庫 //==========清理分塊文件========= clearChunkFiles(chunkFileFolderPath,chunkTotal); return Result.success(true); } /** * 清除分塊文件 * @param chunkFileFolderPath 分塊文件路徑 * @param chunkTotal 分塊文件總數(shù) */ 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(); } }); }
到此這篇關(guān)于spring boot 實現(xiàn)Minio分片上傳的文章就介紹到這了,更多相關(guān)spring boot Minio分片上傳內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mybatis日志配置方式(slf4j、log4j、log4j2)
這篇文章主要介紹了Mybatis日志配置方式(slf4j、log4j、log4j2),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09SpringBoot2.0解決Long型數(shù)據(jù)轉(zhuǎn)換成json格式時丟失精度問題
這篇文章主要介紹了SpringBoot2.0解決Long型數(shù)據(jù)轉(zhuǎn)換成json格式時丟失精度問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06