Spring MVC에서 View Resolver와 템플릿 엔진 동작 방식 학습
- 컨트롤러의 반환값이 어떻게 실제 사용자에게 보여지는 화면(뷰)으로 연결되는지 전체 흐름 이해
View Resolver와 템플릿 엔진 학습 이유
- MVC 흐름의 핵심 구성요소
- 다양한 뷰 기술을 정확히 구분하고 사용하기 위함
- 자동 설정의 구조를 이해하면 오류 해결이 쉬움
- 실무에서 템플릿 전환이나 커스터마이징 이슈 해결
- 국제화, 다국어 처리, 테마 처리와 연관
package hello.servlet.web.springmvc.old;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component("/springmvc/old-controller")
public class OldController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("OldController.handleRequest");
return new ModelAndView("new-form");
}
}
/springmvc/old-controller로 오면 이 컨트롤러가 실행되고, 뷰 이름으로 "new-form"을 반환함new-form.jsp 같은 실제 뷰 파일로 매핑해줌http://localhost:8080/springmvc/old-controller
OldController.handleRequest
Whitelabel Error Page라는 에러 화면이 출력됨new-form이라는 뷰 이름을 리턴함return new ModelAndView("new-form");
new-form"을 보고 어떤 JSP 파일을 보여줘야 하는지 알 수가 없음application.properties
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
prefix : JSP 파일이 어디에 있는지 경로 앞부분
suffix :JSP 파일의 확장자
해당 설정을 하면 "new-form"이라는 뷰 이름은 자동으로 아래와 같이 변환됨
/WEB-INF/views/new-form.jsp
Spring MVC에서는 컨트롤러가 반환한 "new-form"같은 뷰 이름을 진짜 JSP 경로로 바꿔줘야 함
- 이것을 담당하는 것이 바로 뷰 리졸버(View Resolver)
InternalResourceViewResolver를 자동으로 등록해줌prefix와 suffix 정보를 활용해서 new-form을 실제 JSP 경로로 변환해주는 역할을 함// 예시: "new-form" → "/WEB-INF/views/new-form.jsp"
return new ModelAndView("/WEB-INF/views/new-form.jsp");
위와 같이 전체 경로를 직접 다 쓴다면 설정 없이도 동작하긴 함
하지만 권장되지 않는 방식임
Whitelabel Error - 뷰를 찾지 못해서 발생
해결 - application.properties에 뷰 경로 설정 추가
InternalResourceViewResolver - 뷰 이름 -> JSP 경로로 변환
권장 방식 - 뷰 이름만 리턴하고, 실제 경로는 설정으로 처리
- 이제 new-from.jsp 파일만 /WEB-INF/views/ 안에 잘 넣어주면, 실행 시에 정상적으로 폼 출력됨

✅ BeanNameViewResolver (1번 시도)
✅ InternalResourceViewResolver (2번 시도)
/WEB-INF/views/new-form.jsp
InternalResourceView가 생성되었지만, JSTL이 있다면 JstlView가 생성됨 (기능 같고 약간 부가기능 있음)
- JSTL이 프로젝트에 있으면, 스프링이
JstlView로 JSP 뷰를 처리함JstlView는 JSTL 태그가 잘 동작하도록 도와주는 기능이 있는 뷰 클래스
- JSTL : JSP에서 사용하는 표준 태그 라이브러리
- JSP에서 반복문, 조건문, 날짜 포맷, 국제화(i18n) 같은 걸 자바 코드 없이 HTML 태그처럼 사용할 수 있게 해주는 태그 라이브러리
<c:forEach var="item" items="${items}">
<p>${item.name}</p>
</c:forEach>
<% %>로 섞어서 쓰는 방식이라 복잡하고 유지보수가 어려움xml 파일(Maven 예시)
<dependency>
<groupId>jakarta.servlet.jsp.jstl</groupId>
<artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jakarta.servlet.jsp.jstl</artifactId>
<version>3.0.0</version>
</dependency>
| 구분 | InternalResourceView | JstlView |
|---|---|---|
| JSP forward 처리 | ✅ 지원 | ✅ 지원 |
| JSTL 태그 지원 | ❌ JSTL 처리 안 함 | ✅ JSTL 관련 설정 포함 |
| EL context 제공 | ❌ 없음 | ✅ JSTL 태그가 잘 동작하도록 추가 작업 수행 |
jakarta.servlet.jsp.jstl)가 프로젝트에 포함되어 있으면, Spring은 자동으로 JstlView를 사용해서 JSP를 처리해줌InternalResourceViewResolver는 알아서 JstlView로 뷰 객체를 만들어냄InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setViewClass(JstlView.class);
JstlView를 쓰라고 지정할 수도 있지만, Spring boot에선 JSTL 라이브러리만 있으면 자동으로 처리해주기 때문에 따로 설정할 필요는 없음Thymelaef는 JSP + JSTL 조합과는 완전히 다른 자체 템플릿 엔진Thymeleaf 전용 속성(th:if, th:each)으로 처리함<tr th:each="item : ${items}">
<td th:text="${item.name}">샘플</td>
</tr>
JstlView, InternalResourceViewResolver 같은 설정은 필요 없음ThymeleafViewResolver가 자동 등록됨spring-boot-starter-thymeleaf 의존성에 포함되어 있음@Controller + @GetMapping 같은 방식에서는 이 뷰 리졸버 자동 등록이 더 중요함
@Controller
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "greeting"; // 뷰 이름으로 해석됨!
}
}
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
spring-boot-starter-thymeleaf를 넣는 순간:
@Controller
- 리턴값 해석 방식 : 뷰 이름
- 뷰 리졸버 필요 여부 : 필요함
@RestController
- 리턴값 해석 방식 : HTTP 바디(문자열)
- 뷰 리졸버 필요 여부 : 필요 없음