Handler Method : @SessionAttributes

2024. 10. 9. 12:20Spring Framework/Web on Servlet Stack

https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-methods/sessionattributes.html


@SessionAttributes 어노테이션은 HTTP 세션에 특정 모델 속성(Model Attribute)을 저장하여 여러 요청 간에 이 속성을 유지하고 사용할 수 있도록 해줍니다. 이는 주로 폼 데이터를 여러 단계에 걸쳐 처리하거나, 특정 상태를 유지할 필요가 있을 때 유용합니다.

기본 개념

  • @SessionAttributes는 컨트롤러 클래스 레벨에 적용되며, 해당 컨트롤러에서 사용되는 특정 모델 속성이나 속성 타입을 세션에 저장하도록 선언합니다.
  • 이 어노테이션을 사용하면, 한 번 요청에서 모델에 추가된 속성(예: pet 객체)이 여러 요청에 걸쳐 유지됩니다. 모델 속성은 세션에 저장되며, 다른 컨트롤러 메서드에서 이를 다시 꺼내 사용할 수 있습니다.

예시 상황:

사용자가 반려동물 정보를 입력하는 폼을 여러 단계에 걸쳐 처리하고 싶다고 가정해 봅시다. 첫 번째 단계에서는 반려동물의 기본 정보를 입력하고, 두 번째 단계에서는 추가 정보를 입력한 뒤 모든 정보를 저장하는 흐름입니다. 이런 경우 @SessionAttributes를 사용하면 Pet 객체를 세션에 저장하여 각 단계에서 이를 재사용할 수 있습니다.

예시 코드 (Java)

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.validation.BindingResult;

@Controller
@SessionAttributes("pet")  // "pet"이라는 모델 속성을 세션에 저장
public class EditPetForm {

    // 첫 번째 단계: Pet 객체를 모델에 추가하여 세션에 저장
    @ModelAttribute("pet")
    public Pet setUpPetForm() {
        return new Pet();  // 새로운 Pet 객체 생성
    }

    // 두 번째 단계: Pet 객체 사용 및 처리
    @PostMapping("/pets/{id}/edit")
    public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result, SessionStatus status) {
        if (result.hasErrors()) {
            return "petForm";  // 오류가 있을 경우 다시 폼으로 이동
        }
        // 성공적인 처리 후, 세션에서 "pet" 객체 제거
        status.setComplete();  
        return "redirect:/pets";  // 목록 페이지로 리다이렉트
    }
}

코드 설명:

  1. @SessionAttributes("pet"): EditPetForm 컨트롤러에서 사용되는 pet이라는 이름의 모델 속성을 세션에 저장하도록 지정합니다. 이를 통해 pet 객체는 여러 요청 간에 세션을 통해 유지됩니다.
  2. @ModelAttribute("pet"): 첫 번째 요청에서 새로운 Pet 객체를 생성하여 모델에 추가합니다. 이 모델 속성은 @SessionAttributes에 의해 세션에 저장됩니다.
  3. SessionStatus status: processSubmit 메서드의 마지막 단계에서 세션에 저장된 pet 객체를 제거하기 위해 SessionStatus 객체를 사용합니다. status.setComplete() 메서드를 호출하면 세션에 저장된 pet 객체가 삭제됩니다.
  4. BindingResult result: 데이터 바인딩 및 유효성 검사 결과를 처리하는 아규먼트입니다. 폼에 오류가 있을 경우, 다시 폼 페이지로 이동하며 오류 메시지를 표시합니다.

세션 관리 흐름

  1. 첫 번째 요청에서는 @ModelAttribute를 통해 Pet 객체가 생성되고, 세션에 저장됩니다.
  2. 이후 다른 요청에서 이 세션에 저장된 pet 객체를 자동으로 재사용하여 처리할 수 있습니다.
  3. 모든 처리가 완료되면 SessionStatus를 사용해 세션에서 객체를 제거합니다. 이렇게 하지 않으면 세션에 계속 유지될 수 있습니다.

Reactive 스택에서의 사용 (Spring WebFlux)

Spring WebFlux에서는 @SessionAttributes 어노테이션이 지원되지 않습니다. 이는 WebFlux가 비동기적이고 논블로킹(non-blocking) 방식으로 동작하기 때문에, HTTP 세션을 직접적으로 다루는 구조가 아닌 다른 방식으로 상태를 관리해야 하기 때문입니다.

WebFlux에서는 세션 관리를 위해 WebSession을 사용하여 세션 데이터를 다룰 수 있습니다. 이는 MonoFlux 같은 비동기 방식으로 세션 데이터를 처리합니다.

WebFlux 예시 코드

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.server.WebSession;
import reactor.core.publisher.Mono;

@Controller
public class ReactivePetForm {

    @PostMapping("/pets/edit")
    public Mono<String> processSubmit(WebSession session) {
        return session.getAttribute("pet")
                .flatMap(pet -> {
                    // 처리 로직...
                    session.invalidate();  // 세션 데이터 제거
                    return Mono.just("redirect:/pets");
                });
    }
}

코드 설명:

  • WebSession: WebFlux에서 세션을 관리하는 방식입니다. 이 예시에서는 세션에서 pet 객체를 가져와 처리하고, 작업이 완료되면 세션을 무효화(invalidate)하여 세션 데이터를 제거합니다.
  • session.getAttribute("pet"): 세션에서 pet 객체를 가져오는 비동기 처리 방식입니다.

요약

  • @SessionAttributes는 여러 요청 간에 세션을 통해 모델 속성을 유지할 수 있게 해주는 어노테이션입니다.
  • 세션에 저장된 모델 속성은 SessionStatus를 사용하여 명시적으로 제거해야 합니다.
  • Spring WebFlux에서는 @SessionAttributes가 지원되지 않으며, 대신 WebSession을 사용하여 비동기적으로 세션 데이터를 관리합니다.