fix: 修复文件上传接口
This commit is contained in:
parent
f6679fd11a
commit
0a5b2696c2
@ -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
|
||||||
@ -26,9 +28,42 @@ import java.util.UUID;
|
|||||||
@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,10 +105,10 @@ 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;
|
||||||
@ -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;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user