주로 리다이렉트시에 데이터를 전달할 때 사용한다.
리다이렉트 하기 전에 데이터를 HTTP 세션에 저장하고 리다이렉트 요청을 처리 한 다음 그 즉시 제거한다. RedirectAttributes를 통해 사용할 수 있다.
XPath
RedirectAttributes는 리다이렉트시 URI 쿼리 파라미터에 붙여 전달하기 때문에 String 타입으로 변환이 가능한 타입만 사용할 수 있다. 그래서 복합적인 객체를 전달하기에는 어렵다. 그러나 FlashAttributes는 임의의 객체를 세션에 넣어서 전달하기 때문에 복합적인 객체를 전달할 수 있다.
@Controller
@SessionAttributes("event")
public class SampleController {
@GetMapping("/events/form/name")
public String eventsFormName(Model model) {
model.addAttribute("event", new Event());
// 자동으로 세션에 넣어줌
return "events/form-name";
}
@PostMapping("/events/form/name")
public String eventsFormNameSubmit(@ModelAttribute @Valid Event event, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "/events/form-name";
}
return "redirect:/events/form/limit";
}
@GetMapping("/events/form/limit")
public String eventsFormLimit(@ModelAttribute @Valid Event event, Model model) {
model.addAttribute("event", event);
// 자동으로 세션에 넣어줌
return "events/form-limit";
}
@PostMapping("/events/form/limit")
public String eventsFormLimitSubmit(@ModelAttribute @Valid Event event, BindingResult bindingResult, SessionStatus sessionStatus, RedirectAttributes attributes){
if(bindingResult.hasErrors()){
return "/events/form-limit";
}
sessionStatus.setComplete();
// 데이터베이스에서 save 했다고 가정
attributes.addFlashAttribute("newEvent", event);
return "redirect:/events/list";
}
@GetMapping("/events/list")
public String getEvents(@ModelAttribute("newEvent") Event event,
Model model,
@SessionAttriubte LocalDateTime visitTime){
System.out.println(visitTime);
Event spring = new Event();
spring.setName("spring");
spring.setLimit(10);
// 데이터베이스에서 읽어왔다고 가정한다.
List<Event> eventList = new ArrayList<>();
eventList.add(spring);
eventList.add(event);
model.addAttribute("eventList", eventList);
return "/events/list";
}
}
또한 FlashAttributes로 전달해주는 값은 @ModelAttribute로 받을 수도 있지만 바로 Model에 들어온다.
@Controller
@SessionAttributes("event")
public class SampleController {
@GetMapping("/events/form/name")
public String eventsFormName(Model model) {
model.addAttribute("event", new Event());
// 자동으로 세션에 넣어줌
return "events/form-name";
}
@PostMapping("/events/form/name")
public String eventsFormNameSubmit(@ModelAttribute @Valid Event event, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "/events/form-name";
}
return "redirect:/events/form/limit";
}
@GetMapping("/events/form/limit")
public String eventsFormLimit(@ModelAttribute @Valid Event event, Model model) {
model.addAttribute("event", event);
// 자동으로 세션에 넣어줌
return "events/form-limit";
}
@PostMapping("/events/form/limit")
public String eventsFormLimitSubmit(@ModelAttribute @Valid Event event, BindingResult bindingResult, SessionStatus sessionStatus, RedirectAttributes attributes){
if(bindingResult.hasErrors()){
return "/events/form-limit";
}
sessionStatus.setComplete();
// 데이터베이스에서 save 했다고 가정
attributes.addFlashAttribute("newEvent", event);
return "redirect:/events/list";
}
@GetMapping("/events/list")
public String getEvents(Model model,
@SessionAttriubte LocalDateTime visitTime){
System.out.println(visitTime);
Event spring = new Event();
spring.setName("spring");
spring.setLimit(10);
Event newEvent = (Event) model.asMap().get("newEvent");
// 데이터베이스에서 읽어왔다고 가정한다.
List<Event> eventList = new ArrayList<>();
eventList.add(spring);
eventList.add(newEvent);
model.addAttribute("eventList", eventList);
return "/events/list";
}
}
@RunWith(SpringRunner.class)
@WebMvcTest
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void eventForm() throws Exception{
MockHttpServletRequest request = mockMvc.perform(get("/events/form"))
.andDo(print())
.andExpect(view().name("/events/form"))
.andExpect(model().attributeExists("event"))
.andExpect(request().sessionAttribute("event", notNullValue()))
.andReturn().getRequest();
Object event = request.getSession().getAttribute("event");
System.out.println(event);
}
@Test
public void createEvent() throws Exception{
ResultActions result = mockMvc.perform(post("/events")
.param("name", "spring)
.param("limit", "-10"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(model().hasErrors());
ModelAndView mav = result.andReturn().getModelAndView();
Map<String, Object> model = mav.getModel();
System.out.println(model.size());
}
@Test
public void getEvents() throws Exception{
Event newEvent = new Event();
newEvent.setName("Winter is coming.");
newEvent.setLimit(10000);
mockMvc.perform(get("/events/list")
.sessionAttr("visitTime", LocalDateTime.now())
.flashAttr("newEvent", newEvent))
.andDo(print())
.andExpect(status().isOk())
// HTML 본문 테스트
.andExpect(xpath("//p").nodeCount(2));
}
}
참고