서블릿의 비즈니스 로직 처리 방법

  • 서블릿 비즈니스 처리 작업 ★ 서블릿의 핵심

    • 서블릿이 클라이언트로부터 요청을 받으면 그 요청에 대해 작업을 수행하는 것을 의미
  • 웹 프로그램에서 대부분의 비즈니스 처리 작업

    • 대부분 데이터베이스 연동 관련 작업

    • 그 외 다른 서버와 연동해서 데이터를 얻는 작업도 수행

  • 서블릿의 비즈니스 작업 예

    • 웹 사이트 회원 등록 요청 처리

    • 웹 사이트 로그인 요청 처리

    • 쇼핑몰 상품 주문 처리

  • 서블릿의 비즈니스 처리 과정

    • 클라이언트로부터 요청

    • 데이터베이스 연동과 같은 비즈니스 로직 처리

    • 처리 결과를 클라이언트에게 리턴



서블릿에 데이터베이스 연동하기

  • 서블릿은 SQL문을 사용해 데이터베이스에 접근하여 작업

    • 이 과정에서 DAO와 VO 클래스가 사용됨

데이터베이스의 SQL문을 어느정도 알아놔야 진행 가능

DAO나 VO 클래스도 알아두기


서블릿으로 회원 정보 테이블의 회원 정보 조회

  • 조회 단계

    • 웹 브라우저가 서블릿에게 회원 정보 요청

    • MemberServlet은 요청을 받은 후 memberDAO 객체를 생성(create)하여 listMembers() 메서드를 호출

    • listMembers()에서 다시 connDB() 메서드를 호출하여 데이터베이스와 연결 후 SQL문을 실행해 회원 정보를 조회

    • 조회된 회원 정보를 MemberVO 속성에 설정 후 다시 ArrayList에 저장

    • ArrayList를 다시 메서드를 호출한 MemberServlet으로 반환한 후 ArrayList의 MemberVO를 차례데로 가져와 회원 정보를 HTML 태그의 문자열로 만듦

    • 만들어진 HTML 태그를 웹 브라우저로 전송해서 회원 정보를 출력

  • 회원 정보를 저장하는 t_member 테이블의 구성

NO 속성명 컬럼명 자료형 크기 유일키여부 NULL여부 기본값
1 ID id varchar2 10 Y N 기본키  
2 비밀번호 pwd varchar2 10   N    
3 이름 name varchar2 50        
4 이메일 email varchar2 50   N    
5 가입일자 joinDate date     N    
  • DB 생성하기

    • SQL Developer 실행 (회원테이블과 정보를 입력하려고) 및 접속

    • 다음 내역 ▶

--회원 테이블 생성
create table t_member(
  id varchar2(10) primary key,
  pwd varchar2(10),
  name varchar2(50),
  email varchar2(50),
  joinDate date default sysdate --명시적으로 추가하지 않을 경우 현재 시각 입력
);


-- 회원 정보 추가
insert into t_member
values ('hong', '1212', '홍길동', 'hong@gmail.com', sysdate);

insert into t_member
values ('lee', '1212', '이순신', 'lee@test.com', sysdate);

insert into t_member
values ('kim', '1212', '김유신', 'kim@jweb.com', sysdate);

commit; -- SQL Developer에서 테이블에 회원정보를 추가 후 반드시 커밋(commit)을 해줘야 영구적 반영이 됨

select * from t_member;


  • pro07 프로젝트 생성

    • 오라클 DB와 연동하는데 필요한 드라이버인 ojdbc6.jar를 프로젝트의 /WebContent/WEB-INF/lib 폴더에 복붙 (다운 LINK)

    ojdbc6.jar → JDK6, 7, 8과 함께 사용

    찾기 쉽게 일단 /tomcat9/lib에 같이 넣어둠 ㅎㅎ

    • sec01.ex01 패키지 생성 (회원 조회와 관련된 자바 클래스 파일인 MemberDAO, MemberServlet, MemberVO 클래스가 들어갈 것)
  • MemberServlet 클래스 생성

    • 브라우저의 요청을 받음
package sec01.ex01;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Date;
import java.util.List;

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 MemberServlet
 */
@WebServlet("/member")
public class MemberServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @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();
		MemberDAO dao = new MemberDAO(); // SQL문으로 조회할 MemberDAO 객체 생성
		List<MemberVO> list = dao.listMembers();    // listMembers() 메서드로 회원 정보 조회
		
		out.print("<html><body>");
		out.print("<table border=1><tr align='center' bgcolor='lightgreen'>");
		out.print("<td>아이디</td><td>비밀번호</td><td>이름</td><td>이메일</td><td>가입일</td></tr>");
		
		for (int i = 0; i < list.size(); i++)
		{
			MemberVO memberVO = (MemberVO) list.get(i);   // 조회한 회원 정보를 for과 <tr> 태그를 이용해 리스트로 출력
			String id = memberVO.getId();
			String pwd = memberVO.getPwd();
			String name = memberVO.getName();
			String email = memberVO.getEmail();
			Date joinDate = memberVO.getJoinDate();
			out.print("<tr><td>" + id + "</td><td>" + pwd + "</td><td>" + name + "</td><td>" + email + "</td><td>" + joinDate + "</td><tr>");
		}
		out.print("</table></body></html>");
	}

}
  • MemberDAO 클래스 생성

    • 회원 정보 조회 SQL문을 실행하여 조회한 레코드의 컬럼값을 다시 MemberVO 객체의 속성에 설정한 후 ArrayList에 저장하고 호출한 곳으로 반환
package sec01.ex01;

import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class MemberDAO {
	private static final String driver = "oracle.jdbc.driver.OracleDriver";
	private static final String url = "jdbc:oracle:thin:@localhost:1521:XE";
	private static final String user = "sun";
	private static final String pwd = "1234";
	private Connection con;
	private Statement stmt;
	
	
	public List<MemberVO> listMembers()
	{
		List<MemberVO> list = new ArrayList<MemberVO>();
		try
		{
			connDB();
			String query = "select * from t_member";
			System.out.println(query);
			ResultSet rs = stmt.executeQuery(query);
			while (rs.next())
			{
				String id = rs.getString("id");
				String pwd = rs.getString("pwd");
				String name = rs.getString("name");
				String email = rs.getString("email");
				Date joinDate = rs.getDate("joinDate");
				MemberVO vo = new MemberVO();
				vo.setId(id);
				vo.setPwd(pwd);
				vo.setName(name);
				vo.setEmail(email);
				vo.setJoinDate(joinDate);
				list.add(vo);
			}
			rs.close();
			stmt.close();
			con.close();
		} catch (Exception e)
		{
			e.printStackTrace();
		}
		return list;
	}
	
	
	private void connDB()
	{
		try
		{
			Class.forName(driver);
			System.out.println("Oracle 드라이버 로딩 성공");
			con = DriverManager.getConnection(url, user, pwd);
			System.out.println("Connection 생성 성공");
			stmt = con.createStatement();
			System.out.println("Statement 생성 성공");
		}	catch (Exception e)
		{
			e.printStackTrace();
		}
	}
	
}
  • MemberVO 클래스 생성

    • 값을 전달하는 데 사용하는 VO(Value Object) 클래스

TIP1. Getter Setter 만들어주는 거

우클릭 → Source → Generate Getters and Setters

TIP2. 생성자 만들어주기

우클릭 → Source → Generate Constructor using fields

package sec01.ex01;

import java.sql.Date;

public class MemberVO 

{
	private String id;
	private String pwd;
	private String name;
	private String email;
	private Date joinDate;
	
	public MemberVO() {
		System.out.println("MemberVO 생성자 호출");		
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public Date getJoinDate() {
		return joinDate;
	}

	public void setJoinDate(Date joinDate) {
		this.joinDate = joinDate;
	}
}
  • 실행

image


PrepareStatement를 이용한 회원 정보 실습

  • Statement 문의 단점

    • 연동할 때마다 DBMS에서 다시 SQL문을 컴파일해야 하므로 속도가 느림
  • PrepareStatement 인터페이스

    • SQL문을 미리 컴파일해서 재사용

    • Statement 인터페이스보다 훨씬 빠르게 DB작업 수행 가능

    • 데이터베이스와 연동할 때 / 빠른 반복 처리가 필요할 때 사용

  • PrepareStatement 인터페이스 특징

    • Statement 인터페이스를 상속 → 메서드를 그대로 사용

    • Statement : DBMS에 전달하는 SQL문 → 단순한 문자열 → DBMS가 스스로 이해할 수 있도록 컴파일 후 실행
      PrepareStatement : 컴파일된 SQL문을 DBMS에 전달 → 성능 향상

    • 실행하려는 SQL문에 “?”를 넣을 수 있음
      ”?”값만 바꾸어 손쉽게 설정할 수 있어 Statement문보다 SQL문 작성하기가 더 간단함

  • 실습

    • 기존 작성 3개 복붙 (to sec01.ex02)

    • Servlet 매핑을 /member2로 변경

    • MemberDAO 클래스를 PrepareStatement를 이용하여 연동하도록 작성

package sec01.ex02;

import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

public class MemberDAO {
	private static final String driver = "oracle.jdbc.driver.OracleDriver";
	private static final String url = "jdbc:oracle:thin:@localhost:1521:XE";
	private static final String user = "sun";
	private static final String pwd = "1234";
	private Connection con;
	private PreparedStatement pstmt;
	
	
	public List<MemberVO> listMembers()
	{
		List<MemberVO> list = new ArrayList<MemberVO>();
		try
		{
			connDB();
			String query = "select * from t_member";
			System.out.println("prepareStatement: " + query);
			pstmt = con.prepareStatement(query); // prepareStatement() 메서드에 SQL문을 전달해 PrepareStatement 객체를 생성
			ResultSet rs = pstmt.executeQuery(); // 미리 설정한 SQL문을 executeQuery()로 실행
			while (rs.next())
			{
				String id = rs.getString("id");
				String pwd = rs.getString("pwd");
				String name = rs.getString("name");
				String email = rs.getString("email");
				Date joinDate = rs.getDate("joinDate");
				MemberVO vo = new MemberVO();
				vo.setId(id);
				vo.setPwd(pwd);
				vo.setName(name);
				vo.setEmail(email);
				vo.setJoinDate(joinDate);
				list.add(vo);
			}
			rs.close();
			pstmt.close();
			con.close();
		} catch (Exception e)
		{
			e.printStackTrace();
		}
		return list;
	}
	
	
	private void connDB()
	{
		try
		{
			Class.forName(driver);
			System.out.println("Oracle 드라이버 로딩 성공");
			con = DriverManager.getConnection(url, user, pwd);
			System.out.println("Connection 생성 성공");
		}	catch (Exception e)
		{
			e.printStackTrace();
		}
	}
	
}

image

  • 차이

    • 눈으로 보면 Statement를 사용했을 때와 PrepareStatement 사용 결과가 같음

    • DB와 연동할 경우 수행 속도가 좀 더 빠름