[Tomcat] Tomcat, JSP, Servlet 개념 및 구조

2022. 5. 23. 12:49JAVA/Servlet&JSP

1. Servlet과 JSP

JSP(Java Server Page)

  • 확장자가 .jsp 파일
  • html 문서안에 자바 언어를 삽입해 사용할 수 있도록함
  • Servlet을 사용해 웹을 만들 경우 화면 인터페이스 구현이 어렵다는 단점을 보완하기 위해 만든 스크립트 언어

Servlet

  • 확장자가 java 파일
  • 자바의 일반적인 클래스와 동일한 개념
  • 웹을 다룰 수 있도록 해주는 “HttpServlet” 클래스를 상속받은 클래스를 의미함

웹 어플리케이션의 수행과정

  1. 사용자가 URL(또는 IP)을 통해 WEB 서버를 호출하고 요청사항을 객체(request)에 담아서 전송함
  2. WEB 서버는 요청 객체(request)을 받아서 바로 처리하거나 어플리케이션 서버(WAS)로 객체를 전달함
  3. WAS 서버는 요청에 대한 내용과 요청 객체(request)를 받아 적절히 처리함(필요시 DB 작업도 진행함)
  4. WAS 서버는 요청 처리후 결과를 응답 객체(response)에 담다 WEB 서버로 회신
  5. WEB 서버는 응답 객체(response)을 다시 사용자에게 회신
  6. 사용자의 브라우저는 WEB 서버가 보내준 코드를 해석해 화면을 구성하여 출력

 

2. WEB 서버 단일 구성

WEB 서버 수행과정

  1. 사용자가 URL 또는 링크가 걸린 글/그림등을 클릭하여 웹 서버에게 페이지를 요청함
  2. 웹 서버(WEB Server)가 해당하는 페이지를 사용자에게 전송
  3. 웹 브라우저는 페이지를 받아서 화면으로 만든뒤 사용자에게 출력

페이지의 구성

  • html : 페이지의 컨텐츠를 나타냄
  • css : html의 컨텐츠를 꾸며주는 정적 언어
  • javascript : 컨텐츠를 동적으로 표현해주는 스크립트 언어

웹 서버가 브라우저에게 html/css/javascript로 구성된 파일을 전송하면 웹 브라우저는 그 파일을 해석하여 실행합니다.

 

단일 WEB 서버 아키텍처의 단점

  1. 필요한 페이지마다 자바스크립트 등으로 복잡한 로직을 구성해서 모든 페이지를 미리 준비해야함
  2. 복잡한 로직이 들어있는 페이지를 모두 사용자(웹 브라우저)에게 전송해야한다는 문제점을 가짐

3. WEB-WAS 구성

WAS(Web Application Server)

웹 서버가 계산하기 복잡한 연산을 처리해주는 서버

 

WEB-WAS 아키텍처 수행과정

  1. 사용자(브라우저)가 서버에게 서비스를 요청(페이지 또는 복잡한 연산)함
  2. WAS는 사용자의 요청 내용(request)을 받아서 처리한 다음 웹 페이지를 생성하여 사용자에게 전송
  3. WEB 서버는 만들어진 웹 페이지를 사용자에게 전달

WEB-WAS 아키텍처의 장점

  1. WAS에서 프로그래밍 언어(Java, C++ 등)을 사용해 로직을 처리하기 때문에 보다 복잡한 로직 처리가 가능함
  2. 사용자는 WEB 서버가 주는 페이지만 받아서 실행하므로 내부의 로직을 알수 없기 때문에 보안이 강화되는 효과를 얻을 수 있음
  3. 복잡한 연산은 서버단에서 처리하고 사용자(브라우저)에게 결과값만을 전송하기 때문에 사용자는 그만큼 빠르게 결과를 받을 수 있고 받는 정보량(코드)이 줄어들어 네트워크 부하도 줄일 수 있음

WEB-WAS 아키텍처의 특징

  1. WEB 서버와 WAS 서버는 물리적으로 나눌 수도 있고 한 서버안에 기능적으로 나눌수도 있음
  2. WEB, WAS 서버는 서로 수행하는 기능이 다름
    • WEB 서버 : 연산이 필요없는 정적 페이지(또는 이미지, 파일 등)를 처리함
    • WAS 서버 : 연산이 필요한 경우 WAS 서버가 처리하고 WEB 서버에게 전달함

4. WEB-WAS-DB 아키텍처

Database

  • 논리적으로 연관된 하나 이상의 자료의 모음
  • 데이터(내용)들을 고도로 구조화함으로써 검색과 갱신(추가, 수정, 삭제)의 효율화를 시도함
  • 데이터베이스는 DBMS(Database Management System)에 의해서 관리됨
    • DBMS는 데이터베이스를 사용자가 직접 접근하는 대신 데이터베이스를 관리하는 시스템입니다.

Database의 필요 이유

  • WAS 서버가 복잡한 연산을 위해 필요한 각종 정보를 저장해두기 위해서입니다.
  • 사용자가 데이터에 직접 접근하는 것을 방지하여 보안성을 강화하기 위해서입니다.

WEB-WAS-DB 아키텍처 특징

  • 복잡한 연산을 위해 필요한 정보를 데이터베이스에서 가져와서 처리함
  • 사용자가 데이터베이스에 직접 접근할 수 없기 때문에 보안성이 좋음

WEB-WAS-DB 아키텍처 수행과정

  1. 사용자(브라우저)가 로그인 서비스를 요청함. 서비스를 요청하면서 웹 서버에 입력한 ID와 비밀번호 정보를 전달함
  2. 웹 서버는 WAS에게 데이터(ID, 비밀번호)를 전달함
  3. WAS는 로그인 서비스 로직을 처리하는 도중 사용자가 입력한 아이디와 비밀번호에 해당하는 유저가 있는지 데이터베이스에 검색을 요청함
  4. 데이터베이스에서 쿼리 결과를 다시 WAS에게 전달함
  5. WAS에서 WEB 서버를 통해서 사용자에게 로그인 서비스 요청 결과를 응답함

 

5. Java SE & Java EE

Java SE(Java Standard Edition)

Java SE는 Java의 핵심 API와 기능들을 제공하는 에디션입니다. 간단한 응용 프로그램과 서버 구축이 가능함

 

Java EE(Java Enterprise Edition)

  • Java EE는 Java SE의 확장 버전으로 서버 개발을 위한 추가 기능을 제공하는 플랫폼
  • Tomcat 등의 WAS를 이용하는 서버 개발은 Java EE에서 추가로 제공하는 기능을 사용함
  • 특히 JSPServlet을 만들고 실행하는 규칙과 EJB(Enterpise JavaBeans)의 분산 컴포넌트, 웹 서비스 규칙 등을 추가로 가지고 있으며, 서블릿과 JSP를 구현하는 기능을 서블릿 컨테이너라고 함

 

6. Apache Tomcat

  • Apache : WEB Server
  • Apache Tomcat : WAS(Web Application Server)

Apache

Apache는 Apache 재단에서 만든 HTTP 서버이며 웹 서버 전용 기능을 제공합니다.

 

Apache Tomcat

Apache Tomcat은 웹 서버 전용 기능인 Apche와는 다르게 WAS 기능을 제공합니다.

 

Tomcat

  • Tomcat은 WEB/WAS의 기능을 가진 자바 어플리케이션
  • Tomcat은 Java EE 기반으로 생성됨
  • Tomcat(WAS)는 자바로 만들어진 JSPServlet을 구동하기 위한 서블릿 컨테이너 역할을 수행함

Servlet Container란 무엇인가?

  • JSP를 Servlet으로 변경하여 실행해주는 역할을 수행함
  • Servlet의 생명 주기를 관리하며 웹 환경에서 Servlet이 실행될 수 있도록 해주는 프로그램
  • WAS에서는 여러 개의 컨테이너를 구성해서 각각 독립적인 서비스로 구동시키는 것이 가능함

 

WAS의 Servlet Container 수행과정

  1. 웹 서버에서 보내준 요청을 가지고 스레드를 생성함
  2. 필요한 JSP나 Servlet 파일을 실행해서 서비스 요청을 수행함
  3. 수행 결과를 응답 객체(response)에 담아서 사용자에게 전달함

 

7. Servlet & JSP(Java Server Page)

Servlet

  • Servlet은 Java EE에서 제공하는 서블릿 클래스를 상속받은 클래스를 의미함
  • Servlet만을 이용하여 사용자에게 웹 페이지를 생성하여 응답하기에는 불편한점이 존재함
    • 웹페이지 생성시 html 코드를 출력해주는 작업이 매우 번거로움
    • 스트림 객체를 생성하여 사용자에게 응답할 html 코드를 전부 출력해주어야함

다음은 Servlet에서 사용자에게 응답할 html 코드를 출력하기 위해서 스트림 객체에 print하는 코드입니다.

@WebServlet("/home")
public class HomeController extends HttpServlet{

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		OutputStream out = response.getOutputStream();
		PrintStream writer = new PrintStream(out, true);
		
		writer.println("<html>");
		writer.println("<head>");
		writer.println("</head>");
		writer.println("<body>");
		writer.println("<h1>helloWorld~</h1>");
		writer.println("name : " + request.getParameter("name") + "<br/>");
		writer.println("</body>");
		writer.println("</html>");
		writer.close();
		
		
	}

}

Servlet 단독 사용의 문제점

  • 자바안에 html 코드가 들어가 있지만 코드를 삽입하는게 아닌 그저 출력해주는 방식임
  • 복잡한 레이아웃을 가진 페이지를 응답하려면 코드가 길어질 수 밖에 없음

JSP(Java Server Page)

  • Servlet을 단독으로 사용하여 웹 페이지를 구성하는 태그요소들을 출력하는 번거로운 문제를 해결하기 위해 나온 스크립트 언어
  • Servlet은 자바 언어안에 html 코드를 삽입하는 것이라면 JSP는 html 코드안에 자바 언어를 삽입하는 방식
  • 스크립트릿(<% %>)을 삽입하여 그 안에 자바 언어를 넣을 수 있음
  • JSP 파일의 확장자는 .jsp입니다.

다음은 JSP 페이지의 예시입니다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSP 예제</title>
</head>
<body>
	<h1>hello world</h1>
	<%
		for(int i = 0; i < 10; i++){
			out.println(i);
		}
	%>
</body>
</html>

JSP의 실행과정

  1. JSP 파일을 Servlet 파일(.java)로 변환
  2. 변환된 Servlet 파일을 컴파일해서 자바 바이트 코드 파일(.class)을 생성함
  3. 컴파일된 파일을 실행 결과 자바 언어가 모두 사라진 html 코드를 출력함

JSP→ Servlet으로 변환된 코드는 다음과 같습니다.

public final class home_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent,
                 org.apache.jasper.runtime.JspSourceImports {

  private static final javax.servlet.jsp.JspFactory _jspxFactory =
          javax.servlet.jsp.JspFactory.getDefaultFactory();

  private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;

  private static final java.util.Set<java.lang.String> _jspx_imports_packages;

  private static final java.util.Set<java.lang.String> _jspx_imports_classes;

  static {
    _jspx_imports_packages = new java.util.HashSet<>();
    _jspx_imports_packages.add("javax.servlet");
    _jspx_imports_packages.add("javax.servlet.http");
    _jspx_imports_packages.add("javax.servlet.jsp");
    _jspx_imports_classes = null;
  }

  private volatile javax.el.ExpressionFactory _el_expressionfactory;
  private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;

  public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
    return _jspx_dependants;
  }

  public java.util.Set<java.lang.String> getPackageImports() {
    return _jspx_imports_packages;
  }

  public java.util.Set<java.lang.String> getClassImports() {
    return _jspx_imports_classes;
  }

  public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
    if (_el_expressionfactory == null) {
      synchronized (this) {
        if (_el_expressionfactory == null) {
          _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
        }
      }
    }
    return _el_expressionfactory;
  }

  public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
    if (_jsp_instancemanager == null) {
      synchronized (this) {
        if (_jsp_instancemanager == null) {
          _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
        }
      }
    }
    return _jsp_instancemanager;
  }

  public void _jspInit() {
  }

  public void _jspDestroy() {
  }

  public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
      throws java.io.IOException, javax.servlet.ServletException {

    if (!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
      final java.lang.String _jspx_method = request.getMethod();
      if ("OPTIONS".equals(_jspx_method)) {
        response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
        return;
      }
      if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) {
        response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
        response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP�뱾�� �삤吏� GET, POST �삉�뒗 HEAD 硫붿냼�뱶留뚯쓣 �뿀�슜�빀�땲�떎. Jasper�뒗 OPTIONS 硫붿냼�뱶 �삉�븳 �뿀�슜�빀�땲�떎.");
        return;
      }
    }

    final javax.servlet.jsp.PageContext pageContext;
    javax.servlet.http.HttpSession session = null;
    final javax.servlet.ServletContext application;
    final javax.servlet.ServletConfig config;
    javax.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    javax.servlet.jsp.JspWriter _jspx_out = null;
    javax.servlet.jsp.PageContext _jspx_page_context = null;


    try {
      response.setContentType("text/html; charset=UTF-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
      			null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write("\r\n");
      out.write("<!DOCTYPE html>\r\n");
      out.write("<html>\r\n");
      out.write("<head>\r\n");
      out.write("<meta charset=\"UTF-8\">\r\n");
      out.write("<title>JSP �삁�젣</title>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
      out.write("	<h1>hello world</h1>\r\n");
      out.write("	");

		for(int i = 0; i < 10; i++){
			out.println(i);
		}
	
      out.write("\r\n");
      out.write("</body>\r\n");
      out.write("</html>");
    } catch (java.lang.Throwable t) {
      if (!(t instanceof javax.servlet.jsp.SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try {
            if (response.isCommitted()) {
              out.flush();
            } else {
              out.clearBuffer();
            }
          } catch (java.io.IOException e) {}
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
        else throw new ServletException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}

JSP(.jsp) → Servlet(.java) → .class 파일 변환후 최종적으로 사용자에게 전달되는 코드는 다음과 같습니다.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSP 예제</title>
</head>
<body>
	<h1>hello world</h1>
	0
	1
	2
	3
	4
	5
	6
	7
	8
	9
</body>
</html>

 

References

Apache Tomcat
Tomcat(톰캣), JSP, Servlet(서블릿)의 기본 개념 및 구조