hoonii2

[SpringBoot] 04. RequestParam vs RequestBody vs ModelAttribute 본문

개념 공부/(개발) 02. Spring Boot

[SpringBoot] 04. RequestParam vs RequestBody vs ModelAttribute

hoonii2 2023. 1. 27. 16:37

1. 개요

 - View 에서 Data 를 받는 경우 Spring 의 Controller 에서 크게 3가지 방식으로 Data 를 받을 수 있다.

 

2. RequestParam

 - 요청 파라미터를 1개씩 매핑시켜주는 어노테이션 방식으로, URL 로 전달받은 Data 를 매핑시켜준다.

 --> 즉, 단일 데이터를 받기 위해 사용한다.
 --> 정확히는, 클라이언트 요청 Type 이 "application/json" , "application/x-www-form-urlencoded" 이든 "multipart/form-data" 이든 무관하게 key 에 매칭되는 하나의 필드 값을 받는다. 

 - 변수 명과 받은 Data 의 Key 값이 동일한 경우 어노테이션을 생략할 수 있다.
( 다만, 생략하는 경우 Primitive Type 인 경우는 RequestParam , 객체의 경우는 ModelAttribute 으로 매핑된다 )

 

3. RequestBody

 - http body 내에 있는 Json 형태의 Data 를 객체에 매핑시켜주는 어노테이션이다.

 --> 클라이언트 요청 헤더 Content-Type 이 "application/json" 이 아니면 받지 못한다.

 --> 또한 Body 를 통해 Data 를 전달하는 Post 방식에서 사용할 수 있다.
  ( Get 에서 Body 를 사용할 수 있지만, 권장되는 방식이 아니기에 주의할 필요가 있다. )

 

 - Setter 가 없어도 Data 매핑과 무관하게 동작 ( Reflection 기반 ,, 추후 공부 필요 )

 

4. ModelAttribute

 - 클라이언트가 전달하는 form-data 형태의 요청 데이터 내용과 HTTP 쿼리 파라미터 들을 객체에 바인딩한다.
 --> Body 데이터 , URL 데이터 모두 받기 때문에 Get / Post 둘다 사용할 수 있다.

 --> 클라이언트 요청 헤더 Content-Type 이 "multipart/form-data" 인 데이터를 받기 위해 사용한다.

 - 매핑시키는 파라미터의 타입이 객체의 타입과 일치하는지 등의 검증 작업이 추가로 진행되며, 실패 시 BindException 이 발생한다.

 --> 예를 들어, text 형식을 String data 를 전달받은 것을 Int 타입으로 매핑시키는 경우 예외 발생


 - 데이터를 객체에 매핑시키기위해 Setter 를 호출하여 사용한다.

 

 

5. 실제 동작 테스트 진행 

  1) "TestController" 이름의 RestController 작성 ( 3 가지 방식 모두 지정 )

    - RequestParam = /param , /paramdto [ Get 방식 ]

    - RequestBody = /body , /bodydto [ Post 방식 ]

    - ModelAttribute = /model , /modeldto [  Post 방식 ]

mport com.example.parambodymodel_test.dto.TestDTO;
import org.springframework.web.bind.annotation.*;

@RestController
public class TestController {

    @GetMapping("/param")
    public String getMessage(@RequestParam String message){
        return message;
    }

    @GetMapping("/paramdto")
    public TestDTO getMessageDTO1(@RequestParam TestDTO testDTO){
        return testDTO;
    }

    @PostMapping("/body")
    public String doMessage(@RequestBody String message){
        return message;
    }

    @PostMapping("/bodydto")
    public TestDTO doMessage(@RequestBody TestDTO testDTO){
        return testDTO;
    }

    @PostMapping("/model")
    public String getMessageDTO2(@ModelAttribute String message){
        return message;
    }

    @PostMapping("/modeldto")
    public TestDTO getMessageDTO2(@ModelAttribute TestDTO testDTO){
        return testDTO;
    }
}

 

 

  2) DTO 에 Getter 만 있는 경우

import lombok.Getter;

@Getter
public class TestDTO {
    private String name;
    private String message;
}
No Request Response
1 [Get] http://localhost:8080/param?message=123 123
2 [Get] http://localhost:8080/paramdto?message=123 400 Error
3 [Post] http://localhost:8080/body  // Body form-data message=123 400 Error
4 [Post] http://localhost:8080/bodydto  // Body form-data message=123 415 Error
5 [Get] http://localhost:8080/model?message=123  // Body form-data name=test 성공 ( no data )
6 [Get] http://localhost:8080/modeldto?message=123  // Body form-data name=test {
    "name": null,
    "message": null,
}

※ RequestBody 의 경우 Body Type 을 Json 으로 진행해야하는데 Postman 에 해당 Type 이 안보여서 form-data 로 전달하였습니다.

 

-> 2번 : RequestParam 은 1:1 매핑이기에 DTO 객체로 매핑하는 경우 문제가 발생한다.

-> 3번 : RequestBody 는 form-data 형식의 데이터를 받을 수 없다.

-> 4번 : 3번과 마찬가지로 동작하지만, 좀 더 정확한 "Unsupported Media Type" 정보를 알려준다.

-> 5번 : ModelAttribute 는 객체로 매핑시키는데 사용되어서 Data 매핑이 안되는 것 같다.

 

 

  3) DTO 에 Setter 도 있는 경우

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class TestDTO {
    private String name;
    private String message;
}
No Request Response
1 [Get] http://localhost:8080/param?message=123 123
2 [Get] http://localhost:8080/paramdto?message=123 400 Error
3 [Post] http://localhost:8080/body  // Body form-data message=123 400 Error
4 [Post] http://localhost:8080/bodydto  // Body form-data message=123 415 Error
5 [Get] http://localhost:8080/model?message=123  // Body form-data name=test 성공 ( no data )
6 [Get] http://localhost:8080/modeldto?message=123  // Body form-data name=test {
    "name": test,
    "message": 123,
}

-> ModelAttribute 은 Setter 를 통해 객체에 파라미터를 매핑시키는 것을 확인

 

 

Comments