Преглед изворни кода

Merge remote-tracking branch 'origin/master'

lixiaolong пре 2 месеци
родитељ
комит
4173708a09
1 измењених фајлова са 62 додато и 15 уклоњено
  1. 62 15
      platform/src/main/java/com/jzg/controller/FileUploadController.java

+ 62 - 15
platform/src/main/java/com/jzg/controller/FileUploadController.java

@@ -12,6 +12,7 @@ import com.jzg.commons.util.idgen.IdGenerate;
 import com.jzg.mapper.SysUploadFilesMapper;
 import io.minio.*;
 import io.swagger.v3.oas.annotations.Operation;
+import lombok.extern.slf4j.Slf4j;
 import org.jetbrains.annotations.NotNull;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -31,6 +32,7 @@ import java.time.LocalDateTime;
 
 @RestController
 @RequestMapping("/file")
+@Slf4j
 public class FileUploadController extends BaseController {
 
 
@@ -57,42 +59,72 @@ public class FileUploadController extends BaseController {
     public HttpResult uploadFile(@RequestParam("file") MultipartFile file) {
         System.out.printf("调用文件上传接口");
         try {
-            // 获取文件原始名称和扩展名
+            // 获取文件原始名称,用于后续生成对象名
             String originalFileName = file.getOriginalFilename();
+            // 获取文件扩展名(含点号,如 ".jpg"),用于判断文件类型和生成对象名
             String extension = getFileExtension(originalFileName);
+            // 获取文件原始大小,用于压缩效果对比
             long originalSize = file.getSize();
+            // 获取文件的 Content-Type,用于判断是否为图片类型
+            String contentType = file.getContentType();
 
-            // 判断是否为图片文件,若是则进行压缩
-            // 双重校验:通过 Content-Type 和文件扩展名判断
+            // 压缩后的字节数组,初始为null表示未压缩或压缩失败
             byte[] compressedBytes = null;
-            if (ImageUtil.isImage(file.getContentType()) || ImageUtil.isImageExtension(extension)) {
+            // 压缩后的文件扩展名,默认使用原扩展名,PNG转JPEG时会更新
+            String compressedExtension = extension;
+            // 压缩后的 Content-Type,默认使用原类型,PNG转JPEG时会更新
+            String compressedContentType = contentType;
+
+            // 判断是否为图片文件(双重校验:Content-Type 和扩展名)
+            // 图片文件需要进行压缩处理,非图片文件直接上传
+            if (ImageUtil.isImage(contentType) || ImageUtil.isImageExtension(extension)) {
                 compressedBytes = ImageUtil.compressImage(file);
             }
 
+            // 检查压缩结果:压缩成功且压缩后文件不为空
             if (compressedBytes != null && compressedBytes.length > 0) {
-                System.out.printf("图片压缩前大小: %d bytes, 压缩后大小: %d bytes%n", originalSize, compressedBytes.length);
+                // 打印压缩前后大小对比,便于调试和监控压缩效果
+                log.info("图片压缩前大小: {} bytes, 压缩后大小: {} bytes", originalSize, compressedBytes.length);
 
+                // 判断压缩是否有效:如果压缩后文件比原图大或相等,则视为压缩无效
+                // 此时回退到使用原文件上传,避免上传更大的文件
                 if (compressedBytes.length >= originalSize) {
-                    System.out.printf("警告:压缩后图片(%d bytes)比原图(%d bytes)大,使用原图片上传%n", compressedBytes.length, originalSize);
+                    log.info("警告:压缩后图片({} bytes)比原图{} bytes)大,使用原图片上传", compressedBytes.length, originalSize);
                     compressedBytes = null;
                 }
             }
 
-            String fileMd5;
-            String fileEtag;
-            String objectName;
+            // 声明文件哈希值和对象名变量
+            String fileMd5;      // 文件MD5值,用于唯一标识文件
+            String fileEtag;     // 文件ETag值,用于MinIO文件校验
+            String objectName;   // MinIO中的对象名称
 
+            // 根据是否压缩成功,选择不同的处理路径
             if (compressedBytes != null && compressedBytes.length > 0) {
-                // 生成对象名
+                // 压缩成功:基于压缩后的字节数组计算哈希值
                 fileMd5 = FileUtils.getFileMD5(compressedBytes);
                 fileEtag = FileUtils.getFileETag(compressedBytes);
-                objectName = generateObjectName(originalFileName, fileMd5, extension);
+
+                // 特殊处理:当原文件是PNG格式,但压缩后实际是JPEG格式时
+                // 需要更新扩展名和Content-Type,确保文件类型与内容一致
+                // 这是因为ImageUtil在PNG压缩无效时会尝试转为JPEG格式
+                if (".png".equalsIgnoreCase(extension) && isJpegContent(compressedBytes)) {
+                    compressedExtension = ".jpg";
+                    compressedContentType = "image/jpeg";
+                    log.info("PNG图片转换为JPEG格式,扩展名从 {} 变为 {}", extension, compressedExtension);
+                }
+
+                // 使用压缩后的扩展名生成MinIO对象名
+                objectName = generateObjectName(originalFileName, fileMd5, compressedExtension);
             } else {
+                // 压缩失败或非图片文件:基于原文件计算哈希值
                 fileMd5 = FileUtils.getFileMD5(file);
                 fileEtag = FileUtils.getFileETag(file);
+                // 使用原扩展名生成MinIO对象名
                 objectName = generateObjectName(originalFileName, fileMd5, extension);
             }
 
+//            // 检查文件是否已存在于MinIO(功能已注释,如需启用请取消注释)
 //            if (isFileExistsInMinIo(objectName, fileEtag)) {
 //                return HttpResult.ok(getFileFromDatabase(fileEtag,objectName, extension));
 //            }
@@ -100,8 +132,10 @@ public class FileUploadController extends BaseController {
             // 根据是否压缩成功,选择对应的上传方式
             SysUploadFiles sysUploadFiles;
             if (compressedBytes != null && compressedBytes.length > 0) {
-                sysUploadFiles = uploadFileToMinIo(compressedBytes, objectName, fileEtag, extension, file.getContentType());
+                // 上传压缩后的图片字节数组(使用更新后的扩展名和Content-Type)
+                sysUploadFiles = uploadFileToMinIo(compressedBytes, objectName, fileEtag, compressedExtension, compressedContentType);
             } else {
+                // 上传原始文件(非图片或压缩失败时回退)
                 sysUploadFiles = uploadFileToMinIo(file, objectName, fileEtag, extension);
             }
             return HttpResult.ok(sysUploadFiles);
@@ -111,6 +145,22 @@ public class FileUploadController extends BaseController {
         }
     }
 
+    /**
+     * 判断字节数组是否为JPEG格式的图片内容
+     * 通过检测文件魔数(Magic Number)来判断:JPEG的魔数是 FF D8 FF
+     *
+     * @param data 待检测的字节数组
+     * @return 是否为JPEG格式内容
+     */
+    private boolean isJpegContent(byte[] data) {
+        // 参数校验:数据为空或长度不足3字节,无法包含完整的JPEG魔数
+        if (data == null || data.length < 3) {
+            return false;
+        }
+        // JPEG格式魔数检测:FF D8 FF
+        return data[0] == (byte) 0xFF && data[1] == (byte) 0xD8 && data[2] == (byte) 0xFF;
+    }
+
     @PostMapping("/uploadUrl")
     @Operation(summary = "网络文件上传接口", description = "文件上传接口")
     public HttpResult<SysUploadFiles> uploadUrlFile(String urlString, String fileName) {
@@ -237,7 +287,6 @@ public class FileUploadController extends BaseController {
                 .stream(fileInputStream, file.getSize(), -1)
                 .contentType(file.getContentType())
                 .build());
-
         return insertSysUploadFiles(objectName, extension, objectWriteResponse);
     }
 
@@ -249,7 +298,6 @@ public class FileUploadController extends BaseController {
                 .stream(fileInputStream, fileBytes.length, -1)
                 .contentType(contentType)
                 .build());
-
         return insertSysUploadFiles(objectName, extension, objectWriteResponse);
     }
 
@@ -262,7 +310,6 @@ public class FileUploadController extends BaseController {
                 .stream(fileInputStream, contentLength, -1)
                 .contentType(contentType)
                 .build());
-
         return insertSysUploadFiles(objectName, extension, objectWriteResponse);
     }