기록/Spring framework

Http 메세지 Content/type에 따른 스프링에서 요청 data 바인딩 방법. 2023-05-20

최동훈1 2023. 5. 20. 17:11

클라이언트에서 서버로 data를 전송하는 방법은 총 3가지로 정리 할 수 있다.

 

1. 요청 쿼리 스트링(query string) 으로 보내지는 경우

즉 localhost:8080/new/?name=최동훈&age=24 이렇게 클라이언트에서 보내는 경우이다. 이 방식은 HTTP 메세지 바디에 아무런 내용을 넣지 않는 GET 메서드 형식으로 보낸다.

이 방식을 사용했을때 HTTP 메세지의 Content/type은 Content-Type: application/x-www-form-urlencoded 이다. 그런데 메세지 바디에는 아무값도 들어가 있지 않는다.

 

*여기서 나는 의문점이 생겼다. HTTP 메세지의 Content/Type이 HTML 폼 태그에 post 메서드로 전송하는 사실은 같은데,  왜 메세지 바디에 아무 값도 넣어서 보내지 않는 GET 방식과 같은 것일까? 라는 의문점이 생겼다.

내가 얻은 결론은 application/x-www-form-urlencoded 이 형식으로 서버로 data를 어떻게든 보내는 것이다. 이 형식은 

key=value&key=value 형태로 전달된다. 즉, 퀴리 스트링으로 보내는 GET방식이든, 메세지 바디에 이런 형태를 넣어서 서버로 전송하는 POST 방식이든 서버로  key=value&key=value 형태로 data를 전송하는 것이므로 HTTP Content/type 이 같은 것이다.

종합하자면, GET 방식은 데이터가 URL의 querystring으로 들어간다는 것과, POST 방식은 데이터가 http message-body에 들어간다는 차이가 존재한다.

 

 

2.HTTP 메세지의 바디에 data를 넣어서 보내는 경우 (POST 방식)

 

이 경우는 URL에 직접적으로 data의 정보가 들어나지 않는다. 위와 같은 방식의 예를 들겠다.

<form action="/submit" method="post" enctype="application/x-www-form-urlencoded">
  <input type="text" name="username" value="john">
  <input type="password" name="password" value="secret">
  <input type="submit" value="Submit">
</form>

위와 같은 방식으로 HTTP request를 보내는 경우 HTTP 메세지 바디에 아래와 같은 형식으로 데이터에 담겨서 보낸다.

위와 같이 HTML input 태그의 속성 값으로 name 을 줘서 서버로 보내면, name 값을 key 값으로 해서 서버로 전송된다. 

 

 

POST /submit HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded

username=john&password=secret

 

즉 조금더 예시로 들자면 만약 사용자가 submit 버튼을 눌러서 위와 같은 POST 메서드로 서버에게 HTTP request 요청을 보내면 서버는 아래와 같이 data를 받을 수 있다.

@PostMapping("/submit")
public String submitForm(@RequestParam("username") String username, @RequestParam("password") String password) {
    // 폼 필드 값 사용
    // ...
}

 

위와 같이 퀴리 파라미터로 넘어온 urlencoded 방식을 키 값에 따라 String 형식으로 바꾼다. 즉, key와 value 쌍으로 넘어온 application/x-www-form-urlencoded 형식을 자바의 String으로 바꾸어 주는 것이다.

이 @RequestParam을 조금더 응용 한 것이 @ModellAttribute 이다. 이 ModelAttribute는 기존의 RequestParam의 쿼리 스트링 키 값 별로 1:1 mapping 방식이 아니라 객체 안에 자동으로 요청 파라`터의 이름으로 해당 객체의 프로퍼티의 Setter 함수를 호출하여서 값을 바인딩 해준다. 

public void item(@RequestParam String name,
                 @RequestParam int price,
                 Model model){
    Item item = new Item();
    item.setName(name);
    item.setPrice(price);
    model.addAttribute("item", item);
}

즉 원래는 이렇게  하나하나 새로운 객체의 맴버에 클라이언트에서 url-encoded 형식으로 넘어온 request parameter 의 key에 해당하는 value 값을 넣어줘야 하지만 아래와 같이 @ModelAttribute를 사용하면, 요청 파라미터 이름과 일치하는 객체의 프로퍼티 안에 해당 파라미터 이름(key) 의 value 값을 넣어준다. 단 주의해야 할 점이 @ModelAttribute와 @RequestParam 방식은 xxx-url-encoded type 일때만 사용 가능하고 만약 Content/type이 json 이라면 @RequestBody를 사용 하여야 한다.

public void modelAttributeEx(@ModelAttribute Item item, Model model){
	model.addAttribute("item", item);
}

@RequestParam 대신 @ModelAttribute 를 사용할 경우