Spring MVC 패턴의 요청 처리 과정이다.
이렇게 있을 때 7번의 뷰 리졸버를 이용한 뷰 연결하는 것을 Controller와 연관지어서 알아보자.
컨트롤러에서는 ModelAndView를 반환하는데 그것을 알맞은 View로 전달하기 위해 DispatcherServlet에 의해 뷰 리졸버가 호출된다.
즉, 뷰 리졸버는 ModelAndView 객체를 View 영역으로 전달하기 위해 알맞은 View 정보를 설정하는 역할을 한다.
forwarding 과 redirect 를 활용해서 알아볼 것이다.
반환한 String이 뷰 리졸버로 간다고 가정하고 하는 것이다.
mainController
@Controller
public class MainController {
* 설명.
* 뷰 리졸버 인터페이스를 구현한 ThymeleafViewResolver가 현재 처리하게 된다.
* 접두사(prefix) : resources/templates/
* 접미사(suffix) : .html
* 핸들러 메소드가 반환하는 String 값 앞 뒤에 접두사 및 접미사를 붙여 view 를 찾게 된다.
*/
@RequestMapping(value={"/", "/main"})
public String main() {
return "main";
}
}
main.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 align="center">뷰 리졸버를 이용한 뷰 연결하기 (feat.forwarding VS redirect)</h1>
<h3>문자열로 뷰 이름 반환하기</h3>
<button onclick="location.href='string'">문자열로 뷰 이름 반환</button>
<h3>문자열로 redirect</h3>
<button onclick="location.href='string-redirect'">문자열로 뷰 이름 반환하여 리다이렉트</button>
<!-- script 를 써서 javascript 문법 사용 가능-->
<script>
console.log('test');
const message1 = `[[${message1}]]`;
console.log(message1);
</script>
<h3>문자열로 뷰어를 반환하면서 flashAttribute 추가하기</h3>
<button onclick="location.href='string-redirect-attr'">문자열로 뷰 이름 반환하여 리다이렉트</button>
<script>
const flashMessage1 = `[[${flashMessage1}]]`;
console.log(flashMessage1);
</script>
<h3>ModelAndView로 뷰 이름 지정해서 반환하기</h3>
<button onclick="location.href='modelandview'">ModelAndView 뷰 이름까지 저장해서 반환하기</button>
<h3>ModelAndView로 redirect 하기</h3>
<button onclick="location.href='modelandview-redirect'">ModelAndView로 뷰 이름 반환하여 리다이렉트</button>
<script>
const message2 = `[[${param.message2}]]`;
console.log(message2);
</script>
<h3>ModelAndView로 redirect 하면서 flashAttribute 추가</h3>
<button onclick="location.href='modelandview-redirect-attr'">ModelAndView로 뷰 이름 반환하여 리다이렉트 & flash attr 사용하기</button>
<script>
const flashMessage2 = `[[${flashMessage2}]]`;
// console.log(flashMessage2);
if (flashMessage2) {
alert(flashMessage2); // flash 한 번만 쓰는 용도여서 flash가 아니라면 새로고침할 때마다 계속 이 메시지가 뜬다.
}
</script>
</body>
</html>
result.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 align="center" th:text="${forwardMessage}"></h1>
<!-- <h1 align="center" th:text="${message2}"></h1>-->
</body>
</html>
<h1 align="center" th:text="${forwardMessage}"></h1> 부분은 문자열로 뷰 이름 반환할 때만 사용한다.
화면 사진

일단은 문자열로 뷰 이름을 반환해주는 첫 번째 예시를 해보자.
@Controller
public class ResolverController {
/* 설명. 서블릿 때와 마찬가지로 포워딩을 통해 값을 전달할 수 있다. */
@GetMapping("string")
public String stringReturning(Model model) {
model.addAttribute("forwardMessage", "문자열로 뷰 이름 반환");
return "result";
}
}
실행 결과 화면

forwarding은 잘 되는 것을 볼 수 있다.
그럼 Redirect도 잘 될까??
Controller에 추가
@GetMapping("string-redirect")
public String stringRedirect(Model model) {
model.addAttribute("message1", "문자열로 뷰 이름 반환하여 리다이렉트"); // 이건 안 되는 것을 보여주려고 만들었다.
// 위의 상태로 해서 개발자 도구를 킨 채로 버튼을 눌러도 변화가 없다..
return "redirect:/";
}
서블릿 때와 마찬가지로 리다이렉트를 하지만, 파라미터를 활용하지 않고서는 전달할 수 없다.
(스프링은 해법을 제시하니 그것 또한 알아볼 것이다.)
RedirectAttribute 라는 객체에 attribute를 담으면 리다이렉트 시에도 값이 전달된다.
한 번 해보자.
Controller에 추가
@GetMapping("string-redirect-attr")
public String stringRedirectFlashAttribute(RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("flashMessage1", "리다이렉트 attr 사용해 redirect");
return "redirect:/";
}
실행 결과 화면

개발자 도구에서 확인할 수 있다.
그럼 위에서 말한대로 원래는 Controller는 String이 아닌 ModelAndView 형태로 반환해주니 그렇게 해보려고 한다.
그러면서 이제 result.html은
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- <h1 align="center" th:text="${forwardMessage}"></h1>-->
<h1 align="center" th:text="${message2}"></h1>
</body>
</html>
이렇게 바꿔줘야 한다.
바꿔준 뒤 활용해보자.
Controller에 추가
@GetMapping("modelandview")
public ModelAndView modelAndViewTest(ModelAndView mv) {
mv.addObject("message2", "ModelAndView를 이용한 forward");
mv.setViewName("result");
return mv;
}
실행 결과 화면
단순 forward 반환 시에는 Model 만 활용했을 때와 별 차이가 없다. (반환형이 ModelAndView로 바뀐 정도)

Controller에 추가
@GetMapping("modelandview-redirect")
public ModelAndView modelAndViewRedirectTest(ModelAndView mv) {
mv.addObject("message2", "ModelAndView를 이용한 redirect");
mv.setViewName("redirect:/"); // `redirect:/?message2=ModelAndView를+이용한+forward`
return mv;
}
redirect 시에는 ModelAndView에 addObject로 담긴 key와 value 는 parameter로 리다이렉트 된다. (쿼리스트링 형태)
실행 결과 화면

Controller에 추가
@GetMapping("modelandview-redirect-attr")
public ModelAndView modelAndViewRedirectFlashAttribute(ModelAndView mv, RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("flashMessage2", "ModelAndView를 이용한 redirect attribute");
mv.setViewName("redirect:/");
return mv;
}
실행 결과 화면

왜 이건 팝업으로 뜰까?
그 이유는 바로 main.html에서 alert를 활용했기 때문이다.
if (flashMessage2) {
alert(flashMessage2);
}
flash는 한 번만 쓰는 용도여서 flash가 아니라면 새로고침할 때마다 계속 이 메시지가 뜨는데, 이것을 적용하지 않으면 어떤 이벤트가 발생했을 때 새로고침을 하면 해당 이벤트에 대한 팝업이 계속 뜨는 것이다.
나도 포인트가 적립됐다든지 이벤트로 직접 구현해보질 않아서 발생했을 때 flashMessage로 하지 않았을 때 포인트가 적립됐다고 하는 만큼 누적되는건지 궁금하긴 하다.. 알아보고 정리하도록 하겠다.