import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import java.io.IOException;
import java.nio.file.*;
import java.util.UUID;
@Service
public class FileService {
@Value("${file.upload-dir:uploads}")
private String uploadDir;
/**
* 上传文件
* @param file 上传的文件
* @return 文件存储路径
* @throws IOException 文件操作异常
*/
public String uploadFile(MultipartFile file) throws IOException {
// 检查文件是否为空
if (file.isEmpty()) {
throw new IllegalArgumentException("文件不能为空");
}
// 检查文件大小(限制为10MB)
if (file.getSize() > 10 * 1024 * 1024) {
throw new IllegalArgumentException("文件大小不能超过10MB");
}
// 创建上传目录
Path uploadPath = Paths.get(uploadDir);
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
// 生成唯一文件名
String originalFilename = file.getOriginalFilename();
String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
String newFilename = UUID.randomUUID().toString() + fileExtension;
// 保存文件
Path filePath = uploadPath.resolve(newFilename);
Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
return filePath.toString();
}
/**
* 下载文件
* @param filename 文件名
* @return 文件资源
* @throws IOException 文件操作异常
*/
public ResponseEntity<Resource> downloadFile(String filename) throws IOException {
Path filePath = Paths.get(uploadDir).resolve(filename).normalize();
Resource resource = new UrlResource(filePath.toUri());
// 检查文件是否存在
if (!resource.exists() || !resource.isReadable()) {
throw new RuntimeException("文件不存在或不可读");
}
// 返回文件流
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
.body(resource);
}
/**
* 删除文件
* @param filename 文件名
* @return 操作结果
* @throws IOException 文件操作异常
*/
public boolean deleteFile(String filename) throws IOException {
Path filePath = Paths.get(uploadDir).resolve(filename).normalize();
// 检查文件是否存在
if (!Files.exists(filePath)) {
throw new RuntimeException("文件不存在");
}
// 删除文件
return Files.deleteIfExists(filePath);
}
/**
* 获取文件信息
* @param filename 文件名
* @return 文件大小(字节)
* @throws IOException 文件操作异常
*/
public long getFileSize(String filename) throws IOException {
Path filePath = Paths.get(uploadDir).resolve(filename).normalize();
if (!Files.exists(filePath)) {
throw new RuntimeException("文件不存在");
}
return Files.size(filePath);
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
@RestController
@RequestMapping("/api/files")
public class FileController {
@Autowired
private FileService fileService;
@PostMapping("/upload")
public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
try {
String filePath = fileService.uploadFile(file);
return ResponseEntity.ok("文件上传成功: " + filePath);
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("文件上传失败: " + e.getMessage());
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}
@GetMapping("/download/{filename}")
public ResponseEntity<?> downloadFile(@PathVariable String filename) {
try {
return fileService.downloadFile(filename);
} catch (RuntimeException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body("文件下载失败: " + e.getMessage());
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("文件下载失败: " + e.getMessage());
}
}
@DeleteMapping("/{filename}")
public ResponseEntity<String> deleteFile(@PathVariable String filename) {
try {
boolean deleted = fileService.deleteFile(filename);
return deleted ?
ResponseEntity.ok("文件删除成功") :
ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("文件删除失败");
} catch (RuntimeException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body("文件删除失败: " + e.getMessage());
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("文件删除失败: " + e.getMessage());
}
}
@GetMapping("/size/{filename}")
public ResponseEntity<?> getFileSize(@PathVariable String filename) {
try {
long size = fileService.getFileSize(filename);
return ResponseEntity.ok("文件大小: " + size + " 字节");
} catch (RuntimeException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body("获取文件大小失败: " + e.getMessage());
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("获取文件大小失败: " + e.getMessage());
}
}
}
文件存储目录:

application.properties中配置:file.upload-dir=uploads
./uploads,可通过配置修改依赖配置:
<!-pom.xml -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies>
文件上传:
文件下载:

文件管理:
安全性:
normalize())上传文件:

curl -X POST -F "file=@test.txt" http://localhost:8080/api/files/upload
下载文件:
curl -O http://localhost:8080/api/files/download/test.txt
删除文件:
curl -X DELETE http://localhost:8080/api/files/test.txt
获取文件大小:
curl http://localhost:8080/api/files/size/test.txt
这个实现提供了完整的文件操作基础功能,可以根据实际需求进行扩展和定制。