개요
Spring Boot 프로젝트를 Servlet 기반 프로젝트로 변경하는 과정에서 겪은 헤프닝을 공유합니다.
처음에는 단순히 RequestDispatcher("/ .jsp")를 이용하면 바로 화면이 뜰 줄 알았지만, 실제로는 수많은 에러가 발생했습니다.
단순한 코드 오류가 아닌, Spring Boot와 JSP의 동작 원리 차이에서 비롯된 문제를 파헤쳐 보고자 합니다.
- JSP가 어떻게 톰캣에서 처리되는지
- Spring Boot가 JSP와 템플릿을 어떻게 구분하는지
- 왜 디렉터리 구조와 파일 이름이 중요한지
위 내용을 실제 사례를 통해 살펴봅니다.
문제 상황
Servlet에서 아래처럼 /form 요청을 JSP로 포워딩하려고 했습니다.
@WebServlet("/form")
public class FormServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
RequestDispatcher dispatcher = request.getRequestDispatcher("/form.jsp");
dispatcher.forward(request, response);
}
}
그런데 브라우저에서 /form을 요청하면…

…이런 오류가 발생했습니다.
doGet() 메서드에서 JSP로 이동하려 했지만, Spring Boot가 JSP를 찾지 못해 발생한 것입니다.
원인 분석
원인 1. JSP 파일 위치 문제
JSP를 src/main/resources/templates/에 두었음
- 이는 Spring Boot 뷰 리졸버(Thymeleaf, FreeMarker 등 템플릿 엔진) 전용 위치라서 이 디렉터리에 JSP를 둬도, Spring Boot는 JSP를 템플릿으로 처리할 수 없음
JSP 파일은 빌드할 때 자바 코드 → 서블릿으로 변환하고 이 변환 과정과 실행은 서블릿 컨테이너(Tomcat)가 담당.
- 따라서 JSP 파일은 웹 애플리케이션 루트(webapp) 안에 있어야 톰캣이 찾아서 컴파일하고 실행할 수 있음.
- 즉 JSP는 단순한 리소스 파일이 아니라 톰캣이 직접 읽어서 변환해야 하는 뷰 코드라서 webapp 밑에만 둬야함.
- 파일 경로 예시)
src/main/webapp/WEB-INF/jsp/
* WEB-INF 안에 두는 이유
클라이언트가 JSP를 직접 접근하지 못하게 하기 위함입니다. JSP를 순수 뷰 역할로만 쓰게 강제할 수 있어 보안상 안전
원인 2. application.properties 용도 혼동
application.properties에 아래 설정을 추가했습니다.
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
이를 이용하면 getRequestDispatcher("/form.jsp")를 호출할 때 경로를 찾는데는 문제가 없을 것이라 생각하였습니다.
하지만 문제는 templates 폴더에 form.html이 남아 있었습니다.
Spring Boot는 기본적으로 src/main/resources/templates 폴더에 있는 HTML 파일을 Thymeleaf 템플릿으로 인식합니다.
/form 요청 시 Spring이 ViewResolver를 통해 templates/form.html를 먼저 잡기 때문에 JSP가 아닌 Thymeleaf 뷰로 처리하려고 시도하고 결국 포워딩에 실패합니다.
해결 방법
- JSP 파일을 src/main/webapp/WEB-INF/jsp/로 이동
- templates 폴더 안의 같은 이름 HTML 파일 삭제
결과
- /form 요청 시 404 오류 없이 JSP 페이지가 정상 렌더링되었음.
- JSP와 HTML/Thymeleaf 파일 이름이 충돌하면 포워딩이 안 된다는 점 명확히 확인
- Spring Boot에서 JSP를 쓰려면 템플릿 엔진 구조와 JSP 구조를 혼동하면 안 된다는 교훈을 얻었음