WAR(Web Application Archive) 구조에서 웹 애플리케이션은 다음과 같은 디렉터리를 가진다:
webapp/
├── index.html
├── resources/
├── css/
├── js/
└── WEB-INF/
├── web.xml
├── classes/
├── lib/
여기서 WEB-INF는 특별한 보호 디렉터리다.
가장 중요한 특징:
예:
http://localhost:8080/WEB-INF/views/login.jsp → 접근 불가 (404 또는 Forbidden)
Tomcat(웹 컨테이너)이 보안 규약으로 WEB-INF 내부는 외부에서 바로 열리지 못하도록 하며,
오직 서버 내부에서 forward()를 통해서만 접근 가능하다.
이유는 명확하다.
예를 들어:
실제로 외부 접근 허용되면:
그래서 Tomcat의 규칙은 다음과 같다:
서블릿에서 아래처럼 forward() 를 통해 접근해야 한다.
RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/login.jsp");
rd.forward(request, response);
forward는 서버 내부에서 동작하기 때문에 WEB-INF 파일에 접근이 가능하다.
즉,
JSP MVC 구조에서 컨트롤러가 보통 이런 식으로 동작한다:
이 때 JSP 파일이 만약 웹에서 직접 접근된다면
서블릿을 거치지 않고 JSP가 바로 실행되어 MVC 구조가 무너짐.
그래서 JSP는 WEB-INF/views 아래 넣는다.
WEB-INF/views/
login.jsp
home.jsp
각 JSP는 반드시 컨트롤러를 통해서만 접근 가능.
이제 중요한 연결점:
Spring Boot는 내장 톰캣을 사용하며, WAR 구조 대신 JAR 실행 방식을 채택하기 때문에
전통적인 WEB-INF 폴더를 사용하지 않는다.
그러나 역할은 유지해야 하기 때문에 Spring Boot는 이렇게 설계했다:
Spring Boot MVC 구조는 다음과 같다:
src/main/resources/
├── static/
├── templates/
└── application.yml
templates/ Thymeleaf, Mustache, Freemarker 등 서버 렌더링 템플릿 보관static/ CSS, JS, 이미지 등 브라우저에서 직접 접근 가능한 정적 리소스이 구조는 JSP 프로젝트의 다음 구조와 거의 같다:
전통 JSP:
webapp/
├── css, js 등 정적 리소스
└── WEB-INF/views/ (외부 접근 불가)
Spring Boot:
static/ (외부 접근 가능)
templates/ (컨트롤러를 거쳐서만 접근 가능)
즉,
| 역할 | 위치 | 외부 접근 |
|---|---|---|
| 정적 리소스 | webapp/css, js, img | 가능 |
| JSP 파일 | WEB-INF/views | 불가능 (forward만 가능) |
| 역할 | 위치 | 외부 접근 |
|---|---|---|
| 정적 리소스 | static/ | 가능 |
| HTML(Thymeleaf) | templates/ | 불가능 (Controller 필요) |
templates 폴더는 Spring MVC Controller를 거쳐야만 뷰로 렌더링된다.
예:
@GetMapping("/login")
public String login() {
return "login";
}
이렇게 하면 자동으로:
templates/login.html
이 렌더링된다.
브라우저에서 직접:
http://localhost:8080/templates/login.html
접근 불가.
WEB-INF 와 동일한 보안 원리이다.