이번 예제에서는 화면을 보여주는 역할과 사용자가 입력한 데이터를 처리하는 역할을 분리하였다.
@GetMapping
public String page() {
return "shirt";
}
GET 요청은 단순히 화면(shirt.jsp)을 반환한다.
실행 흐름
브라우저
↓
GET /shirt
↓
DispatcherServlet
↓
ShirtController.page()
↓
shirt.jsp
반면,
@PostMapping
public String register(...) {
POST 요청은 사용자가 입력한 데이터를 서버에서 처리한다.
즉,
| GET | POST |
|---|---|
| 화면 조회 | 데이터 처리 |
| View 반환 | 입력 데이터 저장 |
조회와 저장을 서로 분리하여 구현하는 방식을 학습하였다.
Servlet에서는 사용자가 입력한 값을 직접 꺼내야 했다.
String name = request.getParameter("name");
int price =
Integer.parseInt(
request.getParameter("price")
);
Spring MVC에서는
@PostMapping
public String register(
@ModelAttribute ShirtDTO shirtDTO
)
한 줄만 작성하면 된다.
Spring이 내부적으로
ShirtDTO dto = new ShirtDTO();
dto.setName(...);
dto.setPrice(...);
를 자동으로 수행한다.
이 과정을 Data Binding이라고 한다.
즉,
브라우저 입력값
↓
Spring
↓
DTO 생성
↓
Setter 호출
↓
Controller 전달
과정이 자동으로 이루어진다.
이번 DTO는 Lombok을 이용하여 작성하였다.
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class ShirtDTO
각 어노테이션의 역할은 다음과 같다.
| Annotation | 역할 |
|---|---|
| @Getter | Getter 자동 생성 |
| @Setter | Setter 자동 생성 |
| @NoArgsConstructor | 기본 생성자 생성 |
| @AllArgsConstructor | 모든 필드를 포함하는 생성자 생성 |
| @ToString | 객체 출력 메서드 생성 |
특히 Data Binding 과정에서는 Spring이
new ShirtDTO()
를 생성한 뒤 Setter를 호출하기 때문에
기본 생성자와 Setter가 반드시 필요하다는 점을 이해하였다.
Controller에서는 Session 객체도 함께 전달받는다.
@PostMapping
public String register(
@ModelAttribute ShirtDTO shirtDTO,
HttpSession session
)
Session은 사용자마다 독립적으로 유지되는 저장 공간이다.
사용자가 입력한 데이터를
session.setAttribute(
"shirt",
shirtDTO
);
를 이용하여 Session에 저장하였다.
동작 과정은 다음과 같다.
Controller
↓
HttpSession
↓
사용자 정보 저장
↓
다음 요청에서도 사용 가능
Model은 현재 요청에서만 사용할 수 있지만,
Session은 여러 요청에 걸쳐 데이터를 유지할 수 있다는 차이를 이해하였다.
데이터 저장 후
return "redirect:/shirt";
를 반환하였다.
Redirect는 JSP를 바로 실행하는 것이 아니라
브라우저에게
/shirt로 다시 요청하세요.
라고 응답하는 방식이다.
동작 과정은 다음과 같다.
POST /shirt
↓
Controller
↓
redirect:/shirt
↓
브라우저
↓
GET /shirt
↓
shirt.jsp
즉, POST 요청 이후 새로운 GET 요청이 발생한다.
만약
return "shirt";
를 사용하면
사용자가 새로고침(F5)을 눌렀을 때
POST 요청이 다시 실행된다.
POST
↓
상품 등록
↓
새로고침
↓
POST
↓
상품 또 등록
이처럼 같은 데이터가 중복 저장될 수 있다.
Redirect를 사용하면
POST
↓
Redirect
↓
GET
↓
새로고침
↓
GET만 실행
이 되어 중복 저장을 방지할 수 있다.
이러한 패턴을
PRG(Post-Redirect-Get)
패턴이라고 한다.
Step2에서는
model.addAttribute(...)
를 사용하였다.
Step3에서는
session.setAttribute(...)
를 사용하였다.
둘의 차이는 다음과 같다.
| Model | Session |
|---|---|
| 현재 요청에서만 사용 | 여러 요청 동안 유지 |
| View에 데이터 전달 | 사용자 정보 저장 |
| 요청 종료 시 삭제 | Session 종료 시 삭제 |
즉,
Model은 화면을 위한 데이터,
Session은 사용자 상태를 유지하기 위한 데이터라는 점을 이해하였다.
브라우저
↓
GET /shirt
↓
shirt.jsp 출력
↓
사용자 입력
↓
POST /shirt
↓
DispatcherServlet
↓
Spring Data Binding
↓
ShirtDTO 생성
↓
Session 저장
↓
redirect:/shirt
↓
브라우저
↓
GET /shirt
↓
shirt.jsp 출력
| Step2 | Step3 |
|---|---|
| 서버가 DTO 생성 | Spring이 DTO 자동 생성 |
| Model 사용 | Session 사용 |
| GET 요청만 처리 | GET + POST 처리 |
| 화면 출력 중심 | 사용자 입력 처리 |
| Forward | Redirect(PRG) |
Step2는 데이터를 화면으로 전달하는 과정이었다면,
Step3는 사용자가 입력한 데이터를 서버가 처리하는 과정을 학습하는 단계였다.