2020-7-21 스프링 MVC(8) 핸들러메서드(2) - SessionAttirubte, RedirectAttributes, FlashAttribute
SessionAttributes와 SessionAttribute
-
@SessionAttirubtes
- 모델 정보를 HTTP 세션에 저장하는 어노테이션.
-
HttpSession을 직정사용할수도 있지만, 어노테이션에 설정한 이름에 해당하는 모델 정보를 자동으로 세션에 넣어준다.
-
@GetMapping("events/form") public String eventForm(Model model, HttpSession httpSession) { Event newEvent = new Event(); newEvent.setLimit(50); model.addAttribute("event", newEvent); httpSession.setAttribute("event", newEvent); return "/events/form"; } @Test public void eventForm() throws Exception { mockMvc.perform(get("/events/form")) .andDo(print()) .andExpect(view().name("/events/form")) .andExpect(model().attributeExists("event")) .andExpect(request().sessionAttribute("event", notNullValue())); // 세션에 특정값이 있는지 없는지 확인 }
-
-
@ModelAttribute는 세션에 있는 데이터도 바인딩된다.
-
여러화면에서 사용해야할 객체를 공유할때 사용
-
@Controller @SessionAttributes("event") // 이름에 해당하는 모델을 세션에 넣어주는거다. public class SampleController { @GetMapping("events/form") public String eventForm(Model model) { Event newEvent = new Event(); newEvent.setLimit(50); model.addAttribute("event", newEvent); return "/events/form"; } }
-
SessionAttirubte
-
HTTP세션에 들어있는 값을 참조할 때 사용한다.
- HttpSession을 사용할 때에 비해 타입 컨버전을 자동으로 지원한다.
- HTTP 세션에 데이터를 넣고 빼고 싶은 경우 HttpSession을 사용해라
-
@SessionAttributes와는 많이 다르다
-
@SessionAttributes는 해당 컨트롤러 내에서만 동작 => 해당 컨트롤러 안에서 다루는 특정 모델 객체를 세션에 넣고 공유할 때 사용
-
@SessionAttribute는 컨트롤러 밖(인터셉터, 필터 등)에서 만들어 준 세션 데이터에 접근할때 사용
-
@Configuration public class WebConfig implements WebMvcConfigurer { ... @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new VisitTimeInterceptor()); } } public class VisitTimeInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); if (session.getAttribute("visitTime") == null) session.setAttribute("visitTime", LocalDateTime.now()); return true; } } @Controller @SessionAttributes("event") public class SampleController { ... @GetMapping("/events/list") public String getEvents(Model model, @SessionAttribute LocalDateTime visitTime) { System.out.println("==== visitTime : " + visitTime); ... return "/events/list"; } }
-
-
@RedirectAttributes
-
리다이렉트 할때 기본적으로 Primitive type데이터는 URI 쿼리 매개변수에 추가된다
-
스프링부트에서 이 기능이 기본적으로 비활성화
-
Ignore-default-model-on-redirect프로퍼티를 사용하여 활성화 할 수도 있다.
-
@PostMapping("/events/form/limit") public String eventFormLimitSubmit(@Validated @ModelAttribute Event event, BindingResult bindingResult, SessionStatus sessionStatus, Model model) { if (bindingResult.hasErrors()) return "/events/form-limit"; sessionStatus.setComplete(); // session을 비우기 model.addAttribute("name", event.getName()); model.addAttribute("limit", event.getLimit()); return "redirect:/events/list"; } //result http://localhost:8080/events/list?name=redirect&limit=123 => redirect url에 name, limit가 붙었다. => spring.mvc.ignore-default-model-on-redirect=false 설정되있었다. @PostMapping("/events/form/limit") public String eventFormLimitSubmit(@Validated @ModelAttribute Event event, BindingResult bindingResult, SessionStatus sessionStatus, RedirectAttributes redirectAttributes) { if (bindingResult.hasErrors()) return "/events/form-limit"; sessionStatus.setComplete(); // session을 비우기 redirectAttributes.addAttribute("name", event.getName()); redirectAttributes.addAttribute("limit", event.getLimit()); return "redirect:/events/list"; } spring.mvc.ignore-default-model-on-redirect설정을 지우고, redirectAttributes를 이용하면 원하는 값만 전달할 수 있다.
-
-
-
원하는 값만 리다이렉트할때 전달하고 싶다면 RedirectAttributes에 명시적으로 추가할 수 있다.
-
리다이렉트 요청을 처리하는 곳에서 쿼리 매개변수를 @RequestParam, @ModelAttribute로 받을 수 있다.
Flash Attributes
주로 리다이렉트시에 데이터를 전달할때 사용한다
- 데이터가 URI에 노출되지 않는다
- 임의의 객체를 저장할 수 있다
- 보통 HTTP 세션을 사용한다.
리다이렉트 하기전에 데이터를 HTTP 세션에 저장하고 리다이렉트 요청을 처리한 다음 그 즉시 제거한다.
@PostMapping("/events/form/limit")
public String eventFormLimitSubmit(@Validated @ModelAttribute Event event, BindingResult bindingResult, SessionStatus sessionStatus, RedirectAttributes redirectAttributes) {
if (bindingResult.hasErrors())
return "/events/form-limit";
sessionStatus.setComplete(); // session을 비우기
// 불편한점
redirectAttributes.addAttribute("name", event.getName());
redirectAttributes.addAttribute("limit", event.getLimit());
//해결책
redirectAttributes.addFlashAttribute("newEvent", event); // HTTP세션에 들어간다.
return "redirect:/events/list";
}
@Test
public void flashAttributesTest() throws Exception {
Event newEvent = new Event();
newEvent.setLimit(1000);
newEvent.setName("Test event");
mockMvc.perform(get("/events/list")
.sessionAttr("visitTime", LocalDateTime.now())
.flashAttr("newEvent", newEvent))
.andDo(print())
.andExpect(status().isOk());
}
- redirectAttribute에서 addAttribute는 쿼리파라미터를 uri에 붙여야되서 문자열로 변환이 가능해야한다. 객체를 전달하지 못한다.
- addFlashAttribute를 사용하면 객체를 전달할 수 있다. 세션에 들어가고 리다이렉트된 요청이 처리되면 세션에서 제거된다.
MultiPartFile
-
파일 업로드시 사용하는 메서드 아규먼트
-
MultipartResolver빈이 설정 되어 있어야 사용할 수 있다.(스프링부트는 자동으로 설정해준다)
-
POST multipart/form-data 요청에 들어있는 파일을 참조할 수 있다.
-
List<MultipartFile>아규먼트로 여러 파일을 참조할 수 있다.
-
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div th:if="${message}"> <h2 th:text="${message}"></h2> </div> <form method="POST" enctype="multipart/form-data" action="#" th:action="@{/file}"> File: <input type="file" name="file"/> <input type="submit" value="Upload"/> </form> </body> </html>
-
@Controller public class FileController { @GetMapping("file") public String fileUploadForm(Model model) { return "files/index"; } @PostMapping("file") public String fileUpload(@RequestParam MultipartFile file, RedirectAttributes attributes) { // save String message = file.getOriginalFilename() + " is uploaded"; attributes.addFlashAttribute("message", message); return "redirect:/file"; } } @RunWith(SpringRunner.class) @SpringBootTest @AutoConfigureMockMvc public class FileControllerTest { @Autowired private MockMvc mockMvc; @Test public void fileUploadTest() throws Exception { MockMultipartFile file = new MockMultipartFile("file", "text.txt", "text/plain", "hello file".getBytes()); this.mockMvc.perform(multipart("/file").file(file)) .andDo(print()) .andExpect(status().is3xxRedirection()); } }
-
Attributes.addFlashAttribute를 하면 redirect할때 Model에 알아서 값이 담긴다.
- @SpringBootTest를 하면 스프링부트 애플리케이션 기준으로 모든빈을 다 등록해준다. mockMvc를 자동으로 만들어주지 않는다.
-
-