웹 프로그래밍/[ Spring ]

[ Spring ] 02. Servlet(서블릿)을 파헤쳐보자.

kim.svadoz 2021. 6. 30. 16:32
728x90
반응형

Servlet


클라이언트의 요청을 처리하기 위한 기술.

또, 요청에 대한 결과를 반환하는 Servlet 클래스의 구현 규칙을 지킨 자바 웹 프로그래밍 기술

간단히 말해서, 서블릿이란 자바를 사용해 웹을 만들기 위해 필요한 기술이다.

즉, 클라이언트가 어떠한 요청을 하면 그에 대한 결과를 다시 전송 해주어야 하는데, 이러한 역할을 하는 자바 프로그램 인 것이다.

클라이언트로부터 요청이 전달되면 서버에서 실행되며 DB연동이나 서버의 자원을 액세스하여 만들어진 결과를 다시 클라이언트로 응답한다.

이 클라이언트의 요청을 인식하고 실행하도록 하기 위해서는 서블릿은 정해진 규칙대로 작성되어야 하고, 서버가 서블릿을 찾아 실행될 수 있도록 정해진 위치에 작성되어야 한다.

정해진 위치?

표준화된 폴더 구조안에 있는 classes 폴더(서블릿 디렉토리)

89752786-b3c1be80-db10-11ea-94da-d4bb100c5636

  • 특징
    • 클라이언트의 요청에 대해 동적으로 작동하는 웹 어플리케이션 컴포넌트
    • HTML을 사용하여 요청에 응답한다
    • Java Thread를 이용해 동작한다.
    • MVC 패턴에서 Controller로 이용된다.
    • HTTP 프로토콜 서비스를 지원하는 javax.servlet.http.HttpServlet 클래스를 상속받는다.
    • UDP보다 처리 속도가 느리다.
    • HTML 변경시 Servlet을 재컴파일해야 하는 단점이 있다.

일반적으로 웹 서버는 정적인 페이지만을 제공하기 때문에 동적인 페이지를 제공하기 위해서 웹 서버는 다른 곳에 도움을 요청해 동적인 페이지를 작성해야 한다.

동적인 페이지로는 임의의 이미지만을 보여주는 페이지와 같이 사용자가 요청한 시점에 페이지를 생성해서 전달해주는 것을 의미한다.

여기서 웹서버가 동적인 페이지를 제공할 수 있도록 도와주는 어플리케이션이 서블릿이며, 동적인 페이지를 생성하는 어플리케이션이 CGI이다.

서블릿 동작 방식

image-20210609133452649

  1. 사용자(클라이언트)가 URL을 입력하면 HTTP Request가 Servlet Container로 전송한다.
  2. 요청을 전송받은 Servlet Container는 HTTPServletRequest, HttpServletResponse 객체를 생성한다.
  3. web.xml을 기반으로 사용자가 요청한 URL이 어느 서블릿에 대한 요청인지 찾는다.
  4. 해당 서블릿에서 service 메소드를 호출한 후 클라이언트의 GET, POST 여부에 따라 doGet() 또는 doPost()를 호출한다.
  5. doGet() or doPost() 메소드는 동적 페이지를 생성한 후 HttpServletResponse 객체에 응답을 보낸다.
  6. 응답이 끝나면 HTTPServletRequest, HttpServletResponse 두 객체를 소멸시킨다.

서블릿 컨테이너

서블릿을 관리해주는 컨테이너

ex) Tomcat

우리가 서버에 서블릿을 만들었다고 해서 스스로 작동하는 것이 아니고, 서블릿을 관리해주는 것이 필요한데 그러한 역할을 하는 것이 서블릿 컨테이너이다.

서블릿이 어떠한 역할을 수행하는 정의서라고 하면, 서블릿 컨테이너는 그 정의서를 수행한다고 볼 수 있다.

서블릿 컨테이너는 클라이언트의 요청(Request)를 받아주고, 응답(Respone)할 수 있도록, 웹 서버와 소켓으로 통신하며 대표적인 예로 톰캣(Tomcat)이 있다.

톰캣은 실제로 웹 서버와 통신하며 JSPServlet이 작동하는 환경을 제공해준다.

역할

  1. 웹 서버와의 통신 지원
    • 서블릿 컨테이너는 서블릿과 웹 서버가 손쉽게 통신할 수 있도록 해준다.
    • 일반적으로 우리는 소켓을 만들고 listen, accept 등을 해야 하지만 서블릿 컨테이너는 이러한 기능을 API로 제공하여 복잡한 과정을 생략할 수 있게 한다.
    • 그래서 개발자가 서블릿에 구현애야 할 비즈니스 로직에 대해서만 초점을 두게끔 한다.
  2. 서블릿 생명주기(Life Cycle) 관리
    • 서블릿 컨테이너는 서블릿의 탄생과 죽음을 관리한다.
    • 서블릿 클래스를 로딩하여 인스턴스화 하고, 초기화 메소드를 호출하고, 요청이 들어오면 적절한 서블릿 메소드를 호출한다.
    • 또한, 서블릿이 생명을 다 한 순간에는 적절하게 Garbage Collection을 진행하여 편의를 제공한다.
  3. 멀티쓰레드 지원 및 관리
    • 서블릿 컨테이너는 요청이 들어올 때마다 새로운 자바 쓰레드를 하나 생성하는데, HTTP 서비스 메소드를 실행하고나면, 쓰레드는 자동으로 죽게 된다.
    • 원래는 쓰레드를 관리해야 하지만 서버가 다중 쓰레드를 생성 및 운영해주니 쓰레드의 안정성에 대해 걱정하지 않아도 된다.
  4. 선언적인 보안 관리
    • 개발자는 보안에 관련된 내용을 서블릿 또는 자바 클래스에 구현해 놓지 않아도 된다.
    • 일반적으로 보안관리는 XML 배포 서술자에 기록하므로, 보안에 대해 수정할 일이 생겨도 자바 소스 코드를 수정하여 다시 컴파일 하지 않아도 보안관리가 가능하다.

생명주기

image-20210609134925916

  1. 클라이언트의 요청이 들어오면 컨테이너는 해당 서블릿이 메모리에 있는지 확인하고, 없을 경우 init() 메소드를 호출하여 적재한다.
    init() 메소드는 처음 한번만 실행되기 때문에, 서블릿의 쓰레드에서 공통적으로 사용해야 하는 것이 있다면 오버라이딩하여 구현하면 된다.
    실행 중 서블릿이 변경될 경우, 기존 서블릿을 파괴하고 init()을 통해 새로운 내용을 다시 메모리에 적재한다.
  2. init()이 호출된 후 클라이언트의 요청에 따라서 service() 메소드를 통해 요청에 대한 응답이 doGet()doPost()로 분기된다.
    이 때, 서블릿 컨테이너가 클라이언트의 요청이 오면 가장 먼저 처리하는 과정으로 생성된 HttpServletRequest, HttpServletResponse에 의해 request와 response 객체가 제공된다.
  3. 컨테이너가 서블릿에 종료 요청을 하면 destroy() 메소드가 호출되는데 마찬가지로 한번만 실행되며, 종료시에 처리해야 하는 작업들을 destroy() 메소드를 오버라이딩하여 구현하면 된다.

서블릿 작성 규칙

  1. 표준화된 폴더 구조 안에서 서블릿 디렉토리에 저장되어야 된다. - classes 폴더

    • ex) C:\iot\setup\java\work\webwork.metadata.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\serverweb\WEB-INF\classes에 작성되어야 한다. => 이 위치에 서블릿 클래스가 없으면 못 찾는다.
  2. public 클래스로 작성해야 한다.

    • 서버가 찾아서 실행해야 하므로
  3. 서블릿클래스를 상속해야 한다.

    • 서버가 우리가 작성한 서블릿 클래스를 찾아서 생성하고 호출하기 위해서는 서버가 인식할 수 있는(서버가 사용할 수 있는) 타입이어야 하므로 서버가 서버에 등록된 타입으로 서블릿 클래스를 작성한다.
    • Servlet(인터페이스)이 => 아래 클래스서블릿들을 상속해야 한다.
      • GenericServlet(클래스) - 일반적인 내용을 담고 있는 서블릿
      • HttpServlet(클래스) - http프로토콜에 특화된 내요을 담고 있는 서블릿
      • MyServlet - 내가 하고 싶은 일을 담고 있는 서블릿(개발자가 만드는 서블릿)
    • 컨테이너 설정 : properties - build path - add library - tomcat9.0 를 설정한다.
  4. 서버가 호출하는 메소드가 오버라이딩 해야 한다.

    • 서블릿 클래스는 일반 클래스를 사용하는 방법처럼 객체생성해서 사용하는 클래스가 아니다.
    • 서블릿이 호출되면 서버가 서블릿 객체를 생성하고 적절한 시점에 따라 정해진 메소드를 자동으로 호출한다.
    • 즉, 서블릿의 _LifeCycle_을 서버가 관리한다.
    • LifeCycle ? : 객체를 생성하고 소멸하는 것
    • 서버가 적절한 시점에 따라 자동으로 메소드를 호출할 때 원하는 작업을 처리하기 위해서는 서버가 호출하는 메소드를 오버라이딩해서 내가 원하는 내용을 기술해야 한다.

    [오버라이딩할 메소드]

    - init : 서블릿이 초기화될 때 호출

    - service : 클라이언트가 요청을 하면 호출되는 메소드

    => 클라이언트의 요청을 처리할 수 있는 내용을 기술

    => 요청방식의 구분없이 모두 호출

    ex) 로그인, 게시판 목록보기, 회원가입....

    - doGet : service와 동일하게 동작하며 클라이언트가 get방식으로 요청하는 경우에만 호출

    - doPost : service와 동일하게 동작하며 클라이언트가 post방식으로 요청하는 경우에만 호출

    - destroy : 서블릿 객체가 소멸될 때 (메모리에서 해제될 때) 호출

  5. 서블릿을 등록

    • 서버가 서블릿을 찾아서 실행할 수 있도록 서블릿을 web.xml에 등록
    • web.xml? : 서블릿에 대한 내용을 서버에 등록하는 설정파일

    1) 서블릿 등록

    • 사용할 서블릿이 어떤 클래스인지 정의
    <servlet>
          <servlet-name>서블릿의 이름(별칭)</servlet-name>
          <servlet-class>실제 사용할 서블릿클래스(패키지 포함)</servlet-class>
    </servlet>

    ex) basic패키지에 작성한 FirstServlet을 first라는 이름으로 등록

    <servlet>
          <servlet-name>First</servlet-name>
          <servlet-class>basic.FirstServlet</servlet-class>
    </servlet>

    2) 서블릿 매핑

    • 서블릿을 어떤 url로 요청할지 등록
    <servlet-mapping>
          <servlet-name>미리등록한 서블릿의 이름</servlet-name>
          <url-pattern>요청url(반드시 /나 .으로 시작)</url-pattern> 
    </servlet-mapping>

    ex) 위에서 등록한 first서블릿을 /first.multi로 요청

    <servlet-mapping>
          <servlet-name>first</servlet-name>
          <url-pattern>/first.html</url-pattern> //path이름은 내맘대로
    </servlet-mapping>

    => 이렇게 요청하면 first라는 서블릿을 호출할건데 그 first는 basic.FirstServlet에서 만들어진 것이고 그건 basic에 있다.

xml파일은 다른 플랫폼(파이썬, 닷넷 등등등) 에서 사용하기 위해서 만들어진 문서이고 다소 무거운 단점이 있음. => 그래서 나온게 JSON

서블릿 요청 방법

특징

  1. get
    : 요청할 때 입력하는 내용이 url 뒤에 추가되어 전송되는 방식(요청메세지 헤더에 추가)

    • 클라이언트가 입력하는 내용이 그대로 노출된다.
    • 전송할 수 있는 데이터의 크기에 제한이 있다.
    • 서버의 데이터를 가져오기

    ex) 게시판 목록 확인하기, 상품정보 가져오기, 검색하기

  2. post
    : 요청메시지 body에 추가되어 전송되므로 클라이언트에 노출되지 않지만 툴을 이용해서 확인하면 확인할 수 있으므로 암호화해서 전송해야 한다.

    • 보낼 수 있는 데이터 크기에 제한이 없다.
    • 서버의 값을 클라이언트가 원하는 값으로 update하는 경우

    ex) 회원등록(insert문 실행), 회원정보 수정하기(update문 실행), 파일업로드, 메일쓰기

  3. 클라이언트가 전달하는 요청 메시지에서 클라이언트의 입력 정보를 추출하기

    1) 요청

    [요청객체]
    -   ServletRequest (상위)
        -   HttpServletRequest (하위)
    • 클라이언트가 요청 메시지를 서버로 전달하면 여러 가지 클라이언트의 정보가(클라이언트가 입력한 데이터, 쿠키, 세션정보, 클라이언트의 IP, Port...) 서버로 전달된다.
    • 서버는 이 데이터를 가지고 요청객체(요청객체를 만들면서 전달받은 데이터를 요청객체에 셋팅하는 작업을 수행한다.)를 생성한다.
    • http프로토콜에 특화된 내용은 HttpServletRequset에서 찾는다.
    • 일반적인 내용은 ServletRequest에서 찾는다.

    2) 요청정보 추출

    ~~/serverweb/login.do?id=lee&pass=1234

    • id : 파라미터 name
    • lee : 파라미터 value

get 요청

  1. 주소표시줄에 입력하고 요청

    <a href="http://localhost:8088/serverweb/first.multi">받은편지함(하이퍼링크 요청)</a>
    <a href="http://70.12.115.65:8088/serverweb/first.multi">받은편지함(하이퍼링크 요청)</a>
    <a href="/serverweb/first.multi">받은편지함(하이퍼링크 요청)</a>
  2. 하이퍼링크 클릭

    <a href="http://서버ip:port:contextpath/서블릿요청url">하이퍼링크</a>
    <a href="/contextpath/서블릿요청url">하이퍼링크</a>
  3. 태그에서 method속성을 "get"으로 설정하고 submit버튼 선택

    • action속성에서 설정한다
    • form태그를 정의하면서 method속성을 생략하면 get방식으로 요청
    • submit버튼을 눌러서 요청하면
      태그의 action속성에 정의한 서블릿이 요청되며
      내부에 정의한 모든 양식태그들의 name과 value가 서블릿으로 전달된다.

post 요청

  1. 태그에서 method속성을 "post"으로 설정하고 submit버튼 선택

    • action속성에서 설정한다

    • form태그를 정의하면서 method속성을 생략하면 get방식으로 요청

    • submit버튼을 눌러서 요청하면

      태그의 action속성에 정의한 서블릿이 요청되며

      내부에 정의한 모든 양식태그들의 name과 value가 서블릿으로 전달된다.

728x90
반응형