일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 1차원 DP
- 2차원 dp
- 99클럽
- @BeforeAll
- @BeforeEach
- @Builder
- @Entity
- @GeneratedValue
- @GenericGenerator
- @NoargsConstructor
- @Query
- @Table
- @Transactional
- Actions
- Amazon EFS
- amazon fsx
- Android Studio
- ANSI SQL
- api gateway 설계
- api gateway 필터
- ApplicationEvent
- assertThat
- async/await
- AVG
- AWS
- aws eks
- AWS 프리티어
- Azure
- bind
- bitnami kafka
- Today
- Total
기록
Spring에서 multipart/form-data로 리스트(List<T>) 데이터를 받는 방법 본문
시작하면서
Spring에서 multipart/form-data 요청을 처리할 때, 파일과 리스트(List<T>) 데이터를 함께 전송하는 방법이 일반적인 application/json 요청과 다르다.
특히, List<T> 같은 배열 데이터를 JSON으로 보내도 Spring이 자동 변환하지 못하는 경우가 있다.
이 글에서는 Spring이 multipart/form-data 요청에서 List<T>를 자동 변환하도록 처리하는 방법을 정리한다.
📌 문제 상황: multipart/form-data에서 리스트(List<T>)를 받을 수 있을까?
multipart/form-data는 파일과 데이터를 함께 전송할 수 있는 HTTP 요청 방식이다.
그러나, 아래와 같이 리스트(List<T>) 데이터를 JSON으로 보내도 Spring이 자동 변환하지 않는다.
[
{
"fileType": "BINARY",
"description": "파일 설명"
},
{
"fileType": "IMAGE",
"description": "이미지 설명"
}
]
Spring이 fileDetails를 List<T>로 변환하지 못하는 이유는 다음과 같다.
🚨 multipart/form-data에서 List<T> 자동 변환이 불가능한 이유
- multipart/form-data는 JSON이 아닌 key=value 기반의 폼 필드 방식이다.
- application/json 요청과 달리 multipart/form-data는 JSON을 자동 매핑할 수 없다.
- @RequestBody를 사용할 수 없다.
- @RequestBody는 application/json 요청에서만 사용할 수 있으며, multipart/form-data에서는 동작하지 않는다.
- 결과적으로 fileDetails를 List<T>로 자동 변환할 수 없다.
- JSON 데이터를 Text 필드로 전송해도 Spring이 이를 List<T>로 변환하지 못한다.
🚀 해결 방법: fileDetails[i].필드명 형식으로 전달
Spring은 multipart/form-data 요청에서 리스트(List<T>) 데이터를 개별적인 Key로 보내면 자동 변환할 수 있다.
즉, fileDetails[i].필드명 형식으로 데이터를 전송하면, List<T>로 변환된다.
✅ Postman 설정
아래와 같이 각 배열 요소를 개별적인 Key로 추가하면 Spring이 자동 변환할 수 있다.
Key | Type | Value |
files | File | binary1.zip |
files | File | image1.png |
fileDetails[0].fileType | Text | BINARY |
fileDetails[0].description | Text | 파일 설명 |
fileDetails[1].fileType | Text | IMAGE |
fileDetails[1].description | Text | 이미지 설명 |
이렇게 설정하면 Spring이 자동으로 List<T>로 변환한다.
📌 컨트롤러 코드 (@ModelAttribute 활용)
이제, 위 방식대로 데이터를 보내면 Spring 컨트롤러에서 @ModelAttribute를 통해 자동 변환할 수 있다.
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation(summary = "파일 업로드", description = "파일과 관련 데이터를 함께 업로드합니다.")
public ResponseEntity<FileUploadResponse> uploadFiles(
@Valid @ModelAttribute FileUploadRequest request, // Spring이 자동 바인딩
@RequestParam(value = "files", required = false) List<MultipartFile> files,
) {
log.info("Received request: {}", request);
log.info("Received files: {}", files);
// 파일 리스트가 null이면 빈 리스트로 처리
List<MultipartFile> fileList = Optional.ofNullable(files).orElse(Collections.emptyList());
// 파일과 요청 데이터 매칭
List<FileDetail> fileDetails = request.getFileDetails();
if (fileDetails.size() != fileList.size()) {
throw new IllegalArgumentException("파일 개수와 fileDetails 개수가 일치하지 않습니다.");
}
List<ProcessedFile> processedFiles = IntStream.range(0, fileDetails.size())
.mapToObj(i -> ProcessedFile.of(fileDetails.get(i), fileList.get(i)))
.toList();
FileUploadCommand command = FileUploadCommand.of(request);
command.setProcessedFiles(processedFiles);
return ResponseEntity.ok(fileUploadService.processUpload(command));
}
✅ 이제 multipart/form-data에서 List<T>가 자동 변환됨.
✅ 파일과 함께 리스트 데이터를 직관적으로 처리할 수 있음.
📌 React에서 multipart/form-data 요청 보내기
React에서도 FormData를 사용하여 fileDetails[i].필드명 형식으로 데이터를 추가하면 된다.
import axios from 'axios';
const uploadFiles = async () => {
const formData = new FormData();
// 파일 추가
formData.append("files", new File(["binary content"], "binary1.zip"));
formData.append("files", new File(["image content"], "image1.png"));
// fileDetails 리스트를 개별 필드로 추가
formData.append("fileDetails[0].fileType", "BINARY");
formData.append("fileDetails[0].description", "파일 설명");
formData.append("fileDetails[1].fileType", "IMAGE");
formData.append("fileDetails[1].description", "이미지 설명");
// 기타 정보 추가
formData.append("requestId", 1001);
formData.append("description", "업로드 요청입니다");
try {
const response = await axios.post("http://localhost:8080/upload", formData, {
headers: {
"Content-Type": "multipart/form-data"
}
});
console.log("업로드 성공:", response.data);
} catch (error) {
console.error("업로드 실패:", error);
}
};
uploadFiles();
✅ React에서도 Spring이 자동 변환할 수 있도록 fileDetails[i].필드명 형식으로 전송
✅ 이제 Spring에서 List<T>를 문제없이 받을 수 있음
🔥 최종 정리
해결 방법 | 장점 | 단점 | 추천여부 |
✅ fileDetails[i].필드명 형식으로 전달 (@ModelAttribute) | Spring이 자동 변환, JSON 변환 필요 없음 | Postman에서 Key를 여러 개 추가해야 함 | 가장 추천 |
⚠️ @RequestParam String 후 JSON 변환 (ObjectMapper) | Key 개수를 줄일 수 있음 | JSON을 개별적으로 변환해야 함 | 대체 가능 |
✅ Spring이 multipart/form-data에서 List<T>를 자동 변환하도록 만들고 싶다면 fileDetails[i].필드명 형식으로 보내야 한다.
✅ React, Postman, MockMvc 테스트 모두 같은 방식으로 데이터를 보내면 Spring에서 자동 변환 가능! 🚀
'Web > Spring' 카테고리의 다른 글
멀티 모듈 기반 영화 예매 서비스 설계기 : 멀티 모듈 프로젝트 설계(1) - Domain 기반의 모듈 분리 (0) | 2025.03.31 |
---|---|
QueryDSL로 중첩 DTO를 조회하는 방법 (0) | 2025.03.27 |
Hibernate "unsaved transient instance" 오류 해결 방법 : CascadeType.ALL (0) | 2025.03.16 |
assertThat의 주요 메서드와 기본 사용법 (0) | 2025.02.21 |
@Builder 사용 시 주의사항 – Dto에 기본 생성자를 추가해야 한다 (0) | 2025.02.07 |