https://www.baeldung.com/intro-to-servlets
Introduction to Java Servlets | Baeldung의 Introduction to Java Servlets을 번역한 것입니다.
모든 저작권은 Baeldung에 있습니다. All copyrights are in Baeldung.
이 문서에서 우리는 Java에서 웹 개발의 핵심 측면을 살펴볼 것이다 - Servlets.
간단히 말해, Servlet 서블릿
은 요청을 처리하고, 작업하여 응답하여 돌려주는 클래스이다.
예를 들어 우리는 Servlet을 사용하여 HTML form을 통해 사용자로부터 입력을 받고, 데이터베이스에서 레코드를 쿼리하고, 페이지를 동적으로 생성할 수 있다.
Servlet
은 Servlet Container 서블릿 컨테이너
라는 또 다른 Java 애플리케이션의 제어 하에 있다.
웹 서버에서 실행 중인 애플리케이션이 요청을 수신하면 서버는 요청을 서블릿 컨테이너
로 전달한다.
서블릿 컨테이너
는 요청을 타겟 서블릿으로 전달한다.
우리의 웹 애플리케이션에 서블릿 지원을 추가하기 위해서, javax.servlet-api 의존성이 요구된다.
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
물론 앱을 배포할 Servlet 컨테이너도 구성해야 한다. : https://www.baeldung.com/tomcat-deploy-war
서블릿의 생명 주기를 정의하는 몇가지 메소드를 살펴보자.
init 메소드는 오직 한번만 호출되도록 설계되었다. 서블릿 인스턴스가 존재하지 않으면 web container는 다음과 같이 동작한다.
- Servlet 클래스를 로드한다.
- Servlet 인스턴스를 생성한다.
- init 메소드를 호출하여 초기화한다.
서블릿이 요청을 수신하기 위해선 init 메소드가 성공적으로 완료되어야 한다.
init 메서드가 ServletException을 발생시키거나 웹 서버가 정의한 시간 내에 반환되지 않으면 Servlet 컨테이너는 서블릿을 서비스에 배치할 수 없다.
public void init() throws ServletException {
// Initialization code like set up database etc....
}
이 메소드는 서블릿이 init() 메소드를 성공적으로 완료했을 때만 호출될 수 있다.
Container는 클라이언트의 요청을 처리하기 위해 service() 메소드를 호출하고 HTTP request type(GET, POST, PUT, DELETE 등) 을 해석하며, doGet, doPost, doPut, doDelete 메서드를 호출한다.
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
// ...
}
서블릿 컨테이너가 서블릿을 서비스에서 제외하기 위해 호출한다.
이 메서드는 서블릿의 서비스 메서드 내의 모든 스레드가 종료되거나 timeout된 후에만 호출된다.
컨테이너가 이 메서드를 호출한 후에는 서블릿에서 sevice() 메서드를 다시 호출하지 않는다.
public void destroy() {
//
}
먼저 컨텍스트 루트를 javax-servlets-1.0-SNAPSHOT에서 /로 변경한다.
<Context path="/" docBase="javax-servlets-1.0-SNAPSHOT"></Context>
$CATALINA_HOME\conf\server.xml.의 Host 태그 아래에 있다.
이제 form을 사용하여 정보를 처리하는 전체 예시를 시작해보자.
시작에 앞서, form을 통해 POST된 정보를 수집하고 RequestDispatcher를 사용하여 결과를 반환하는 /calulateServlet을 사용하여 서블릿을 정의해보자.
@WebServlet(name = "FormServlet", urlPatterns = "/calculateServlet")
public class FormServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
String height = request.getParameter("height");
String weight = request.getParameter("weight");
try {
double bmi = calculateBMI(
Double.parseDouble(weight),
Double.parseDouble(height));
request.setAttribute("bmi", bmi);
response.setHeader("Test", "Success");
response.setHeader("BMI", String.valueOf(bmi));
request.getRequestDispatcher("/WEB-INF/jsp/index.jsp").forward(request, response);
} catch (Exception e) {
request.getRequestDispatcher("/WEB-INF/jsp/index.jsp").forward(request, response);
}
}
private Double calculateBMI(Double weight, Double height) {
return weight / (height * height);
}
}
위에서 볼 수 있듯이, @WebServlet
어노테이션이 달린 클래스는 javax.servlet.http.HttpServlet 클래스를 확장해야 한다.
@WebServlet
어노테이션은 Java EE 6 이후에서 사용할 수 있다.
@WebServlet
주석은 배포 시에 컨테이너에 의해 처리되며 지정된 URL 패턴에서 해당 서블릿을 사용할 수 있다.
어노테이션을 사용하여 URL 패턴을 정의하면 서블릿 매핑에 web.xml이라는 XML 배포 descriptor를 사용하지 않아도 된다.
어노테이션을 사용하지 않고 서블릿을 매핑하려면 기존 web.xml을 사용하면 된다.
<web-app ...>
<servlet>
<servlet-name>FormServlet</servlet-name>
<servlet-class>com.root.FormServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FormServlet</servlet-name>
<url-pattern>/calculateServlet</url-pattern>
</servlet-mapping>
</web-app>
그 다음, 기본적인 HTML form을 만들어보자.
<form name="bmiForm" action="calculateServlet" method="POST">
<table>
<tr>
<td>Your Weight (kg) :</td>
<td><input type="text" name="weight"/></td>
</tr>
<tr>
<td>Your Height (m) :</td>
<td><input type="text" name="height"/></td>
</tr>
<th><input type="submit" value="Submit" name="find"/></th>
<th><input type="reset" value="Reset" name="reset" /></th>
</table>
<h2>${bmi}</h2>
</form>
마지막으로 모든 것이 예상대로 작동하는지 확인하기 위해 간단한 테스트를 작성해보자.
public class FormServletLiveTest {
@Test
public void whenPostRequestUsingHttpClient_thenCorrect()
throws Exception {
HttpClient client = new DefaultHttpClient();
HttpPost method = new HttpPost(
"http://localhost:8080/calculateServlet");
List<BasicNameValuePair> nvps = new ArrayList<>();
nvps.add(new BasicNameValuePair("height", String.valueOf(2)));
nvps.add(new BasicNameValuePair("weight", String.valueOf(80)));
method.setEntity(new UrlEncodedFormEntity(nvps));
HttpResponse httpResponse = client.execute(method);
assertEquals("Success", httpResponse
.getHeaders("Test")[0].getValue());
assertEquals("20.0", httpResponse
.getHeaders("BMI")[0].getValue());
}
}
Servlet 기술이 HTTP 프로토콜에 한정되지 않는다는 것을 이해하는 것이 중요하다.
실제로는(거의 항상 그렇지만) Servlet은 generic 인터페이스이고 HttpServlet은 그 인터페이스의 화장으로 doGet, doPost 등과 같은 HTTP 특정 지원을 추가한다.
마지막으로, Servlet 기술은 JSP(자바 서버 페이지), 스프링 MVC등과 같은 수많은 다른 웹 기술들의 메인 드라이버이기도 하다.
이번 간단한 문서를 통해 우리는 Java 웹 애플리케이션에서 서블릿의 기초를 알아보았다.