톰캣은 Servlet Container, Servlet Engine으로써 Servlet을 실행하여 동작합니다.
웹 프로젝트 폴더를 생성할 때 같이 생성한 web.xml 파일에는 클라이언트가 어떤 URL을 요청했을 때 어떤 Servlet 파일을 실행시킬 것인지를 매핑해놓은 파일입니다.
톰캣은 web.xml에 매핑되어진 자바 파일을 Servlet으로 변환시키고, 그 Servlet을 실행하여 요청에 응답하게 됩니다.
이 때 Servlet으로 변환되기 위해서는 개발자가 Servlet이라는 것을 명시해줘야 하는데, 그 방법은 Servlet 구조를 통해 알아보겠습니다.
Servlet으로 변환되기 위해서는 기본적으로 다음의 구조를 만족해야 합니다.
톰캣에서 만들어 놓은 HttpServlet 클래스를 상속
HTTP 요청 메서드인 Get방식과 Post 방식을 처리하기 위해 doGet()과 doPost()를 오버라이딩
매개변수로는 HttpServletReqeust, HttpServletResponse 클래스를 정의합니다.
톰캣은 web.xml 파일을 확인하여 Servlet 클래스를 매핑한 후, 이를 실행한다고 초반에 언급했었습니다.
그런데 어노테이션을 활용하면 web.xml에 직접 작성하여 매핑을 할 필요가 없습니다.
위에서 생성한 클래스를 보면 @WebServlet("/hello") 어노테이션을 확인할 수 있습니다.
톰캣은 어노테이션을 확인하여 "해당 Servlet으로 접근하기 위해서는 URL에 /hello로 접근하면 된다"는 매핑을 합니다.
Servlet 클래스를 만들면 자동으로 어노테이션이 생성되고, 이를 수정하여 URL을 바꿀 수도 있습니다.
아래와 같이 xml을 작성하면, Servlet과 URL이 매핑됩니다.
( 이미 선언된 어노테이션과 중복되면 톰캣 실행이 안됩니다. )
MappingTest hello MappingTest /hello servlet-name web.xml에서 매핑을 구분하기 위한 이름 과 의 이 같은 것을 확인할 수 있습니다. servlet-class Servlet 클래스 이름 url-pattern Serlvet에 대응하는 URL 루트 경로는 생략합니다. 어노테이션으로 매핑하는 것이 훨씬 간단하므로, "web.xml 파일로 직접 Servlet과 URL을 매핑 시킬 수 있다" 정도만 알아두시면 좋을 것 같습니다.참고로 기존에 작성된 태그는 URL에 특정 파일경로가 아닌 도메인만 입력했을 때 보여 줄 페이지를 나열한 것입니다.
즉, 대표 페이지 목록을 나열한 것이라고 생각하면 됩니다.
예를 들어, 클라이언트가 localhost:8080/testing 으로 요청했을 했을 경우, ( 저의 Root 경로가 testing임을 참고해주세요. )
index.html
index.htm
index.jsp
...
순서로 소개 페이지를 찾게 됩니다.
이 부분은 Servlet 매핑과 관련이 없지만 참고로 말씀드렸습니다.
doGet(), doPost() 메서드는 HTTP 요청을 처리하는 메서드라고 언급했었습니다.
그리고 각 메서드는 HttpServletRequest , HttpServletResponse 두 객체를 파라미터로 명시하는데,
이 두 객체는 톰캣에서 미리 작성해둔 클래스이며, HTTP 요청과 응답에 대한 정보들을 모두 갖고 있습니다.
앞으로는 이들을 간단하게 request , response 객체라고 말하도록 하겠습니다.
request 객체
클라이언트가 요청할 때 함께 전송한 데이터들이 있습니다.
예를 들어, URL 파라미터, form에서 전송한 데이터들이 있습니다.
response 객체
서버에서 클라이언트로 응답 할 때 필요한 데이터들이 있습니다.
예를 들어, 응답 결과 상태 코드, 클라이언트가 요청한 HTML 문서 같은 것들이 있습니다.
이 두 객체가 하는 일은 앞으로도 계속 나오게 되므로 API는 그 때 그 때 확인하도록 하겠습니다.
지금은 request , response 객체가 HTTP 요청과 응답을 처리하는 객체라는 것만 알면 될 것 같습니다.
Servlet은 클라이언트의 요청을 받아서 비즈니스 로직 처리, DB에 접근 등의 요청을 처리한 후, 다시 사용자에게 응답하는 것이 주 역할입니다.
즉, 요청을 관리한다는 점에서 MVC 패턴의 컨트롤러 역할을 합니다.
( MVC에 대해서는 여기를 참고해주세요. )
사용자에게 응답하는 문서는 JSP 파일을 사용하는데, 왜 Servlet을 사용하지 않고 JSP를 사용할까요?
그 이유를 알기 위해서 Servlet을 사용할 때 얼마나 불편한지 확인해보겠습니다.
위에서 생성한 Servlet 클래스에서 클라이언트에게 응답을 하기 위해 doGet() 메서드를 간단하게 수정합니다.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 헤더는 PrintWriter 위에 작성해야 한다.
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<h1>하이</h1>");
}
response.setContentType()
HTTP 응답 헤더를 작성하는 코드입니다.
헤더이므로 HTTP body보다 위에 작성합니다.
response.getWriter()
브라우저에 출력할 메시지를 작성합니다.
이제 서버를 실행 시킨 후, 브라우저에서 URL로 요청을 해보겠습니다.
( 실행이 된 상태라면 재실행을 해주셔야 컴파일이 됩니다. )
저는 프로젝트 Root가 testing이고, Servlet 클래스 이름이 hello이므로, localhost:8080/testing/hello 경로로 요청을 보냈습니다.
Servlet으로 응답해도 페이지가 잘 응답되는 것을 확인할 수 있는데요.
그런데 out.println() 메서드로 HTML 태그를 자동완성 없이 일일이 쓰는 것은 너무 고통스럽습니다.
게다가 들여쓰기가 없으므로 가독성도 좋지 않고, 실수할 우려도 있죠.
이런식으로 html을 작성하는 것은 바람직하지 않은 것 같습니다.
다음의 사진은 어떤 JSP 파일을 Servlet으로 작성한 파일의 일부입니다.
JSP 파일에서 60줄이었는데, Servlet으로 변환되니 200줄이 되었습니다.
즉, Servlet으로 응답 페이지를 보여주는 것은 비효율적입니다.
그래서 HTML 문서에 Java 코드를 넣을 수 있는 JSP가 필요한 것입니다.
JSP는 MVC 패턴에서 View에 해당합니다.
정리하면 JSP/Servlet을 사용한다는 것은 "모든 요청은 Servlet으로 받고 클라이언트에게 보여 줄 페이지는 JSP로 작성한다"고 할 수 있습니다.
이상으로 Servlet에 대한 개념에 대해 알아보았습니다.
Servlet이 아닌 JSP에서 직접 요청을 받아서 JSP로 응답하는 방법도 있는데 이를 모델1이라고 합니다.
즉, Controller와 View를 모두 JSP가 담당하고 있는 것이죠.
그리고 이 글에서 다뤘던 방식인 Servlet으로 요청을 받고 JSP로 응답하는 방법을 모델2라고 합니다.