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.time.LocalDate;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@RestController
@ -26,9 +28,42 @@ import java.util.UUID;
@CrossOrigin
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/}")
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<Resource> getImage(HttpServletRequest request) throws IOException {
String path = request.getRequestURI().replace("/api/upload/image", "");
@ -70,10 +105,10 @@ 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;
@ -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;