HTTP 요청 데이터 3가지 전달 방법
GET – 쿼리 파라미터
- /url?username=hello&age=20
- 메시지 바디 없이 URL에 데이터를 전달
POST – HTML Form
- content-type: application/x-www-form-urlencoded
- 메시지 바디에 쿼리 파라미터 형식(usermane=hello&age=20)으로 전달
HTTP 메시지 바디에 데이터를 직접 담아서 요청
- 주로 JSOM 데이터 형식을 사용
- {“username” : “hello”, “age” : 20}
@RequestParam
Get 쿼리 파라미터 전송과 POST HTML Form 전송 방식 둘 다 조회할 수 있다.
다음과 같이 URL 요청이 들어올 때 @RequestParam을 이용하면 다음과 같이 사용할 수 있다.
Get 쿼리 파라미터 받기
/request-param?username=does&age=25
@GetMapping("/request-param")
public String requestParam(
@RequestParam("username") String memberName,
@RequestParam("age") int memberAge) {
return memberName + memberAge;
}
파라미터로 받는 변수명과 URL의 변수명이 일치하면 어노테이션에 value 값을 생략할 수도 있다.
@GetMapping("/request-param")
public String requestParam(@RequestParam String username, @RequestParam int age) {
return username + age;
}
받는 타입이 String, Integer, int 등의 단순 타입이면 @RequestParam 자체도 생략 가능하다. 하지만 가급적 @RequestParam을 붙이면 쿼리 파라미터에서 값을 읽는다는 것을 명시적으로 알 수 있으므로 붙이는 것이 좋을 것 같다.
@GetMapping("/request-param")
public String requestParam(String username, int age) {
return username + age;
}
required, defaultValue
@RequestParam에는 파라미터 값이 없는 경우에 대비할 수 있는 required와 defaultValue 속성이 있다.
required는 기본값이 true이며 쿼리 파라미터가 URL에 생략되어 있으면 400 에러가 발생한다.
ex) /request-param?username=does
defaultValue는 쿼리 파라미터가 없을 경우 기본값을 설정할 수 있다. 기본값을 설정할 경우 required는 의미가 없다.
@RequestParam(required = true, defaultValue = "guest") String username
위와 같이 사용하면 반드시 파라미터가 있어야 하며 없을 경우 기본값을 "guest"라 설정한다는 뜻이다.
Map으로 받기
요청 파라미터 값을 변수명이 아닌 Map<String, Object> 형태로 조회할 수도 있다.
@GetMapping("/request-param-map")
public String requestParamMap(@RequestParam Map<String, Object> paramMap) {
return (String) paramMap.get("username") + paramMap.get("age");
}
HTML Form 데이터 받기
HTML Form으로 Post 요청을 보내면 다음과 같이 @PostMapping과 @RequestParam을 함께 사용할 수 있다.
<form action="/request-param" method="post">
username: <input type="text" name="username" />
age: <input type="text" name="age" />
<button type="submit">전송</button>
</form>
@PostMapping("/request-param")
public String postRequestParam(@RequestParam String username, @RequestParam int age) {
return username + age;
}
그런데 Form으로 보낼 데이터가 많아질 경우 위와 같이 파라미터를 나열해서 받으면 코드가 매우 길어진다. 데이터들을 필드로 가지는 객체를 파라미터로 받아올 수 있다면 문제는 해결될 것이다.
@ModelAttribute
Form을 통해 넘어온 요청 파라미터를 사용해 객체를 만드는 과정을 자동화해준다. 아래와 같이 사용하면 Form의 데이터를 통해 객체를 바로 받아올 수 있다.
@PostMapping("/model-attribute")
public String modelAttribute(@ModelAttribute User user) {
return user.getUsername() + user.getAge();
}
이때 사용되는 User 객체는 모든 필드 값을 받는 생성자 혹은 모든 필드의 setter가 열려있어야 한다.
static class User {
String username;
int age;
public User(String username, int age) {
this.username = username;
this.age = age;
}
// 생성자가 있다면 setter는 없어도 되고 setter가 있다면 생성자는 기본 생성자만 있어도 충분
public void setUsername(String username) {
this.username = username;
}
public void setAge(int age) {
this.age = age;
}
}
@RequestParam처럼 @ModelAttribute도 생략이 가능하다. 스프링은 파라미터를 받는 어노테이션을 생략할 때 다음과 같은 규칙을 적용한다.
- String , int , Integer 같은 단순 타입 = @RequestParam
- 나머지 = @ModelAttribute (커스텀 객체)
주의할 점!
만약 User 객체를 응답 값으로 보낼 경우(return user) User 객체의 각 필드의 getter가 정의되어 있어야 한다. getter가 없으면 406 에러가 발생한다. 객체를 다시 JSON 데이터로 변환할 때 getter를 사용하기 때문이다.
@PostMapping("/model-attribute")
public User modelAttribute(@ModelAttribute User user) {
return user; // 406 에러 발생!!
}
static class User {
private String username;
private int age;
public User(String username, int age) {
this.username = username;
this.age = age;
}
}
@RequestBody
Form을 통해서가 아닌 HTTP 바디에 직접 데이터가 넘어오는 경우에 @RequestParam과 @ModelAttribute는 사용할 수 없고 @RequestBody를 사용해야 한다.
HTTP 바디에 단순 텍스트 받기
HTTP 바디에 "hello"라는 텍스트가 들어있다면 아래와 같이 조회할 수 있다.
@PostMapping("/request-body")
public String requestBodyString(@RequestBody String body) {
return body;
}
HTTP 바디에 JSON 데이터 받기 (MAP)
아래와 같이 Map으로 JSON 데이터를 받을 수 있다.
@PostMapping("/request-body-map")
public String requestBodyJason(@RequestBody Map<String, Object> json) {
return (String) json.get("username") + json.get("age");
}
JSON 데이터 자바 객체로 받기
@ModelAttribute처럼 @RequestBody를 이용하면 java 객체로 요청 데이터를 받을 수 있다.
@PostMapping("/request-body-object")
public User requestBodyJason(@RequestBody User user) {
return user;
}
주의할 점!
- @RequestBody로 객체를 받으려면 우선 객체의 기본 생성자가 반드시 있어야 한다. 다른 이유 때문에 기본 생성자 이외의 생성자가 존재한다면 기본 생성자도 꼭 명시적으로 가지고 있어야 한다.
- JSON 데이터와 매핑되는 필드의 getter 혹은 setter가 존재해야 한다. 둘 다 존재하지 않으면 데이터를 객체의 필드로 매핑해주지 못한다.
- @ModelAttribute와 마찬가지로 위와 같이 객체를 바로 응답으로 보낼 경우 필드들의 getter가 존재해야 한다.
참고
'스프링 > 스프링MVC' 카테고리의 다른 글
서블릿과 서블릿 컨테이너 (0) | 2022.04.24 |
---|