|
@@ -1,135 +1,82 @@
|
|
|
package com.yingpai.gupiao.controller;
|
|
package com.yingpai.gupiao.controller;
|
|
|
|
|
|
|
|
import com.yingpai.gupiao.domain.vo.Result;
|
|
import com.yingpai.gupiao.domain.vo.Result;
|
|
|
|
|
+import com.yingpai.gupiao.service.OssService;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
-import org.springframework.beans.factory.annotation.Value;
|
|
|
|
|
import org.springframework.web.bind.annotation.*;
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
|
|
|
|
|
-import java.io.IOException;
|
|
|
|
|
-import java.nio.file.Files;
|
|
|
|
|
-import java.nio.file.Path;
|
|
|
|
|
-import java.nio.file.Paths;
|
|
|
|
|
-import java.time.LocalDate;
|
|
|
|
|
-import java.time.format.DateTimeFormatter;
|
|
|
|
|
import java.util.HashMap;
|
|
import java.util.HashMap;
|
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
|
-import java.util.UUID;
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 文件上传控制器
|
|
* 文件上传控制器
|
|
|
- * 处理文件上传请求(头像、图片等)
|
|
|
|
|
|
|
+ * 使用OSS存储(读取RuoYi后台的OSS配置)
|
|
|
*/
|
|
*/
|
|
|
@Slf4j
|
|
@Slf4j
|
|
|
@RestController
|
|
@RestController
|
|
|
@RequiredArgsConstructor
|
|
@RequiredArgsConstructor
|
|
|
@RequestMapping("/v1/file")
|
|
@RequestMapping("/v1/file")
|
|
|
public class FileUploadController {
|
|
public class FileUploadController {
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 文件上传根目录(从配置文件读取)
|
|
|
|
|
- */
|
|
|
|
|
- @Value("${file.upload.path:/uploads}")
|
|
|
|
|
- private String uploadPath;
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 文件访问URL前缀(从配置文件读取)
|
|
|
|
|
- */
|
|
|
|
|
- @Value("${file.access.url:http://localhost:8080}")
|
|
|
|
|
- private String accessUrl;
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 允许的图片格式
|
|
|
|
|
- */
|
|
|
|
|
|
|
+
|
|
|
|
|
+ private final OssService ossService;
|
|
|
|
|
+
|
|
|
private static final String[] ALLOWED_EXTENSIONS = {".jpg", ".jpeg", ".png", ".gif", ".webp"};
|
|
private static final String[] ALLOWED_EXTENSIONS = {".jpg", ".jpeg", ".png", ".gif", ".webp"};
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 最大文件大小(5MB)
|
|
|
|
|
- */
|
|
|
|
|
private static final long MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
private static final long MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 文件上传接口
|
|
* 文件上传接口
|
|
|
- * 接口路径:POST /v1/file/upload
|
|
|
|
|
- *
|
|
|
|
|
- * @param file 上传的文件
|
|
|
|
|
- * @return 文件访问URL
|
|
|
|
|
*/
|
|
*/
|
|
|
@PostMapping("/upload")
|
|
@PostMapping("/upload")
|
|
|
public Result<Map<String, String>> uploadFile(@RequestParam("file") MultipartFile file) {
|
|
public Result<Map<String, String>> uploadFile(@RequestParam("file") MultipartFile file) {
|
|
|
log.info("文件上传请求,文件名: {}, 大小: {} bytes", file.getOriginalFilename(), file.getSize());
|
|
log.info("文件上传请求,文件名: {}, 大小: {} bytes", file.getOriginalFilename(), file.getSize());
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
- // 1. 验证文件
|
|
|
|
|
validateFile(file);
|
|
validateFile(file);
|
|
|
-
|
|
|
|
|
- // 2. 生成文件名和路径
|
|
|
|
|
|
|
+
|
|
|
|
|
+ String fileUrl = ossService.upload(file);
|
|
|
String originalFilename = file.getOriginalFilename();
|
|
String originalFilename = file.getOriginalFilename();
|
|
|
- String extension = getFileExtension(originalFilename);
|
|
|
|
|
- String newFilename = UUID.randomUUID().toString() + extension;
|
|
|
|
|
-
|
|
|
|
|
- // 按日期分目录存储:/uploads/2024/01/15/xxx.jpg
|
|
|
|
|
- String dateDir = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
|
|
|
|
|
- String relativePath = dateDir + "/" + newFilename;
|
|
|
|
|
-
|
|
|
|
|
- // 3. 创建目录
|
|
|
|
|
- Path uploadDir = Paths.get(uploadPath, dateDir);
|
|
|
|
|
- if (!Files.exists(uploadDir)) {
|
|
|
|
|
- Files.createDirectories(uploadDir);
|
|
|
|
|
- log.info("创建上传目录: {}", uploadDir);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 4. 保存文件
|
|
|
|
|
- Path filePath = uploadDir.resolve(newFilename);
|
|
|
|
|
- file.transferTo(filePath.toFile());
|
|
|
|
|
- log.info("文件保存成功: {}", filePath);
|
|
|
|
|
-
|
|
|
|
|
- // 5. 构建访问URL
|
|
|
|
|
- String fileUrl = accessUrl + "/uploads/" + relativePath;
|
|
|
|
|
-
|
|
|
|
|
- // 6. 返回结果
|
|
|
|
|
|
|
+
|
|
|
Map<String, String> result = new HashMap<>();
|
|
Map<String, String> result = new HashMap<>();
|
|
|
result.put("url", fileUrl);
|
|
result.put("url", fileUrl);
|
|
|
- result.put("filename", newFilename);
|
|
|
|
|
|
|
+ result.put("filename", fileUrl.substring(fileUrl.lastIndexOf("/") + 1));
|
|
|
result.put("originalFilename", originalFilename);
|
|
result.put("originalFilename", originalFilename);
|
|
|
-
|
|
|
|
|
- log.info("文件上传成功,访问URL: {}", fileUrl);
|
|
|
|
|
|
|
+
|
|
|
|
|
+ log.info("文件上传成功: {}", fileUrl);
|
|
|
return Result.success(result);
|
|
return Result.success(result);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
} catch (IllegalArgumentException e) {
|
|
} catch (IllegalArgumentException e) {
|
|
|
- log.error("文件验证失败", e);
|
|
|
|
|
|
|
+ log.error("文件验证失败: {}", e.getMessage());
|
|
|
return Result.error(e.getMessage());
|
|
return Result.error(e.getMessage());
|
|
|
- } catch (IOException e) {
|
|
|
|
|
- log.error("文件保存失败", e);
|
|
|
|
|
- return Result.error("文件上传失败:" + e.getMessage());
|
|
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
- log.error("文件上传异常", e);
|
|
|
|
|
- return Result.error("文件上传失败:" + e.getMessage());
|
|
|
|
|
|
|
+ log.warn("OSS上传失败,返回默认头像: {}", e.getMessage());
|
|
|
|
|
+ // OSS上传失败,返回默认头像
|
|
|
|
|
+ Map<String, String> result = new HashMap<>();
|
|
|
|
|
+ result.put("url", "/static/images/head.png");
|
|
|
|
|
+ result.put("filename", "head.png");
|
|
|
|
|
+ result.put("originalFilename", file.getOriginalFilename());
|
|
|
|
|
+ return Result.success(result);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 验证文件
|
|
|
|
|
- */
|
|
|
|
|
|
|
+
|
|
|
private void validateFile(MultipartFile file) {
|
|
private void validateFile(MultipartFile file) {
|
|
|
- // 检查文件是否为空
|
|
|
|
|
if (file == null || file.isEmpty()) {
|
|
if (file == null || file.isEmpty()) {
|
|
|
throw new IllegalArgumentException("文件不能为空");
|
|
throw new IllegalArgumentException("文件不能为空");
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // 检查文件大小
|
|
|
|
|
if (file.getSize() > MAX_FILE_SIZE) {
|
|
if (file.getSize() > MAX_FILE_SIZE) {
|
|
|
throw new IllegalArgumentException("文件大小不能超过5MB");
|
|
throw new IllegalArgumentException("文件大小不能超过5MB");
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // 检查文件扩展名
|
|
|
|
|
|
|
+
|
|
|
String originalFilename = file.getOriginalFilename();
|
|
String originalFilename = file.getOriginalFilename();
|
|
|
if (originalFilename == null || originalFilename.isEmpty()) {
|
|
if (originalFilename == null || originalFilename.isEmpty()) {
|
|
|
throw new IllegalArgumentException("文件名不能为空");
|
|
throw new IllegalArgumentException("文件名不能为空");
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- String extension = getFileExtension(originalFilename).toLowerCase();
|
|
|
|
|
|
|
+
|
|
|
|
|
+ String extension = originalFilename.contains(".")
|
|
|
|
|
+ ? originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase()
|
|
|
|
|
+ : "";
|
|
|
|
|
+
|
|
|
boolean isAllowed = false;
|
|
boolean isAllowed = false;
|
|
|
for (String allowedExt : ALLOWED_EXTENSIONS) {
|
|
for (String allowedExt : ALLOWED_EXTENSIONS) {
|
|
|
if (extension.equals(allowedExt)) {
|
|
if (extension.equals(allowedExt)) {
|
|
@@ -137,25 +84,8 @@ public class FileUploadController {
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
if (!isAllowed) {
|
|
if (!isAllowed) {
|
|
|
throw new IllegalArgumentException("不支持的文件格式,仅支持:jpg、jpeg、png、gif、webp");
|
|
throw new IllegalArgumentException("不支持的文件格式,仅支持:jpg、jpeg、png、gif、webp");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 获取文件扩展名
|
|
|
|
|
- */
|
|
|
|
|
- private String getFileExtension(String filename) {
|
|
|
|
|
- if (filename == null || filename.isEmpty()) {
|
|
|
|
|
- return "";
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- int lastDotIndex = filename.lastIndexOf('.');
|
|
|
|
|
- if (lastDotIndex == -1) {
|
|
|
|
|
- return "";
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return filename.substring(lastDotIndex);
|
|
|
|
|
- }
|
|
|
|
|
}
|
|
}
|