|
@@ -0,0 +1,132 @@
|
|
|
+package com.backendsys.modules.sdk.douyincloud.tos.service.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.util.NumberUtil;
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
+import com.backendsys.exception.CustException;
|
|
|
+import com.backendsys.modules.common.utils.CommonUtil;
|
|
|
+import com.backendsys.modules.sdk.douyincloud.tos.service.DouyinTosService;
|
|
|
+import com.backendsys.modules.upload.entity.SysUploadResult;
|
|
|
+import com.volcengine.tos.TOSV2;
|
|
|
+import com.volcengine.tos.TOSV2ClientBuilder;
|
|
|
+import com.volcengine.tos.TosClientException;
|
|
|
+import com.volcengine.tos.TosServerException;
|
|
|
+import com.volcengine.tos.comm.event.DataTransferListener;
|
|
|
+import com.volcengine.tos.comm.event.DataTransferStatus;
|
|
|
+import com.volcengine.tos.comm.event.DataTransferType;
|
|
|
+import com.volcengine.tos.model.object.ObjectMetaRequestOptions;
|
|
|
+import com.volcengine.tos.model.object.PutObjectInput;
|
|
|
+import com.volcengine.tos.model.object.PutObjectOutput;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.web.multipart.MultipartFile;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+
|
|
|
+// 对象接口 -> 上传对象
|
|
|
+// https://www.volcengine.com/docs/6349/79898
|
|
|
+@Service
|
|
|
+public class DouyinTosServiceImpl implements DouyinTosService {
|
|
|
+
|
|
|
+ private String REGION = "cn-beijing";
|
|
|
+ private String ENDPOINT = "tos-cn-beijing.volces.com";
|
|
|
+ private String DOMAIN = "tt8742f1ff1875cd2201-env-33n84bi3xr.tos-cn-beijing.volces.com";
|
|
|
+ private String BUCKET_NAME = "tt8742f1ff1875cd2201-env-33n84bi3xr";
|
|
|
+ private String ACCESS_KEY_ID = "AKLTNmFiMjBjMTZjZDYxNDlhZmI2OTc2M2U4MWZlODhhNGY";
|
|
|
+ private String SECRET_ACCESS_KEY = "TVRjME9UUmhabUZtWW1JNU5EWXhORGhoWVdJME16Z3pNbUprWkRKa1lqTQ==";
|
|
|
+
|
|
|
+
|
|
|
+ // [抖音云COS] 获取进度函数
|
|
|
+ private static DataTransferListener getDataTransferListener() {
|
|
|
+ return new DataTransferListener() {
|
|
|
+ // 自定义实现 DataTransferListener 的 dataTransferStatusChange 接口
|
|
|
+ @Override
|
|
|
+ public void dataTransferStatusChange(DataTransferStatus dataTransferStatus) {
|
|
|
+
|
|
|
+ long once = dataTransferStatus.getRwOnceBytes();
|
|
|
+ long current = dataTransferStatus.getConsumedBytes();
|
|
|
+ long total = dataTransferStatus.getTotalBytes();
|
|
|
+
|
|
|
+ if (dataTransferStatus.getType() == DataTransferType.DATA_TRANSFER_STARTED) {
|
|
|
+ System.out.println("putObject started.");
|
|
|
+ } else if (dataTransferStatus.getType() == DataTransferType.DATA_TRANSFER_RW) {
|
|
|
+
|
|
|
+ // 计算百分比
|
|
|
+ double percentage = NumberUtil.mul(current, 100) / total;
|
|
|
+ System.out.printf("putObject progress: [%d / %d] = %.02f%% \n", current, total, percentage);
|
|
|
+
|
|
|
+// System.out.printf("putObject, send %d bytes once, has sent %d bytes, total %d bytes.\n",
|
|
|
+// dataTransferStatus.getRwOnceBytes(), dataTransferStatus.getConsumedBytes(),
|
|
|
+// dataTransferStatus.getTotalBytes());
|
|
|
+
|
|
|
+ } else if (dataTransferStatus.getType() == DataTransferType.DATA_TRANSFER_FAILED) {
|
|
|
+ System.out.printf("putObject failed, has sent %d bytes, total %d bytes.\n", dataTransferStatus.getConsumedBytes(), total);
|
|
|
+ } else if (dataTransferStatus.getType() == DataTransferType.DATA_TRANSFER_SUCCEED) {
|
|
|
+ System.out.printf("putObject succeed, has sent %d bytes, total %d bytes.\n", dataTransferStatus.getConsumedBytes(), total);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * [抖音云COS] 上传对象
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public SysUploadResult putObject(MultipartFile multipartFile, String object_key) throws IOException {
|
|
|
+
|
|
|
+ if (multipartFile.isEmpty()) throw new CustException("file 上传文件不能为空");
|
|
|
+
|
|
|
+ // 生成 UUID 文件名
|
|
|
+ String filename = CommonUtil.generateUUIDFilename(multipartFile);
|
|
|
+
|
|
|
+ // 如果不传 object_key,则默认使用临时文件夹 (/temp/UUID文件名)
|
|
|
+ if (StrUtil.isEmpty(object_key)) object_key = "temp/" + filename;
|
|
|
+ System.out.println("Upload object: " + object_key);
|
|
|
+
|
|
|
+ // ------------------------------------------------------------------------------
|
|
|
+
|
|
|
+ // 初始化 TosClient
|
|
|
+ TOSV2 tos = new TOSV2ClientBuilder().build(REGION, ENDPOINT, ACCESS_KEY_ID, SECRET_ACCESS_KEY);
|
|
|
+
|
|
|
+ // TOSV2 提供的所有接口均会抛出 TosException 异常,需要使用 try-catch 进行捕获并处理。
|
|
|
+ try{
|
|
|
+
|
|
|
+ // 设置上传的桶名和对象名
|
|
|
+ PutObjectInput putObjectInput = new PutObjectInput()
|
|
|
+ .setBucket(BUCKET_NAME)
|
|
|
+ .setKey(object_key)
|
|
|
+ .setContent(multipartFile.getInputStream());
|
|
|
+
|
|
|
+ // 以下代码展示如何处理进度条
|
|
|
+ // 在 ObjectMetaRequestOptions 中设置文件大小,可在进度条中显示 total 总长度,否则 DataTransferStatus.getTotalBytes 值为 -1。
|
|
|
+ ObjectMetaRequestOptions options = new ObjectMetaRequestOptions().setContentLength(multipartFile.getSize());
|
|
|
+ putObjectInput.setOptions(options);
|
|
|
+ // 自定义实现 DataTransferListener,实现进度条功能
|
|
|
+ DataTransferListener listener = getDataTransferListener();
|
|
|
+ putObjectInput.setDataTransferListener(listener);
|
|
|
+
|
|
|
+ // 上传对象
|
|
|
+ PutObjectOutput output = tos.putObject(putObjectInput);
|
|
|
+
|
|
|
+ // 自定义返回结果实体
|
|
|
+ SysUploadResult result = new SysUploadResult();
|
|
|
+ result.setKey(object_key);
|
|
|
+ result.setRequest_id(output.getRequestInfo().getRequestId());
|
|
|
+ result.setE_tag(output.getEtag());
|
|
|
+ result.setDomain(DOMAIN);
|
|
|
+ return result;
|
|
|
+
|
|
|
+ } catch (TosClientException e) {
|
|
|
+ // 操作失败,捕获客户端异常,一般情况是请求参数错误,此时请求并未发送
|
|
|
+ System.out.println("putObject failed (TosClientException)");
|
|
|
+ throw new CustException(e.getMessage());
|
|
|
+ } catch (TosServerException e) {
|
|
|
+ // 操作失败,捕获服务端异常,可以获取到从服务端返回的详细错误信息
|
|
|
+ System.out.println("putObject failed (TosServerException)");
|
|
|
+ throw new CustException(e.getMessage());
|
|
|
+ } catch (Throwable t) {
|
|
|
+ // 作为兜底捕获其他异常,一般不会执行到这里
|
|
|
+ System.out.println("putObject failed (Throwable)");
|
|
|
+ throw new CustException(t.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+}
|