Spring Boot를 공부하다 보면 단순히 URL로 데이터를 전달하는 것에서 한 단계 더 나아가 사용자가 입력한 데이터를 서버로 전송하고 처리하는 방법을 배우게 된다.
이전 프로젝트에서는 @RequestParam을 이용해 URL의 Query Parameter를 받아 HTML 화면에 출력했다.
/greeting?name=Spring
이번 프로젝트에서는 HTML Form을 통해 사용자가 직접 데이터를 입력하고 서버가 이를 처리하는 방법을 학습하였다.
이번 프로젝트의 목표는 간단하다.
사용자가
http://localhost:8080/greeting
에 접속하면 다음과 같은 Form이 나타난다.
ID : [ ]
Message : [ ]
[Submit]
사용자가 값을 입력하고 Submit 버튼을 누르면
Result
id : 1
content : Hello Spring
처럼 입력한 내용이 새로운 화면에 출력된다.
즉,
HTML Form으로 입력한 데이터를 Spring Boot가 받아 처리하는 과정을 배우는 것이 이번 프로젝트의 핵심이다.
이전 프로젝트와 가장 큰 차이는 데이터를 전달하는 방식이다.
| Serving Web Content | Handling Form Submission |
|---|---|
| URL Parameter 사용 | HTML Form 사용 |
| GET 요청 | GET + POST 요청 |
@RequestParam 사용 | @ModelAttribute 사용 |
| URL에서 데이터 읽기 | Form에서 데이터 읽기 |
예를 들어
이전에는
/greeting?name=Spring
처럼 URL을 통해 데이터를 전달했다.
이번에는
ID : 1
Message : Hello Spring
을 Form에 입력하여 서버로 전송한다.
전체 동작 과정을 먼저 이해하면 이후 내용을 훨씬 쉽게 이해할 수 있다.
브라우저
↓
GET /greeting
↓
GreetingController
↓
greeting.html
↓
사용자가 Form 작성
↓
Submit
↓
POST /greeting
↓
GreetingController
↓
Greeting 객체 생성
↓
result.html
↓
결과 출력
이번 프로젝트에서는
GET과 POST가 각각 다른 역할을 수행한다.
먼저 사용자가
GET /greeting
으로 접속하면 다음 메서드가 실행된다.
@GetMapping("/greeting")
public String greetingForm(Model model) {
model.addAttribute("greeting", new Greeting());
return "greeting";
}
여기서 GET 요청의 역할은
사용자에게 입력 화면(Form)을 보여주는 것이다.
마지막의
return "greeting";
은
templates/greeting.html
을 실행하라는 의미이다.
다음 코드가 처음에는 조금 이해하기 어렵다.
model.addAttribute("greeting", new Greeting());
아직 사용자가 아무것도 입력하지 않았는데
왜 객체를 먼저 생성할까?
그 이유는
Thymeleaf와 Form을 연결하기 위해서이다.
즉,
Greeting 객체
↓
HTML Form
↓
사용자 입력
↓
Greeting 객체에 자동 저장
이라는 구조를 만들기 위해
빈 객체를 먼저 생성하는 것이다.
public class Greeting {
private long id;
private String content;
}
Greeting 클래스는
사용자가 입력한 데이터를 저장하는 객체이다.
예를 들어
ID : 1
Message : Hello Spring
을 입력하면
Greeting 객체는
Greeting
id = 1
content = "Hello Spring"
상태가 된다.
이처럼 데이터를 저장하기 위한 객체를
DTO(Data Transfer Object) 또는 Model 객체라고 한다.
HTML은 다음과 같이 작성된다.
<form
th:action="@{/greeting}"
th:object="${greeting}"
method="post">
<input th:field="*{id}" />
<input th:field="*{content}" />
</form>
여기서 중요한 속성을 하나씩 살펴보자.
th:action="@{/greeting}"
Submit 버튼을 누르면
POST /greeting
으로 요청을 보낸다.
즉,
Form 데이터를 어디로 전송할지 지정하는 역할을 한다.
method="post"
는
데이터를 POST 방식으로 서버에 전송한다.
HTTP Method의 역할을 정리하면 다음과 같다.
| Method | 역할 |
|---|---|
| GET | 데이터 조회 |
| POST | 데이터 전송 및 생성 |
이번 프로젝트는
사용자가 입력한 데이터를 서버로 보내야 하므로 POST를 사용한다.
th:object="${greeting}"
이 Form은
Controller가 전달한
Greeting 객체
와 연결된다는 의미이다.
즉,
Form에서 입력하는 값들이
Greeting 객체에 저장될 준비를 하는 것이다.
<input th:field="*{id}" />
<input th:field="*{content}" />
각 입력창은
Greeting 객체의 변수와 연결된다.
Greeting.id
↓
id 입력창
----------------
Greeting.content
↓
Message 입력창
사용자가 입력한 값은
Greeting 객체의 변수에 자동으로 저장된다.
사용자가 Submit 버튼을 누르면
다음 메서드가 실행된다.
@PostMapping("/greeting")
public String greetingSubmit(
@ModelAttribute Greeting greeting,
Model model) {
model.addAttribute("greeting", greeting);
return "result";
}
이번 프로젝트의 핵심은 바로 이 메서드이다.
@PostMapping("/greeting")
은
POST /greeting
요청이 들어왔을 때
해당 메서드를 실행한다는 의미이다.
같은 URL이라도
HTTP Method에 따라
다른 메서드를 실행할 수 있다.
GET /greeting
↓
Form 출력
--------------------
POST /greeting
↓
입력 데이터 처리
이번 프로젝트에서 새롭게 등장하는 어노테이션이다.
@ModelAttribute Greeting greeting
의 의미는
Form 데이터를 Greeting 객체에 자동으로 저장하라.
예를 들어
사용자가
ID : 10
Message : Hello Spring
을 입력했다면
Spring은 내부적으로
Greeting greeting = new Greeting();
greeting.setId(10);
greeting.setContent("Hello Spring");
을 자동으로 수행한다.
즉,
개발자가 직접
setId()
setContent()
를 호출할 필요가 없다.
이것이 @ModelAttribute의 가장 큰 장점이다.
이전 프로젝트에서는
@RequestParam
을 사용하였다.
이번에는
@ModelAttribute
를 사용하였다.
둘의 차이는 다음과 같다.
| @RequestParam | @ModelAttribute |
|---|---|
| 하나의 값을 받을 때 사용 | 여러 값을 객체로 받을 때 사용 |
| Query Parameter 사용 | Form 데이터 사용 |
| String, int 등 단일 데이터 | 객체 전체를 생성 |
예를 들어
이전 프로젝트에서는
@RequestParam String name
으로 하나의 값만 받았다.
하지만
이번 프로젝트에서는
Greeting
객체 전체를 자동으로 생성하여 사용한다.
Controller의 마지막에는
return "result";
가 있다.
Spring은
templates/result.html
을 찾아 실행한다.
HTML에서는
<p th:text="'id : ' + ${greeting.id}"></p>
<p th:text="'content : ' + ${greeting.content}"></p>
처럼 작성되어 있다.
여기서
${greeting.id}
${greeting.content}
는
Controller에서 전달한 Greeting 객체의 데이터를 출력하는 것이다.
이번 프로젝트의 전체 흐름을 하나의 그림으로 정리하면 다음과 같다.
사용자
↓
GET /greeting
↓
GreetingController
↓
greeting.html 출력
↓
사용자가 Form 입력
↓
Submit
↓
POST /greeting
↓
GreetingController
↓
@ModelAttribute
↓
Greeting 객체 생성
↓
Model 저장
↓
result.html
↓
사용자가 입력한 데이터 출력
이번 프로젝트를 통해 다음과 같은 내용을 학습하였다.
@GetMapping@PostMappingModelGreeting 객체@ModelAttributeth:objectth:field이번 프로젝트를 통해 Spring MVC에서 사용자의 입력을 서버가 처리하는 전체 과정을 이해할 수 있었다.
특히 가장 중요한 개념은 @ModelAttribute였다.
이전에는 @RequestParam을 이용하여 URL의 값을 하나씩 전달받았다면, 이번에는 Form의 여러 입력값을 하나의 객체로 자동 변환하여 사용할 수 있었다.
또한 Thymeleaf의 th:object와 th:field를 이용하면 HTML Form과 Java 객체를 자연스럽게 연결할 수 있다는 점도 알게 되었다.
이번 프로젝트는 이후 회원가입, 로그인, 게시글 작성과 같은 기능을 구현하기 위한 가장 기본적인 Form 처리 방식이므로 반드시 이해하고 넘어가야 하는 내용이라고 생각한다.