인트로~
오늘 회사에서 신입사원이 화면단에서 데이터를 data: JSON으로 넘기는데 뒤에 있던 일부 객체 필드를 누락시켰더니 서버에서 전체 JSON이 그대로 받아졌다고 했다. 그럴 수밖에 없는 게 @RequestBody는 말 그대로 HTTP 요청의 바디(body)를 그대로 긁어서 Java 객체로 매핑해주는 방식이기때문이다.
하지만 문제는… 회사 프로젝트가 레거시라서 요청을 @RequestBody Map<String, Object>로 받고 있다는 거였다. 이러면 JSON 구조가 조금만 달라도 바로 400 Bad Request 터지는 구조다ㅋㅋ
@RequestParam으로 바꾸면안되냐고 말하길래 그럼 이제는 JSON 객체를 제대로 묶어서 받지도 못하고 필드 하나하나 전부 파라미터로 풀어서 받아서 다시 조립할거냐구.. ㄹㅈㄷ 비효율
그래서 생각난김에 `@RequestParam`과 `@RequestBody`의 차이 그리고 왜 DTO로 받아야 하는지 정리해보려고 한다.
1. @RequestParam과 @RequestBody 차이
둘 다 클라이언트에서 데이터를 받아오는 방식이지만 어디에 데이터를 담아서 보내느냐에 따라 처리 방식이 완전히 달라진다.
1-1. @RequestParam
- 주로 URL의 쿼리 파라미터나 폼 데이터를 처리할 때 사용한다.
- 간단한 검색 조건이나 필터값, 페이지 번호 등을 받을 때 적합하다.
요청 :
POST /greet?name=승민&age=30
Controller :
@PostMapping("/greet")
public String greet(@RequestParam String name, @RequestParam int age) {
return "안녕 " + name + ", 나이는 " + age;
}
1-2. @RequestBody
- HTTP 요청 본문(Body) 에 담긴 JSON 데이터를 처리할 때 사용한다.
- 회원가입, 게시글 등록, 주문 생성 등 구조화된 객체 전체를 받아야 할 때 쓰인다.
- 이때는 보통 프론트엔드에서 `application/json` 형식으로 복잡한 구조의 데이터를 보낸다.
요청 :
POST /greet
Content-Type: application/json
{
"name": "승민",
"age": 30
}
DTO클래스 :
public record GreetRequest(String name, int age) {}
Controller :
@PostMapping("/greet")
public String greet(@RequestBody GreetRequest request) {
return "안녕 " + request.name() + ", 나이는 " + request.age();
}
2. 동작 방식은 어떻게 다를까?
`@RequestParam`은 스프링은 내부적으로 WebDataBinder를 사용해서 파라미터 값을 타입에 맞게 변환해서 매핑해준다.
`@RequestBody`는 JSON 파서를 이용해서 HTTP Body를 읽고 그걸 자바 객체로 변환한다.
여기엔 Jackson의 ObjectMapper가 사용된다.
`@RequestParam`은 URL이나 폼데이터 → 자바 변수
`@RequestBody`는 JSON → 자바 객체
3. DTO를 써야 하는 이유
간단한 필터, 검색, 페이지네이션 등엔 `@RequestParam`을 쓰고
데이터 생성/수정 요청은 거의 대부분 `@RequestBody + DTO 조합`으로 처리한다.
무작정 Map<String, Object>로 받거나 Entity 객체를 그대로 @RequestBody에 쓰는 건 실무에서 안티패턴이니 주의해야 한다.
3-1. DTO 사용이유
- 타입 안정성 확보 → 컴파일 시점에 오류 잡힘
- 유효성 검증 가능 → @Valid, @NotNull 등 활용 가능
- Swagger 연동 용이 → 문서 자동 생성
- 도메인 모델과 분리 → 보안상 안전 (Entity 직접 노출 금지)
public class SignupRequest {
@NotBlank
private String email;
@Size(min = 6)
private String password;
}@PostMapping("/signup")
public ResponseEntity<?> signup(@Valid @RequestBody SignupRequest request) {
return ResponseEntity.ok("회원가입 완료");
}
3-2. @RequestBody Map<String, Object>의 위험성
- 보안 취약: {"role":"ADMIN"} 같은 데이터 조작 가능
- 유효성 검증 불가(@Valid, @NotNull 등)
- 문서화 불가 (Swagger 문서화 자동 연동불가)
- 실수 방지 어려움, 구조 예측 불가
@PostMapping("/hack")
public ResponseEntity<?> hack(@RequestBody Map<String, Object> payload) {
// JSON 전체를 그대로 받음
...
}
4. 결론
`@RequestParam`은 말 그대로 URL이나 폼에서 파라미터처럼 전달되는 데이터를 받을 때 쓰인다.
그에 반해 `@RequestBody`는 요청의 본문에 담긴 JSON 데이터를 읽어올 때 사용된다.
단순 값 몇 개 받을 때는 @RequestParam으로 충분하지만
회원가입, 게시글 작성처럼 여러 필드가 있는 경우에는 DTO 객체를 정의해서 `@RequestBody`로 받는 것이 타입 안정성, 문서화, 유효성 검증 등에서 훨씬 유리하다.
클라이언트가 보낸 데이터를 신뢰하지 말고 명확하게 구조화된 DTO를 통해 안전하게 처리하는 것이 가장 중요하다~
안전하고 유지보수 가능한 API 설계를 위해서는 @RequestBody + DTO + 유효성 검증 조합이 필수당
불필요한 JSON 필드는 받지도~ 믿지도 말자~
끘~
'공부일기.. > Spring' 카테고리의 다른 글
| [Spring] Spring Boot MySQL 설정 (커넥션 풀, OSIV, SQL 로깅) (0) | 2025.09.18 |
|---|---|
| [Spring Boot] application.yml 설정파일 마스타~~ (0) | 2025.09.14 |
| [Redis] Redis 동작원리 : 속도 빠른이유 (4) | 2025.08.21 |
| Redis 활용시 직렬화/역직렬화를 해야하는 이유 (ObjectMapper) (4) | 2025.08.17 |
| Redis 캐시1 - RedisCacheManager (@Cacheable) 사용하기 (3) | 2025.08.16 |