데이터 베이스와 통신하기 위한 기능을 모듈화 하는 것
Data Access Object의 약자로, 서버가 데이터베이스에 접근하는 기능을 모듈화 한 것이다.
Data Transfer Object의 약자로, 데이터베이스의 자료형과 자바의 자료형이 다르기 때문에, 데이터의 가공이 필요한데, 이 때 데이터베이스의 데이터를 자바에서 쓸 수 있게 만들어주는 것이다.
책에 대한 정보를 검색하는 BookServlet을 하나 만들어준다.
package com.servlet;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.Statement;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
@WebServlet("/BookServlet")
public class BookServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html; charset = UTF-8");
PrintWriter out = response.getWriter();
// driver loading을 위한 기본 정보
String database = "jspDB"; // db이름
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost/" + database;
String id = "js";
String pw = "1234";
// 연결을 위한 Connection 객체
Connection con = null;
// 통신하기 위한 statement 객체
Statement stmt = null;
// select 결과 값을 담기 위한 ResultSet 객체
ResultSet res = null;
try{
Class.forName(driver); // driver loading
con = (Connection)DriverManager.getConnection(url, id, pw); // connection
stmt = (Statement)con.createStatement(); // statement
String sql = " SELECT * FROM book "; // query
res = stmt.executeQuery(sql); // run
// select 쿼리의 결과 값을 한 행씩 읽어온다.
while(res.next()){
int bookId = res.getInt("book_id");
String bookName = res.getString("book_name");
String bookLoc = res.getString("book_loc");
out.print("book id: "+ bookId+ ", ");
out.print("book name: "+ bookName+ ", ");
out.print("book location: "+ bookLoc+ "<br> ");
}
} catch (Exception e) {
e.printStackTrace();
} finally { // 자원을 반납해준다.
try {
if(res != null) res.close();
if(stmt != null) stmt.close();
if(con != null) con.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
위의 코드는 DAO와 DTO를 사용하지 않은 코드이다. 이 코드를 DAO와 DTO를 사용하여 변화시켜보겠다.
그럼 BookServlet.java / BookDAO.java / BookDTO.java 총 3개의 파일로 나눠지는 것이다.
먼저 BookDTO부터 만들어 보겠다.(일반적으로 .dto 패키지를 새로 만들어서 dto파일들 끼리 모아놓는다.)
DTO는 데이터베이스의 자료형을 자바에서 쓸 수 있게 바꿔주는 역할을 하기 때문에, 해당 테이블의 정보를 가지고 있다. 따라서 해당 테이블의 column 들을 변수로 선언해주고, 초기화 해주고, getter를 이용하여 값을 가져올 수 도 있어야한다.
실질적으로 DB와 연결하고, 데이터를 가져오는 것은 DAO에서 일어난다.
DAO도 DTO와 마찬가지로 일반적으로 .dao 패키지를 새로 만들어 DAO 파일끼리 모아서 사용한다.
먼저, DAO의 생성자에서 driver loading을 해준다. 즉 DAO 객체가 호출됨과 동시에 DB 드라이버도 메모리에 올려주는 것이다.
그런 다음 필요한 기능들을 메서드로 만들어서 구현한다. select 메서드를 예시로 만들어보겠다.(필요에 따라 update, delete, insert 등 여러 메서드를 구현해서 사용하면 된다.)
select 쿼리는 리턴 값이 많기 때문에 ArrayList로 받아줘야한다. ArrayList의 타입은 아까 만들어 준, BookDTO 타입이다. 즉, DTO를 이용해서 DB의 데이터를 자바에서 다룰 수 있는 것이다.
먼저, ArrayList를 선언해주고, Connection 객체 / PreparedStatement(or Statement) 객체 / ResultSet 객체(select 쿼리이기 때문) 를 선언해준다.
실제로 DB에 접근하는 부분은 DAO와 DTO를 쓰지 않을 때 처럼, try - catch구문을 사용해주어야한다.
driver loading 단계는 DAO객체가 생성 될 때, 생성자에서 해주었기 때문에, connection 단계부터 진행한다.
DB에서 데이터를 읽어와서 DTO 객체를 호출한 후, 생성된 DTO 객체를 ArrayList에 넣어준다.
마지막으로, 사용한 객체들의 resource를 반납해준다.
select 메서드는 아래와 같다.
DAO와 DTO를 이용하여, DB에 관한 기능들을 분리시켰기 때문에, 기존 servlet에서는 DAO객체만 생성해주고, 만들어준 메서드를 사용만 해주면 된다.
// BookServlet.java
package com.servlet;
import com.servlet.dao.BookDAO;
import com.servlet.dto.BookDTO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
@WebServlet("/BookServlet")
public class BookServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html; charset = UTF-8");
PrintWriter out = response.getWriter();
BookDAO bookDAO = new BookDAO(); // DAO 객체 호출(DB driver 메모리에 올라감)
ArrayList<BookDTO> list = bookDAO.select(); // DAO 객체의 select 메서드 호출
// 출력해보기
for(int i=0;i<list.size();i++){
BookDTO bookDTO = list.get(i);
int bookId = bookDTO.getBookId();
String bookName = bookDTO.getBookName();
String bookLoc = bookDTO.getBookLoc();
out.print("book id: "+ bookId+ ", ");
out.print("book name: "+ bookName+ ", ");
out.print("book location: "+ bookLoc+ "<br> ");
}
}
}
// BookDAO.java
package com.servlet.dao;
import com.mysql.jdbc.Connection;
import com.servlet.dto.BookDTO;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
public class BookDAO {
// driver loading을 위한 기본 정보
String database = "jspDB"; // db이름
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost/" + database;
String id = "js";
String pw = "1234";
// BookDAO가 생성되면서 같이 드라이버도 메모리에 올라갈 수 있도록 생성자에 코딩
public BookDAO() {
try{
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
// 실제로 DB에 접근하여 데이터를 가져오는 역할을 하는 메서드
public ArrayList<BookDTO> select() {
ArrayList<BookDTO> list = new ArrayList<BookDTO>();
// 연결을 위한 Connection 객체
Connection con = null;
// 통신하기 위한 PreparedStatement 객체
PreparedStatement pstmt = null;
// select 결과 값을 담기 위한 ResultSet 객체
ResultSet res = null;
// 실제로 DB에 접근하는 부분
try{
con = (Connection) DriverManager.getConnection(url, id, pw); // connection
String sql = "SELECT * FROM book"; // query
pstmt = con.prepareStatement(sql); // preparedStatement
res = pstmt.executeQuery(); // run
while(res.next()){
int bookId = res.getInt("book_id");
String bookName = res.getString("book_name");
String bookLoc = res.getString("book_loc");
BookDTO bookDTO = new BookDTO(bookId, bookName, bookLoc); // DTO 객체에 DB에서 읽어온 값 넣어서 호출
list.add(bookDTO); // arraylist에 생성된 DTO객체 넣어줌
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(res != null) res.close();
if(pstmt != null) pstmt.close();
if(con != null) con.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return list;
}
}
// BookDTO.java
package com.servlet.dto;
// book에 대한 정보를 가지고 있는 것
public class BookDTO {
// book DB의 column을 모두 만들어 줌
int bookId;
String bookName;
String bookLoc;
// 생성자에서 변수들 초기화
public BookDTO(int bookId, String bookName, String bookLoc) {
this.bookId = bookId;
this.bookName = bookName;
this.bookLoc = bookLoc;
}
public int getBookId() {
return bookId;
}
public String getBookName() {
return bookName;
}
public String getBookLoc() {
return bookLoc;
}
}