본문 바로가기
Everyday Study

2024.10.10(목) { @ModelAttribute와 @SessionAttributes ,@GetMapping("/{id}") }

by xogns93 2024. 10. 10.

@ModelAttribute@SessionAttributes는 모두 스프링 MVC에서 데이터 바인딩과 세션 관리를 위해 사용됩니다. 이 두 애노테이션을 함께 사용하면, 세션에 저장된 데이터를 쉽게 바인딩하거나, 세션 속성에 접근할 수 있습니다. @ModelAttribute는 주로 폼 데이터 바인딩에 사용되고, @SessionAttributes세션에 특정 모델 속성을 저장하여 여러 요청 간에 유지할 수 있게 해줍니다.

아래에서 @ModelAttribute@SessionAttributes를 함께 사용하는 방식에 대해 설명하겠습니다.

1. @ModelAttribute@SessionAttributes의 역할

@ModelAttribute

  • 바인딩: @ModelAttribute는 요청 파라미터를 자동으로 모델 객체에 바인딩하는 데 사용됩니다. 주로 폼 데이터를 자바 객체에 바인딩하거나, 모델 객체를 뷰로 전달할 때 사용합니다.
  • 뷰에서 사용: 모델에 추가된 속성은 뷰(HTML, JSP 등)에서 쉽게 참조할 수 있습니다.

@SessionAttributes

  • 세션 저장: @SessionAttributes특정 모델 속성을 세션에 저장하여, 해당 속성이 여러 요청 간에 유지되도록 합니다.
  • 다중 요청 간 상태 유지: 주로 사용자 세션 상태를 유지하거나, 여러 페이지에 걸친 폼 데이터를 유지할 때 사용됩니다.

2. @ModelAttribute@SessionAttributes를 함께 사용

이 두 애노테이션을 함께 사용하면, 컨트롤러에서 처리된 데이터를 세션에 저장하고, 이후의 요청에서도 세션에 저장된 데이터에 접근할 수 있습니다.

예시 시나리오

사용자가 여러 단계를 거쳐서 데이터를 입력하는 폼이 있다고 가정해 봅시다. 사용자는 페이지를 이동하면서 입력한 데이터를 세션에 저장해야 하고, 마지막 단계에서 세션에 저장된 모든 데이터를 제출할 수 있어야 합니다.

1) @SessionAttributes@ModelAttribute를 설정한 컨트롤러

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.ui.Model;

@Controller
@SessionAttributes("userForm")  // "userForm" 모델 속성을 세션에 저장
public class UserController {

    // 첫 번째 단계: 사용자가 첫 번째 페이지를 요청할 때 userForm 객체 생성
    @RequestMapping("/step1")
    public String step1(Model model) {
        model.addAttribute("userForm", new UserForm());  // 새로운 UserForm 객체를 모델에 추가하고 세션에 저장
        return "step1";  // "step1.html"로 이동
    }

    // 두 번째 단계: 사용자가 입력한 데이터 처리
    @RequestMapping("/step2")
    public String step2(@ModelAttribute("userForm") UserForm userForm) {
        // "userForm" 모델 속성은 세션에 저장된 객체를 참조
        // 폼 데이터를 바인딩하여 userForm 객체에 자동으로 설정됨
        return "step2";  // "step2.html"로 이동
    }

    // 마지막 단계: 세션에 저장된 userForm 데이터 제출
    @RequestMapping("/submit")
    public String submit(@ModelAttribute("userForm") UserForm userForm, SessionStatus sessionStatus) {
        // 세션에 저장된 "userForm"을 사용하여 데이터 처리
        // 이후 세션을 정리
        sessionStatus.setComplete();  // 세션에 저장된 "userForm" 속성 제거
        return "result";  // 결과 페이지로 이동
    }
}

3. 동작 흐름 설명

  1. 첫 번째 단계 (/step1):
    • 사용자가 /step1 URL을 요청하면, 컨트롤러는 UserForm 객체를 생성하고 세션에 저장합니다.
    • @SessionAttributes("userForm") 덕분에 userForm 객체가 세션에 유지됩니다.
    • 이 단계에서 사용자는 폼에 데이터를 입력하고, 해당 데이터는 세션에 저장userForm 객체에 바인딩됩니다.
  2. 두 번째 단계 (/step2):
    • 사용자가 /step2 페이지로 이동하면, 세션에 저장된 userForm 객체가 자동으로 바인딩됩니다.
    • 스프링은 세션에서 userForm을 가져와 사용자가 입력한 데이터를 유지하며, 이후의 폼 데이터가 계속해서 이 객체에 바인딩됩니다.
  3. 최종 단계 (/submit):
    • 사용자가 최종적으로 폼을 제출하면, userForm 객체에 저장된 데이터를 처리하고, 제출 후 sessionStatus.setComplete()를 호출하여 세션에서 userForm을 제거합니다. 이는 세션이 더 이상 필요하지 않음을 의미합니다.

4. 세션 속성에 접근하는 @ModelAttribute

  • @ModelAttribute세션에 저장된 모델 속성을 매개변수로 주입받을 수 있습니다. 즉, 세션에 이미 저장된 속성을 폼이나 다른 페이지에서 계속해서 사용할 수 있습니다.
  • 사용자가 세션에 저장된 데이터를 수정하거나 추가할 때, @ModelAttribute폼 데이터를 바인딩할 때 자동으로 세션 데이터를 사용할 수 있습니다.

5. 세션 속성 관리와 SessionStatus

  • SessionStatus.setComplete(): 세션에 저장된 특정 속성을 더 이상 사용할 필요가 없을 때, 이를 명시적으로 제거할 수 있습니다. 세션 속성을 정리하지 않으면 세션이 계속해서 유지되며, 다른 페이지에서 의도치 않게 사용될 수 있습니다.
  • 세션 상태 관리: 여러 요청 간 상태를 유지하기 위해 필요한 속성만을 세션에 저장하고, 불필요한 속성은 제거하는 것이 중요합니다. 세션이 길어지면 메모리와 리소스를 많이 차지할 수 있기 때문에 적절히 관리해야 합니다.

6. 요약

  • @ModelAttribute: 주로 폼 데이터 바인딩모델 속성을 컨트롤러 메서드에 전달하는 데 사용됩니다. 세션에 저장된 속성에 접근할 수 있으며, 폼 데이터를 자동으로 바인딩해줍니다.
  • @SessionAttributes: 특정 모델 속성을 세션에 저장하여, 여러 요청 간 상태를 유지하는 데 사용됩니다.
  • 두 애노테이션을 함께 사용하면, 세션에 저장된 모델 속성에 자동으로 접근할 수 있고, 폼 데이터를 바인딩하여 여러 페이지에 걸친 폼 데이터 처리도 가능합니다.

@GetMapping("/{id}")에서 중괄호 {}는 경로 변수(Path Variable)를 나타냅니다. 이는 URL 경로의 일부분을 변수로 사용하여 메서드에서 해당 값을 동적으로 처리할 수 있게 해줍니다.

 

@GetMapping("/posts/{id}")
public String getPostById(@PathVariable("id") Long id, Model model) {
    // id를 사용하여 처리
    Post post = postService.findById(id);
    model.addAttribute("post", post);
    return "post/detail";
}

위 코드를 통해 설명하자면:

  • @GetMapping("/posts/{id}")는 /posts/1, /posts/2 같은 경로에서 id 값을 추출하여 해당 메서드로 전달하는 역할을 합니다.
  • {id}는 경로에서 동적으로 변하는 부분을 나타내며, 이를 통해 URL의 일부분을 변수로 받아 처리할 수 있습니다.
  • @PathVariable("id")를 사용하여 해당 경로에서 가져온 값을 메서드 인자로 전달받아 사용하게 됩니다.

즉, @GetMapping("/posts/{id}")에서 {id}는 URL의 변수 부분을 의미하며, 이 값을 받아서 메서드 내부에서 처리할 수 있게 해주는 역할을 합니다.