tsurumure 8 mesiacov pred
rodič
commit
03e0f0f505

+ 1 - 0
db/sys_upload.sql

@@ -9,6 +9,7 @@ CREATE TABLE `sys_upload` (
     PRIMARY KEY (`id`),
     `id` BIGINT(10) AUTO_INCREMENT COMMENT 'ID',
     `category_id` BIGINT(10) COMMENT '分类ID',
+    `request_id` VARCHAR(100) COMMENT '请求响应ID',
     `user_id` BIGINT(10) COMMENT '上传用户ID',
     `name` VARCHAR(255) NOT NULL COMMENT '文件名称',
     `content_type` VARCHAR(255) NOT NULL COMMENT '文件类型',

+ 0 - 13
src/main/java/com/backendsys/modules/common/utils/CommonUtil.java

@@ -1,17 +1,4 @@
 package com.backendsys.modules.common.utils;
 
-import cn.hutool.core.convert.Convert;
-import cn.hutool.core.lang.UUID;
-import org.springframework.web.multipart.MultipartFile;
-
-
 public class CommonUtil {
-
-    // [文件] 生成新的文件名 (UUID + 后缀名)
-    public static String generateUUIDFilename(MultipartFile multipartFile) {
-        String originalFileName = multipartFile.getOriginalFilename();
-        String suffix = originalFileName.substring(originalFileName.lastIndexOf("."));
-        return Convert.toStr(UUID.randomUUID()) + suffix;
-    }
-
 }

+ 41 - 0
src/main/java/com/backendsys/modules/common/utils/FilenameUtil.java

@@ -0,0 +1,41 @@
+package com.backendsys.modules.common.utils;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.lang.UUID;
+import org.springframework.web.multipart.MultipartFile;
+
+public class FilenameUtil {
+
+    public static String getFilenameSuffix(MultipartFile multipartFile, boolean includeDot) {
+        String originalFileName = multipartFile.getOriginalFilename();
+        int dotIndex = originalFileName.lastIndexOf(".");
+        // 根据 includeDot 参数决定是否包含点
+        if (includeDot) {
+            return originalFileName.substring(dotIndex);
+        } else {
+            return originalFileName.substring(dotIndex + 1);
+        }
+    }
+
+    // [文件名] 生成新的文件名 (UUID + 后缀名)
+    public static String generateUUIDFilename(MultipartFile multipartFile) {
+        return Convert.toStr(UUID.randomUUID()) + getFilenameSuffix(multipartFile, true);
+    }
+
+    /**
+     * Inserts "_thumb" between the file name and extension.
+     * @param filePath The original file path.
+     * @return The modified file path with "_thumb" inserted.
+     */
+    public static String insertThumbSuffix(String filePath) {
+        int dotIndex = filePath.lastIndexOf('.');
+        if (dotIndex != -1) {
+            return filePath.substring(0, dotIndex) + "-thumb" + filePath.substring(dotIndex);
+        } else {
+            return filePath;
+        }
+    }
+
+
+
+}

+ 3 - 3
src/main/java/com/backendsys/modules/sdk/tencent/cos/service/TencentCosService.java

@@ -12,12 +12,12 @@ public interface TencentCosService {
     // [腾讯云COS] 上传对象
     UploadResult putObject(MultipartFile file, String object_key) throws IOException;
 
-    // [腾讯云COS] 查询对象是否存在
-    boolean doesObjectExist(String object_key);
-
     // [腾讯云COS] 删除对象
     void deleteObject(String object_key);
 
+    // [腾讯云COS] 查询对象是否存在
+    boolean doesObjectExist(String object_key);
+
     // [腾讯云COS] 获得临时图片地址
     URL generateUrl(String object_key, Integer minutes);
 }

+ 46 - 24
src/main/java/com/backendsys/modules/sdk/tencent/cos/service/impl/TencentCosServiceImpl.java

@@ -1,15 +1,10 @@
 package com.backendsys.modules.sdk.tencent.cos.service.impl;
 
 import cn.hutool.core.convert.Convert;
-import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.util.StrUtil;
-import cn.hutool.crypto.digest.DigestUtil;
-import com.backendsys.entity.System.SysFile.SysFileCategoryDTO;
-import com.backendsys.entity.System.SysFile.SysFileDTO;
-import com.backendsys.entity.Tencent.TencentCos.MultipartUploadRespDTO;
 import com.backendsys.exception.CustException;
 import com.backendsys.modules.common.config.security.utils.HttpRequestUtil;
-import com.backendsys.modules.common.utils.CommonUtil;
+import com.backendsys.modules.common.utils.FilenameUtil;
 import com.backendsys.modules.sdk.tencent.cos.entity.Progress;
 import com.backendsys.modules.sdk.tencent.cos.entity.ProgressData;
 import com.backendsys.modules.sdk.tencent.cos.service.TencentCosService;
@@ -29,8 +24,6 @@ import com.qcloud.cos.transfer.Transfer;
 import com.qcloud.cos.transfer.TransferManager;
 import com.qcloud.cos.transfer.TransferProgress;
 import com.qcloud.cos.transfer.Upload;
-import com.qcloud.cos.utils.IOUtils;
-import net.coobird.thumbnailator.Thumbnails;
 import org.joda.time.DateTime;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -39,14 +32,15 @@ import org.springframework.web.multipart.MultipartFile;
 
 import java.io.*;
 import java.net.URL;
+import java.net.URLEncoder;
 import java.util.Arrays;
 import java.util.Date;
 import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import static org.aspectj.weaver.tools.cache.SimpleCacheFactory.path;
 
+// 图片处理概述
+// https://cloud.tencent.com/document/product/436/42215
+////            // https://cloud.tencent.com/document/product/460/6929
+////            // https://github.com/tencentyun/cos-java-sdk-v5/blob/master/src/main/java/com/qcloud/cos/demo/ci/BasicImageProcessing.java
 @Service
 public class TencentCosServiceImpl implements TencentCosService {
 
@@ -105,13 +99,16 @@ public class TencentCosServiceImpl implements TencentCosService {
             progress.setState(state);
             progress.setData(progressData);
             sseUtil.send(httpRequestUtil.getUserId(), progress);
-            // System.out.println(transfer.getState());    // state: (完成 Completed, 失败 Failed)
-        }
 
+            // state: (完成 Completed, 失败 Failed)
+            // System.out.println(transfer.getState());
+        }
     }
 
-
-    // [腾讯云COS] 上传对象
+    /**
+     * [腾讯云COS] 上传对象
+     * - 如果对象是图片,则同时产生缩略图
+     */
     @Override
     public UploadResult putObject(MultipartFile multipartFile, String object_key) {
 
@@ -121,25 +118,49 @@ public class TencentCosServiceImpl implements TencentCosService {
         try {
 
             // 如果不传 object_key,则默认使用临时文件夹 (/temp) + MD5文件名
-
-            String filename = CommonUtil.generateUUIDFilename(multipartFile);
-            if (StrUtil.isEmpty(object_key)) {
-                object_key = "temp/" + filename;
-            }
+            String filename = FilenameUtil.generateUUIDFilename(multipartFile);
+            if (StrUtil.isEmpty(object_key)) object_key = "temp/" + filename;
             System.out.println("Upload object: " + object_key);
 
-            // 创建 PutObjectRequest 对象,PutObject 请求。(异步)
+            // [配置]
             ObjectMetadata metadata = new ObjectMetadata();
+            // 设置流大小 (只有设置了才有进度)
             metadata.setContentLength(multipartFile.getSize());
+
+//            // [图片处理] -----------------------------------------------------------
+////            // 设置请求头规则 (基础图片处理) (当  fileid 与 ObjectKey 相同时,处理后的图片将覆盖原图存储;不相同时将分别存储原图和处理后图片)
+////            // https://cloud.tencent.com/document/product/460/6929
+////            // https://github.com/tencentyun/cos-java-sdk-v5/blob/master/src/main/java/com/qcloud/cos/demo/ci/BasicImageProcessing.java
+//            /*
+//                [支持处理的原图格式]
+//                - 普通格式: jpg/jpeg、png、bmp、webp、tiff、gif
+//                - 高级格式: avif、heif/heic、tpg、apng、psd、svg、raw、ai、eps、dng、cr3、crw、mos、erf、3fr、fff、kdc、dcr、rw2、pef、sr2、srf、arw、nef、nrw、orf、mef、mrw
+//             */
+//            // 判断图片类型
+//            List<String> imageType = Arrays.asList("jpg", "jpeg", "png", "bmp", "webp", "tiff", "gif");
+//            boolean isImage = imageType.contains(FilenameUtil.getFilenameSuffix(multipartFile, false).toLowerCase());
+//            if (isImage) {
+//                // 选用样式1,并限定缩略图的宽高最小值为100×100 绝对质量为60
+//                String rule = "imageView2/1/w/100/h/100/q/60";
+////                String rule = "imageMogr2/thumbnail/!50p";
+//                String object_key_thumb = "/" + FilenameUtil.insertThumbSuffix(object_key);
+//                String object_key_thumb_encode = URLEncoder.encode(object_key_thumb, "UTF-8");
+//                String picOperations = "{\"is_pic_info\":1,\"rules\":[{\"fileid\":\"" + object_key_thumb_encode + "\",\"rule\":\"" + rule + "\"}]}";
+//                System.out.println("picOperations = " + picOperations);
+//                metadata.setHeader("Pic-Operations", picOperations);
+//            }
+//            // --------------------------------------------------------------------
+
+            // 创建 PutObjectRequest 对象,PutObject 请求。(异步)
             PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKET_NAME, object_key, multipartFile.getInputStream(), metadata);
 
             // 普通上传 (没有进度)
-//            cosClient.putObject(putObjectRequest);
+//          //  cosClient.putObject(putObjectRequest);
 
             // 高级上传
             TransferManager transferManager = TencentCosUtil.createTransferManager(cosClient);
             Upload upload = transferManager.upload(putObjectRequest);   // 返回一个异步结果Upload
-            showTransferProgress(filename, upload);                          // 查询上传进度,直到上传结束
+            showTransferProgress(filename, upload);                     // 查询上传进度,直到上传结束
             UploadResult uploadResult = upload.waitForUploadResult();   // 捕获可能出现的异常
             return uploadResult;
 
@@ -215,6 +236,7 @@ public class TencentCosServiceImpl implements TencentCosService {
     public void deleteObject(String object_key) {
         COSClient cosClient = getClient();
         cosClient.deleteObject(BUCKET_NAME, object_key);
+        // cosClient.deleteObject(BUCKET_NAME, FilenameUtil.insertThumbSuffix(object_key));
         cosClient.shutdown();
     }
 

+ 28 - 0
src/main/java/com/backendsys/modules/sdk/tencent/cos/utils/TencentBasicImageUtil.java

@@ -0,0 +1,28 @@
+package com.backendsys.modules.sdk.tencent.cos.utils;
+
+import com.qcloud.cos.COSClient;
+import com.qcloud.cos.model.GetObjectRequest;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+
+public class TencentBasicImageUtil {
+
+    public static void imageProcessing(COSClient cosClient, String bucket_name, String object_key, String rule) {
+        //图片在bucket中的相对位置,比如根目录下file文件夹中的demo.png路径为file/demo.png
+        GetObjectRequest getObj = new GetObjectRequest(bucket_name, object_key);
+        getObj.putCustomQueryParameter(rule, null);
+        cosClient.getObject(getObj); // , new File("demo.png")
+    }
+
+    /**
+     * 选用样式1,并限定缩略图的宽高最小值为400 × 600 绝对质量为85
+     * https://cloud.tencent.com/document/product/460/6929
+     */
+    public static void quickThumbnailTemplate(COSClient cosClient, String bucket_name, String object_key) {
+        String rule = "imageView2/1/w/400/h/600/q/85";
+        imageProcessing(cosClient, bucket_name, object_key, rule);
+    }
+
+}

+ 13 - 14
src/main/java/com/backendsys/modules/upload/controller/SysUploadController.java

@@ -34,29 +34,20 @@ public class SysUploadController {
 
     /**
      * 获取上传文件列表
+     * - 缩略图 (?imageView2/1/w/100/h/100/q/60)
      */
     @GetMapping("/api/v2/upload/getUploadFileList")
     public Result getUploadFileList(@Validated SysUpload sysUpload) {
         return Result.success().put("data", sysUploadService.selectUploadList(sysUpload));
     }
 
-    /**
-     * 删除上传文件
-     */
-    @PreAuthorize("@ss.hasPermi(1.1)")
-    @DeleteMapping("/api/v2/upload/removeUploadFile")
-    public Result removeUploadFile(@Validated(SysUpload.Delete.class) @RequestBody SysUpload sysUpload) {
-        return Result.success(sysUploadService.removeUploadFile(sysUpload));
-    }
-
-
     /**
      * 上传文件 (单文件上传不超过 20MB)
      */
     @PreAuthorize("@ss.hasPermi(1.1)")
-    @PostMapping("/api/v2/upload/simpleUpload")
-    public Result uploadSmall(@RequestParam("file") MultipartFile multipartFile) {
-        return Result.success().put("data", sysUploadService.uploadSmall(multipartFile));
+    @PostMapping("/api/upload/uploadSmall")
+    public Result uploadSmall(@RequestParam("file") MultipartFile multipartFile, Long category_id) {
+        return Result.success().put("data", sysUploadService.uploadSmall(multipartFile, category_id));
     }
 
     /**
@@ -78,7 +69,6 @@ public class SysUploadController {
         }
         return emitter;
     }
-
 //    /**
 //     * [SSE] 测试发送
 //     */
@@ -89,4 +79,13 @@ public class SysUploadController {
 //        return "success";
 //    }
 
+    /**
+     * 删除上传文件
+     */
+    @PreAuthorize("@ss.hasPermi(1.1)")
+    @DeleteMapping("/api/v2/upload/removeUploadFile")
+    public Result removeUploadFile(@Validated(SysUpload.Delete.class) @RequestBody SysUpload sysUpload) {
+        return Result.success().put("data", sysUploadService.removeUploadFile(sysUpload));
+    }
+
 }

+ 2 - 0
src/main/java/com/backendsys/modules/upload/entity/SysUpload.java

@@ -1,6 +1,7 @@
 package com.backendsys.modules.upload.entity;
 
 import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import jakarta.validation.constraints.NotEmpty;
@@ -15,6 +16,7 @@ public class SysUpload {
     @TableId(type = IdType.AUTO)
     private Long id;
     private Long category_id;
+    private String request_id;
     private Long user_id;
     private String name;
     private String content_type;

+ 4 - 4
src/main/java/com/backendsys/modules/upload/service/SysUploadService.java

@@ -10,10 +10,10 @@ public interface SysUploadService {
 
     // 获取上传文件列表
     PageEntity selectUploadList(SysUpload sysUpload);
-    // 删除上传文件
-    Map<String, Object> removeUploadFile(SysUpload sysUpload);
 
+    // 上传文件 (单文件大小不超过 n)
+    SysUpload uploadSmall(MultipartFile file, Long category_id);
 
-    // 上传文件 (单文件上传不超过 n)
-    SysUpload uploadSmall(MultipartFile file);
+    // 删除上传文件
+    Map<String, Object> removeUploadFile(SysUpload sysUpload);
 }

+ 27 - 28
src/main/java/com/backendsys/modules/upload/service/impl/SysUploadServiceImpl.java

@@ -50,40 +50,14 @@ public class SysUploadServiceImpl implements SysUploadService {
     }
 
     /**
-     * 删除上传文件
-     */
-    @Override
-    public Map<String, Object> removeUploadFile(SysUpload sysUpload) {
-
-        // [Delete] 删除文件记录
-        SysUpload entity = sysUploadDao.selectOne(new LambdaQueryWrapper<SysUpload>().eq(SysUpload::getObject_key, sysUpload.getObject_key()));
-        if (entity != null) {
-            sysUploadDao.delete(new LambdaQueryWrapper<SysUpload>().eq(SysUpload::getObject_key, sysUpload.getObject_key()));
-        }
-
-        // [异步任务] 创建一个 CompletableFuture 来执行异步任务
-        CompletableFuture.runAsync(() -> {
-            // [腾讯云] 删除对象
-            Boolean isObjectExist = tencentCosService.doesObjectExist(sysUpload.getObject_key());
-            if (isObjectExist) {
-                tencentCosService.deleteObject(sysUpload.getObject_key());
-                System.out.println("Delete cos object: " + sysUpload.getObject_key());
-            }
-        });
-
-        return Map.of("object_key", sysUpload.getObject_key());
-    }
-
-
-    /**
-     * 上传文件 (单文件上传不超过 n)
+     * 上传文件 (单文件大小不超过 n)
      * - 5MB = 5242880
      * - 20MB = 20971520
      * - 100MB = 104857600
      * - 1GB = 1073741824
      */
     @Override
-    public SysUpload uploadSmall(MultipartFile multipartFile) {
+    public SysUpload uploadSmall(MultipartFile multipartFile, Long category_id) {
         try {
 
             // 判断文件是否超过大小
@@ -99,6 +73,8 @@ public class SysUploadServiceImpl implements SysUploadService {
                 UploadResult uploadResult = tencentCosService.putObject(multipartFile, null);
                 // [新增] 上传文件记录
                 sysUploadEntity = new SysUpload();
+                sysUploadEntity.setCategory_id(category_id);
+                sysUploadEntity.setRequest_id(uploadResult.getRequestId());
                 sysUploadEntity.setUser_id(httpRequestUtil.getUserId());
                 sysUploadEntity.setObject_key(uploadResult.getKey());
                 sysUploadEntity.setName(FileNameUtil.getName(uploadResult.getKey()));
@@ -111,6 +87,7 @@ public class SysUploadServiceImpl implements SysUploadService {
                 sysUploadDao.insert(sysUploadEntity);
             } else {
                 // [更新] 上传文件记录
+                sysUploadEntity.setCategory_id(category_id);
                 sysUploadEntity.setUpdate_time(DateUtil.now());
                 sysUploadDao.updateById(sysUploadEntity);
             }
@@ -121,4 +98,26 @@ public class SysUploadServiceImpl implements SysUploadService {
         }
     }
 
+    /**
+     * 删除上传文件 (包括缩略图,如果有的话)
+     */
+    @Override
+    public Map<String, Object> removeUploadFile(SysUpload sysUpload) {
+
+        // [Delete] 删除文件记录
+        SysUpload entity = sysUploadDao.selectOne(new LambdaQueryWrapper<SysUpload>().eq(SysUpload::getObject_key, sysUpload.getObject_key()));
+        if (entity != null) {
+            sysUploadDao.delete(new LambdaQueryWrapper<SysUpload>().eq(SysUpload::getObject_key, sysUpload.getObject_key()));
+        }
+
+        // [异步任务] 创建一个 CompletableFuture 来执行异步任务
+        CompletableFuture.runAsync(() -> {
+            // [腾讯云] 删除对象
+            tencentCosService.deleteObject(sysUpload.getObject_key());
+            System.out.println("Delete cos object: " + sysUpload.getObject_key());
+        });
+
+        return Map.of("object_key", sysUpload.getObject_key());
+    }
+
 }