반응형
📌 @SessionAttributes
여러 단계에 걸쳐서 입력된 데이터를 HttpSession에 옮겨담아 데이터가 유지되도록 해주는 어노테이션
- Model 객체에 저장되는 데이터를 HttpSession에 저장시키는 어노테이션
- 컨트롤러 클래스에 @SessionAttributes 어노테이션이 있으면
해당 컨트롤러의 요청핸들러 메서드에서 Model객체에 저장되는 데이터를 HttpSession 객체의 속성으로 저장시켜서 해당 요청이 완료된 후에도 Model객체에 저장한 데이터가 유지되도록 한다. - 다른 요청핸들러 메서드와 Model객체에 저장된 데이터를 공유하기 위해서다.
- Model객체에 저장되는 모든 데이터가 HttpSession에 저장되는 것이 아니라,
@SessionAttributes 어노테이션에서 지정한 이름과 동일한 이름으로 Model 객체에 저장되는 데이터만 대상이 된다.
💡 사용예시)
- 하나의 Form클래스를 크게 만들고 1단계, 2단계, 3단계로 나눈다.
- 입력단계로 진입하는 곳에서 미리 그 객체를 만들어서 Model에 담는다.
1. Form클래스
@Getter
@Setter
@ToString
public class OrderForm {
// 1단계에서 입력되는 값(orderform.jsp)
private int productNo;
private String name;
private int price;
private int amount;
private int totalPrice;
// 2단계에서 입력되는 값(payform.jsp)
private String payType;
private String cardno;
private int months;
private int payAmount;
}
2. Controller
@Controller
@RequestMapping("/order")
@RequiredArgsConstructor
@SessionAttributes({"orderForm"}) // ==> 해당 Controller 안에서 orderForm이라는 이름으로
public class OrderController { // Model에 담기는 게 있으면, Session의 속성으로 옮겨담는 역할
private final ProductService productService;
@GetMapping("/step1")
public String step1(@RequestParam("no") int productNo, Model model) {
// 1. 주문폼 화면에 출력할 상품정보를 조회하고, Model객체에 저장한다.
Product product = productService.getProduct(productNo);
model.addAttribute("product", product);
// 2. 여러 단계로 구분된 입력작업에서 입력되는 데이터를 저장할 OrderForm객체를 생성하고,
// Model객체에 저장한다.
// "orderForm"이라는 이름으로 Model객체에 저장되는 데이터는
// @SessionAttributes("orderForm") 설정 때문에 OrderForm객체가 HttpSession에 자동으로 저장된다.
model.addAttribute("orderForm", new OrderForm());
return "order/orderform";
}
// 2단계, 3단계에서는 1단계에서 전달받은 Model의 데이터가 변경되지 않고 유지된다.
@PostMapping("/step2")
public String step2(OrderForm orderForm) {
return "order/payform";
}
@PostMapping("/step3")
public String step3(OrderForm orderForm) {
return "order/completed";
}
}
3. payform.jsp (2단계)
${orderForm.프로퍼티명 }
으로 출력 가능
<table class="table">
<thead>
<tr>
<th>상품이름</th>
<td>${orderForm.name }</td>
<th>상품가격</th>
<td><fmt:formatNumber value="${orderForm.price }" /> 원</td>
</tr>
<tr>
<th>구매수량</th>
<td><fmt:formatNumber value="${orderForm.amount }" /> 개</td>
<th>총 구매가격</th>
<td><fmt:formatNumber value="${orderForm.totalPrice }" /> 원</td>
</tr>
</thead>
</table>
📌 @ModelAttribute
클라이언트로부터의 요청 데이터를 받아와 컨트롤러 메서드의 매개변수에 바인딩하는 어노테이션
(주로 HTML 폼으로부터 받은 데이터를 모델에 바인딩하거나, 공통적인 데이터를 모델에 추가하는 데 사용됨)
- 메서드에 @ModelAttribute 어노테이션을 지정하면,
Spring mvc는 요청핸들러 메서드를 실행하기 전에 @ModelAttribute 어노테이션이 지정된 메서드를 먼저 실행해서 그 메서드가 반환하는 값을 Model 객체에 저장시킨다. - @ModelAttribute 어노테이션을 ControllerAdvice에 등록해놓으면 모든 컨트롤러에서 사용 가능하고, Controller에서 정의하면 해당 컨트롤러에서만 사용 가능하다.
- 따라서, 많은 요청핸들러 메서드가 실행된 다음에 내부이동하는 JSP에서 특정한 값을 표현하는 (공통적인)부분이 있으면,
각각의 요청핸들러 메서드에서 그 정보를 조회해서 Model객체에 저장하지 말고
@ModelAttribute 어노테이션이 지정된 메서드에서 정보를 조회하고 반환하도록 하자.
✔️ 과정
1. 요청핸들러 메서드의 매개변수에 적용했을 때
public String sample(@ModelAttribute("sampleForm") SampleForm form) { ... }
- @ModelAttribute 어노테이션이 지정된 객체를 자동으로 생성한다.
만약, "sampleForm"이라는 이름으로 HttpSession에 저장된 객체가 있으면 그 객체를 가져온다. - 요청객체의 요청파라미터 값을 분석해서 SampleForm객체에 바인딩한다.
- @ModelAttribute 어노테이션이 지정된 객체는 Model객체에 "sampleForm"이라는 이름으로 저장되고, 뷰페이지에 값을 출력할 수 있다.
2. 메서드에 적용했을 때
@ModelAttribute("categories")
public List<Category> categories() {
List<Category> categories = categoryService.getAllCategories();
return categories;
}
- 요청핸들러 메서드가 실행되기 전에 @ModelAttribute가 지정된 메서드부터 먼저 실행된다.
- @ModelAttribute 어노테이션이 부착된 메서드가 반환하는 값을 자동으로 Model객체에 저장한다.
- 요청핸들러 메서드가 실행된다.
- 여러 JSP에서 공통으로 사용하는 데이터를 @ModelAttribute 어노테이션을 적용한 메서드로 Model객체에 저장시키면 각각의 요청핸들러 메서드에서 그 데이터를 Model객체에 저장시키는 작업을 수행할 필요가 없다.
💡 예시)
1. ControllerAdvice
@ControllerAdvice
@RequiredArgsConstructor
public class ModelAttributeAdvice {
private final ProductService productService;
// 해당 메서드가 반환하는 값을 Model 객체에 저장시키는데,
// 그 이름이 name = "productCategories"
// (중간단계 없이 jsp에서 이 이름으로 바로 호출 가능)
@ModelAttribute(name = "productCategories")
public List<ProductCategory> productCategories() {
return productService.getAllProductCategories();
}
}
2. category.jsp
<div class="card">
<div class="card-header">상품 카테고리</div>
<div class="list-group list-group-flush">
<!-- productCategories 사용 -->
<c:forEach var="category" items="${productCategories }">
<a href="/product/list?catNo=${category.no}"
class="list-group-item list-group-item-action">
${category.name }
</a>
</c:forEach>
</div>
</div>
3. list.jsp / detail.jsp
<div class="col-3">
<!-- include 지시어로 category.jsp 파일 삽입 -->
<%@ include file="../common/category.jsp" %>
</div>
❓ 두 어노테이션의 차이점
- Q. 둘다 Model에 저장하고, 지정한 변수명으로 jsp에서 출력할 수 있는 건 똑같은데 무슨 차이지?
- A. 둘의 역할은 엄연히 다르다.
각각의 개념을 다시 살펴보면,
@SessionAttributes는 여러 단계에 걸쳐서 입력된 데이터를 HttpSession에 옮겨담아 데이터가 유지되도록 해주는 어노테이션이고,
@ModelAttribute는 클라이언트로부터의 요청 데이터를 받아와 컨트롤러 메서드의 매개변수에 바인딩하는 어노테이션이다.
@ModelAttribute 단독 사용 시 여러 단계로 구분된 입력작업에서 데이터 유지가 되지 않고,
@SessionAttributes는 컨트롤러 메소드의 매개변수로 전달된 요청 데이터를 처리하는 데는 사용되지 않는다.
< 해당 글은 velog에서 이전하며 옮겨온 글로, 가독성이 좋지 않을 수 있는 점 양해 부탁드립니다. >
🔗 velog 버전 보기 : https://velog.io/@ryuneng2/Spring-SessionAttributes-ModelAttribute
'BackEnd > Spring' 카테고리의 다른 글
[Spring] @ResponseBody, @RestController (0) | 2025.01.18 |
---|---|
[Spring] @Transactional 트랜잭션 처리 (0) | 2025.01.18 |
[Spring] AOP 활용 - @ControllerAdvice, @ExceptionHandler (0) | 2025.01.18 |
[Spring] mybatis의 selectKey를 통한 시퀀스 획득 (0) | 2025.01.18 |
[Spring] Spring Security 설정하기(FilterChain 처리 과정) (0) | 2025.01.18 |