[Spring] @SessionAttributes와 @ModelAttribute 어노테이션 (차이점)

류넹·2024년 3월 11일
1

Spring

목록 보기
31/50

📌 @SessionAttributes

여러 단계에 걸쳐서 입력된 데이터를 HttpSession에 옮겨담아 데이터가 유지되도록 해주는 어노테이션

  • Model 객체에 저장되는 데이터를 HttpSession에 저장시키는 어노테이션

  • 컨트롤러 클래스에 @SessionAttributes 어노테이션이 있으면
    해당 컨트롤러의 요청핸들러 메서드에서 Model객체에 저장되는 데이터를 HttpSession 객체의 속성으로 저장시켜서 해당 요청이 완료된 후에도 Model객체에 저장한 데이터가 유지되도록 한다.

  • 다른 요청핸들러 메서드와 Model객체에 저장된 데이터를 공유하기 위해서다.

  • Model객체에 저장되는 모든 데이터가 HttpSession에 저장되는 것이 아니라,
    @SessionAttributes 어노테이션에서 지정한 이름과 동일한 이름으로 Model 객체에 저장되는 데이터만 대상이 된다.



💡 사용예시)

  1. 하나의 Form클래스를 크게 만들고 1단계, 2단계, 3단계로 나눈다.
  2. 입력단계로 진입하는 곳에서 미리 그 객체를 만들어서 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) { ... }
  1. @ModelAttribute 어노테이션이 지정된 객체를 자동으로 생성한다.
    만약, "sampleForm"이라는 이름으로 HttpSession에 저장된 객체가 있으면 그 객체를 가져온다.
  2. 요청객체의 요청파라미터 값을 분석해서 SampleForm객체에 바인딩한다.
  3. @ModelAttribute 어노테이션이 지정된 객체는 Model객체에 "sampleForm"이라는 이름으로 저장되고, 뷰페이지에 값을 출력할 수 있다.

2. 메서드에 적용했을 때

@ModelAttribute("categories")
public List<Category> categories() {
	List<Category> categories = categoryService.getAllCategories();
    return categories;
}
  1. 요청핸들러 메서드가 실행되기 전에 @ModelAttribute가 지정된 메서드부터 먼저 실행된다.
  2. @ModelAttribute 어노테이션이 부착된 메서드가 반환하는 값을 자동으로 Model객체에 저장한다.
  3. 요청핸들러 메서드가 실행된다.
  4. 여러 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는 컨트롤러 메소드의 매개변수로 전달된 요청 데이터를 처리하는 데는 사용되지 않는다.

profile
학습용 커스터마이징 간단 개발자 사전

0개의 댓글