Bläddra i källkod

1.修改文件上传插件

1 2 veckor sedan
förälder
incheckning
a518242144

+ 5 - 0
imwork-commons/imwork-commons-core/src/main/java/top/imwork/commons/core/pojo/FileUploadRequest.java

@@ -27,6 +27,11 @@ public class FileUploadRequest {
      */
     private List<MultipartFile> files;
 
+    /**
+     * 原始文件名
+     */
+    private String fileName;
+
     /**
      * 业务类型(如:avatar, document, product等)
      */

+ 0 - 5
imwork-commons/imwork-commons-core/src/main/java/top/imwork/commons/core/pojo/FileUploadResponse.java

@@ -40,11 +40,6 @@ public class FileUploadResponse {
      */
     private String message;
 
-    /**
-     * 上传时间
-     */
-    private LocalDateTime uploadTime;
-
     /**
      * 上传结果列表(多文件时使用)
      */

+ 22 - 73
imwork-windows/imwork-silos/src/main/java/top/imwork/window/silos/controller/oss/FilesUploadController.java

@@ -10,6 +10,7 @@ import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
+import top.imwork.commons.core.enums.HttpStatusCodeEnum;
 import top.imwork.commons.core.pojo.ApiResponse;
 import top.imwork.commons.core.pojo.FileUploadRequest;
 import top.imwork.commons.core.pojo.FileUploadResponse;
@@ -17,6 +18,7 @@ import top.imwork.commons.core.pojo.ResponseMsg;
 import top.imwork.window.silos.service.oss.FileUploadServiceImpl;
 import top.imwork.window.silos.utils.SecurityUtils;
 
+import java.io.IOException;
 import java.util.List;
 
 /**
@@ -86,79 +88,26 @@ public class FilesUploadController {
      * 通用文件上传接口(支持单文件和双文件)
      * 使用JSON格式接收参数,文件通过Multipart上传
      */
-    @PostMapping("/upload")
-    public ResponseEntity<FileUploadResponse> uploadFile(
-            @Valid FileUploadRequest request) {
-
-        log.info("收到文件上传请求,业务类型:{},用户ID:{}",
-                request.getBusinessType(), request.getUserId());
-
-        FileUploadResponse response = fileUploadService.upload(request);
-
-        HttpStatus status = response.getSuccess() ?
-                HttpStatus.OK : HttpStatus.BAD_REQUEST;
-
-        return ResponseEntity.status(status).body(response);
-    }
-
-    /**
-     * 传统表单方式上传(单文件)
-     */
-    @PostMapping("/upload/single")
-    public ResponseEntity<FileUploadResponse> uploadSingleFile(
-            @RequestParam("file") @NotNull MultipartFile file,
-            @RequestParam(value = "businessType", required = false, defaultValue = "common") String businessType,
-            @RequestParam(value = "userId", required = false) Long userId,
-            @RequestParam(value = "description", required = false) String description) {
-
-        FileUploadResponse response = fileUploadService.uploadSingleFile(
-                file, businessType, userId, description);
-
-        return getResponseEntity(response);
-    }
-
-    /**
-     * 传统表单方式上传(多文件)
-     */
-    @PostMapping("/upload/multiple")
-    public ResponseEntity<FileUploadResponse> uploadMultipleFiles(
-            @RequestParam("files") @NotNull List<MultipartFile> files,
-            @RequestParam(value = "businessType", required = false, defaultValue = "common") String businessType,
-            @RequestParam(value = "userId", required = false) Long userId,
-            @RequestParam(value = "description", required = false) String description) {
-
-        FileUploadResponse response = fileUploadService.uploadMultipleFiles(
-                files, businessType, userId, description);
-
-        return getResponseEntity(response);
-    }
-
-    /**
-     * 简化版上传接口(最常用)
-     */
-    @PostMapping("/upload/simple")
-    public ResponseEntity<FileUploadResponse> uploadSimple(
-            @RequestParam(value = "file", required = false) MultipartFile file,
-            @RequestParam(value = "files", required = false) List<MultipartFile> files,
-            @RequestParam(value = "businessType", defaultValue = "common") String businessType) {
-
-        FileUploadRequest request = new FileUploadRequest();
-        if (file != null && !file.isEmpty()) {
-            request.setFile(file);
-        }
-        if (files != null && !files.isEmpty()) {
-            request.setFiles(files);
+    @PostMapping("/file/upload")
+    public ResponseMsg uploadFiles(@Valid FileUploadRequest request){
+        FileUploadResponse uploadResponse = null;
+        if (request.getFile() != null || !request.getFile().isEmpty()) {
+            // 2. 安全检查
+            String securityCheck = SecurityUtils.checkFileSecurity(request.getFile());
+            if (securityCheck != null) {
+                log.warn("文件安全检查失败: {}", securityCheck);
+                return ResponseMsg.buildResponse(HttpStatusCodeEnum.BAD_REQUEST.getCode(), securityCheck);
+            }
+            // 3. 上传文件
+            uploadResponse = fileUploadService.upload(request);
+            log.info("文件上传成功: {}", uploadResponse.getFilePath());
+            return ResponseMsg.buildResponse(uploadResponse);
+        } else if (!request.getFiles().isEmpty()) {
+            uploadResponse = fileUploadService.upload(request);
+            return ResponseMsg.buildResponse(uploadResponse);
+        } else {
+            // 1. 基础校验
+            return ResponseMsg.buildResponse(HttpStatusCodeEnum.BAD_REQUEST.getCode(), "文件不能为空");
         }
-        request.setBusinessType(businessType);
-
-        FileUploadResponse response = fileUploadService.upload(request);
-
-        return getResponseEntity(response);
-    }
-
-    private ResponseEntity<FileUploadResponse> getResponseEntity(FileUploadResponse response) {
-        HttpStatus status = response.getSuccess() ?
-                HttpStatus.OK : HttpStatus.BAD_REQUEST;
-        return ResponseEntity.status(status).body(response);
     }
 }

+ 55 - 20
imwork-windows/imwork-silos/src/main/java/top/imwork/window/silos/service/oss/FileUploadServiceImpl.java

@@ -72,10 +72,14 @@ public class FileUploadServiceImpl implements FileUploadService {
                 .fileType(file.getContentType())
                 .fileSize(file.getSize())
                 .fileHash(FileUtils.calculateFileHash(filePath.toFile()))
-                .uploadTime(LocalDateTime.now())
                 .build();
     }
 
+    /**
+     * 生成安全文件名
+     * @param originalFilename 原始文件名
+     * @return 安全文件名
+     */
     private String generateSafeFilename(String originalFilename) {
         String extension = FileUtils.getFileExtension(originalFilename);
         String baseName = originalFilename.substring(0, originalFilename.lastIndexOf('.'));
@@ -111,21 +115,56 @@ public class FileUploadServiceImpl implements FileUploadService {
     }
 
     @Override
-    public FileUploadResponse upload(FileUploadRequest request) {
+    public FileUploadResponse upload(FileUploadRequest request){
         FileUploadResponse response = new FileUploadResponse();
-        response.setUploadTime(LocalDateTime.now());
 
-        try {
+        //单一文件
+        if(!request.getFile().isEmpty()){
+            MultipartFile file = request.getFile();
+            // 1.生成安全文件名
+            String originalFilename = file.getOriginalFilename();
+            String fileExtension = FileUtils.getFileExtension(originalFilename);
+            String safeFilename = generateSafeFilename(originalFilename);
+            // 2.创建日期目录
+            String dateDir = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
+            String fullPath = uploadPath + dateDir + "/";
+            // 3.确保目录存在
+            Path directory = Paths.get(fullPath);
+            try {
+                Files.createDirectories(directory);
+                // 4.保存文件
+                Path filePath = directory.resolve(safeFilename);
+                Files.copy(file.getInputStream(), filePath);
+                // 5.生成文件URL
+                String fileUrl = "/uploads/" + dateDir + "/" + safeFilename;
+                // 6.二次安全检查(文件内容检查)
+                if (!SecurityUtils.isFileContentSafe(filePath.toFile())) {
+                    // 删除危险文件
+                    Files.deleteIfExists(filePath);
+                    throw new SecurityException("文件内容包含危险代码");
+                }
+                // 返回文件信息
+                return FileUploadResponse.builder()
+                        .fileName(originalFilename)
+                        .filePath(filePath.toString())
+                        .fileUrl(fileUrl)
+                        .fileType(file.getContentType())
+                        .fileSize(file.getSize())
+                        .fileHash(FileUtils.calculateFileHash(filePath.toFile()))
+                        .build();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        //多文件
+        else if(!request.getFiles().isEmpty()){
             List<MultipartFile> filesToUpload = getFilesFromRequest(request);
-
             if (filesToUpload.isEmpty()) {
                 response.setSuccess(false);
                 response.setMessage("未接收到任何文件");
                 return response;
             }
-
             List<FileUploadResponse.FileInfo> fileInfos = new ArrayList<>();
-
             for (MultipartFile file : filesToUpload) {
                 FileUploadResponse.FileInfo fileInfo = uploadSingleFileInternal(
                         file,
@@ -135,14 +174,12 @@ public class FileUploadServiceImpl implements FileUploadService {
                 );
                 fileInfos.add(fileInfo);
             }
-
             // 检查上传结果
             long successCount = fileInfos.stream()
                     .filter(FileUploadResponse.FileInfo::getUploadSuccess)
                     .count();
 
             response.setFileInfos(fileInfos);
-
             if (successCount == filesToUpload.size()) {
                 response.setSuccess(true);
                 response.setMessage("所有文件上传成功");
@@ -153,20 +190,18 @@ public class FileUploadServiceImpl implements FileUploadService {
                 response.setSuccess(false);
                 response.setMessage("所有文件上传失败");
             }
+            return response;
+        }else{
 
-            // 如果是单文件,也设置fileInfo字段
-            if (filesToUpload.size() == 1) {
-                response.setFileInfo(fileInfos.get(0));
-            }
-
-        } catch (Exception e) {
-            log.error("文件上传失败", e);
-            response.setSuccess(false);
-            response.setMessage("上传失败:" + e.getMessage());
+            return response;
         }
-
-        return response;
     }
+
+    /**
+     * 读取表单中的文件
+     * @param request 表单数据
+     * @return 文件列表
+     */
     private List<MultipartFile> getFilesFromRequest(FileUploadRequest request) {
         List<MultipartFile> files = new ArrayList<>();
 

+ 0 - 1
imwork-windows/imwork-silos/src/main/java/top/imwork/window/silos/utils/SecurityUtils.java

@@ -7,7 +7,6 @@ import org.springframework.web.multipart.MultipartFile;
 import java.io.File;
 import java.io.IOException;
 import java.nio.file.Files;
-import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.List;
 /**

+ 4 - 4
imwork-windows/imwork-silos/src/main/resources/static/assets/library/jplugins/filesUpload/js/compactUpload.js

@@ -328,6 +328,7 @@
         // 实际的上传代码(注释掉,需要后端接口)
         const formData = new FormData();
         formData.append('file', this.file);
+        formData.append('files', this.file);
         formData.append('fileName', this.file.name);
         setTimeout(() => {
             $.ajax({
@@ -344,15 +345,14 @@
                     return xhr;
                 },
                 success: function(response) {
-                    if (response.success) {
+                    if (response.code === 200) {
                         const mockResponse = {
                             success: true,
                             message: '文件上传成功',
                             filePath: response.data.filePath,
                             fileHash: response.data.fileHash,
-                            fileName: this.file.name,
-                            fileSize: this.file.size,
-                            uploadId: this.settings.uploadId,
+                            fileName: response.data.fileName,
+                            fileSize: response.data.fileSize,
                             uploadedAt: new Date().toISOString()
                         };
 

+ 1 - 1
imwork-windows/imwork-silos/src/main/resources/static/business/cms/book/info/js/update.js

@@ -8,7 +8,7 @@ function compactUpload(){
     // 初始化紧凑型上传插件
     $('#compactUpload').compactUpload({
         uploadId: 'coverImage',
-        uploadApi: '/api/upload',
+        uploadApi: '/api/file/upload',
         allowedTypes: 'image/*,.pdf,.doc,.docx,.txt',
         maxSize: 100,
         blockedExtensions: ['exe', 'bat', 'cmd', 'sh', 'php', 'js', 'py'],