주니어 기초 코딩공부/JSP 기초

[JSP] 서블릿 기초 개념 설명

jju_developer 2023. 1. 27. 21:14
728x90

안녕하세요 오늘은 서블릿 기초에 대해 알아보겠습니다.

 

기본적으로 서블릿이란?

자바로 만들어진 프로그램을 서버에서 실행하기 위해 만들어진 것입니다.

특히 웹 서비스 개발에 특화되어 있으며 데이터베이스 연동, 외부 서비스 연동을 통해 정적인 웹에 

동적인 정보 제공을 가능하게 합니다.

 

▼JSP 설명

 

[JSP] 자바 서버 페이지(JavaServer Pages ) 란 무엇인가? 기초 설명

안녕하세요, 오늘도 어김없이 코딩 공부하러 온 jju_developer입니다. 오늘은 정말 중요한 자바 서버 페이지에 대한 기초 설명에 대한 정리본을 공유드립니다. JSP의 사용 추세는 점점 줄어들고 있지

jju240.tistory.com

 

서블릿 기초

 서블릿은 JSP 표준이 나오기 전에 만들어진 표준으로

자바로 웹 애플리케이션을 개발할 수 있도록 하기 위해 만들어졌습니다.

 

 

[일반적인 서블릿의 개발 과정]


1. 서블릿 규약에 따라 자바 코드를 작성한다.
2. 자바 코드를 컴파일해서 클래스 파일을 생성한다.
3. 클래스 파일을 /WEB-INF/classes 폴더에 패키지에 알맞게 위치시킨다.
4. web.xml 파일에 서블릿 클래스를 설정한다.
5. 톰캣 등의 컨테이너를 실행한다.
6. 웹 브라우저에서 확인한다.

 

[web.xml로 매핑하기]

 

 서블릿 클래스를 생성했다면 그다음으로 할 작업은 WEB-INF 폴더의 web.xml 파일에 서블릿 클래스를 등록해야 합니다.

HttpServlet을 상속 받은 서블랫 클래스

 

HttpServlet을 상속받은 서블랫 클래스입니다.

부모의 doGet 메서드를 재정의 하였습니다.

PrintWriter out = response.getWriter();

java.io.PrintWriter 로 out 객체를 만들어 출력하도록 하였습니다.

 

response 객체에 담아서 웹에 전달하게 됩니다.

web.xml의 정의
브라우저에 전송

이렇게 NowServlet.jsp를 실행했을 때 주소창에 /now가 들어오면 실행하도록 되어있습니다.

 

 

[애노테이션으로 매핑하기]

 

 서블릿 3.0 버전부터는 @WebServlet 애노테이션을 사용하면 web.xml 파일에 따로 등록하지 않아도 서블릿으로 등록됩니다.

애노테이션
http://localhost:8080/chap17/hello?name=jju

 

 

 

 

HTTP 각 방식별 구현 메서드


GET 방식은 doGet() 메서드를 이용해서 처리하고, POST 방식의 경우 doPost() 메서드를 이용해서 처리하도록 정의하고 있습니다.

 

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
... // GET 방식에 대한 처리
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
... // Post 방식에 대한 처리
}

 

 

서블릿 로딩과 초기화

 최초 요청이 발생하면 서블릿 객체를 생성합니다.

 

<DBCPInit2.java>

package jdbc;

import java.sql.DriverManager;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

import org.apache.commons.dbcp2.ConnectionFactory;
import org.apache.commons.dbcp2.DriverManagerConnectionFactory;
import org.apache.commons.dbcp2.PoolableConnection;
import org.apache.commons.dbcp2.PoolableConnectionFactory;
import org.apache.commons.dbcp2.PoolingDriver;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

public class DBCPInit2 extends HttpServlet {

	@Override
	public void init() throws ServletException {
		loadJDBCDriver();
		initConnectionPool();
	}


	private void loadJDBCDriver() {
		String driverClass = getInitParameter("jdbcdriver");
		try {
			Class.forName(driverClass);
		} catch (ClassNotFoundException ex) {
			throw new RuntimeException("fail to load JDBC Driver", ex);
		}
	}

	private void initConnectionPool() {
		try {
			String jdbcUrl = getInitParameter("jdbcUrl");
			String username = getInitParameter("dbUser");
			String pw = getInitParameter("dbPass");

			ConnectionFactory connFactory = 
					new DriverManagerConnectionFactory(jdbcUrl, username, pw);

			PoolableConnectionFactory poolableConnFactory = 
					new PoolableConnectionFactory(connFactory, null);
			poolableConnFactory.setValidationQuery("select 1");

			GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
			poolConfig.setTimeBetweenEvictionRunsMillis(1000L * 60L * 5L);
			poolConfig.setTestWhileIdle(true);
			poolConfig.setMinIdle(4);
			poolConfig.setMaxTotal(50);

			GenericObjectPool<PoolableConnection> connectionPool = 
					new GenericObjectPool<>(poolableConnFactory, poolConfig);
			poolableConnFactory.setPool(connectionPool);
			
			Class.forName("org.apache.commons.dbcp2.PoolingDriver");
			PoolingDriver driver = 
					(PoolingDriver) DriverManager.getDriver("jdbc:apache:commons:dbcp:");
			String poolName = getInitParameter("poolName");
			driver.registerPool(poolName, connectionPool);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}	
}

 

<web.xml>

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
		http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	version="3.1">

	<servlet>
		<servlet-name>now</servlet-name>
		<servlet-class>example.NowServlet</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>now</servlet-name>
		<url-pattern>/now</url-pattern>
	</servlet-mapping>

	<servlet>
		<servlet-name>DBCPInit2</servlet-name>
		<servlet-class>jdbc.DBCPInit2</servlet-class>
		<init-param>
			<param-name>jdbcdriver</param-name>
			<param-value>com.mysql.jdbc.Driver</param-value>
		</init-param>
		<init-param>
			<param-name>jdbcUrl</param-name>
			<param-value>
	            jdbc:mysql://localhost:3306/chap14?characterEncoding=utf8
	        </param-value>
		</init-param>
		<init-param>
			<param-name>dbUser</param-name>
			<param-value>jspexam</param-value>
		</init-param>
		<init-param>
			<param-name>dbPass</param-name>
			<param-value>jsppw</param-value>
		</init-param>
		<init-param>
			<param-name>poolName</param-name>
			<param-value>chap14</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

</web-app>

 

여기에 param으로 정의해 놓은 것을 <DBCPInit2.java> 에서 받아서 활용합니다.

 

배포될 때 web.xml이 텍스트 파일로 되어있어서 코드 변경에 용의 합니다.

 

즉, 유지보수가 쉬워지게 됩니다.

그런 되도록 설계한 코드가 바로 DBCPInit2 클래스를 만들었기 때문이죠!

 

 

<viewMemberUsingPool.jsp>

<%@ page contentType = "text/html; charset=utf-8" %>
<%@ page import = "java.sql.DriverManager" %>
<%@ page import = "java.sql.Connection" %>
<%@ page import = "java.sql.Statement" %>
<%@ page import = "java.sql.ResultSet" %>
<%@ page import = "java.sql.SQLException" %>
<html>
<head><title>회원 목록</title></head>
<body>

MEMBMER 테이블의 내용
<table width="100%" border="1">
<tr>
	<td>이름</td><td>아이디</td><td>이메일</td>
</tr>
<%
	
	Connection conn = null;
	Statement stmt = null;
	ResultSet rs = null;
	
	try {
		String jdbcDriver = "jdbc:apache:commons:dbcp:chap14";
		String query = "select * from MEMBER order by MEMBERID";
		conn = DriverManager.getConnection(jdbcDriver);
		stmt = conn.createStatement();
		rs = stmt.executeQuery(query);
		while(rs.next()) {
%>
<tr>
	<td><%= rs.getString("NAME") %></td>
	<td><%= rs.getString("MEMBERID") %></td>
	<td><%= rs.getString("EMAIL") %></td>
</tr>
<%
		}
	} finally {
		if (rs != null) try { rs.close(); } catch(SQLException ex) {}
		if (stmt != null) try { stmt.close(); } catch(SQLException ex) {}
		if (conn != null) try { conn.close(); } catch(SQLException ex) {}
	}
%>
</table>

</body>
</html>

conn = DriverManager.getConnection(jdbcDriver);

getConnection으로 하나씩 가져와 conn 객체에 담습니다.

이것을 실행하면 지난 시간에 배운 mysql과 연동된 테이블이 출력되는 것을 볼 수 있습니다.

 

 

서블릿 생명주기

서블릿 클래스는 기본적으로 doGet(), doPost()와 같이 HTTP 요청 메서드에 따라 필요한 메서드를 오버라이딩해 구현하는 구조이며 서블릿 컨테이너에 의해 객체의 생성과 소멸등이 관리되므로 필요에 따라 특정 라이프사이클 이벤트에 동작하는 메서드를 구현하기도 합니다.

서블릿의 생성과 소멸은 다음과 같은 과정을 거칩니다.

  1. 사용자 URL요청에 따른 서블릿 실행
  2. 이때 서블릿 인스턴스가 생성되지 않았다면 인스턴스 생성(new -> 생성자 호출) 후 init() 메서드 호출
  3. 이미 객체가 생성되어 있는 경우라면 각 요청별로 WAS에서 스레드를 생성해 서블릿의 service() 메서드 호출
  4. 사용자 요청에 따라 doGet(), doPost() 등 메서드 호출
  5. 서블릿 컨테이너의 종료를 포함해 서블릿 변경등 기존 서블릿을 정리해야 할 때 destroy() 메서드 호출

 

[서블릿 초기화 : init() 메서드]

클라이언트에 요청이 들어오면 컨테이너는 해당 서블릿이 메모리에 있는지 확인합니다.

해당 서블릿이 메모리에 없을 경우에는 서블릿을 메모리에 다시 적재해야 하는데, 이때 서블릿의 init() 메서드가 호출되며 각종 초기화 작업을 수행합니다.

즉 init() 메서드는 처음 한 번만 실행되므로 해당 서블릿에 각각의 스레드에서 공통적으로 사용하기 위해 필요한 작업이 있다면 init() 메서드를 오버라이딩해서 구현합니다.

 

만일 실행 중에 서블릿이 변경될 경우에는 기존 서블릿은 종료(destroy) 되고,

새로운 내용을 다시 적재하려고 init() 메서드를 호출합니다.

 

[요청/응답 : service() 메서드]

init() 메서드는 최초에 한 번만 수행되고 이후 요청은 스레드로 실행되며,

각각 service() 메서드를 통해 doGet( )이나 doPost( )로 분기됩니다.

이때 파라미터로 HttpServlet Request와 HttpServletResponse 클래스 타입인 request와 response 객체가 제공되는데,

사용자 요청 처리는 request로, 응답 처리는 response 객체로 처리합니다.

 

 

[서블릿 종료 : destroy() 메서드]

컨테이너로부터 서블릿 종료 요청이 있을 때 destroy() 메서드를 호출합니다.

init() 메서드와 마찬가지로 한 번만 실행되며, 서블릿이 종료되면서 정리해야 할 작업이 있을 때는 destroy() 메서드를 오버라이딩해서 구현합니다.

(대부분의 경우 컨테이너는 실행된 상태에서 특정 서블릿을 로드/언로드 하는 기능이 있습니다)

 

 

올바른 서블릿 활용

일반적으로 서블릿은 앞으로 배울 MVC 패턴에서 컨트롤러의 역할 구현을 위해 사용합니다.

클라이언트로부터 전달되는 데이터 (form 입력 데이터, url 파라미터등)를 처리하기 위한 다양한 방법과

효과적인 데이터 처리를 위한 객체 맵핑 url redirection이나 forwarding(포워딩) 개념에 대해서도 이해가 필요하고,

자유롭게 구현할 수 있어야 합니다.

 

[올바른 서블릿 활용을 위해 필요한 항목]

  • MVC 패턴 기반의 웹 애플리케이션 설계
  • 뷰 템플릿 엔진의 사용(JSP, Freemarker 등)
  • form 처리를 위해 Apache Commons BeanUtils 라이브러리 사용
  • Rest API 구현의 경우 JAX-RS 사용
  • 리스너와 필터 서블릿의 활용
  • request, response, session, ServletContext 객체의 이해와 활용

 

 

 

 

 

그럼 지금까지 서블릿에 대한 기초 설명을 마치겠습니다.

 

오늘도 수고하셨습니다.

 

 

 

참고자료 : https://dinfree.com/lecture/backend/javaweb_1.1.html

728x90