[Spring] 21. @RequestBody란?
이전 글에서는 @ModelAttribute와 DTO 바인딩에 대해 살펴봤습니다. @ModelAttribute는 HTML form이나 요청 파라미터로 전달된 값을 DTO 객체에 담을 때 사용합니다.
이번 글에서는 JSON 요청 데이터를 객체로 받는 @RequestBody에 대해 정리하겠습니다. Spring에서 REST API를 만들 때 자주 사용하는 어노테이션입니다.
핵심은 간단합니다. @RequestBody는 요청 Body에 들어있는 JSON 데이터를 Java 객체로 변환해서 Controller 메서드에서 사용할 수 있게 해줍니다.
1. @RequestBody란?
@RequestBody는 HTTP 요청 Body에 담긴 데이터를 Java 객체로 받을 때 사용하는 어노테이션입니다. 주로 JSON 데이터를 받을 때 사용합니다.
예를 들어 클라이언트가 다음과 같은 JSON 데이터를 서버로 보낸다고 생각해보겠습니다.
{
"title": "Spring 공부",
"content": "RequestBody 정리",
"category": "backend"
}
Controller에서는 이 JSON 데이터를 DTO로 받을 수 있습니다.
@PostMapping("/api/boards")
@ResponseBody
public String write(@RequestBody BoardDto boardDto) {
System.out.println(boardDto.getTitle());
System.out.println(boardDto.getContent());
System.out.println(boardDto.getCategory());
return "ok";
}
위 코드에서 @RequestBody는 요청 Body에 들어온 JSON 값을 BoardDto 객체로 변환합니다.
JSON 요청 Body
→ @RequestBody
→ BoardDto 객체로 변환
→ Controller 메서드에서 사용
2. 요청 Body란?
HTTP 요청은 크게 요청 URL, Header, Body 등으로 구성됩니다. 그중 Body는 서버로 보낼 데이터를 담는 영역입니다.
POST /api/boards
Content-Type: application/json
{
"title": "Spring 공부",
"content": "RequestBody 정리"
}
여기서 아래 JSON 부분이 요청 Body입니다.
{
"title": "Spring 공부",
"content": "RequestBody 정리"
}
@RequestBody는 이 Body 안에 들어있는 데이터를 읽어서 Java 객체로 바꿔줍니다.
3. JSON과 DTO 매핑
JSON의 key 이름과 DTO의 필드명이 같으면 Spring이 값을 매핑할 수 있습니다.
{
"title": "Spring 공부",
"content": "RequestBody 정리",
"category": "backend"
}
public class BoardDto {
private String title;
private String content;
private String category;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
}
매핑 흐름은 다음과 같습니다.
JSON title
→ BoardDto.title
JSON content
→ BoardDto.content
JSON category
→ BoardDto.category
즉, JSON의 key와 DTO 필드명을 맞추는 것이 중요합니다.
4. @ModelAttribute와 @RequestBody 차이
@ModelAttribute와 @RequestBody는 둘 다 요청 데이터를 객체로 받을 수 있습니다. 하지만 받는 데이터 형태가 다릅니다.
| 구분 | @ModelAttribute | @RequestBody |
| 주 사용 데이터 | HTML form 데이터 | JSON 요청 Body |
| 데이터 예시 | title=Spring&content=내용 |
{"title":"Spring","content":"내용"} |
| 주 사용 방식 | JSP, Thymeleaf form | REST API, fetch, axios |
| Controller 예시 | write(BoardDto boardDto) |
write(@RequestBody BoardDto boardDto) |
처음에는 이렇게 구분하면 됩니다.
HTML form 전송
→ @ModelAttribute 또는 DTO 바인딩
JSON 전송
→ @RequestBody
5. HTML form 전송 예시
먼저 HTML form 전송을 보겠습니다. 이 방식은 보통 @ModelAttribute나 DTO 바인딩으로 받습니다.
<form action="/board/write" method="post">
<input type="text" name="title">
<textarea name="content"></textarea>
<button type="submit">등록</button>
</form>
@PostMapping("/board/write")
public String write(BoardDto boardDto) {
return "redirect:/board/list";
}
이 구조에서는 form의 name 값이 DTO 필드에 매핑됩니다.
name="title"
→ BoardDto.title
name="content"
→ BoardDto.content
이 방식은 화면 기반 게시판, 회원가입, 로그인 폼에서 자주 사용합니다.
6. JSON 전송 예시
이번에는 JSON 전송입니다. JavaScript의 fetch를 사용해서 JSON 데이터를 보낼 수 있습니다.
fetch("/api/boards", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
title: "Spring 공부",
content: "RequestBody 정리",
category: "backend"
})
});
이 요청은 JSON 데이터를 요청 Body에 담아 서버로 보냅니다. Controller에서는 @RequestBody로 받을 수 있습니다.
@PostMapping("/api/boards")
@ResponseBody
public String write(@RequestBody BoardDto boardDto) {
return "ok";
}
요청 흐름은 다음과 같습니다.
JavaScript 객체
→ JSON 문자열로 변환
→ 요청 Body에 담아 전송
→ @RequestBody가 DTO로 변환
→ Controller에서 사용
7. Content-Type이 중요한 이유
JSON 데이터를 보낼 때는 요청 Header에 Content-Type: application/json을 지정하는 것이 중요합니다.
headers: {
"Content-Type": "application/json"
}
이 Header는 서버에게 요청 Body에 들어있는 데이터 형식이 JSON이라는 것을 알려줍니다.
Content-Type: application/json
→ 요청 Body가 JSON 형식이라는 의미
만약 JSON을 보내면서 Content-Type을 제대로 지정하지 않으면 Spring이 요청 Body를 기대한 방식으로 읽지 못할 수 있습니다.
8. @ResponseBody와 함께 보기
@RequestBody는 요청 Body를 읽는 역할입니다. 반대로 @ResponseBody는 응답 Body에 데이터를 직접 담아 반환하는 역할입니다.
| @RequestBody | 요청 Body의 JSON을 Java 객체로 받습니다. |
| @ResponseBody | Java 객체나 문자열을 응답 Body로 직접 반환합니다. |
예를 들어 다음 코드는 JSON 요청을 받고 문자열을 응답합니다.
@PostMapping("/api/boards")
@ResponseBody
public String write(@RequestBody BoardDto boardDto) {
return "ok";
}
화면 이름을 반환하는 것이 아니라 응답 데이터 자체를 반환합니다.
return "ok";
→ ok라는 응답 데이터 반환
이 구조는 API를 만들 때 자주 사용합니다.
9. @RestController와 함께 사용하기
API Controller에서는 @Controller와 @ResponseBody를 함께 쓰는 대신 @RestController를 사용할 수 있습니다.
@RestController
@RequestMapping("/api/boards")
public class BoardApiController {
@PostMapping
public String write(@RequestBody BoardDto boardDto) {
return "ok";
}
}
@RestController는 Controller의 메서드 반환값을 View 이름으로 보지 않고, 응답 Body 데이터로 처리합니다.
@Controller + @ResponseBody
→ 응답 데이터를 직접 반환
@RestController
→ 기본적으로 응답 데이터를 직접 반환
그래서 REST API를 만들 때는 @RestController를 자주 사용합니다.
10. JSON 배열 받기
@RequestBody는 JSON 객체뿐만 아니라 JSON 배열도 받을 수 있습니다.
[
{
"title": "첫 번째 글",
"content": "내용 1"
},
{
"title": "두 번째 글",
"content": "내용 2"
}
]
Controller에서는 List로 받을 수 있습니다.
@PostMapping("/api/boards/bulk")
public String writeBulk(@RequestBody List<BoardDto> boardList) {
System.out.println("등록 개수: " + boardList.size());
return "ok";
}
요청 Body의 JSON 배열이 List<BoardDto>로 변환됩니다.
JSON 배열
→ @RequestBody
→ List<BoardDto>
11. JSON key와 DTO 필드명이 다르면?
JSON key와 DTO 필드명이 다르면 값이 제대로 들어오지 않을 수 있습니다.
{
"boardTitle": "Spring 공부"
}
public class BoardDto {
private String title;
}
JSON에서는 boardTitle로 보냈는데 DTO 필드는 title입니다. 이름이 다르기 때문에 자동 매핑이 되지 않을 수 있습니다.
가장 쉬운 방법은 JSON key와 DTO 필드명을 맞추는 것입니다.
{
"title": "Spring 공부"
}
public class BoardDto {
private String title;
}
특별히 이름을 다르게 써야 한다면 JSON 매핑 어노테이션을 사용할 수도 있지만, 처음에는 이름을 맞추는 방식으로 이해하는 것이 좋습니다.
12. @RequestBody를 쓰기 좋은 상황
@RequestBody는 JSON 데이터를 주고받는 API에서 자주 사용합니다.
| 상황 | 예시 |
| 프론트엔드에서 JSON 전송 | React, Vue, JavaScript fetch 요청 |
| REST API 작성 | POST /api/boards |
| JSON 객체를 DTO로 받고 싶을 때 | @RequestBody BoardDto boardDto |
| JSON 배열을 List로 받고 싶을 때 | @RequestBody List<BoardDto> |
반대로 JSP나 Thymeleaf의 일반 form 전송이라면 @ModelAttribute 또는 DTO 바인딩을 사용하는 경우가 더 많습니다.
13. 자주 하는 실수
1) form 전송을 @RequestBody로 받으려는 경우
HTML form 전송은 보통 @RequestBody가 아니라 DTO 바인딩이나 @ModelAttribute로 받습니다.
<form action="/board/write" method="post">
<input type="text" name="title">
<button type="submit">등록</button>
</form>
@PostMapping("/board/write")
public String write(BoardDto boardDto) {
return "redirect:/board/list";
}
2) JSON 전송인데 Content-Type을 빼먹는 경우
JSON 데이터를 보낼 때는 Content-Type: application/json을 지정하는 것이 중요합니다.
fetch("/api/boards", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
title: "Spring"
})
});
3) JSON.stringify를 빼먹는 경우
fetch로 JSON을 보낼 때는 JavaScript 객체를 JSON 문자열로 바꿔야 합니다.
body: JSON.stringify({
title: "Spring"
})
JSON.stringify를 빼먹으면 서버가 기대한 JSON 형태로 받지 못할 수 있습니다.
4) JSON key와 DTO 필드명이 다른 경우
JSON key와 DTO 필드명이 다르면 값이 들어오지 않을 수 있습니다. 처음에는 이름을 맞추는 것이 가장 안전합니다.
JSON key: title
DTO 필드: title
이름을 맞추면 매핑이 쉽다.
5) @Controller에서 @ResponseBody를 빼먹는 경우
@Controller에서 문자열을 반환하면 Spring은 그 문자열을 View 이름으로 해석할 수 있습니다. API 응답 데이터를 직접 반환하려면 @ResponseBody를 붙이거나 @RestController를 사용해야 합니다.
@PostMapping("/api/boards")
@ResponseBody
public String write(@RequestBody BoardDto boardDto) {
return "ok";
}
14. 전체 흐름 정리
JSON 요청을 @RequestBody로 받는 흐름은 다음과 같습니다.
1. 클라이언트가 JavaScript 객체를 만든다.
2. JSON.stringify로 JSON 문자열로 변환한다.
3. Content-Type을 application/json으로 지정한다.
4. 요청 Body에 JSON을 담아 서버로 보낸다.
5. Controller에서 @RequestBody로 DTO를 받는다.
6. Spring이 JSON을 DTO 객체로 변환한다.
7. Controller가 Service를 호출한다.
8. 필요한 결과를 응답한다.
이 흐름을 이해하면 프론트엔드와 백엔드가 JSON으로 데이터를 주고받는 구조를 더 쉽게 만들 수 있습니다.
정리
@RequestBody는 요청 Body에 들어있는 JSON 데이터를 Java 객체로 받을 때 사용하는 어노테이션입니다. REST API에서 JSON 요청을 DTO로 받을 때 자주 사용합니다.
| @RequestBody | 요청 Body의 JSON을 Java 객체로 변환합니다. |
| @ModelAttribute | HTML form 데이터나 요청 파라미터를 객체로 받습니다. |
| @ResponseBody | 응답 데이터를 Body에 직접 담아 반환합니다. |
| @RestController | 기본적으로 응답 데이터를 Body로 반환하는 Controller입니다. |
처음에는 다음 기준으로 기억하면 좋습니다.
HTML form 데이터
→ @ModelAttribute 또는 DTO 바인딩
JSON 요청 데이터
→ @RequestBody
응답 데이터를 직접 반환
→ @ResponseBody 또는 @RestController
연습해보기
아래 JSON 요청을 받을 DTO와 Controller 메서드를 작성해보세요.
{
"memberId": "springUser",
"memberPw": "1234",
"memberName": "스프링사용자"
}
예시는 다음과 같습니다.
public class MemberJoinDto {
private String memberId;
private String memberPw;
private String memberName;
// getter, setter
}
@RestController
@RequestMapping("/api/members")
public class MemberApiController {
@PostMapping
public String join(@RequestBody MemberJoinDto memberJoinDto) {
return "ok";
}
}
다음 글에서는 응답 데이터를 직접 반환하는 @ResponseBody와 @RestController에 대해 정리하겠습니다.

'Tech Stack > Spring Boot' 카테고리의 다른 글
| [Spring] 23. ResponseEntity란? (0) | 2026.07.16 |
|---|---|
| [Spring] 22. @ResponseBody와 @RestController (1) | 2026.07.15 |
| [Spring] 20. @ModelAttribute와 DTO 바인딩 (0) | 2026.07.13 |
| [Spring] 19. @PathVariable이란? (0) | 2026.07.12 |
| [Spring] 18. @RequestParam이란? (0) | 2026.07.11 |