[Spring] Request vs Model vs Session과 @SessionAttributes 사용법

민지·2024년 1월 23일
0

앞선 포스팅의 @RequestParam과 model 개념을 배울 때 잠깐 request scope와 model scope, session scope에 대해 언급했었다. 이번 포스팅에서는 해당 3가지 개념의 scope를 비교해보고, 그 중 세션을 사용하는 방법인 @SessionAttributes에 대해 정리해보겠다.

1. Request scope VS Model scope VS Session scope

request scope

request에 있는 모든 값들은 오직 그 request URL에서만 유효하다.

예를 들어, login 페이지의 request에서 유효했던 name과 password 값들은, welcome 페이지로 가면 name과 password 값이 존재하지 않음을 볼 수 있었다. (개발자 도구 탭, network, payload data에)

즉, login.jsp에서 사용가능했던 name과 password값들은 welcome.jsp에서는 존재하기 않아서 사용할 수 없었다.

model scope

model scope는 by default로, request scope와 동일하게 작동한다. 즉, 컨트롤러 코드에서 넣은 model 값 또한 해당 URL의 뷰에서만 사용가능하고, 다른 뷰에서는 모델값을 사용할 수 없었다.

그렇기에 더 오래 값들을 기억하고 사용하고 싶다면, 보다 더 넓은 범위인 session에 값을 집어넣으면 된다.

session scope

결론부터 말하자면, session의 범위는 다수의 request URL에서 유지된다.

Session scope에서는 세부정보(값)들이 다수의 request URL에 걸쳐 저장된다. request가 login -> welcome으로 가는 것과 같이, 다수의 request URL에서 session값인 name이 유지되는 것을 확인할 수 있었다! (이때, name은 session scope에 저장된 것임!)

세션에 값을 넣으려면 @SessionAttributes 어노테이션을 사용하면 된다.

2. @SessionAttributes 사용법

1. model scope

해당 model 값은, 해당 request URL에서만 값이 유지된다.

// listTodos.jsp
<html>
	<head>
		<title>List Todos Page</title>
	</head>
	<body>
		<div>Welcome ${name}</div>
		<div>Your todos are : ${todos}</div>

	</body>
</html>

// TodoController.java
@Controller
public class TodoController {

	private TodoService todoService;

	@Autowired
	public TodoController(TodoService todoService) {
		super();
		this.todoService = todoService;
	}

	// list-todos
	@RequestMapping("/list-todos")
	public String listAllTodos(ModelMap model) {

		List<Todo> todos = todoService.findByUsername("minjiki2");

		model.addAttribute("todos", todos);

		return "listTodos";
	}
}

즉, 위 코드에서 model에 todos만 넣었고, 그 todos는 "/list-todos"에서만 값이 유지된다. 그러니 listTodos.jsp에서는 유효한 모델 값은 todos만 되니, name값은 없어서 공백으로 나온다.

왜냐하면, model.put("name", name); 은 /login + POST method와 RequestMapping된 LoginController의 gotoWelcomePage메서드에 추가되어 있기 때문이다.

2. Session scope - @SessionAttributes

그렇기에 name값을 오래도록 기억할 수 있도록, LoginController에서 @SessionAttributes를 사용해 세션에 name값을 넣자!

핵심을 말하자면, LoginController에서 model.put("name", name);의 "name속성값"이 /login request URL 뿐만 아니라 다른 URL인 /list-todos request URL에서도 유지되길 원했다. 그래서 @SessionAttributes를 이용해 model.put("name", name"); 을 넣을 때, model scope가 아닌 session scope으로 속성값의 범위를 넓혔다.

이렇게 하면, "name" 속성값이 세션에서 관리되므로 다수의 여러 request URL에서 공유되어 유지 가능하다!

@SessionAttributes 사용법

컨트롤러 메서드의 모델에 넣은 (model.addAttribute("name", value)나 model.put("name", value)를 통해) 정보 중에서, @SessionAttributes에서 지정한 이름과 동일한 이름이 있다면, 이를 "model에 추가될 때" session scope에 저장해준다.

// @SessionAttributes 예제코드
@Controller
@SessionAttributes("event")
public class SampleController {
	
    @RequestMapping("/events/form")
    public String getEvent(Model model){
    	Event event = new Event();
        event.setLimit(50);
        event.setName("event1");
        
        model.addAttribute("event", event); // 속성명 - 속성값
        
        return "/events/form";
    }
}

@SessionAttributes 어노테이션 사용시 주의할 점!

  1. model.put("name", value); 또는 model.addAttribute("name", value); 으로 컨트롤러에서 model에 넣는 속성명과 @SessionAttributes의 괄호 안의 속성명이 같아야 한다.
    • model.addAttribute의 속성명과 @SessionAttributes의 괄호 안의 값이 같아야, model에 추가될 때 자동으로 (model보다 훨씬 오래 가는) 세션으로 넣어주기에
  1. 해당 세션을 사용하는 컨트롤러 모두에 @SessionAttributes를 추가해준다.
    • 즉, LoginController와 TodoController 모두에 @SessionAttributes를 추가해주었다.

3. @SessionAttributes를 추가한 LoginController와 TodoController

// LoginController.java
@Controller
@SessionAttributes("name")
public class LoginController {

	private AuthenticationService authenticationService;

	@Autowired
	public LoginController(AuthenticationService authenticationService) {
		super();
		this.authenticationService = authenticationService;
	}

	@RequestMapping(method = RequestMethod.GET, value = "/login")
	public String gotoLoginPage() {

		return "login";
	}

	@RequestMapping(method = RequestMethod.POST, value = "/login")
	public String gotoWelcomePage(@RequestParam String name, @RequestParam String password, ModelMap model) {

		if (authenticationService.authenticate(name, password)) {
			model.put("name", name);

			return "welcome";
		}
		String errorMsg = "admin login is failed! Please try again";
		model.put("error", errorMsg);
		return "login";
	}
}


@Controller
@SessionAttributes("name")
public class TodoController {

	private TodoService todoService;

	@Autowired
	public TodoController(TodoService todoService) {
		super();
		this.todoService = todoService;
	}

	// list-todos
	@RequestMapping("/list-todos")
	public String listAllTodos(ModelMap model) {

		List<Todo> todos = todoService.findByUsername("minjiki2");

		model.addAttribute("todos", todos);

		return "listTodos";
	}
}

name속성값을 model scope가 아닌 보다 넓은 범위의 session scope으로 추가하고 나서야 앞선 실행결과와 달리, Welcome "admin" 값이 나왔다.

마치며..

  • Request Scope -> 해당 request가 발생한 URL에서 값이 유지된다.

  • Session Scope -> 세부정보가 다수의 request URL에 걸쳐 저장된다.

    • request가 login -> welcome URL로 이동하는 것과 같이, 다수의 request URL에서 session값인 name이 유지되는 것을 확인할 수 있었다. (이때의 name은 session scope에 저장한 것임)
  • Model Scope

    • by default로, 모델에 넣는 속성값은 request scope에서 작동되지만 @SessionAttributes 어노테이션을 통해 Session Scope에서도 작동할 수 있게끔 한다.

이 시리즈는 Udemy 강의의 내용을 정리한 것입니다.
https://www.udemy.com/course/spring-boot-and-spring-framework-korean/

profile
배운 내용을 바로바로 기록하자!

0개의 댓글