컨트롤러에서 데이터를 인자에 할당하는 대표적인 방법으로는 @RequestBody 와 @RequestParam 이 있다.
@Controller
public class UserController {
@PostMapping("/receive")
public String age(@RequestParam String name) {
System.out.println("통신 성공");
System.out.println(">>> " + name);
return "index";
}
}
@Controller
public class UserController {
@PostMapping("/receive")
public String age(@RequestBody String name) {
System.out.println("통신 성공");
System.out.println(">>> " + name);
return "index";
}
}
이번 포스팅에서는 두 방식의 차이점에 대해서 알아보려고 한다.
form태그로 데이터를 전달
먼저 기본적인 형태인 <form> 태그를 통해서 데이터를 전송해보자
왼쪽과 같이 데이터를 전송하여 컨트롤러에서 @RequestBody를 이용하여 데이터를 받아보았다.
@Controller
public class UserController {
@PostMapping("/receive")
public String age(@RequestBody String req) {
System.out.println("통신 성공");
System.out.println(">>> " + req);
return "result";
}
}
//출력 결과
//통신 성공
//>>> name=jun&age=13
우리가 입력한 'jun' 이라는 이름과 '13' 이라는 나이가 잘 전달이 되었지만 단지 'name=jun&age=13' 이라는 String 으로 전달되어 전달된 데이터를 사용하기에는 불편함이 있다.
그렇다면 이번엔 @RequestParam 으로 받아보자.
@Controller
public class UserController {
@PostMapping("/receive")
public String age(@RequestParam String name) {
System.out.println("통신 성공");
System.out.println(">>> " + name);
return "result";
}
}
//출력 결과
//통신 성공
//>>> jun
@RequestBody 로 데이터를 받을 때는 메서드의 변수명이 상관이 없었지만, @RequestParam 으로 데이터를 받을때는 데이터를 저장하는 이름으로 메서드의 변수명을 설정해주어야 한다.
결과적으로 jun 이라는 이름이 잘 전달이 되었고, 이번엔 name 이라는 변수에 할당이 되어 사용하기에도 용이하다.
Json형식으로 데이터를 전달
이번에는 ajax를 이용하여 데이터를 전달해보도록 하겠다.
ajax 는 Asynchronous JavaScript and XML 의 약자로서 비동기적으로 서버와 브라우저가 데이터를 주고 받는 방식이다.
대표적인 예로 javaScript 의 fetch API 가 있다.
많은 사람들이 사용하는 방법인데, 이번엔 fetch API 로 데이터를 전송하고 데이터를 받아보자.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button id="postData">
데이터 전송
</button>
<script>
const $postDataButton = document.querySelector("#postData")
const postData = event => {
console.log("데이터 전송");
fetch("/receive", {
method: 'post',
headers: {
'content-type': 'application/json'
},
body : JSON.stringify({
name : "jun",
age : "13"
})
})
}
$postDataButton.addEventListener("click", postData);
</script>
</body>
</html>
위와 같이 코드를 작성하면 출력되는 페이지는 다음과 같다.
'데이터 전송' 버튼을 누르면
'/receive' 주소로,
post 방식으로,
{name : "jun",
age : "13}
이라는 데이터가 Json의 형태로 전송이 된다.
이 데이터를 @RequestParam 을 이용하여 받아보자.
@Controller
public class UserController {
@PostMapping("/receive")
public String age(@RequestParam String name) {
System.out.println("통신 성공");
System.out.println(">>> " + name);
return "result";
}
}
위와 같이 컨트롤러를 구현한 후 데이터를 전송해보았지만 에러가 발생하였다.
MissingServletRequestParameterException: Required String parameter 'name' is not present
name 이라는 파라미터가 없다고 한다.
그 이유는 기본적으로 @RequestParam 은 url 상에서 데이터를 찾기 때문이다.
우리가 위에서 <form> 태그를 이용하여 데이터를 입력하고 제출 버튼을 누르면 입력한 데이터들이 url을 통해서 전달된다.
예를 들면 'http://localhost:8080/receive?name=jun&age=13' 이런 식이다.
반면에 Json형식으로 데이터를 전달할때는, url은 http://localhost:8080/receive로 변함이 없고 body에 데이터를 포함하여 전송하기 때문에 @RequestParam 으로는 받을 수 없는 것이다.
그렇다면 한번 fetch API 로 데이터를 전달하되 전송하는 주소를 /receive?name=jun&age=13 으로 변경하고 전달해보면 어떻게 될까?
//출력 결과
//통신 성공
//>>> jun
정상적으로 name 변수에 jun 이 할당이 되었다.
이제 다시 본론으로 돌아와 '/receive' 주소로 데이터를 전송하고 @RequestBody 로 데이터를 받아보자.
@Controller
public class UserController {
@PostMapping("/receive")
public String age(@RequestBody String req) {
System.out.println("통신 성공");
System.out.println(">>> " + req);
return "result";
}
}
//출력 결과
//통신 성공
//>>> {"name":"jun","age":"13"}
<form> 태그로 데이터를 전달하고 @RequestBody 로 받았을 때와 차이가 없어 보인다.
하지만 여기에는 큰 차이가 있다.
자동 객체 생성
만약 다음과 같이 name 과 age 를 필요로 하는 Person 클래스가 있고 getter 가 구현되어 있다면
public class Person {
private String name;
private int age;
public Person() {
}
public Person(final String name) {
this.name = name;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
다음과 같은 기능이 가능하다.
@Controller
public class UserController {
@PostMapping("/receive")
public String age(@RequestBody Person person) {
System.out.println("통신 성공");
System.out.println(">>> " + person);
return "result";
}
}
//출력 결과
//통신 성공
//>>> Person{name='jun', age=13}
신기하게도 Person 객체를 자동으로 생성해 주었다.
@RequestBody 가 아닌 @RequestParam 을 이용한다면 불가능하다. 한번 시도해보자.
비동기통신에서 @RequestParam 으로 데이터를 전달받기 위해 /receive?name=jun&age=13 의 주소로 데이터를 전송하고 @RequestParam 으로 데이터를 받아 같은 행동을 취했지만 에러가 발생하는 모습이다.
@Controller
public class UserController {
@PostMapping("/receive")
public String age(@RequestParam Person person) {
System.out.println("통신 성공");
System.out.println(">>> " + person);
return "result";
}
}
//출력 결과
.MissingServletRequestParameterException: Required Person parameter 'person' is not present]
@RequestBody, @RequestParam 모두 Map<String,String> 으로 결과를 받아올 수도 있다.
@Controller
public class UserController {
@PostMapping("/receive")
public String age(@RequestBody Map<String,String> map) {
System.out.println("통신 성공");
System.out.println(">>> " + map.get("name"));
System.out.println(">>> " + map.get("age"));
return "result";
}
}
//출력 결과
//통신 성공
//>>> jun
//>>> 13
정리
@RequestBody | @RequestParam | |
객체 생성 | 가능 | 불가능 |
각 변수별로 데이터 저장 |
불가능 | 가능 |
url상에서 데이터를 전달하는 경우(form 태그 등) @RequestParam 을 이용하고,
그 외의 경우 @RequestBody 를 이용하자!
'Spring' 카테고리의 다른 글
스프링부트 / Spring Rest Docs 를 통한 문서 자동화 Tutorial (0) | 2020.05.25 |
---|---|
스프링부트 / JWT 방식으로 로그인 구현하기 (5) | 2020.05.20 |
스프링부트 어노테이션 / @PathVariable (0) | 2020.05.01 |
스프링부트 어노테이션 / @RestController(vs @Controller) 이해하기 (0) | 2020.05.01 |
스프링부트 / Bean 이해하기 (0) | 2020.04.27 |