fix: 修复文件上传接口

This commit is contained in:
MaDaLei 2026-04-17 13:09:22 +08:00
parent f6679fd11a
commit 0a5b2696c2

View File

@ -17,7 +17,9 @@ import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
@RestController @RestController
@ -25,10 +27,43 @@ import java.util.UUID;
@RequiredArgsConstructor @RequiredArgsConstructor
@CrossOrigin @CrossOrigin
public class FileController { public class FileController {
private static final Set<String> IMAGE_EXT = Set.of(
".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".heic", ".heif", ".jpe"
);
private static final Set<String> VIDEO_EXT = Set.of(
".mp4", ".mov", ".m4v", ".webm", ".avi", ".mkv", ".3gp"
);
@Value("${upload.path:uploads/}") @Value("${upload.path:uploads/}")
private String uploadPath; 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/**") @GetMapping("/image/**")
public ResponseEntity<Resource> getImage(HttpServletRequest request) throws IOException { public ResponseEntity<Resource> getImage(HttpServletRequest request) throws IOException {
String path = request.getRequestURI().replace("/api/upload/image", ""); String path = request.getRequestURI().replace("/api/upload/image", "");
@ -70,15 +105,15 @@ public class FileController {
return result; return result;
} }
String originalFilename = file.getOriginalFilename();
String contentType = file.getContentType(); String contentType = file.getContentType();
boolean isImage = contentType != null && contentType.startsWith("image/");
boolean isVideo = contentType != null && contentType.startsWith("video/"); if (!isAllowedMediaType(contentType, originalFilename)) {
if (!isImage && !isVideo) {
result.put("code", 400); result.put("code", 400);
result.put("message", "只能上传图片或视频"); result.put("message", "只能上传图片或视频");
return result; return result;
} }
try { try {
// 创建上传目录 // 创建上传目录
String datePath = LocalDate.now().toString().replace("-", "/"); String datePath = LocalDate.now().toString().replace("-", "/");
@ -87,16 +122,26 @@ public class FileController {
if (!dir.exists()) dir.mkdirs(); if (!dir.exists()) dir.mkdirs();
// 生成文件名 // 生成文件名
String originalFilename = file.getOriginalFilename();
String ext = ""; String ext = "";
if (originalFilename != null && originalFilename.contains(".")) { 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; String filename = UUID.randomUUID().toString().replace("-", "") + ext;
// 保存文件 // 保存文件流式写入避免大视频一次性进内存
Path filePath = Paths.get(dirPath, filename); Path filePath = Paths.get(dirPath, filename);
Files.write(filePath, file.getBytes()); file.transferTo(filePath.toFile());
// 返回访问URL/api/upload/image/ + 日期路径 + 文件名 // 返回访问URL/api/upload/image/ + 日期路径 + 文件名
String url = "/api/upload/image/" + datePath + "/" + filename; String url = "/api/upload/image/" + datePath + "/" + filename;