본문 바로가기
Java Web Programming/3. Servlet

[Servlet] 서블릿과 JDBC - Database 연동 (DB 연동) / annotation 기반 설정

by 파프리카_ 2020. 8. 25.
728x90
반응형

* Dynamic Project 2.5 version과 3.1 version의 차이!

Annotation 기반 서블릿 설정 제공 여부의 차이! (Servlet 3.0이상 버전에서 제공)

 

[ annotation & Web Container ] 

> annotation

Servlet class의 상단부에 

@WebServlet( url-pattern ) 을 명시하면,

기존 web.xml의 url-pattern 설정과 동일한 효과를 가진다.

 

어노테이션 기반 설정개발의 생산성을 위해 지원한다.

→ 소스 코드 상의 기술(tech)이다.

 

전역적인 설정 (ex-ServletContext의 context-param/session config 등)은 web.xml에서 하고, → 유지보수성

개별 서블릿에 관련된 설정은 어노테이션 설정을 권장한다. → 생산성

 ⇒ web.xml의 정보를 읽고, 각 서블릿의 개별적인 @어노테이션 정보를 읽어서 두가지 모두를 메모리에 적재한다.

 

> Web Container

WAS (Web Application Server) : Web Server + Web Container

 

Web Contatiner 

1) Serlvet, JSP 실행 환경 제공 ⇒ Servlet, JSP 라이브러리 제공

2) Servlet LifeCycle을 관리

3) JSP를 Servlet으로 생성

4) ServletContext(공유자원)와 ServletConfig를 생성

 


* 아래 예제 실행 단계

step2.FindMemberCountServlet(Serlvet class)을 최초로 실행할 때, 웹 컨테이너 동작은 다음과 같다.

①  Web Container는 자신의 설정 정보인 web.xml과 @WebServlet annotation 정보를 로딩

②  ServletContext를 생성 ( context-param 정보로 함께 할당 )

③  SerlvetContextListener를 implements한 class(TestListner)가 있으면 contextInitialized()를 실행한다.

    → 이 때, 시스템에서 한번만 수행하면 되는 DB Driver Loading을 실행시킨다.

④  FindMemberCountServlet의 객체 생성 init(SerlvetConfig) service() 계열의 메서드(doGet() or doPost()) 실행

 


[ '회원 목록 조회' Servlet 만들기 ] 

sql

--1. web_member TABLE 생성
CREATE TABLE web_member(
    id        varchar2(100)  primary key,
    password  varchar2(100)  not null,
    name      varchar2(100)  not null,
    address   varchar2(100)  not null
);

--2. DB 추가
INSERT INTO web_member(id, password, name, address) 
VALUES('java', '1234', '아이유', '강릉');
INSERT INTO web_member(id, password, name, address) 
VALUES('servlet', 'abcd', '조승우', '원주');

[ table ] 


html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- request method를 명시하지 않으면, 기본이 get방식 -->
<form action="FindMemberCount">
	<input type="submit" value="조회">
</form>
</body>
</html>

form의 action에서 찾아가는 url이 FindMemberCount이다.

이는 servlet class 중 FindMemberCountServlet에 annotation으로 표시되어있다.

@WebServlet("/FindMemberCount")

/ 뒤의 url-pattern이 명시되게 되는데, html의 action과 servlet의 annotation이 일치한다면,

- annotation 기반 서블릿 제공의 경우, 해당 servlet으로 가는 것이다.


XML

계속 공유해서 사용하는 자원 (dbDriver, dbUrl 등) 을 context-param에 저장해준다!

- dbDriver => Driver Loading을 위해 필요한 변수 => ServletContextListener에서 사용

- dbUrl, userName, userPass => Connection을 위해 필요한 변수 => Serlvet의 Init()에서 사용

 

/web.xml

  <!-- JDBC 정보를 context-param에 저장 -->
  <context-param>
  <param-name>dbDriver</param-name>
  <param-value>oracle.jdbc.OracleDriver</param-value>
  </context-param>

  <context-param>
  <param-name>dbUrl</param-name>
  <param-value>jdbc:oracle:thin:@127.0.0.1:1521:xe</param-value>
  </context-param>

  <context-param>
  <param-name>userName</param-name>
  <param-value>scott</param-value>
  </context-param>

  <context-param>
  <param-name>userPass</param-name>
  <param-value>tiger</param-value>
  </context-param>

servlet Listener class

JDBC 단계에서 DB Driver Loading은 한번만 실행되면 되므로,

ServletContextListener의 contextInitialized()에서 하도록 한다. 

(* servlet class의 init() 단계보다 먼저 실행된다)

 

/TestListener.java

package listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

/**
 * JDBC 연동을 위해 Driver Loading을 실행하기 위한 Listener class
 */
@WebListener
public class TestListener implements ServletContextListener {

	
    public void contextDestroyed(ServletContextEvent event)  { 
         System.out.println("======contextDestroyed========");
    }

	/**
     * contextInitialized : 웹어플리케이션 시작 시 한번 실행
     */
    public void contextInitialized(ServletContextEvent event)  { 
    	//Driver Loading
    	String dbDriver = event.getServletContext().getInitParameter("dbDriver");
    	try {
			Class.forName(dbDriver);
			System.out.println("contextIntialized DB Driver Loading");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
    	
    }
	
}

servlet class

web.xml의 context-param에 있는 객체들을 ( 그 중 Connection에 필요한 객체들 )

servlet의 init() 단계에서 getServletContext.getIntitParmeter(name)을 통해 가져와서 사용한다.

⇒  Connection 단계는 개별 작업이기 때문에, Listener단계가 아닌 각 Servlet생성 후 그 안의 init() 단계에서 각 Connection에 맞는 정보를 가져오도록 한다.

 

* 생성자(생성 단계)가 아닌 init (초기화) 단계에서 Connection 변수 정보를 할당하는 이유

SerlvetContext를 사용하기 위해서는 ServletConfig의 주소값이 필요하다. (즉, ServletConfig 생성 이후에 ServletContext를 사용 가능하다.) Servlet의 생성자 (생성 단계) 에서 ServletConfig가 생성되기 때문에, 생성자를 통해 ServletConfig가 생성된 후에, init()에서 ServletContext를 이용하여 web.xml의 context-param 변수들을 가져와 Connection 정보를 가져오는 것이다.

 

/FindMemberCountServlet.java

package step2;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class FindMemberCountServlet
 */
//html의 form에서 action의 url-pattern과 
//annotation의 주소가 같은지 확인 ! (매핑이 잘 되는가 확인)
@WebServlet("/FindMemberCount")
public class FindMemberCountServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	//JDBC 정보 변수
	//private String dbDriver;
	private String dbUrl;
	private String userName;
	private String userPass;
	
	//init() method
	//web.xml에 있는 context-param 정보 가져와서
	//각 변수에 할당하기
	@Override
	public void init() throws ServletException {
		//dbDriver = getServletContext().getInitParameter("dbDriver");
		dbUrl = getServletContext().getInitParameter("dbUrl");
		userName = getServletContext().getInitParameter("userName");
		userPass = getServletContext().getInitParameter("userPass");
	}
	
	// Service : doGet method
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setContentType("text/html; charset=utf-8");
		// PrintWriter : process stream
		PrintWriter out = response.getWriter();

		// browser에 출력
		out.println("<html><body bgcolor=yellow>");

		/* JDBC 연동 */
		
		// SQL 실행객체
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			// 1. 사용할 JDBC 드라이버를 등록 
			// => ServletContextListener에서 로딩한다
			//Class.forName(dbDriver);
			//System.out.println("DB Driver Loading");

			// 2. 드라이버를 사용하여 Oracle SQL 서버와 연결
			con = DriverManager.getConnection(dbUrl, userName, userPass);
			System.out.println("DB Connection");

			// 3. SQL 작성 : 총 회원 수 출력
			String sql = "SELECT count(*) FROM web_member";

			// 4. 커넥션 객체로부터 SQL를 던질 객체를 준비
			pstmt = con.prepareStatement(sql);

			// 5. SQL를 던지는 객체를 사용하여 서버에 질의 : ResultSet
			rs = pstmt.executeQuery();
			
			// 6. 서버에서 가져온 데이터를 사용하여 HTML 만들어서 웹 브라우저로 출력
			rs.next(); // 커서를 아래로 이동시킨다
			out.println("총 회원수 : "+ rs.getString(1));
			
			// 7. SQL 실행 객체 닫기
			rs.close();
			pstmt.close();
			con.close();
			
		} catch (SQLException e) {
			e.printStackTrace();
		} 
		
		out.println("</body></html>");

		// flush
		out.close();
	}

}

 

[ 브라우저 결과 ]

 


-- 추가 예제 --

 

요구사항

step3. FindMemberByIdServlet  이용


- 아이디에 해당하는 회원이 있으면
아이디 : java
이름: 아이유
주소 : 판교

- 없으면
( 아이디 )에 해당하는 회원정보가 없습니다.

 

html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<form method="GET" action="FindMemberByIdServlet">
	아이디<input type="text" name="memberId" required="required">
	<input type="submit" value="검색">
</form>

</body>
</html>

 

Servlet Class

/FindMemberByIdServlet.java

package step3;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@WebServlet("/FindMemberByIdServlet")
public class FindMemberByIdServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
    //JDBC 정보 변수 - Connection용
	private String dbUrl;
	private String userName;
	private String userPass;
	
	//Driver Loading은 Listner에서 시행되고 있음
	
	//init()단계에서 Connection에 필요한 변수 정보 할당
	@Override
	public void init() throws ServletException {
		dbUrl = getServletContext().getInitParameter("dbUrl");
		userName = getServletContext().getInitParameter("userName");
		userPass = getServletContext().getInitParameter("userPass");

	}
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html; charset=utf-8");
		PrintWriter out = response.getWriter();	
		
		/* JDBC 연동 */
		
		// SQL 실행 객체
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			// Connection
			con = DriverManager.getConnection(dbUrl, userName, userPass);
			
			// SQL 문 정의
			String sql = "SELECT id, name, address FROM web_member"
					+ " WHERE id = ?";
			
			// PreparedStatement
			pstmt = con.prepareStatement(sql);
			
			// setString을 통해 SQL문 완성
			// browser로부터 입력받은 memberId를 id에 할당
			String id = request.getParameter("memberId");
			//setString에 id값을 넣음
			pstmt.setString(1, id);		
			
			// 실행하여 ResultSet에 할당
			rs = pstmt.executeQuery();
			
			// browser 화면에 표시
			if (rs.next()) {
				out.println("아이디: " + rs.getString("id")+"<br>");
				out.println("이름: " + rs.getString("name")+"<br>");
				out.println("주소: " + rs.getString("address"));
			} else {
				out.println(id + " 해당 아이디의 회원정보가 없습니다.");
			}
			
			// close
			rs.close();
			pstmt.close();
			con.close();
		} catch (SQLException e) {
			e.printStackTrace();
		} 
		
		
		// flush
		out.close();
	}

}

[ 브라우저 결과 ]

- 아이디가 있을 경우

- 아이디가 없을 경우

728x90
반응형