스프링 API 요청 별 DTO 매핑 어노테이션 정리

박의진·2025년 11월 24일

API 요청 별 DTO 매핑 어노테이션 방식에 대한 것 을 정리하고자 기록한다.

주로 GET 방식으로 요청 할 때 queryString을 DTO로 변환해주는 @ModelAttribute 와 @RequestParam을 썼던 것 같고
POST방식에서는 @RequestBody 방식을 많이 썼다.

이번에 form-data 전송을 위한 MultipartFile데이터 처리에 대한 궁금이 생겨 기록 고고띵 한다.

일단! MultipartFile은 은 @RequestParam랑은 써봤던 것 같은데 @RequestPart 이번에 써보게 되면서 궁금해짐 👀

내 궁금증에 대한 요약을 해보자면 ❗️

✅ 결론 요약
✔ MultipartFile은 @RequestParam 또는 @RequestPart만 가능하다.
❌ @RequestBody MultipartFile는 절대 안 된다. (스프링 구조상 불가능)

🔍 왜 MultipartFile은 @RequestBody로 받을 수 없을까?
1) @RequestBody는 순수한 Body(JSON/XML/Raw data) 를 받아서 변환하는 구조를 가지며 이런 걸 HttpMessageConverter 로 변환해주는 방식이다. ➡️ 그런데 multipart/form-data는 메시지 컨버터가 아니라 MultipartResolver가 처리함.

2) multipart/form-data는 하나의 Body가 아니라 여러 파트의 조합 ➡️ form-data([key, value]) , form-data([key2,value2])

🔥 스프링이 Multipart를 처리하는 흐름

요청이 오면 → MultipartResolver가 multipart를 파싱
각 part를 Map 형태로 저장
file part는 → MultipartFile 객체로 매핑
그리고 컨트롤러 파라미터로 바인딩됨
즉, MultipartFile은 MultipartResolver가 생성한 객체이기 때문에
@RequestBody처럼 메시지 컨버터가 처리할 수 없음.

그리고 두번째로 파일 데이터 처리하면서 궁금했떤 RequestPart 랑 RequestParam 차이점 ‼️

🔥 핵심 요약 (한 문장 버전)
✔ @RequestParam → form-data의 “텍스트 필드” 또는 “파일” 같은 단순 파트에 사용
✔ @RequestPart → JSON + 파일처럼 “multipart/form-data 내부의 객체(JSON) 또는 파일 파트"를 명확히 구분해 받는 데 사용한다.
즉, 단순 텍스트 + 파일 → @RequestParam
JSON + 파일 → @RequestPart

@RequestParam으로 JSON 매핑 ? 가능은 하다.
근데 JSON 이 스트링 형식으로 변환되어서 요청이 오기 때문에 직접 역직렬화 작업을 진행해야 한다.

✅ 파일 업로드에서 @ModelAttribute를 쓸까 ?
✔ @ModelAttribute는 텍스트 필드 + 파일을 함께 DTO로 묶어서 받고 싶을 때 가능하다.
✔ JSON + 파일 조합에서는 절대 사용 못함 → 이건 반드시 @RequestPart.
✔ 추가로 @ModelAttribute는 GET 요청에서 쿼리 스트링(query string)을 DTO로 매핑할 때 가장 대표적으로 쓰는 방식이다.

요청시 매핑하고 싶은 DTO 예시를 들자면 이렇게 텍스트와+파일 조합의 form-data를 보내고 아래 예시와 같은 DTO로 @ModelAttribute가 변환한다.

/*DTO*/
public class UploadRequest {

    private String title;
    private String description;
    private MultipartFile file;

    // getter/setter
}


/*컨트롤러에서 요청 처리시 예시 */
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<?> upload(@ModelAttribute UploadRequest request) {
}

📌 GET에서 ModelAttribute가 좋은 이유
✔ DTO의 모든 필드에 자동으로 바인딩된다
스프링의 DataBinder가 필드명과 동일하게 파라미터를 매칭함.
✔ 기본값 처리, 타입 변환이 자동
int, boolean 같은 primitive 타입도 자동 변환.
✔ 파라미터 개수가 많아질수록 유지보수성 증가
필드 추가해도 컨트롤러 시그니처 변경할 필요 없음.
✔ 검증(Validation)도 쉽게 적용 가능
@Valid + @ModelAttribute 조합이 자연스럽게 동작.

🔥 스프링 웹 요청 매핑 어노테이션 완전 비교표
📌 RequestParam / RequestPart / ModelAttribute / RequestBody 전체 비교

구분@RequestParam@RequestPart@ModelAttribute@RequestBody
주 사용 용도단순 파라미터(key=value), 단일 파일JSON + 파일 조합 (multipart 파트 구분)쿼리스트링, form-data(text+file) DTO 매핑JSON을 DTO로 받을 때
주로 사용하는 Content-Typemultipart/form-data, application/x-www-form-urlencoded, query-stringmultipart/form-datamultipart/form-data, query-string, x-www-form-urlencodedapplication/json
JSON 받을 수 있는가?❌ 직접 받을 수 없음 (String만 가능)✔ JSON → DTO 자동 매핑❌ 불가능✔ JSON → DTO 자동 매핑
파일(MultipartFile) 받을 수 있는가?✔ 가능✔ 가능✔ 가능 (DTO 필드로 가능)❌ 불가능
자동 객체 변환기본 타입만JSON / 파일 자동 분리DTO 자동 바인딩 (Key-Value)JSON → DTO 메시지 컨버터
언제 주로 쓰는가?텍스트 + 파일 간단 업로드JSON 메타데이터 + 파일 업로드GET 쿼리스트링 → DTO 매핑 / form-data DTO 매핑JSON POST/PUT 요청
클라이언트 FormData 요구 방식formData.append("file", file)formData.append("meta", blob(JSON))key=value 구조 그대로 사용JSON body
복잡한 구조 처리XX
멀티파트 구조 인식부분적으로✔ multipart 파트 단위로 분석✔ 값 바인딩 형태X (multipart 자체는 못 파싱)
스프링 내부 처리 방식WebDataBinderMultipartResolver + HttpMessageConverterWebDataBinderHttpMessageConverter
GET 요청에 사용거의 안 씀✔ (대표적)

🔍 각 어노테이션 핵심 요약 (1줄씩)
@RequestParam
→ 단순한 form-data / query parameter / 파일을 받을 때 가장 일반적인 방식.
@RequestPart
→ multipart/form-data 안에서 JSON + 파일 같은 복합 구조를 받을 때 필수.
@ModelAttribute
→ 여러 텍스트 필드를 DTO로 묶고 싶을 때 (GET/POST 모두), 파일도 DTO에 포함 가능. (쿼리 스트링으로 온 요청도 해당 어노테이션으로 매핑가능)
@RequestBody
→ JSON 요청 바디를 DTO로 변환할 때 유일하게 사용해야 하는 방식.

profile
주니어 백엔드 개발자의 개발 log💻

0개의 댓글