스프링 MVC 활용(20) : 핸들러 메소드 12부 - FlashAttributes

de_sj_awa·2021년 7월 4일
0
post-custom-banner

20. 핸들러 메소드 12부 - FlashAttributes

주로 리다이렉트시에 데이터를 전달할 때 사용한다.

  • 데이터가 URI에 노출되지 않는다.
  • 임의의 객체를 저장할 수 있다.
  • 보통 HTTP 세션을 사용한다.

리다이렉트 하기 전에 데이터를 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));
    }
}

참고

profile
이것저것 관심많은 개발자.
post-custom-banner

0개의 댓글