当前位置: 首页 > news >正文

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

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

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

1. 使用 MultipartFile 数组接收

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

java

@RestController
@RequestMapping("/api/upload")
public class FileUploadController {@PostMapping("/multiple")public ResponseEntity<String> 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<String> uploadMultipleFilesList(@RequestParam("files") List<MultipartFile> files) {if (files == null || files.isEmpty()) {return ResponseEntity.badRequest().body("请选择至少一个文件");}// 处理文件逻辑同上// ...return ResponseEntity.ok("成功上传 " + files.size() + " 个文件");
}

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

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

java

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

java

@PostMapping(value = "/with-data", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<String> uploadFilesWithData(FileUploadDTO fileUploadDTO) {List<MultipartFile> 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<String> 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=10MB
spring.servlet.multipart.max-request-size=50MB# 启用多部分文件上传
spring.servlet.multipart.enabled=true# 指定临时文件存储目录(可选)
spring.servlet.multipart.location=/tmp

或者使用 YAML 格式:

yaml

spring:servlet:multipart:max-file-size: 10MBmax-request-size: 50MBenabled: truelocation: /tmp

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

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

java

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

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

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

java

@Service
public class FileStorageService {private final Path fileStorageLocation;@Autowiredpublic 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);}
}@ControllerAdvice
public 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();// 添加多个文件到FormDataselectedFiles.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<MultipartFile> 列表接收多个文件

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

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

关键配置点:

  • 配置文件上传大小限制

  • 处理文件上传异常

  • 实现文件存储逻辑

  • 提供适当的错误反馈

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

http://www.xdnf.cn/news/1401427.html

相关文章:

  • 项目管理常用的方法有哪些
  • 三菱 PLC的中断指令/中断指针
  • 构建现代化的“历史上的今天“网站:从API到精美UI的全栈实践
  • 北方苍鹰优化算法优化的最小二乘支持向量机NGO-LSSVM多输入多输出回归预测【MATLAB】
  • 2025年06月 Scratch 图形化(二级)真题解析#中国电子学会#全国青少年软件编程等级考试
  • Robolectric如何启动一个Activity
  • 倾斜摄影是选择RGB图像还是多光谱影响进行操作?
  • Transformer:从入门到精通
  • 嵌入式Linux驱动开发:蜂鸣器驱动
  • stack queue的实现 deque的底层结构 priority_queue的实现
  • 【Java实战⑦】从入门到精通:Java异常处理实战指南
  • 漫谈《数字图像处理》之分水岭分割
  • AUTOSAR进阶图解==>AUTOSAR_TR_ClassicPlatformReleaseOverview
  • 计算机毕设项目 基于Python与机器学习的B站视频热度分析与预测系统 基于随机森林算法的B站视频内容热度预测系统
  • observer pattern 最简上手笔记
  • 如何调整Linux系统下单个文件的最大大小?
  • hadoop安欣医院挂号看诊管理系统(代码+数据库+LW)
  • 2025年高性能计算年会
  • centos7.9的openssh漏洞修复脚本
  • w嵌入式分享合集125
  • 【Day 33】Linux-MySQL 备份与恢复详解
  • 【机器学习入门】3.3 FP树算法——高效挖掘频繁项集的“树状神器”
  • SNMPv3开发--简单使用
  • bevformer模型训练过程
  • 嵌入式Linux输入子系统驱动开发
  • Python实现点云AABB和OBB包围盒
  • 后台技术方案设计经验之谈
  • FPGA增量式方差与均值计算
  • 银河麒麟V10(Phytium,D2000/8 E8C, aarch64)开发Qt
  • 【计算机网络】生产问题排查:如何使用Wireshark抓包/读取抓包文件进行网络分析