회사에서 일하면서 Map과 File을 동시에 Request받아야 할 일이 생겼습니다.
Content-Type - Application/json
Map 객체는 JSON 형태로 보내야 합니다.
예를 들어, 클라이언트에서 JavaScript 객체 형태로 Map 데이터를 JSON으로 변환하여 서버에 전송할 수 있습니다.
{
"key1": "value1",
"key2": "value2"
}
이 데이터는 HTTP 요청의 Content-Type이 application/json이어야 하며,
Spring의 @RequestBody 어노테이션을 사용하여 매핑할 수 있습니다.
@PostMapping("/api/data")
public String handleData(@RequestBody Map<String, Object> map) {
// map 데이터 처리
return "Data received";
}
Content-Type: multipart/formed-data
반면, 파일 데이터를 전송하려면 Content-Type이 multipart/form-data이어야 합니다.
이때는 파일 외에도 다른 폼 데이터(예: 텍스트 데이터)도 함께 전송할 수 있습니다.
클라이언트는 파일을 FormData 객체로 만들어 전송합니다.
const formData = new FormData();
formData.append("file", fileInput.files[0]);
formData.append("key1", "value1");
formData.append("key2", "value2");
fetch('/api/upload', {
method: 'POST',
body: formData
});
서버에서는 @RequestParam을 사용하여 파일을 받아올 수 있습니다.
예를 들어, 파일을 MultipartFile 객체로 받을 수 있습니다.
@PostMapping("/api/upload")
public ResponseEntity<String> handleFileUpload(@RequestParam("file") MultipartFile file) {
// 파일과 추가 파라미터 처리
return ResponseEntity.ok("File uploaded successfully");
}
문제점:
Map 데이터와 File 데이터를 동시에 처리할 때의 주요 문제는 Content-Type 헤더가 서로 다르다는 점입니다.
- **application/json**은 JSON 형태의 데이터를 서버에서 처리하기 위한 것이고,
- **multipart/form-data**는 파일 업로드와 같은 다중 폼 데이터 전송을 위한 것입니다.
이때 문제가 발생하는 이유는 Spring이 Content-Type을 기준으로 요청을 처리하는 방식에 있습니다.
만약 하나의 요청에 두 가지 Content-Type이 혼합되어 있으면
Spring은 이를 구분할 수 없어서 오류가 발생할 수 있습니다.
문제 발생 시:
클라이언트에서 파일과 JSON 데이터를 함께 전송하려 할 때, Spring은 이를 처리하기 위한 별도의 로직이 필요합니다.
만약 파일과 JSON 데이터를 함께 보내면, Spring은 기본적으로 하나의 Content-Type만 인식할 수 있기 때문에,
파일을 받을 때는 multipart/form-data로 인식하고,
JSON 데이터는 application/json으로 처리하려고 시도하면서 충돌이 발생할 수 있습니다.
오류 메시지 예시:
org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
이 오류는 @RequestBody로 JSON 데이터를 처리하려고 시도하면서
@RequestParam으로 처리해야 할 파일이 누락된 것처럼 처리되는 경우 발생할 수 있습니다.
해결 방법:
Map형태는 무조건 Json형태로만 보내어야 할까?
우리는 정해진 틀에만 의존하지 않고, 유연한 방식으로 파일과 데이터를 처리할 수 있어야합니다.
Map형태도 동일하게 form-data형태로 추가를 해주어 실제 file로 받을 수 있게 해준 후
백엔드에서 클라이언트에서 JSON 형태로 보내는 Map 데이터를 String으로 받아서,
이를 다시 Map 객체로 변환하여 사용할 수 있습니다.
@PostMapping("/api/upload")
public String handleFileAndData(
@RequestPart("file") MultipartFile file,
@RequestPart("mapData") String mapData) {
// Map 데이터는 JSON 형태로 받아서 Map으로 변환
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> map = null;
try {
map = objectMapper.readValue(mapData, new TypeReference<Map<String, Object>>(){});
} catch (JsonProcessingException e) {
e.printStackTrace();
return ResponseEntity.badRequest().body("Invalid map data");
}
// 파일과 map 데이터 처리
return "File and data received successfully";
}
이렇게 File 형태로 데이터를 받은 후 file객체의 문자열을 객체화 시켜주는 Object Mapper를 활용하여
다시 객체화 시켜줌으로써 백엔드에서 Map데이터를 사용 할 수 있게 되었습니다~!
'현업에 종사하면서 발견한 문제점' 카테고리의 다른 글
@Controller, @RestController 차이점 (0) | 2024.02.25 |
---|---|
DTO 와 VO의 차이에 대하여 (0) | 2024.02.25 |