[스프링] 2. 웹 백엔드 프로그래밍 기초 - 서블릿 및 서블릿 작성방법

JM·2022년 11월 25일
0
post-thumbnail

학습목표

  • 자바 웹 어플리케이션의 구조를 이해한다.
  • 서브릿에 대하여 이해한다.

자바 웹 어플리케이션(Java Web Application)

  • WAS에 설치되어 동작하는 어플리케이션
  • 자바 웹 어플리케이션에는 HTML,CSS,이미지,자바로 작성된 클래스, 각종 설정 파일 등이 포함된다.
  • 블로그, 쇼핑몰과 같은 것들이 web app이다.

자바 웹 어플리케이션의 폴더 구조

https://github.com/JMsuper/boostcourse_web_backend/raw/main/img/%EC%9E%90%EB%B0%94%20%EC%9B%B9%20%EC%96%B4%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98%20%ED%8F%B4%EB%8D%94%20%EA%B5%AC%EC%A1%B0.png

  • WEB-INF 폴더와 web.xml파일이 중요하다.
  • web.xml파일은 웹 어플리케이션에 관한 정보를 다 가지고 있는 파일이다.(서블릿 버전을 포함한다.)
  • WEB-INF 폴더 하위 폴더인 lib 폴더에는 각종 jar파일 형태의 라이브러리 파일들이 들어간다.
  • 작성한 servlet 파일들은 classes 폴더안에 들어간다.

이클립스에서 실행된 Dynamic Web Project

  • 이클립스에서 Dynamic Web Project의 Servlet을 실행하면, 해당 프로젝트가 이클립스가 관리하는 .metadata 폴더아래에 자바 웹 어플리케이션 폴더 구조로 만들어져 실행된다.
  • 경로 elipse-workspace -> .metadata -> .plugins -> org.elipse.wst.server.coretmp0 -> wtpwebapps실제 폴더에서 web.xml파일은 ROOT 폴더 하위 폴더에 들어가있다. https://github.com/JMsuper/boostcourse_web_backend/raw/main/img/%EC%9E%90%EB%B0%94%20%EC%9B%B9%20%ED%8F%B4%EB%8D%94.png
  • web.xml 파일
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <web-app version="2.5" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"> </web-app>

Servlet이란?

  • 자바 웹 어플리케이션의 구성요소 중 동적인 처리를 하는 프로그램
  • 서블릿을 정의 해보면
    • 서블릿(servlet)은 WAS에서 동작하는 Java 클래스이다.
    • 서블릿은 HttpServlet 클래스를 상속받아야 한다.
    • 서블릿만으로 HTML을 표현하기는 무리가 있다.
    • 서블릿과 JSP로부터 최상의 결과를 얻으려면, 웹 페이지를 개발할 때 이 두 가지를조화롭게 사용해야 한다. 예 : 웹 페이지를 구성하는 화면(HTML)은 JSP로 표현하고, 복잡한 프로그래밍은 서블릿으로 구현한다.

Servlet의 탄생배경

먼저, CGI(Common Gateway Interface)에 대해서 알아야 한다.
웹의 역사에서 동적 페이지를 필요해짐에 따라, 서버는 클라이언트의 요청에 응답하여 처리하는 프로그램이 필요해졌다. 즉, 미리 저장해두었던 정적 페이지가 아닌 요구사항에 맞춰 만들어진 동적 페이지를 응답해줘야 하는 상황에 직면했다.
이를 해결하기 위해 등장한 것이 CGI이다. CGI란 웹 서버와 외부 프로그램 사이에 정보를 주고받는 일종의 규약을 말한다. CGI의 의미는 공통 게이트웨이 인터페이스인데, 이를 풀어서 생각해보자.

공통 : 너도 나도 포함된다.
게이트웨이 : 연결 다리.
인터페이스 : 상호간의 연결을 쉽게 해주는 것.

그런데 CGI는 프로세스 단위로 실행된다는 단점을 가지고 있었다. 웹 서버에 요청이 많아지면 그 만큼 실행되는 프로세스가 많아져 서버에 부하가 발생한다. 이를 보완하기 위해 프로세스가 아닌 스레드 단위로 동작하는 프로그램이 등장하게 된다. 그것이 바로 Servlet이다.

https://github.com/JMsuper/boostcourse_web_backend/raw/main/img/CGI%20%ED%94%8C%EB%A1%9C%EC%9A%B0.png


Servlet과 CGI의 차이점

참고링크 : https://www.geeksforgeeks.org/difference-between-java-servlet-and-cgi/

BasisServletCGI
Approach스레드 기반프로세스 기반
사용 언어JAVA상관없음
OOPOX
PortabilityOX
Persistence명시적으로 해제될 때까지 메모리에 유지요청 종료시 해제
Server IndepentOX
Data SharingOX

Request, Response 객체 이해

요청과 응답

WAS는 웹 브라우저로부터 Servlet요청을 받으면,
요청할 때 가지고 있는 정보를 HttpServletRequest객체를 생성하여 저장
웹 브라우저에게 응답을 보낼 때 사용하기 위하여 HttpServletResponse객체를 생성
생성된 HttpServletRequest, HttpServletResponse 객체를 서블릿에게 전달
추상화를 통해 http프로토콜에 맞춰 직접 구현하지 않아도 된다.

HttpServletRequest

http프로토콜의 request정보를 서블릿에게 전달하기 위한 목적으로 사용
헤더정보, 파라미터, 쿠키, URI, URL 등의 정보를 읽어 들이는 메소드를 가지고 있다.
Body의 Stream을 읽어 들이는 메소드를 가지고 있다.

HttpServletResponse

WAS는 어떤 클라이언트가 요청을 보냈는지 알고 있고, 해당 클라이언트에게 응답을 보내기 위한 HttpServletResponse객체를 생성하여 서블릿에게 전달
WAS는 클라이언트의 주소를 알고 있어, 개발자는 Response객체에 정보만 담아두면 WAS가 클라이언트에게 전달해준다.
서블릿은 해당 객체를 이용하여 content type, 응답코드, 응답 메시지등을 전송



Servlet 작성 방법

실제 개발에서 Servlet을 직접 사용하지는 않는다. 프레임워크들이 더 쉽게 구현할 수 있도록 도와주기 때문에 프레임워크를 쓴다. 그럼에도 불구하고, Servlet이 없이는 프레임워크들도 동작할 수 없기 때문에, Servlet을 이해하는 것은 웹의 동작을 이해하는데 도움이 된다.

학습 목표

  • 서블릿을 작성할 수 있다.
  • 서블릿 버전에 따른 web.xml을 적절하게 작성할 수 있다.

Servlet 작성방법은 2가지로 나뉨

  1. Servlet 3.0 spec 이상에서 사용하는 방법
    • web.xml파일을 사용하지 않음.
    • 자바 어노테이션(annotation)을 사용
  2. Servlet 3.0 spec 미만에서 사용하는 방법
    • Servlet을 등록할 때 web.xml파일에 등록

Servlet 3.0 spec 이상

@WebServlet("/ttt")
public class TenServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public TenServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8;");
		PrintWriter out = response.getWriter();
		out.print("<h1>1-10까지 출력!!</h1>");
		for(int i = 1; i <= 10; i++) {
			out.print(i+"<br>");
		}
		out.close(); 
	}
}

class 위에 있는 @WebServlet("/ttt")문구가 annotation이다. 이를 통해 web.xml 파일없이 "/ttt" 요청이들어왔을 때, 해당 클래스의 메소드를 이용하도록 만들 수 있다.

response.setContentType("text/html;charset=utf-8;"); : 응답 객체의 ContentType을 지정한다. 클라이언트가 서버로 부터 데이터를 전송받을 때, 해당 데이터가어떤 타입의 데이터인지 알아야지 이를 parsing할 수 있다.

PrintWriter out = response.getWriter(); : HttpServletResponse 객체의 메소드인 getWriter()함수는 PrintWriter 객체를 리턴한다.PrintWriter 객체를 통해 response body에 담길 데이터를 입력할 수 있다.

serialVersionUID? 정체가 뭔가?

private static final long serialVersionUID = 1L;
HttpServlet은 Serializable 인터페이스를 implements 한다. IDE에서는 Serializable 인터페이스의 구현체에 대해 위 변수를 할당하는 것을 추천한다. 그렇다면 왜 그럴까?
같은 클래스라도 위 직렬화ID에 따라 구분된다. 명시적으로 위 직렬화ID를 할당하지 않으면, 컴파일러에서 임의로 할당한다. 그런데, 직렬화ID가 수정될 경우, 역직렬화 과정에서 에러가 발생할 수 있다고 한다. 이러한 이유로 직렬화ID를 명시하는 것을 추천한다.
(더 자세한 내용은 따로 'Java 직렬화'라는 포스팅을 해야겠다.)


servlet 3.0 미만

web.xml 파일 중 일부

  <servlet>
    <description></description>
    <display-name>TenServlet</display-name>
    <servlet-name>TenServlet</servlet-name>
    <servlet-class>exam.TenServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>TenServlet</servlet-name>
    <url-pattern>/ten</url-pattern>
  </servlet-mapping>

의미 : 클라이언트가 요청할 때 "/ten"이라는 url로 요청하게 되면, servlet-name이 같은 servlet을 찾아서 실제 클래스인 "exam"이라는 패키지 안에 있는 "TenServlet" 실행시켜주세요.

만약 찾지 못할 경우 404페이지를 리턴한다. 존재한다면, servlet-name을 보고 똑같은 이름의 servlet을 찾는다.

서블릿 라이프사이클

학습목표

  • 서블릿의 생명주기를 이해한다.

LifecycleServlet 작성

  • 서블릿 생명주기를 확인할 수 있는 LifecycleServlet을 작성한다.
  • HttpServlet의 3가지 메소드를 오버라이딩
    - init()
    - service(request, response)
    - destroy()

과정

  1. 클라이언트가 url을 통해 서버에게 요청
  2. 서버는 url을 확인하여 mapping 되어있는 클래스를 찾음
  3. 해당 클래스가 메모리에 존재하는 지 확인
  4. 존재하면 service()를 호출하고 존재하지 않으면 클래스의 객체 생성

init() : 클래스의 생성자와 유사하게 클래스가 최초 생성될 때 1번 호출된다. 만약, destory()가 호출된 이후라면, 서블릿을 재생성하기 때문에 init()함수가 재호출된다.
service() : 클라이언트로 부터 요청이 있을 때마다 호출된다.
destroy() : 서버 코드의 수정과 같은 변화가 있거나, WAS가 종료될 때 호출된다.

service(request, response) 메소드

  • HttpServlet의 service메소드는 템플릿 메소드 패턴으로 구현
    - 클라이언트의 요청이 GET일 경우에는 자신이 가지고 있는 doGet(request,response)를 호출
    - 클라이언트의 요청이 POST일 경우에는 자신이 가지고 있는 doPost(request,response)를 호출
  • 즉, service 메소드는 클라이언트의 요청 종류에 따라 지정된 메소드를 호출한다.

service(request, response)메소드의 oracle document

Receives standard HTTP requests from the public service method and dispatches them to the doXXX methods defined in this class.


서블릿 라이프사이클 Deep Dive

서블릿 컨테이너(ex. tomcat)에서 서블릿이 어떻게 생성되는지에 관해 더 깊이 알아보고자 한다.
현재 상황을 'HTTP request가 서블릿 컨테이너에 전달되고 서블릿 컨테이너는 적절한 서블릿을 찾아 해당 서블릿을 생성하는 중'이라고 가정한다.

profile
블로그 이전 : https://blog.naver.com/tjsqls2067

0개의 댓글