5 분 소요

이제 본격적으로 사용자의 요청을 처리하기 위한 서블릿을 사용해보자.

서블릿 생성하기

서블릿 클래스를 담는 자바 파일은 src/main/java 폴더에 저장된다. 해당 폴더에 서블릿 클래스가 담긴 자바 파일을 생성해보겠다.

  1. src/main/java 폴더 위에서 마우스 우클릭 후 [New] → [Other]를 클릭한다.

    20240820_21160794.png

  2. 그러면 다음과 같은 창이 뜰 것인데, 목록에서 [web] 폴더의 [Servlet]을 누르고 [Next] 버튼을 누른다.

    2.PNG

  3. 다음 창에서 [Java package]와 [Class name]을 각각 적는다. 그 후 [Next >] 버튼을 누른다.

    3.PNG

  4. 다음 창에서 [Name] 란에 서블릿 이름을 입력한다. 여기서는 “processLogin”라고 지었다. 이전에 만들었던 login.html 파일 내 form 태그의 action 속성값에 “processLogin”이라는 값이 적혀있기 때문에 해당 이름을 서블릿 이름으로 결정한 것이다. 그래야 해당 form 태그에 입력된 정보들을 이 서블릿이 처리할 수 있게 된다. 이제 [Next >] 버튼을 누른다.

    스크린샷 2024-08-21 085333.png

  5. 다음 창을 보면, “Constructors from superclass”에 체크 표시가 되어있으면, 부모 클래스의 생성자를 호출하는 코드인 super(); 코드를 기본으로 제공해준다. 또한, doGet, doPost는 각각 doGet(), doPost() 메서드를 기본으로 정의해준다는 뜻으로, 이후 각각 GET과 POST 요청을 처리하는 기능을 한다. 이 창에서 건드릴 건 없다. 바로 [Finish]를 누른다.

    5.PNG

  6. 그러면 다음과 같이 src/main/java 폴더 내부에 패키지 폴더를 비롯한 LoginServlet.java 파일이 생성된다. 해당 파일에 서블릿 클래스가 정의되는 것이다.

    6.PNG

그리고 해당 자바 파일 내부 코드는 다음과 같다.

package com.cola.web.user;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.getWriter().append("Served at: ").append(request.getContextPath());
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

예제 1-1. LoginServlet.java

위 코드의 LoginServlet 클래스가 서블릿 클래스이다. 해당 클래스 내부에는 각각 GET과 POST 방식의 HTTP 요청을 받아 처리하는 메서드인 doGet(), doPost() 메서드가 정의되어 있다.

이렇게 하여 서블릿 클래스를 생성하는 법에 대해 살펴보았다. 참고로 나중에 간단한 테스트를 위해 위의 LoginServlet.java 파일 내부를 다음과 같이 바꿔보겠다.

package com.cola.web.user;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class LoginServlet
 */
public class LoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
  /**
    * @see HttpServlet#HttpServlet()
    */
  public LoginServlet() {
    System.out.println("=== 로그인을 위한 서블릿 인스턴스가 생성되었습니다. ===");  // 변경된 코드.
  }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("=== GET 요청을 서블릿에서 처리하였습니다. ===");  // 변경된 코드.
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("=== POST 요청을 서블릿에서 처리하였습니다. ===");  // 변경된 코드.
	}

}

예제 1-2. LoginServlet.java

web.xml

7.PNG

src/main/webapp 폴더 내부의 WEB-INF 폴더 내부에 있는 web.xml 파일은 웹 앱 환경 설정 파일이다. 서버 구동 시 web.xml 파일을 토대로 웹 앱을 실행하기에 중요한 파일이다.

또한, 해당 파일 내부에는 앞선 방식과 똑같이 서블릿을 생성하면 해당 서블릿의 패키지 경로, 서블릿 클래스명, 서블릿 이름 등의 정보가 web.xml 파일에 자동으로 등록된다. 해당 파일은 서블릿 객체들을 관리하는 역할을 하기에 빼놓을 수 없는 파일이다.

web.xml 파일을 더블클릭하면 다음과 같이 내용이 나온다.

화면 캡처 2024-08-21 085605.png

위와 같은 xml 형태를 보려면 아래의 [Source]를 클릭해야 볼 수 있다.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>MyFirstWebApp</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.jsp</welcome-file>
    <welcome-file>default.htm</welcome-file>
  </welcome-file-list>
  <servlet>
    <description></description>
    <display-name>processLogin</display-name>
    <servlet-name>processLogin</servlet-name>
    <servlet-class>com.cola.web.user.LoginServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>processLogin</servlet-name>
    <url-pattern>/processLogin</url-pattern>
  </servlet-mapping>
</web-app>

web.xml

위 파일 내용을 보면, <servlet> 태그 내부에는 앞서 서블릿 생성 시 붙였던 이름인 “processLogin”이 <servlet-name> 태그에 적혀있고, 앞서 생성한 서블릿 클래스의 이름인 LoginServlet이 패키지 경로와 함께 <servlet-class> 태그에 기록된 것을 확인할 수 있다. 그리고 그 아래에 <servlet-mapping> 태그 내부에도 서블릿 이름인 “processLogin”가 보이는데, <url-pattern>을 보면 알겠지만, 이후에 서블릿을 통해 HTTP 요청을 처리하고자 할 때 url 주소 끝에 /processLogin을 덧붙여서 HTTP 요청을 하면, 이 경로와 매핑된 LoginServlet 객체가 생성되어 이를 처리하게 된다.

만약 서블릿을 삭제하고 다시 새로운 서블릿을 생성하고자 한다면, 그 전에 web.xml에 등록된 기존 서블릿에 관한 설정들도 모두 지워야 한다. 그래야 동일한 이름의 서블릿을 재생성할 수 있다. 확인 결과, web.xml 파일 내에 해당 서블릿 정보가 담겨 있는 <servlet><servlet-mapping> 이 둘 모두 지워야 함을 확인했다.

또한 web.xml 파일이 수정되면 서버를 껐다 켜야 수정 사항이 반영된다.

서블릿으로 HTTP 요청 처리해보기

이제 생성된 서블릿을 통해 클라이언트에서 들어오는 HTTP 요청을 처리해보자.

HTML의 form 태그를 통해 클라이언트가 HTTP 요청을 할 때 요청 방식은 GET과 POST 중에서만 지정할 수 있다. 또한 서블릿은 이 요청 방식을 처리할 수 있어야 한다.

먼저 POST 요청 방식을 살펴보겠다. 해당 요청 방식은 HTML의 form 태그의 method 속성으로 “POST”라고 입력해야 클라이언트가 서블릿에 POST 요청을 할 수 있게 된다. 따라서 form 태그의 method 속성을 “POST”로 지정한 상태에서 웹 페이지로 가보자.

9.PNG

해당 페이지에서 아이디 및 비밀번호를 아무렇게 입력한 뒤 “로그인” 버튼을 눌러보자. 그러면 웹 페이지는 다음과 같은 상태가 되고…

10.PNG

이클립스의 “console” 창을 보면 다음의 메세지가 뜬 것을 볼 수 있다.

// 생략
=== 로그인을 위한 서블릿 인스턴스가 생성되었습니다. ===
=== POST 요청을 서블릿에서 처리하였습니다. ===

11.PNG

이를 통해, POST 방식의 요청을 하면 LoginServlet 클래스로부터 인스턴스가 생성되며, 이 서블릿 객체의 doPost() 메서드에서 해당 요청을 처리한다는 것을 알 수 있다.

또한, 웹 페이지를 자세히 보면 url 경로 맨 뒤에 “/processLogin”이 붙은 것을 볼 수 있다. 이는 앞서 web.xml의 <url-pattern> 태그에서 봤던 데이터와 똑같음을 알 수 있다. 즉, 해당 url 경로가 LoginServlet 서블릿 클래스와 연결되어 해당 경로로 HTTP 요청을 보내면 해당 서블릿 객체가 생성되어 요청을 처리하는 구조인 것을 유추할 수 있다.

GET 방식으로 서블릿에 HTTP 요청을 보내는 데에는 두 가지 방법을 떠올릴 수 있겠다. 하나는 앞서 언급한 form 태그의 method 속성값을 GET으로 설정하는 것이고, 또 하나는 앞서 보았던 http://localhost:8080/MyFirstWebApp/processLogin 경로를 브라우저 url 입력란에 직접 입력하여 요청하는 것이다. 새 탭에서 위 경로를 입력해보았다. 그랬더니 이클립스의 “console”창에 새로운 메시지가 떴다.

=== GET 요청을 서블릿에서 처리하였습니다. ===

즉, doGet() 메서드를 통해 GET 방식의 HTTP 요청이 처리되었음을 유추할 수 있다.

요청 실패 시 HTTP 상태 코드 살펴보기

위와 같이 클라이언트로부터 전송된 요청을 서블릿이 처리하는 과정에서, 만약 요청에 실패하면 어떻게 되는지 간단히 살펴보자.

LoginServlet 클래스에서 doPost() 메서드 코드 전체를 주석 처리한 후, 앞선 페이지에서 “로그인” 버튼을 눌러보자(form 태그의 method 속성값은 “POST”인 상태여야 한다).

12.PNG

그러면 위와 같이 405 상태 코드와 함께 HTTP 요청 처리에 실패하였다는 결과가 나온다. 이는 POST 방식의 HTTP 요청을 처리할 메서드가 정의되지 않았기에 나타나는 결과로, 이 경우에 “Method Not Allowed”란 상태 메시지와 함께 405 상태 코드가 뜨는 것이다.

이를 통해, 클라이언트로부터 전송되는 HTTP 요청 방식을 처리할 수 있도록 해당 메서드를 정의해야한다는 것을 알 수 있다.

이번에는 doPost, doGet 메서드 모두 존재하나, 해당 메서드 내부에서 코드를 잘못 짜서 에러가 나는 상황이라면 그 결과는 어떻게 될까? 이번에는 doPost 메서드 내부에 System.out.println(0/0) 이라는 코드를 삽입하여 일부러 0으로 나누는 연산을 하여 에러를 일으켜보자.

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	System.out.println(0 / 0);  // 에러 발생 코드
	System.out.println("=== POST 요청을 서블릿에서 처리하였습니다. ===");  // 변경된 코드.
}

웹 페이지에서 다시 로그인 버튼을 누르면…

13.PNG

위와 같이 상태 코드 500의 요청 실패 화면이 뜬다. 에러 메시지는 이클립스의 “console”창에도 같이 뜬다. 이 경우, 예외가 발생하는 코드에서 예외를 없애야 정상적으로 HTTP 요청을 처리할 수 있게 된다.


References

[1] 채규태, “채쌤의 Servlet&JSP 프로그래밍 핵심”, (쌤즈, 2023)

This content is licensed under CC BY-NC 4.0

댓글남기기