From 0a5b2696c235595c048de13809b5eec7b1f13336 Mon Sep 17 00:00:00 2001 From: MaDaLei Date: Fri, 17 Apr 2026 13:09:22 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../petstore/controller/FileController.java | 63 ++++++++++++++++--- 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/petstore/controller/FileController.java b/src/main/java/com/petstore/controller/FileController.java index 81feb33..c82231c 100644 --- a/src/main/java/com/petstore/controller/FileController.java +++ b/src/main/java/com/petstore/controller/FileController.java @@ -17,7 +17,9 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.time.LocalDate; import java.util.HashMap; +import java.util.Locale; import java.util.Map; +import java.util.Set; import java.util.UUID; @RestController @@ -25,10 +27,43 @@ import java.util.UUID; @RequiredArgsConstructor @CrossOrigin public class FileController { - + + private static final Set IMAGE_EXT = Set.of( + ".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".heic", ".heif", ".jpe" + ); + private static final Set VIDEO_EXT = Set.of( + ".mp4", ".mov", ".m4v", ".webm", ".avi", ".mkv", ".3gp" + ); + @Value("${upload.path:uploads/}") private String uploadPath; + /** + * 微信小程序 uni.uploadFile 常为 application/octet-stream;须优先认扩展名,再认 MIME。 + */ + static boolean isAllowedMediaType(String contentType, String originalFilename) { + if (hasMediaExtension(originalFilename)) { + return true; + } + if (contentType == null || contentType.isBlank()) { + return false; + } + String ct = contentType.toLowerCase(Locale.ROOT).trim(); + if (ct.startsWith("image/") || ct.startsWith("video/")) { + return true; + } + // 微信客户端上传常见:无正确 MIME,按二进制传 + return "application/octet-stream".equals(ct); + } + + private static boolean hasMediaExtension(String originalFilename) { + if (originalFilename == null || !originalFilename.contains(".")) { + return false; + } + String ext = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase(Locale.ROOT); + return IMAGE_EXT.contains(ext) || VIDEO_EXT.contains(ext); + } + @GetMapping("/image/**") public ResponseEntity getImage(HttpServletRequest request) throws IOException { String path = request.getRequestURI().replace("/api/upload/image", ""); @@ -70,15 +105,15 @@ public class FileController { return result; } + String originalFilename = file.getOriginalFilename(); String contentType = file.getContentType(); - boolean isImage = contentType != null && contentType.startsWith("image/"); - boolean isVideo = contentType != null && contentType.startsWith("video/"); - if (!isImage && !isVideo) { + + if (!isAllowedMediaType(contentType, originalFilename)) { result.put("code", 400); result.put("message", "只能上传图片或视频"); return result; } - + try { // 创建上传目录 String datePath = LocalDate.now().toString().replace("-", "/"); @@ -87,16 +122,26 @@ public class FileController { if (!dir.exists()) dir.mkdirs(); // 生成文件名 - String originalFilename = file.getOriginalFilename(); String ext = ""; if (originalFilename != null && originalFilename.contains(".")) { - ext = originalFilename.substring(originalFilename.lastIndexOf(".")); + ext = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase(Locale.ROOT); + if (ext.length() > 10) { + ext = ""; + } + } + if (ext.isEmpty()) { + boolean looksVideo = contentType != null && contentType.toLowerCase(Locale.ROOT).startsWith("video/"); + // application/octet-stream 且无扩展名时,大文件更可能是视频 + if (!looksVideo && "application/octet-stream".equalsIgnoreCase(String.valueOf(contentType).trim())) { + looksVideo = file.getSize() > 3 * 1024 * 1024L; + } + ext = looksVideo ? ".mp4" : ".jpg"; } String filename = UUID.randomUUID().toString().replace("-", "") + ext; - // 保存文件 + // 保存文件(流式写入,避免大视频一次性进内存) Path filePath = Paths.get(dirPath, filename); - Files.write(filePath, file.getBytes()); + file.transferTo(filePath.toFile()); // 返回访问URL(/api/upload/image/ + 日期路径 + 文件名) String url = "/api/upload/image/" + datePath + "/" + filename;