웹 게시판을 스프링 프레임워크 없이 서블릿만으로만 구현하는 도중 jsp 파일이 외부 css, js 파일들을 로딩하지 못하는 문제에 마주했다.
이 문제를 해결하기 위한 과정에서 새로운 사실들을 알게되었다.
- 우선 브라우저는 html, jsp 페이지들을 받아와 렌더하는 과정에서
<link rel='stylesheet'type="text/css"
같은 링크 태그를 마주한다. - 별도의 새로운 Request를 서버에 요청한다.
- 이 과정에서 자바 서블릿 프로젝트의 경우 DefaultServlet이 이 정적 콘텐츠들을 처리한다.
문제는, 개발자가 자신이 만든 servlet.java 코드 속 WebServlet 애노테이션에 루트 url을 매핑해주었을 때 생긴다.
우선 서블릿 컨테이너와 웹 애플리케이션은 다음과 같은 url pattern 으로 연동이 가능하다.
- '/' 로 시작하고 '/*' 으로 끝나는 path 매칭
- "*.action" 과 같은 확장자 매칭
- '/' 만 정의한 경우 디폴트 서블릿
- 그 외 동치 매칭
내 프로젝트에서 발생한 문제가 바로 위의 3번이었다.
나의 경우 프론트 컨트롤러 패턴으로, 디스패쳐 서블릿이 모든 리퀘스트를 받아 각 컨트롤러(커맨드) 메서드에 전달하는 방식을 택했다.
즉 한 서블릿에서 모든 리퀘스트를 받게 디자인했다.
처음엔 '/*'와 같이 모든 url들을 동적으로 매칭하려고 했다.
@WebServlet("/*")
public class FrontController extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response){
String url = request.getRequestURI();
if (Objects.equals(url, "/")) {
request.getRequestDispatcher("/home.jsp").forward(request, response);
}
}
이렇게되면 디스패쳐 서블릿이 모든 정적 요청들을 다 받아들인다.
즉 정적 리소스들을 처리해주는 디폴트 서블릿으로 도달하지 못하고 위 프론트컨트롤러 자바클래스 내에서 처리를 시도한다.
(정적 리소스 처리가 불가하다)
이후 정적 리소스에 대한 리퀘스트까지 프론트컨트롤러 서블릿에서 처리한다는 것을 깨달은 후 다음과 같이 매핑했다.
@WebServlet("/")
public class FrontController extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response){
String url = request.getRequestURI();
if (Objects.equals(url, "/")) {
request.getRequestDispatcher("/home.jsp").forward(request, response);
}
}
위처럼 매핑하면 FrontController 내에서 jsp 파일로 포워드하고 있으니 jsp 파일 자체는 서빙되지만, 거기에 포함된 js, css 파일들은 로드되지 않는다. 첫번째 경우처럼 모든 리퀘스트를 가로채서 생기는 경우는 아니다.
그럼 왜?
위 코드가 css, js 파일들을 로드하지 못하는 이유는 url value가 '/' 로 정의된 경우는 상술했듯 디폴트서블릿인데, 이는 org.apache.catalina.servlets
패키지 안에 존재하며 위치는 tomcat/lib/catalina.jar 에 묶여있다.
이 디폴트서블릿은 HTML, CSS, JS, IMG 같은 정적 리소스들을 처리한다.
즉 정적 리소스를 처리할 디폴트 서블릿을 개발자가 디스패쳐서블릿에 재정의함으로써 정적 파일들이 적절하게 로딩되지 않는것이다.
이제 원인을 알았으니 디폴트 서블릿을 재정의 하지않게 value 혹은 urlPattern을 변경해주면 CSS 가 잘 로딩된다.
@WebServlet(urlPatterns = {"/home", "/login", "/signup"} )
public class FrontController extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response){
String url = request.getRequestURI();
if (Objects.equals(url, "/")) {
request.getRequestDispatcher("/home.jsp").forward(request, response);
}
}
'개발 > 자바' 카테고리의 다른 글
myBatis 3) 쿼리에 파라미터에 객체 전달 시 프로퍼티 찾지 못할 때 (0) | 2023.02.10 |
---|---|
myBatis 3 쿼리문에 parameter 문법 (${}, #{}) (0) | 2023.02.09 |
자바의 데이터 타입과 메모리 영역 (0) | 2023.01.03 |
자바 클래스패스(classpath)란? (0) | 2022.12.19 |