SpringBoot后端接收多個(gè)文件多種實(shí)現(xiàn)方法
在SpringBoot中接收多個(gè)文件有多種方式,下面我將詳細(xì)介紹各種方法及其實(shí)現(xiàn)。
1. 使用 MultipartFile 數(shù)組接收
這是最直接的方式,適用于前端使用相同字段名上傳多個(gè)文件的情況。
@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("請(qǐng)選擇至少一個(gè)文件");
}
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());
// 可以在這里添加文件信息到數(shù)據(jù)庫(kù)等操作
}
}
return ResponseEntity.ok("成功上傳 " + files.length + " 個(gè)文件");
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("文件上傳失敗: " + e.getMessage());
}
}
}2. 使用 MultipartFile 列表接收
與數(shù)組方式類似,但使用列表可能在某些情況下更方便。
@PostMapping("/multiple-list")
public ResponseEntity<String> uploadMultipleFilesList(
@RequestParam("files") List<MultipartFile> files) {
if (files == null || files.isEmpty()) {
return ResponseEntity.badRequest().body("請(qǐng)選擇至少一個(gè)文件");
}
// 處理文件邏輯同上
// ...
return ResponseEntity.ok("成功上傳 " + files.size() + " 個(gè)文件");
}3. 使用 DTO 對(duì)象接收文件和其他表單數(shù)據(jù)
當(dāng)需要同時(shí)接收文件和其他表單數(shù)據(jù)時(shí),可以使用 DTO 對(duì)象。
public class FileUploadDTO {
private List<MultipartFile> files;
private String category;
private String description;
// 構(gòu)造函數(shù)、getter和setter
public FileUploadDTO() {}
public List<MultipartFile> getFiles() {
return files;
}
public void setFiles(List<MultipartFile> files) {
this.files = files;
}
// 其他getter和setter...
}@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("請(qǐng)選擇至少一個(gè)文件");
}
// 處理文件和其他數(shù)據(jù)
for (MultipartFile file : files) {
if (!file.isEmpty()) {
// 保存文件,同時(shí)可以使用category和description
// ...
}
}
return ResponseEntity.ok("成功上傳 " + files.size() + " 個(gè)文件,分類: " + category);
}4. 處理大文件和分塊上傳
對(duì)于大文件,可以使用分塊上傳的方式。
@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 {
// 生成唯一文件標(biāo)識(shí)(如果未提供)
String uniqueFileId = fileId != null ? fileId : UUID.randomUUID().toString();
// 創(chuàng)建臨時(shí)目錄存儲(chǔ)分塊
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);
}
}
// 刪除臨時(shí)目錄
Path tempDir = Paths.get("temp", fileId);
Files.deleteIfExists(tempDir);
}5. 配置文件上傳屬性
在 application.properties 或 application.yml 中配置文件上傳屬性:
# 配置文件上傳大小限制 spring.servlet.multipart.max-file-size=10MB spring.servlet.multipart.max-request-size=50MB # 啟用多部分文件上傳 spring.servlet.multipart.enabled=true # 指定臨時(shí)文件存儲(chǔ)目錄(可選) spring.servlet.multipart.location=/tmp
或者使用 YAML 格式:
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 50MB
enabled: true
location: /tmp6. 自定義文件上傳配置類
如果需要更高級(jí)的配置,可以創(chuàng)建一個(gè)配置類:
@Configuration
public class FileUploadConfig {
@Bean
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
// 單個(gè)文件最大
factory.setMaxFileSize(DataSize.ofMegabytes(10));
// 總上傳數(shù)據(jù)最大
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. 完整的文件上傳服務(wù)示例
下面是一個(gè)更完整的文件上傳服務(wù)示例,包含異常處理和文件存儲(chǔ)邏輯:
@Service
public 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(
"無(wú)法創(chuàng)建文件存儲(chǔ)目錄", ex);
}
}
public String storeFile(MultipartFile file) {
// 標(biāo)準(zhǔn)化文件名
String fileName = StringUtils.cleanPath(file.getOriginalFilename());
try {
// 檢查文件名是否包含非法字符
if (fileName.contains("..")) {
throw new FileStorageException(
"抱歉! 文件名包含無(wú)效的路徑序列 " + fileName);
}
// 生成唯一文件名(避免重名覆蓋)
String uniqueFileName = UUID.randomUUID().toString() + "_" + fileName;
// 復(fù)制文件到目標(biāo)位置
Path targetLocation = this.fileStorageLocation.resolve(uniqueFileName);
Files.copy(file.getInputStream(), targetLocation,
StandardCopyOption.REPLACE_EXISTING);
return uniqueFileName;
} catch (IOException ex) {
throw new FileStorageException(
"無(wú)法存儲(chǔ)文件 " + fileName + ". 請(qǐng)重試!", 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. 異常處理
創(chuàng)建自定義異常和全局異常處理器:
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 "文件存儲(chǔ)錯(cuò)誤: " + exc.getMessage();
}
@ResponseBody
@ExceptionHandler(MultipartException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public String handleMultipartException(MultipartException exc) {
return "文件上傳格式錯(cuò)誤: " + exc.getMessage();
}
}9. 前端調(diào)用示例
前端使用 Vue.js 調(diào)用后端接口的示例:
// 使用axios上傳多個(gè)文件
const uploadFiles = async () => {
const formData = new FormData();
// 添加多個(gè)文件到FormData
selectedFiles.forEach(file => {
formData.append('files', file);
});
// 添加其他表單數(shù)據(jù)(如果需要)
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
);
// 更新進(jìn)度顯示
}
});
console.log('上傳成功:', response.data);
} catch (error) {
console.error('上傳失敗:', error);
}
};總結(jié)
Spring Boot 接收多個(gè)文件的主要方式包括:
- 使用
MultipartFile[]數(shù)組接收多個(gè)文件 - 使用
List<MultipartFile>列表接收多個(gè)文件 - 使用 DTO 對(duì)象同時(shí)接收文件和其他表單數(shù)據(jù)
- 實(shí)現(xiàn)分塊上傳處理大文件
關(guān)鍵配置點(diǎn):
- 配置文件上傳大小限制
- 處理文件上傳異常
- 實(shí)現(xiàn)文件存儲(chǔ)邏輯
- 提供適當(dāng)?shù)腻e(cuò)誤反饋
這些方法可以根據(jù)實(shí)際需求進(jìn)行組合和擴(kuò)展,以滿足不同的文件上傳場(chǎng)景。
以上就是SpringBoot后端接收多個(gè)文件多種實(shí)現(xiàn)方法的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot接收多個(gè)文件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用httpclient無(wú)需證書調(diào)用https的示例(java調(diào)用https)
這篇文章主要介紹了使用httpclient無(wú)需證書調(diào)用https的示例(java調(diào)用https),需要的朋友可以參考下2014-04-04
Spring?Security內(nèi)置過濾器的維護(hù)方法
這篇文章主要介紹了Spring?Security的內(nèi)置過濾器是如何維護(hù)的,本文給我們分析一下HttpSecurity維護(hù)過濾器的幾個(gè)方法,需要的朋友可以參考下2022-02-02
Java實(shí)現(xiàn)InputStream的任意拷貝方式
這篇文章主要介紹了Java實(shí)現(xiàn)InputStream的任意拷貝方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
JPA中@JoinColumn的name和referencedColumnName屬性的區(qū)別及說明
這篇文章主要介紹了JPA中@JoinColumn的name和referencedColumnName屬性的區(qū)別及說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
詳解在Spring Boot框架下使用WebSocket實(shí)現(xiàn)消息推送
這篇文章主要介紹了詳解在Spring Boot框架下使用WebSocket實(shí)現(xiàn)消息推送,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2016-12-12
擴(kuò)展Hibernate使用自定義數(shù)據(jù)庫(kù)連接池的方法
這篇文章主要介紹了擴(kuò)展Hibernate使用自定義數(shù)據(jù)庫(kù)連接池的方法,涉及Hibernate數(shù)據(jù)庫(kù)操作擴(kuò)展的相關(guān)技巧,需要的朋友可以參考下2016-03-03
Java實(shí)時(shí)監(jiān)控日志文件并輸出的方法詳解
這篇文章主要給大家介紹了關(guān)于Java實(shí)時(shí)監(jiān)控日志文件并輸出的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編一起來(lái)學(xué)習(xí)學(xué)習(xí)吧。2017-06-06

