> 技术文档 > Spring Boot 后端接收多个文件的方法

Spring Boot 后端接收多个文件的方法


Spring Boot 后端接收多个文件的方法

在 Spring Boot 中接收多个文件有多种方式,下面我将详细介绍各种方法及其实现。

1. 使用 MultipartFile 数组接收

这是最直接的方式,适用于前端使用相同字段名上传多个文件的情况。

java

@RestController@RequestMapping(\"/api/upload\")public class FileUploadController { @PostMapping(\"/multiple\") public ResponseEntity uploadMultipleFiles( @RequestParam(\"files\") MultipartFile[] files) { if (files.length == 0) { return ResponseEntity.badRequest().body(\"请选择至少一个文件\"); } try { for (MultipartFile file : files) { if (!file.isEmpty()) {  // 保存文件到指定位置  String fileName = StringUtils.cleanPath(file.getOriginalFilename());  Path path = Paths.get(\"uploads\", fileName);  Files.createDirectories(path.getParent());  Files.write(path, file.getBytes());  // 可以在这里添加文件信息到数据库等操作 } } return ResponseEntity.ok(\"成功上传 \" + files.length + \" 个文件\"); } catch (IOException e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)  .body(\"文件上传失败: \" + e.getMessage()); } }}

2. 使用 MultipartFile 列表接收

与数组方式类似,但使用列表可能在某些情况下更方便。

java

@PostMapping(\"/multiple-list\")public ResponseEntity uploadMultipleFilesList( @RequestParam(\"files\") List files) { if (files == null || files.isEmpty()) { return ResponseEntity.badRequest().body(\"请选择至少一个文件\"); } // 处理文件逻辑同上 // ... return ResponseEntity.ok(\"成功上传 \" + files.size() + \" 个文件\");}

3. 使用 DTO 对象接收文件和其他表单数据

当需要同时接收文件和其他表单数据时,可以使用 DTO 对象。

java

public class FileUploadDTO { private List files; private String category; private String description; // 构造函数、getter和setter public FileUploadDTO() {} public List getFiles() { return files; } public void setFiles(List files) { this.files = files; } // 其他getter和setter...}

java

@PostMapping(value = \"/with-data\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)public ResponseEntity uploadFilesWithData(FileUploadDTO fileUploadDTO) { List files = fileUploadDTO.getFiles(); String category = fileUploadDTO.getCategory(); String description = fileUploadDTO.getDescription(); if (files == null || files.isEmpty()) { return ResponseEntity.badRequest().body(\"请选择至少一个文件\"); } // 处理文件和其他数据 for (MultipartFile file : files) { if (!file.isEmpty()) { // 保存文件,同时可以使用category和description // ... } } return ResponseEntity.ok(\"成功上传 \" + files.size() + \" 个文件,分类: \" + category);}

4. 处理大文件和分块上传

对于大文件,可以使用分块上传的方式。

java

@PostMapping(\"/chunk\")public ResponseEntity uploadChunk( @RequestParam(\"file\") MultipartFile file, @RequestParam(\"chunkNumber\") int chunkNumber, @RequestParam(\"totalChunks\") int totalChunks, @RequestParam(\"originalFileName\") String originalFileName, @RequestParam(value = \"fileId\", required = false) String fileId) { try { // 生成唯一文件标识(如果未提供) String uniqueFileId = fileId != null ? fileId : UUID.randomUUID().toString(); // 创建临时目录存储分块 Path chunkPath = Paths.get(\"temp\", uniqueFileId, String.valueOf(chunkNumber)); Files.createDirectories(chunkPath.getParent()); Files.write(chunkPath, file.getBytes()); // 如果是最后一块,合并所有分块 if (chunkNumber == totalChunks - 1) { mergeChunks(uniqueFileId, totalChunks, originalFileName); return ResponseEntity.ok(\"文件上传完成\"); } return ResponseEntity.ok(\"分块上传成功\"); } catch (IOException e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(\"分块上传失败: \" + e.getMessage()); }}private void mergeChunks(String fileId, int totalChunks, String originalFileName) throws IOException { Path mergedPath = Paths.get(\"uploads\", originalFileName); Files.createDirectories(mergedPath.getParent()); try (OutputStream os = new FileOutputStream(mergedPath.toFile())) { for (int i = 0; i < totalChunks; i++) { Path chunkPath = Paths.get(\"temp\", fileId, String.valueOf(i)); Files.copy(chunkPath, os); // 删除已合并的分块 Files.deleteIfExists(chunkPath); } } // 删除临时目录 Path tempDir = Paths.get(\"temp\", fileId); Files.deleteIfExists(tempDir);}

5. 配置文件上传属性

在 application.properties 或 application.yml 中配置文件上传属性:

properties

# 配置文件上传大小限制spring.servlet.multipart.max-file-size=10MBspring.servlet.multipart.max-request-size=50MB# 启用多部分文件上传spring.servlet.multipart.enabled=true# 指定临时文件存储目录(可选)spring.servlet.multipart.location=/tmp

或者使用 YAML 格式:

yaml

spring: servlet: multipart: max-file-size: 10MB max-request-size: 50MB enabled: true location: /tmp

6. 自定义文件上传配置类

如果需要更高级的配置,可以创建一个配置类:

java

@Configurationpublic class FileUploadConfig { @Bean public MultipartConfigElement multipartConfigElement() { MultipartConfigFactory factory = new MultipartConfigFactory(); // 单个文件最大 factory.setMaxFileSize(DataSize.ofMegabytes(10)); // 总上传数据最大 factory.setMaxRequestSize(DataSize.ofMegabytes(50)); return factory.createMultipartConfig(); } @Bean public CommonsMultipartResolver multipartResolver() { CommonsMultipartResolver resolver = new CommonsMultipartResolver(); resolver.setDefaultEncoding(\"UTF-8\"); resolver.setMaxUploadSize(52428800); // 50MB resolver.setMaxUploadSizePerFile(10485760); // 10MB return resolver; }}

7. 完整的文件上传服务示例

下面是一个更完整的文件上传服务示例,包含异常处理和文件存储逻辑:

java

@Servicepublic class FileStorageService { private final Path fileStorageLocation; @Autowired public FileStorageService(FileStorageProperties fileStorageProperties) { this.fileStorageLocation = Paths.get(fileStorageProperties.getUploadDir()) .toAbsolutePath().normalize(); try { Files.createDirectories(this.fileStorageLocation); } catch (Exception ex) { throw new FileStorageException( \"无法创建文件存储目录\", ex); } } public String storeFile(MultipartFile file) { // 标准化文件名 String fileName = StringUtils.cleanPath(file.getOriginalFilename()); try { // 检查文件名是否包含非法字符 if (fileName.contains(\"..\")) { throw new FileStorageException(  \"抱歉! 文件名包含无效的路径序列 \" + fileName); } // 生成唯一文件名(避免重名覆盖) String uniqueFileName = UUID.randomUUID().toString() + \"_\" + fileName; // 复制文件到目标位置 Path targetLocation = this.fileStorageLocation.resolve(uniqueFileName); Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING); return uniqueFileName; } catch (IOException ex) { throw new FileStorageException( \"无法存储文件 \" + fileName + \". 请重试!\", ex); } } public Resource loadFileAsResource(String fileName) { try { Path filePath = this.fileStorageLocation.resolve(fileName).normalize(); Resource resource = new UrlResource(filePath.toUri()); if (resource.exists()) { return resource; } else { throw new FileNotFoundException(\"文件未找到 \" + fileName); } } catch (MalformedURLException ex) { throw new FileNotFoundException(\"文件未找到 \" + fileName); } }}

8. 异常处理

创建自定义异常和全局异常处理器:

java

public class FileStorageException extends RuntimeException { public FileStorageException(String message) { super(message); } public FileStorageException(String message, Throwable cause) { super(message, cause); }}@ControllerAdvicepublic class FileUploadExceptionAdvice { @ResponseBody @ExceptionHandler(MaxUploadSizeExceededException.class) @ResponseStatus(HttpStatus.PAYLOAD_TOO_LARGE) public String handleMaxSizeException(MaxUploadSizeExceededException exc) { return \"文件太大! 最大允许大小是 10MB\"; } @ResponseBody @ExceptionHandler(FileStorageException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public String handleFileStorageException(FileStorageException exc) { return \"文件存储错误: \" + exc.getMessage(); } @ResponseBody @ExceptionHandler(MultipartException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public String handleMultipartException(MultipartException exc) { return \"文件上传格式错误: \" + exc.getMessage(); }}

9. 前端调用示例

前端使用 Vue.js 调用后端接口的示例:

javascript

// 使用axios上传多个文件const uploadFiles = async () => { const formData = new FormData(); // 添加多个文件到FormData selectedFiles.forEach(file => { formData.append(\'files\', file); }); // 添加其他表单数据(如果需要) formData.append(\'category\', \'documents\'); formData.append(\'description\', \'一些重要文件\'); try { const response = await axios.post(\'/api/upload/multiple\', formData, { headers: { \'Content-Type\': \'multipart/form-data\' }, onUploadProgress: (progressEvent) => { const percentCompleted = Math.round( (progressEvent.loaded * 100) / progressEvent.total ); // 更新进度显示 } }); console.log(\'上传成功:\', response.data); } catch (error) { console.error(\'上传失败:\', error); }};

总结

Spring Boot 接收多个文件的主要方式包括:

  1. 使用 MultipartFile[] 数组接收多个文件

  2. 使用 List 列表接收多个文件

  3. 使用 DTO 对象同时接收文件和其他表单数据

  4. 实现分块上传处理大文件

关键配置点:

  • 配置文件上传大小限制

  • 处理文件上传异常

  • 实现文件存储逻辑

  • 提供适当的错误反馈

这些方法可以根据实际需求进行组合和扩展,以满足不同的文件上传场景。