172 lines
6.3 KiB
Java

package com.designhub.controller;
import com.designhub.common.Result;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.PostConstruct;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
/**
* 文件上传Controller
*/
@Slf4j
@RestController
@RequestMapping("/api/upload")
@Tag(name = "文件上传", description = "文件上传相关API")
public class UploadController {
@Value("${file.upload.path:./uploads}")
private String uploadPath;
@Value("${file.upload.max-size:52428800}")
private long maxSize;
@Value("${file.upload.allowed-extensions:.xls,.xlsx,.doc,.docx,.pdf,.zip}")
private String allowedExtensions;
private static final Set<String> ALLOWED_EXTENSIONS_SET = new HashSet<>();
@PostConstruct
public void init() {
String[] extensions = allowedExtensions.split(",");
for (String ext : extensions) {
ALLOWED_EXTENSIONS_SET.add(ext.trim().toLowerCase());
}
// 确保上传目录存在
try {
Path path = Paths.get(uploadPath);
if (!Files.exists(path)) {
Files.createDirectories(path);
log.info("创建上传目录: {}", uploadPath);
}
} catch (IOException e) {
log.error("创建上传目录失败: {}", e.getMessage());
}
}
/**
* 上传文件
*/
@PostMapping("/file")
@Operation(summary = "上传文件", description = "支持Excel、Word、PDF、ZIP等格式")
public Result<Map<String, Object>> uploadFile(@RequestParam("file") MultipartFile file) {
try {
// 验证文件
if (file == null || file.isEmpty()) {
return Result.error(400, "文件不能为空");
}
// 验证文件大小
if (file.getSize() > maxSize) {
return Result.error(400, String.format("文件大小不能超过 %d MB", maxSize / 1024 / 1024));
}
// 验证文件扩展名
String originalFilename = file.getOriginalFilename();
if (originalFilename == null || originalFilename.isEmpty()) {
return Result.error(400, "文件名不能为空");
}
String extension = getFileExtension(originalFilename);
if (!ALLOWED_EXTENSIONS_SET.contains(extension.toLowerCase())) {
return Result.error(400, String.format("不支持的文件格式,支持的格式:%s", allowedExtensions));
}
// 生成文件存储路径
String dateDir = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
String fileName = generateFileName(originalFilename);
String relativePath = dateDir + "/" + fileName;
String fullPath = uploadPath + "/" + relativePath;
// 确保目录存在
Path targetPath = Paths.get(fullPath);
Files.createDirectories(targetPath.getParent());
// 保存文件
file.transferTo(targetPath.toFile());
log.info("文件上传成功: originalName={}, savedPath={}, size={}",
originalFilename, fullPath, file.getSize());
// 构建返回数据
Map<String, Object> data = new HashMap<>();
data.put("fileName", originalFilename);
data.put("filePath", relativePath);
data.put("fileUrl", "/api/upload/download?path=" + relativePath);
data.put("fileSize", file.getSize());
data.put("fileType", extension);
return Result.success(data);
} catch (IOException e) {
log.error("文件上传失败: {}", e.getMessage(), e);
return Result.error(500, "文件上传失败: " + e.getMessage());
} catch (Exception e) {
log.error("文件上传异常: {}", e.getMessage(), e);
return Result.error(500, "文件上传异常: " + e.getMessage());
}
}
/**
* 下载文件
*/
@GetMapping("/download")
@Operation(summary = "下载文件", description = "根据文件路径下载文件")
public org.springframework.http.ResponseEntity<org.springframework.core.io.Resource> downloadFile(
@RequestParam("path") String filePath) {
try {
String fullPath = uploadPath + "/" + filePath;
Path path = Paths.get(fullPath);
if (!Files.exists(path)) {
return org.springframework.http.ResponseEntity.notFound().build();
}
org.springframework.core.io.Resource resource =
new org.springframework.core.io.UrlResource(path.toUri());
return org.springframework.http.ResponseEntity.ok()
.header(org.springframework.http.HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + resource.getFilename() + "\"")
.body(resource);
} catch (Exception e) {
log.error("文件下载失败: {}", e.getMessage(), e);
return org.springframework.http.ResponseEntity.internalServerError().build();
}
}
/**
* 获取文件扩展名
*/
private String getFileExtension(String filename) {
int lastDotIndex = filename.lastIndexOf('.');
if (lastDotIndex > 0 && lastDotIndex < filename.length() - 1) {
return filename.substring(lastDotIndex);
}
return "";
}
/**
* 生成唯一文件名
*/
private String generateFileName(String originalFilename) {
String extension = getFileExtension(originalFilename);
String nameWithoutExt = originalFilename.substring(0, originalFilename.lastIndexOf('.'));
String timestamp = String.valueOf(System.currentTimeMillis());
String random = UUID.randomUUID().toString().substring(0, 8);
return nameWithoutExt + "_" + timestamp + "_" + random + extension;
}
}