为了为文件上传增删改查(CRUD)API接口并带上版本号,可以按照以下方式设计URL和实现相应的功能。我们将为上传文件、获取文件列表、获取单个文件、删除文件和更新文件内容创建API端点。
API 设计
- POST /api/v1/files/upload:上传文件
- GET /api/v1/files:获取文件列表
- GET /api/v1/files/{filename}:获取单个文件
- DELETE /api/v1/files/{filename}:删除文件
- PUT /api/v1/files/{filename}:更新文件
完整的实现
1. 创建控制器 FileController
package com.example.fileuploaddemo.controller;import com.example.fileuploaddemo.service.FileStorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;@RestController
@RequestMapping("/api/v1/files")
public class FileController {@Autowiredprivate FileStorageService fileStorageService;@PostMapping("/upload")public ResponseEntity<Map<String, String>> uploadFile(@RequestParam("file") MultipartFile file) {String message;try {String fileName = fileStorageService.save(file);message = "Uploaded the file successfully: " + fileName;return ResponseEntity.status(HttpStatus.OK).body(Map.of("message", message));} catch (Exception e) {message = "Could not upload the file: " + file.getOriginalFilename() + "!";return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(Map.of("message", message));}}@GetMappingpublic ResponseEntity<List<String>> listFiles() {List<String> fileNames = fileStorageService.loadAll().map(Path::getFileName).map(Path::toString).collect(Collectors.toList());return ResponseEntity.status(HttpStatus.OK).body(fileNames);}@GetMapping("/{filename}")public ResponseEntity<Resource> getFile(@PathVariable String filename) {Resource file = fileStorageService.loadAsResource(filename);return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"").body(file);}@DeleteMapping("/{filename}")public ResponseEntity<Map<String, String>> deleteFile(@PathVariable String filename) {try {fileStorageService.delete(filename);return ResponseEntity.status(HttpStatus.OK).body(Map.of("message", "Deleted the file successfully: " + filename));} catch (Exception e) {return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(Map.of("message", "Could not delete the file: " + filename + "!"));}}@PutMapping("/{filename}")public ResponseEntity<Map<String, String>> updateFile(@PathVariable String filename, @RequestParam("file") MultipartFile file) {try {fileStorageService.update(filename, file);return ResponseEntity.status(HttpStatus.OK).body(Map.of("message", "Updated the file successfully: " + filename));} catch (Exception e) {return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(Map.of("message", "Could not update the file: " + filename + "!"));}}
}
2. 更新服务 FileStorageService
package com.example.fileuploaddemo.service;import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.nio.file.*;
import java.util.stream.Stream;@Service
public class FileStorageService {private final Path fileStorageLocation = Paths.get("uploads").toAbsolutePath().normalize();public FileStorageService() {try {Files.createDirectories(this.fileStorageLocation);} catch (Exception ex) {throw new RuntimeException("Could not create the directory where the uploaded files will be stored.", ex);}}public String save(MultipartFile file) {try {String fileName = file.getOriginalFilename();Path targetLocation = this.fileStorageLocation.resolve(fileName);Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);return fileName;} catch (IOException ex) {throw new RuntimeException("Could not store file " + file.getOriginalFilename() + ". Please try again!", ex);}}public Stream<Path> loadAll() {try {return Files.walk(this.fileStorageLocation, 1).filter(path -> !path.equals(this.fileStorageLocation)).map(this.fileStorageLocation::relativize);} catch (IOException ex) {throw new RuntimeException("Could not read the files!", ex);}}public Resource loadAsResource(String fileName) {try {Path filePath = this.fileStorageLocation.resolve(fileName).normalize();Resource resource = new UrlResource(filePath.toUri());if (resource.exists() || resource.isReadable()) {return resource;} else {throw new RuntimeException("Could not read the file: " + fileName);}} catch (MalformedURLException ex) {throw new RuntimeException("Could not read the file: " + fileName, ex);}}public void delete(String fileName) {try {Path filePath = this.fileStorageLocation.resolve(fileName).normalize();Files.deleteIfExists(filePath);} catch (IOException ex) {throw new RuntimeException("Could not delete the file: " + fileName, ex);}}public void update(String fileName, MultipartFile file) {try {Path targetLocation = this.fileStorageLocation.resolve(fileName);Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);} catch (IOException ex) {throw new RuntimeException("Could not update the file " + file.getOriginalFilename() + ". Please try again!", ex);}}
}
3. 主应用程序类
package com.example.fileuploaddemo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class FileUploadDemoApplication {public static void main(String[] args) {SpringApplication.run(FileUploadDemoApplication.class, args);}
}
4. 配置文件
在 src/main/resources
目录下的 application.properties
文件中添加任何需要的配置(通常不需要特别配置)。
测试
启动应用程序后,可以使用工具(如Postman)进行如下测试:
- 上传文件:POST
http://localhost:8080/api/v1/files/upload
,选择文件进行上传。 - 获取文件列表:GET
http://localhost:8080/api/v1/files
。 - 获取单个文件:GET
http://localhost:8080/api/v1/files/{filename}
。 - 删除文件:DELETE
http://localhost:8080/api/v1/files/{filename}
。 - 更新文件:PUT
http://localhost:8080/api/v1/files/{filename}
,选择新的文件进行更新。
总结
通过以上步骤,我们创建了一个文件上传接口并生成了增删改查的API。这个示例展示了如何使用Spring Boot处理文件的上传、存储、读取、删除和更新。可以根据需要扩展和调整此示例,以满足实际的业务需求。