elipse-workspace
-> .metadata
-> .plugins
-> org.elipse.wst.server.core
> tmp0
-> wtpwebapps
실제 폴더에서 web.xml파일은 ROOT 폴더 하위 폴더에 들어가있다. <?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>
먼저, CGI(Common Gateway Interface)에 대해서 알아야 한다.
웹의 역사에서 동적 페이지를 필요해짐에 따라, 서버는 클라이언트의 요청에 응답하여 처리하는 프로그램이 필요해졌다. 즉, 미리 저장해두었던 정적 페이지가 아닌 요구사항에 맞춰 만들어진 동적 페이지를 응답해줘야 하는 상황에 직면했다.
이를 해결하기 위해 등장한 것이 CGI이다. CGI란 웹 서버와 외부 프로그램 사이에 정보를 주고받는 일종의 규약을 말한다. CGI의 의미는 공통 게이트웨이 인터페이스인데, 이를 풀어서 생각해보자.
공통
: 너도 나도 포함된다.
게이트웨이
: 연결 다리.
인터페이스
: 상호간의 연결을 쉽게 해주는 것.
그런데 CGI는 프로세스 단위로 실행된다는 단점을 가지고 있었다. 웹 서버에 요청이 많아지면 그 만큼 실행되는 프로세스가 많아져 서버에 부하가 발생한다. 이를 보완하기 위해 프로세스가 아닌 스레드 단위로 동작하는 프로그램이 등장하게 된다. 그것이 바로 Servlet이다.
참고링크 : https://www.geeksforgeeks.org/difference-between-java-servlet-and-cgi/
Basis | Servlet | CGI |
---|---|---|
Approach | 스레드 기반 | 프로세스 기반 |
사용 언어 | JAVA | 상관없음 |
OOP | O | X |
Portability | O | X |
Persistence | 명시적으로 해제될 때까지 메모리에 유지 | 요청 종료시 해제 |
Server Indepent | O | X |
Data Sharing | O | X |
WAS는 웹 브라우저로부터 Servlet요청을 받으면,
요청할 때 가지고 있는 정보를 HttpServletRequest객체를 생성하여 저장
웹 브라우저에게 응답을 보낼 때 사용하기 위하여 HttpServletResponse객체를 생성
생성된 HttpServletRequest, HttpServletResponse 객체를 서블릿에게 전달
추상화를 통해 http프로토콜에 맞춰 직접 구현하지 않아도 된다.
http프로토콜의 request정보를 서블릿에게 전달하기 위한 목적으로 사용
헤더정보, 파라미터, 쿠키, URI, URL 등의 정보를 읽어 들이는 메소드를 가지고 있다.
Body의 Stream을 읽어 들이는 메소드를 가지고 있다.
WAS는 어떤 클라이언트가 요청을 보냈는지 알고 있고, 해당 클라이언트에게 응답을 보내기 위한 HttpServletResponse객체를 생성하여 서블릿에게 전달
WAS는 클라이언트의 주소를 알고 있어, 개발자는 Response객체에 정보만 담아두면 WAS가 클라이언트에게 전달해준다.
서블릿은 해당 객체를 이용하여 content type, 응답코드, 응답 메시지등을 전송
실제 개발에서 Servlet을 직접 사용하지는 않는다. 프레임워크들이 더 쉽게 구현할 수 있도록 도와주기 때문에 프레임워크를 쓴다. 그럼에도 불구하고, Servlet이 없이는 프레임워크들도 동작할 수 없기 때문에, Servlet을 이해하는 것은 웹의 동작을 이해하는데 도움이 된다.
@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에 담길 데이터를 입력할 수 있다.
private static final long serialVersionUID = 1L;
HttpServlet은 Serializable
인터페이스를 implements
한다. IDE에서는 Serializable
인터페이스의 구현체에 대해 위 변수를 할당하는 것을 추천한다. 그렇다면 왜 그럴까?
같은 클래스라도 위 직렬화ID에 따라 구분된다. 명시적으로 위 직렬화ID를 할당하지 않으면, 컴파일러에서 임의로 할당한다. 그런데, 직렬화ID가 수정될 경우, 역직렬화 과정에서 에러가 발생할 수 있다고 한다. 이러한 이유로 직렬화ID를 명시하는 것을 추천한다.
(더 자세한 내용은 따로 'Java 직렬화'라는 포스팅을 해야겠다.)
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을 찾는다.
init()
: 클래스의 생성자와 유사하게 클래스가 최초 생성될 때 1번 호출된다. 만약, destory()가 호출된 이후라면, 서블릿을 재생성하기 때문에 init()함수가 재호출된다.
service()
: 클라이언트로 부터 요청이 있을 때마다 호출된다.
destroy()
: 서버 코드의 수정과 같은 변화가 있거나, WAS가 종료될 때 호출된다.
Receives standard HTTP requests from the public service method and dispatches them to the doXXX methods defined in this class.
서블릿 컨테이너(ex. tomcat)에서 서블릿이 어떻게 생성되는지에 관해 더 깊이 알아보고자 한다.
현재 상황을 'HTTP request가 서블릿 컨테이너에 전달되고 서블릿 컨테이너는 적절한 서블릿을 찾아 해당 서블릿을 생성하는 중'이라고 가정한다.