1. 개요
웹 애플리케이션을 개발할 때 종종 여러보기에서 동일한 속성을 참조해야합니다. 예를 들어, 여러 페이지에 표시해야하는 장바구니 내용이있을 수 있습니다.
이러한 속성을 저장하기에 좋은 위치는 사용자 세션입니다.
이 예제에서는 간단한 예제에 초점을 맞추고 세션 속성 작업을위한 두 가지 다른 전략을 살펴 봅니다 .
- 범위 프록시 사용
- @ SessionAttributes 어노테이션 사용
2. Maven 설정
Spring Boot 스타터를 사용하여 프로젝트를 부트 스트랩하고 필요한 모든 의존성을 가져올 것입니다.
설정에는 부모 선언, 웹 스타터 및 thymeleaf 스타터가 필요합니다.
또한 단위 테스트에서 몇 가지 추가 유틸리티를 제공하기 위해 스프링 테스트 스타터를 포함 할 것입니다.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
이러한 의존성의 최신 버전은 Maven Central 에서 찾을 수 있습니다 .
3. 사용 사례 예
이 예에서는 간단한 "TODO"애플리케이션을 구현합니다. TodoItem 인스턴스를 생성하기위한 양식 과 모든 TodoItem 을 표시하는 List보기가 있습니다.
양식을 사용하여 TodoItem 을 생성 하면 양식의 후속 액세스가 가장 최근에 추가 된 TodoItem 의 값으로 미리 채워 집니다 . 우리는 사용합니다 t을 양식 값 "기억"하는 방법을 보여 자신의 기능을 세션 범위에 저장됩니다.
2 개의 모델 클래스는 간단한 POJO로 구현됩니다.
public class TodoItem {
private String description;
private LocalDateTime createDate;
// getters and setters
}
public class TodoList extends ArrayDeque<TodoItem>{
}
우리 하여 ToDoList의 클래스는 확장 의 ArrayDeque을 우리에게를 통해 가장 최근에 추가 된 항목에 편리하게 액세스 제공하는 peekLast와의 방법을.
2 개의 컨트롤러 클래스가 필요합니다 : 우리가 살펴볼 각 전략에 대해 하나씩. 미묘한 차이가 있지만 핵심 기능은 둘 다에 표시됩니다. 각각에는 3 개의 @RequestMapping 이 있습니다 .
- @GetMapping ( "/ form") –이 메서드는 양식을 초기화하고 양식보기를 렌더링합니다. TodoList 가 비어 있지 않은경우메서드는 가장 최근에 추가 된 TodoItem으로 양식을 미리 채 웁니다 .
- ( "/ 양식") @PostMapping -이 방법은 제출 된 추가하기위한 책임이있다 가 ToDoItem을 받는 하여 ToDoList 하고 List의 URL로 리디렉션.
- @GetMapping (“/ todos.html”) – 이 메소드는표시를 위해 TodoList 를 모델 에추가하고 List보기를 렌더링합니다.
4. 범위 프록시 사용
4.1. 설정
이 설정에서 TodoList 는 프록시에 의해 지원되는 세션 범위 @Bean 으로 구성됩니다 . @Bean 이 프록시 라는 사실은 우리가 싱글 톤 범위의 @Controller 에 주입 할 수 있다는 것을 의미합니다 .
컨텍스트가 초기화 될 때 세션이 없기 때문에 Spring은 TodoList 의 프록시를 생성 하여 의존성으로 주입합니다. TodoList 의 대상 인스턴스는 요청에 의해 필요할 때 필요에 따라 인스턴스화됩니다.
Spring의 빈 범위에 대한보다 심층적 인 논의 는 주제에 대한 기사를 참조하십시오 .
먼저 @Configuration 클래스 내에서 빈을 정의합니다 .
@Bean
@Scope(
value = WebApplicationContext.SCOPE_SESSION,
proxyMode = ScopedProxyMode.TARGET_CLASS)
public TodoList todos() {
return new TodoList();
}
다음으로 빈을 @Controller에 대한 의존성으로 선언하고 다른 의존성과 마찬가지로 삽입합니다.
@Controller
@RequestMapping("/scopedproxy")
public class TodoControllerWithScopedProxy {
private TodoList todos;
// constructor and request mappings
}
마지막으로 요청에서 Bean을 사용하는 것은 단순히 해당 메소드를 호출하는 것을 포함합니다.
@GetMapping("/form")
public String showForm(Model model) {
if (!todos.isEmpty()) {
model.addAttribute("todo", todos.peekLast());
} else {
model.addAttribute("todo", new TodoItem());
}
return "scopedproxyform";
}
4.2. 단위 테스트
범위가 지정된 프록시를 사용하여 구현을 테스트하기 위해 먼저 SimpleThreadScope를 구성합니다 . 이렇게하면 단위 테스트가 테스트중인 코드의 런타임 조건을 정확하게 시뮬레이션 할 수 있습니다.
먼저 TestConfig 와 CustomScopeConfigurer를 정의합니다 .
@Configuration
public class TestConfig {
@Bean
public CustomScopeConfigurer customScopeConfigurer() {
CustomScopeConfigurer configurer = new CustomScopeConfigurer();
configurer.addScope("session", new SimpleThreadScope());
return configurer;
}
}
이제 양식의 초기 요청에 초기화되지 않은 TodoItem이 포함되어 있는지 테스트하여 시작할 수 있습니다 .
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
@Import(TestConfig.class)
public class TodoControllerWithScopedProxyIntegrationTest {
// ...
@Test
public void whenFirstRequest_thenContainsUnintializedTodo() throws Exception {
MvcResult result = mockMvc.perform(get("/scopedproxy/form"))
.andExpect(status().isOk())
.andExpect(model().attributeExists("todo"))
.andReturn();
TodoItem item = (TodoItem) result.getModelAndView().getModel().get("todo");
assertTrue(StringUtils.isEmpty(item.getDescription()));
}
}
제출이 리디렉션을 발행하고 후속 양식 요청이 새로 추가 된 TodoItem으로 미리 채워져 있는지 확인할 수도 있습니다 .
@Test
public void whenSubmit_thenSubsequentFormRequestContainsMostRecentTodo() throws Exception {
mockMvc.perform(post("/scopedproxy/form")
.param("description", "newtodo"))
.andExpect(status().is3xxRedirection())
.andReturn();
MvcResult result = mockMvc.perform(get("/scopedproxy/form"))
.andExpect(status().isOk())
.andExpect(model().attributeExists("todo"))
.andReturn();
TodoItem item = (TodoItem) result.getModelAndView().getModel().get("todo");
assertEquals("newtodo", item.getDescription());
}
4.3. 토론
범위가 지정된 프록시 전략을 사용하는 주요 기능은 요청 매핑 메서드 서명에 영향을주지 않는다는 것입니다. 이것은 @SessionAttributes 전략에 비해 매우 높은 수준의 가독성을 유지합니다 .
컨트롤러에는 기본적으로 단일 범위가 있다는 것을 기억하는 것이 도움이 될 수 있습니다 .
이것이 우리가 프록시되지 않은 세션 범위 빈을 단순히 주입하는 대신 프록시를 사용해야하는 이유입니다. 더 작은 범위의 빈을 더 큰 범위의 빈에 주입 할 수 없습니다.
이 경우이 경우 Scope 'session'is not active for the current thread를 포함하는 메시지와 함께 예외가 트리거 됩니다.
세션 범위로 컨트롤러를 정의하려는 경우 proxyMode 지정을 피할 수 있습니다. 특히 각 사용자 세션에 대해 컨트롤러 인스턴스를 만들어야하므로 컨트롤러를 만드는 데 비용이 많이 드는 경우 단점이있을 수 있습니다.
참고 하여 ToDoList가 주입을위한 다른 구성 요소에 사용할 수 있습니다. 이는 사용 사례에 따라 장점 또는 단점이 될 수 있습니다. 전체 애플리케이션에서 빈을 사용할 수 있도록 만드는 것이 문제가되는 경우 다음 예제에서 볼 수 있듯이 @SessionAttributes 를 사용하는 대신 인스턴스의 범위를 컨트롤러로 지정할 수 있습니다 .
5. @SessionAttributes 어노테이션 사용
5.1. 설정
이 설정에서는 TodoList 를 Spring 관리 @Bean 으로 정의하지 않습니다 . 대신 @ModelAttribute 로 선언 하고 @SessionAttributes 어노테이션을 지정 하여 컨트롤러의 세션 범위를 지정합니다 .
컨트롤러에 처음 액세스하면 Spring은 인스턴스를 인스턴스화하고 Model에 배치합니다 . @SessionAttributes에 빈을 선언하기 때문에 Spring은 인스턴스를 저장할 것이다.
Spring 의 @ModelAttribute 에 대한 더 자세한 논의 는 주제에 대한 기사를 참조하십시오 .
먼저 컨트롤러에 메소드를 제공하여 Bean을 선언하고 @ModelAttribute로 메소드에 어노테이션을 추가합니다 .
@ModelAttribute("todos")
public TodoList todos() {
return new TodoList();
}
다음으로 컨트롤러에게 @SessionAttributes 를 사용하여 TodoList 를 세션 범위로 처리하도록 알립니다 .
@Controller
@RequestMapping("/sessionattributes")
@SessionAttributes("todos")
public class TodoControllerWithSessionAttributes {
// ... other methods
}
마지막으로 요청 내에서 Bean을 사용하기 위해 @RequestMapping 의 메소드 서명에 해당 Bean에 대한 참조를 제공합니다 .
@GetMapping("/form")
public String showForm(
Model model,
@ModelAttribute("todos") TodoList todos) {
if (!todos.isEmpty()) {
model.addAttribute("todo", todos.peekLast());
} else {
model.addAttribute("todo", new TodoItem());
}
return "sessionattributesform";
}
에서 @PostMapping의 방법, 우리는 주입 RedirectAttributes을 하고 전화 addFlashAttribute을 우리의 반환하기 전에 만약 RedirectView을 . 이것은 첫 번째 예제와 비교하여 구현에서 중요한 차이점입니다.
@PostMapping("/form")
public RedirectView create(
@ModelAttribute TodoItem todo,
@ModelAttribute("todos") TodoList todos,
RedirectAttributes attributes) {
todo.setCreateDate(LocalDateTime.now());
todos.add(todo);
attributes.addFlashAttribute("todos", todos);
return new RedirectView("/sessionattributes/todos.html");
}
Spring은 URL 매개 변수의 인코딩을 지원하기 위해 리디렉션 시나리오에 대한 Model 의 특수 RedirectAttributes 구현을 사용합니다 . 리디렉션 중에 모델에 저장된 모든 속성 은 일반적으로 URL에 포함 된 경우에만 프레임 워크에서 사용할 수 있습니다.
addFlashAttribute 를 사용 하여 URL에서 인코딩 할 필요없이 TodoList 가 리디렉션을 유지하기를 원한다는 것을 프레임 워크에 알립니다 .
5.2. 단위 테스트
폼 뷰 컨트롤러 메서드의 단위 테스트는 첫 번째 예제에서 살펴본 테스트와 동일합니다. 그러나 @PostMapping 테스트 는 동작을 확인하기 위해 플래시 속성에 액세스해야하기 때문에 약간 다릅니다.
@Test
public void whenTodoExists_thenSubsequentFormRequestContainsesMostRecentTodo() throws Exception {
FlashMap flashMap = mockMvc.perform(post("/sessionattributes/form")
.param("description", "newtodo"))
.andExpect(status().is3xxRedirection())
.andReturn().getFlashMap();
MvcResult result = mockMvc.perform(get("/sessionattributes/form")
.sessionAttrs(flashMap))
.andExpect(status().isOk())
.andExpect(model().attributeExists("todo"))
.andReturn();
TodoItem item = (TodoItem) result.getModelAndView().getModel().get("todo");
assertEquals("newtodo", item.getDescription());
}
5.3. 토론
@ModelAttribute 와 @SessionAttributes 세션의 속성을 저장하기위한 전략은 간단한 솔루션을 추가 컨텍스트 구성 또는 Spring 관리 필요하지 않습니다 @Bean 들 .
첫 번째 예와는 달리, 그것은 주입하는 것이 필요 하여 ToDoList를 에 @RequestMapping의 방법 .
또한 리디렉션 시나리오에 플래시 속성을 사용해야합니다.
6. 결론
이 기사에서 우리는 Spring MVC에서 세션 속성 작업을위한 두 가지 전략으로 범위가 지정된 프록시와 @SessionAttributes 를 사용하는 방법을 살펴 보았습니다 . 이 간단한 예에서 세션에 저장된 모든 속성은 세션 수명 동안 만 유지됩니다.
서버 재시작 또는 세션 시간 초과 사이에 속성을 유지해야하는 경우 정보 저장을 투명하게 처리하기 위해 Spring Session을 사용할 수 있습니다. 한 번 봐 가지고 우리의 기사 자세한 내용은 Spring 세션에 있습니다.
항상 그렇듯이이 기사에서 사용 된 모든 코드 는 GitHub 에서 사용할 수 있습니다 .
- https://docs.spring.io/spring-framework/docs/current/reference/html
- https://www.baeldung.com/spring-mvc-session-attributes
'Java' 카테고리의 다른 글
Spring Cloud 작업 소개 (0) | 2021.03.18 |
---|---|
Spring 5 기능성 Bean 등록 (0) | 2021.03.18 |
Spring Boot에서 임베디드 컨테이너(tomcat, jetty, undertow) 비교 (0) | 2021.03.17 |
Apache Shiro 소개 (0) | 2021.03.17 |
HTTP 호출자를 사용한 Spring Remoting 소개 (0) | 2021.03.17 |