From 885290e4d0d0c7fad3f538d901c616e49c3d6985 Mon Sep 17 00:00:00 2001
From: 胡仁荣 <897853850@qq.com>
Date: 星期二, 18 七月 2023 18:15:58 +0800
Subject: [PATCH] oss分块上传

---
 src/main/java/com/qxueyou/scc/teach/res/service/impl/HweiYunOBSServiceImpl.java |  348 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 342 insertions(+), 6 deletions(-)

diff --git a/src/main/java/com/qxueyou/scc/teach/res/service/impl/HweiYunOBSServiceImpl.java b/src/main/java/com/qxueyou/scc/teach/res/service/impl/HweiYunOBSServiceImpl.java
index 7343731..8964cf2 100644
--- a/src/main/java/com/qxueyou/scc/teach/res/service/impl/HweiYunOBSServiceImpl.java
+++ b/src/main/java/com/qxueyou/scc/teach/res/service/impl/HweiYunOBSServiceImpl.java
@@ -7,10 +7,12 @@
 import com.obs.services.model.*;
 import com.qxueyou.scc.base.model.FileMeta;
 import com.qxueyou.scc.base.model.Result;
-import com.qxueyou.scc.base.util.CollectionUtils;
-import com.qxueyou.scc.base.util.QFileUtils;
-import com.qxueyou.scc.base.util.UUIDUtils;
+import com.qxueyou.scc.base.service.ICacheService;
+import com.qxueyou.scc.base.service.impl.CommonAppService;
+import com.qxueyou.scc.base.util.*;
 import com.qxueyou.scc.config.HweiOBSConfig;
+import com.qxueyou.scc.teach.res.model.Res;
+import com.qxueyou.scc.teach.res.model.ResDir;
 import com.qxueyou.scc.teach.res.model.ResFile;
 import com.qxueyou.scc.teach.res.service.HweiYunOBSService;
 import com.qxueyou.scc.teach.res.service.IFileService;
@@ -19,13 +21,20 @@
 import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
+import org.aspectj.util.FileUtil;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.HashOperations;
 import org.springframework.stereotype.Service;
 import org.springframework.web.multipart.MultipartFile;
 
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 
 /**
  * @ClassName: HweiYunOBSServiceImpl
@@ -36,7 +45,7 @@
  */
 @Slf4j
 @Service
-public class HweiYunOBSServiceImpl implements HweiYunOBSService {
+public class HweiYunOBSServiceImpl extends CommonAppService implements HweiYunOBSService {
 
     private final Logger log = LogManager.getLogger(HweiYunOBSServiceImpl.class);
     @Autowired
@@ -44,6 +53,13 @@
 
     @Autowired
     FileService fileService;
+
+    /**
+     * redis 妯℃澘
+     */
+    @Autowired
+    ICacheService cache;
+
 
     public final static String FILE_TYPE_VIDEO = "video";
 
@@ -105,6 +121,7 @@
         return false;
     }
 
+
     @Override
     public List<FileMeta> fileUpload(MultipartFile uploadFile, String objectKey) {
         ObsClient obsClient = null;
@@ -125,17 +142,19 @@
             }
             InputStream inputStream = uploadFile.getInputStream();
             long available = inputStream.available();
-//            PutObjectRequest request = new PutObjectRequest(bucketName,objectKey,inputStream);
             PutObjectRequest request = new PutObjectRequest(bucketName,destPath,inputStream);
             ObjectMetadata objectMetadata = new ObjectMetadata();
             objectMetadata.setContentLength(available);
             request.setMetadata(objectMetadata);
-//            request.
             // 璁剧疆瀵硅薄璁块棶鏉冮檺涓哄叕鍏辫
             request.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ);
             PutObjectResult result = obsClient.putObject(request);
             fileMeta = new FileMeta();
             ResFile file = fileService.insertFileToDBTwo(objectKey, uploadFile.getSize(), result.getObjectUrl(), uploadFile.getContentType());
+//            SetObjectMetadataRequest ObjectMetadataRequest = new SetObjectMetadataRequest(bucketName, destPath);
+//            ObjectMetadataRequest.setContentDisposition("inline");
+//            obsClient.setObjectMetadata(ObjectMetadataRequest);
+
             fileMeta.setFileId(file.getFileId());
             fileMeta.setPath(result.getObjectUrl());
             fileMeta.setFileSize(uploadFile.getSize() / 1024 + "kb");
@@ -154,6 +173,115 @@
             hweiOBSConfig.destroy(obsClient);
         }
         return null;
+    }
+
+    @Override
+    public List<FileMeta> fnepian(MultipartFile uploadFile, String objectKey) throws IOException {
+        ObsClient obsClient = null;
+        List<FileMeta> files = new ArrayList<FileMeta>(2);
+        FileMeta fileMeta = null;
+        // 姣忎釜鍒嗙墖鐨勫ぇ灏忥紝鐢ㄤ簬璁$畻鏂囦欢鏈夊灏戜釜鍒嗙墖銆傚崟浣嶄负瀛楄妭銆�
+        final long partSize = 10 * 1024 * 1024L;   //10 MB銆�
+        String bucketName = hweiOBSConfig.getBucketName();
+        obsClient = hweiOBSConfig.getInstance();
+        // objectName 鏄矾寰勶紝鍒嗙墖鏂囦欢鏈�缁堟暣鍚堢殑璺緞
+        String objectName = "multipartUpload/"+objectKey;
+        // 鍒涘缓InitiateMultipartUploadRequest瀵硅薄銆�
+        InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectName);
+        InitiateMultipartUploadResult prebuilt = obsClient.initiateMultipartUpload(request);
+        InputStream inputStream = uploadFile.getInputStream();
+        // 鑾峰彇鍏ㄥ眬id
+        String uploadId = prebuilt.getUploadId();
+        // 濡傛灉骞跺彂閲忓ぇ鐨勮瘽 鍒濆鍖栫嚎绋嬫睜  20绾跨▼鏁伴噺
+        //  ExecutorService executorService = Executors.newFixedThreadPool(20);
+        // partTags鏄疨artEtag鐨勯泦鍚堛�侾artEtag鐢卞垎鐗囩殑ETag鍜屽垎鐗囧彿缁勬垚銆�
+        List<PartEtag> partTags = new ArrayList<PartEtag>();
+        File file = MultipartFileToFile(uploadFile);
+        // 璁$畻鏈夊灏戜釜鍒嗙墖
+        int partCount = (int) (file.length() / partSize);
+        // 濡傛灉鍙栦綑鏁颁笉涓洪浂鍒欒拷鍔犱竴涓�
+        if (file.length() % partSize != 0) {
+            partCount++;
+        }
+
+        try {
+            for (int i = 0; i < partCount; i++) {
+                long startPos = i * partSize;
+                long curPartSize = (i + 1 == partCount) ? (file.length() - startPos) : partSize;
+                // 璺宠繃宸茬粡涓婁紶鐨勫垎鐗囥��
+                inputStream.skip(startPos);
+                UploadPartRequest uploadPartRequest = new UploadPartRequest();
+                uploadPartRequest.setBucketName(bucketName);
+                uploadPartRequest.setObjectKey(objectName);
+                uploadPartRequest.setUploadId(uploadId);
+                uploadPartRequest.setInput(inputStream);
+                // 璁剧疆鍒嗙墖澶у皬銆傞櫎浜嗘渶鍚庝竴涓垎鐗囨病鏈夊ぇ灏忛檺鍒讹紝鍏朵粬鐨勫垎鐗囨渶灏忎负100 KB銆�
+                uploadPartRequest.setPartSize(curPartSize);
+                // 璁剧疆鍒嗙墖鍙枫�傛瘡涓�涓笂浼犵殑鍒嗙墖閮芥湁涓�涓垎鐗囧彿锛屽彇鍊艰寖鍥存槸1~10000锛屽鏋滆秴鍑烘鑼冨洿锛孫bs灏嗚繑鍥濱nvalidArgument閿欒鐮併��
+                uploadPartRequest.setPartNumber( i + 1);
+                // 姣忎釜鍒嗙墖涓嶉渶瑕佹寜椤哄簭涓婁紶锛岀敋鑷冲彲浠ュ湪涓嶅悓瀹㈡埛绔笂浼狅紝obs浼氭寜鐓у垎鐗囧彿鎺掑簭缁勬垚瀹屾暣鐨勬枃浠躲��
+                UploadPartResult uploadPartResult = obsClient.uploadPart(uploadPartRequest);
+                // 姣忔涓婁紶鍒嗙墖涔嬪悗锛孫bS鐨勮繑鍥炵粨鏋滃寘鍚玃artETag銆侾artETag灏嗚淇濆瓨鍦╬artTags涓��
+                partTags.add(new PartEtag(uploadPartResult.getEtag(), uploadPartResult.getPartNumber()));
+            }
+            // 寮�濮嬬嚎绋嬫睜鏃跺�欎娇鐢細绛夊緟涓婁紶瀹屾垚
+         /*   executorService.shutdown();
+            while (!executorService.isTerminated())
+            {
+                try
+                {
+                    executorService.awaitTermination(5, TimeUnit.SECONDS);
+                }
+                catch (InterruptedException e)
+                {
+                    e.printStackTrace();
+                }
+            }*/
+            fileMeta = new FileMeta();
+            // 鍚堝苟鍒嗙墖娈�
+            // 鍦ㄦ墽琛屽畬鎴愬垎鐗囦笂浼犳搷浣滄椂锛岄渶瑕佹彁渚涙墍鏈夋湁鏁堢殑partETags銆俹bs鏀跺埌鎻愪氦鐨刾artETags鍚庯紝浼氶�愪竴楠岃瘉姣忎釜鍒嗙墖鐨勬湁鏁堟�с�傚綋鎵�鏈夌殑鏁版嵁鍒嗙墖楠岃瘉閫氳繃鍚庯紝obs灏嗘妸杩欎簺鍒嗙墖缁勫悎鎴愪竴涓畬鏁寸殑鏂囦欢銆�
+            CompleteMultipartUploadRequest multipartUploadRequest = new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partTags);
+            // 瀹屾垚鍒嗙墖涓婁紶銆�
+            CompleteMultipartUploadResult completeMultipartUploadResult = obsClient.completeMultipartUpload(multipartUploadRequest);
+            // 杩斿洖鍏ㄥ眬id锛屾《鍚嶏紝瀵硅薄鍚嶇О 鐢ㄤ簬鍚庣画澶勭悊 姣斿鍙栨秷鍒嗙墖涓婁紶锛屾煡璇㈠垎鐗囦俊鎭瓑
+            fileMeta.setPath(completeMultipartUploadResult.getObjectUrl());
+            fileMeta.setFileSize(uploadFile.getSize() / 1024 + "kb");
+            fileMeta.setFileType(uploadFile.getContentType());
+            fileMeta.setFileName(objectKey);
+            files.add(fileMeta);
+            return files;
+        }catch (Exception e){
+            log.error("鍒嗙墖寰幆涓婁紶澶辫触锛�"+e.getMessage());
+            return null;
+        }
+    }
+    public static File MultipartFileToFile(MultipartFile multiFile) {
+        // 鑾峰彇鏂囦欢鍚�
+        String fileName = multiFile.getOriginalFilename();
+        // 鑾峰彇鏂囦欢鍚庣紑
+        String prefix = fileName.substring(fileName.lastIndexOf("."));
+        // 鑻ラ』瑕侀槻姝㈢敓鎴愮殑涓存椂鏂囦欢閲嶅,鑳藉鍦ㄦ枃浠跺悕鍚庢坊鍔犻殢鏈虹爜
+
+        try {
+            File file = File.createTempFile(getFileNameNotPrefix(fileName), prefix);
+            multiFile.transferTo(file);
+            return file;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+    /**
+     * 鑾峰彇鏂囦欢鍚嶄笉甯﹀悗缂�
+     *
+     * @param fileName
+     * @return
+     */
+    public static String getFileNameNotPrefix(String fileName) {
+        String prefix = fileName.substring(fileName.indexOf("."));
+        int num = prefix.length();//寰楀埌鍚庣紑鍚嶉暱搴�
+        String fileOtherName = fileName.substring(0, fileName.length() - num);//寰楀埌鏂囦欢鍚嶃�傚幓鎺変簡鍚庣紑
+        return fileOtherName;
     }
 
     private String getDestPath(String name) {
@@ -197,4 +325,212 @@
         }
         return null;
     }
+
+    /**
+     * 鏂囦欢鍒嗙墖涓婁紶瀹炵幇閫昏緫锛屽悇鍒嗙墖鏄绾跨▼涓婁紶
+     *
+     * @param input       杈撳叆娴�
+     * @param uniqueId    璧勬簮鍞竴id(鍓嶇浼犲叆)
+     * @param chunkNumber 鍒嗙墖缂栧彿
+     * @param chunkSize   鍒嗙墖澶у皬
+     * @param totalChunk  鍒嗙墖鎬绘暟
+     * @param fileName    鏂囦欢鍚�
+     * @return
+     */
+    public Result uploadChunk(InputStream input, String uniqueId, int chunkNumber, long chunkSize, int totalChunk,
+                              String fileName) {
+
+        HashOperations<Object, Object, Object> _cacheMap = cache.template().opsForHash();
+
+        ObsClient obsClient = new ObsClient(hweiOBSConfig.getAccessKey(),hweiOBSConfig.getSecurityKey(),hweiOBSConfig.getEndPoint());
+
+        //缁欏垵濮嬪寲棰勭暀1.2绉掗挓鐨勬椂闂�
+        try {
+            if (chunkNumber < 4) {
+                Thread.sleep(1200l);
+            }
+        } catch (InterruptedException e) {
+            log.error(e.getMessage(), e);
+        }
+
+        //鑾峰彇鍒嗙墖涓婁紶id(闃块噷浜慜SS鍒濆鍖栧垎鐗囦笂浼犱换鍔¤繑鍥�,鍜寀niqueId鍙妅ey涓�涓�瀵瑰簲),鑻ヨ幏鍙栦笉鍒帮紝鍒�10绉掑唴寰幆鍗佹鐩磋嚦鑾峰彇鍒帮紝鍚﹀垯杩斿洖閿欒
+        String uploadId = getUploadId(uniqueId);
+
+        if (uploadId == null) {
+            return new Result(false);
+        }
+
+        String key = (String) _cacheMap.get(uniqueId + ClientUtils.getUserId(), "key");
+        boolean exists = true;
+
+        //涓婁紶鐗囨
+        if (!_cacheMap.hasKey(uploadId, String.valueOf(chunkNumber))) {
+            //寮�濮嬩笂浼�
+            UploadPartRequest uploadPartRequest = new UploadPartRequest(hweiOBSConfig.getBucketName(), key);
+            uploadPartRequest.setUploadId(uploadId);
+            // 璁剧疆鍒嗘鍙凤紝鑼冨洿鏄�1~10000
+            uploadPartRequest.setPartNumber(chunkNumber);
+            // 璁剧疆鍒嗘澶у皬
+            uploadPartRequest.setPartSize(chunkSize);
+            uploadPartRequest.setInput(input);
+
+            UploadPartResult partResult = obsClient.uploadPart(uploadPartRequest);
+            exists = false;
+
+            _cacheMap.put(uploadId, String.valueOf(chunkNumber), partResult.getEtag());
+        }
+
+
+        //鍏ㄩ儴鐗囨涓婁紶瀹屾垚,璋冪敤client complete鏂规硶瀹屾垚鍒嗙墖涓婁紶浠诲姟锛屽苟鎻掑叆鏁版嵁搴�
+        if (_cacheMap.size(uploadId) != null
+                && _cacheMap.size(uploadId) >= totalChunk
+                && !_cacheMap.hasKey(uniqueId + ClientUtils.getUserId(), "finish")) {
+            List<PartEtag> tags = new ArrayList<>(5);
+            _cacheMap.entries(uploadId).forEach((k, v) -> {
+                tags.add(new PartEtag((String) v, Integer.parseInt((String) k)));
+            });
+
+            CompleteMultipartUploadResult completeMultipartUploadResult = obsClient.completeMultipartUpload(new CompleteMultipartUploadRequest(hweiOBSConfig.getBucketName(), key, uploadId,
+                    tags));
+
+            System.out.println(completeMultipartUploadResult.getObjectUrl());
+
+            ObjectMetadata metadata = obsClient.getObjectMetadata(hweiOBSConfig.getBucketName(), key);
+
+
+
+
+//            obsClient.setObjectAcl(hweiOBSConfig.getBucketName(), key, AccessControlList.REST_CANNED_PUBLIC_READ);
+            //鏍囪瀹屾垚
+            _cacheMap.put(uniqueId + ClientUtils.getUserId(), "finish", "true");
+
+//            //鏇存柊鏁版嵁搴撲俊鎭�
+            updateFile((String) _cacheMap.get(uniqueId + ClientUtils.getUserId(), "fileId"), metadata.getContentLength(), metadata.getContentMd5(), key, fileName);
+
+            //閿�姣佺紦瀛�
+            cache.template().expire(uniqueId + ClientUtils.getUserId(), 1, TimeUnit.MINUTES);
+        }
+
+        return new Result(true, "hit", exists, "fileId", _cacheMap.get(uniqueId + ClientUtils.getUserId(), "fileId"), "path", _cacheMap.get(uniqueId + ClientUtils.getUserId(), "path"));
+    }
+
+    @Override
+    public Result initUploadChunk(String uniqueId, String fileName, String md5) {
+        String path = getDestPath(fileName);
+        String key = chopPath(path);
+
+        //娓呯紦瀛�
+        cache.template().delete(uniqueId + ClientUtils.getUserId());
+
+        InitiateMultipartUploadRequest initiateMultipartUploadRequest = new InitiateMultipartUploadRequest(hweiOBSConfig.getBucketName(), key);
+        ObjectMetadata objectMetadata = new ObjectMetadata();
+        objectMetadata.setObjectStorageClass(StorageClassEnum.STANDARD);
+        initiateMultipartUploadRequest.setMetadata(new ObjectMetadata());
+
+        //璋冪敤OSS SDK 鎺ュ彛杩斿洖uploadId
+        ObsClient obsClient = new ObsClient(hweiOBSConfig.getAccessKey(),hweiOBSConfig.getSecurityKey(),hweiOBSConfig.getEndPoint());
+
+        String uploadId = obsClient.initiateMultipartUpload(initiateMultipartUploadRequest).getUploadId();
+
+        //涓洪厤鍚堝垎鐗囦笂浼狅紝鍚庡彴鍏堟柊寤烘枃浠惰褰�
+
+        ResFile file = newFileToDB(fileName, path, getFileType(fileName), 0l, md5);
+
+        //娣诲姞鍒扮紦瀛�
+        cache.template().opsForHash().put(uniqueId + ClientUtils.getUserId(), "uploadId", uploadId);
+        cache.template().opsForHash().put(uniqueId + ClientUtils.getUserId(), "key", key);
+        cache.template().opsForHash().put(uniqueId + ClientUtils.getUserId(), "path", path);
+        cache.template().opsForHash().put(uniqueId + ClientUtils.getUserId(), "fileId", file.getFileId());
+
+        //闃叉浜х敓杩囧缂撳瓨鍨冨溇
+        cache.template().expire(uniqueId + ClientUtils.getUserId(), 1, TimeUnit.DAYS);
+        ResFile file1 = new ResFile();
+        file1.setUpdateId(uploadId);
+        file1.setFileId(file.getFileId());
+        file1.setPath(file.getPath());
+        return new Result(true,"cs",file1);
+    }
+
+    /**
+     * 鏇存柊鏂囦欢淇℃伅鍒版暟鎹簱
+     *
+     * @param fileId
+     * @param fileLength
+     * @param md5
+     * @param path
+     * @param fileName
+     * @return
+     */
+    private ResFile updateFile(String fileId, long fileLength, String md5, String path, String fileName) {
+
+        ResFile file = new ResFile();
+
+        file.setFileId(fileId);
+        file.setSize(fileLength);
+        file.setMd5Hash(md5);
+        file.setPath(path);
+        file.setFileName(fileName);
+
+        cache.template().opsForList().rightPush("BaseOssServiceUpdate", file);
+
+        return file;
+
+    }
+    /**
+     * 鎻掑叆鏂囦欢淇℃伅鍒版暟鎹簱
+     *
+     * @param name
+     * @param relativePath 鐩稿璺緞
+     * @param type         鏂囦欢绫诲瀷锛岄潪鏂囦欢鏍煎紡
+     * @return
+     */
+    private ResFile newFileToDB(String name, String relativePath, String type, Long fileSize, String md5) {
+        ResFile file = new ResFile();
+
+        TraceUtils.setCreateTrace(file);
+        file.setFileName(name);
+        file.setFileFormat(QFileUtils.getFileFormat(name));
+        file.setFileType(type);
+        file.setMd5Hash(md5);
+        file.setPath(relativePath);
+        file.setSize(fileSize == null ? 0 : fileSize);
+        file.setDeleteFlag(false);
+        save(file);
+        return file;
+
+    }
+
+    /**
+     * 濡傛灉璺緞浠� / 鎴� \ 寮�澶达紝闇�瑕佹埅鍙�
+     *
+     * @param destPath
+     * @return
+     */
+    public String chopPath(String destPath) {
+        if (destPath.startsWith("/") || destPath.startsWith("\\")) {
+            return destPath.substring(1);
+        }
+        return destPath;
+    }
+    /**
+     * 鑾峰彇鍒嗙墖涓婁紶id(闃块噷浜慜SS鍒濆鍖栧垎鐗囦笂浼犱换鍔¤繑鍥�,鍜寀niqueId鍙妅ey涓�涓�瀵瑰簲),鑻ヨ幏鍙栦笉鍒帮紝鍒�10绉掑唴寰幆鍗佹鐩磋嚦鑾峰彇鍒帮紝鍚﹀垯杩斿洖閿欒
+     *
+     * @param uniqueId
+     * @return
+     */
+    private String getUploadId(String uniqueId) {
+        HashOperations<Object, Object, Object> _cacheMap = cache.template().opsForHash();
+        String uploadId = (String) _cacheMap.get(uniqueId + ClientUtils.getUserId(), "uploadId");
+        int tryCount = 0;
+        while (uploadId == null && tryCount < 10) {
+            try {
+                Thread.sleep(1000l);
+                uploadId = (String) _cacheMap.get(uniqueId + ClientUtils.getUserId(), "uploadId");
+                tryCount++;
+            } catch (InterruptedException e) {
+                log.error(e, e);
+            }
+        }
+        return uploadId;
+    }
 }

--
Gitblit v1.8.0