BackEnd/Java

[JDBC] dto / dao / common(Template) / run / service / view

Hojung7 2024. 8. 27. 23:43

 

DTO(Data Transfer Object) - 값을 묶어서 전달하는 용도의 객체

- DB에 데이터를 전달하거나, 가져올 때 사용
 → DB 특정 테이블의 한 행의 데이터를 저장할 수 있는 형태로 class 작성
DAO(Data Access Object)  
JDBCTemplate JDBC 관련 작업을 위한 코드를 미리 작성해서 제공하는 클래스

 - getConnection() + AutoCommit false
 - commit() / rollback()
 - 각종 close()
Service - 비지니스 로직 처리

- DB에 CRUD 후 결과 반환 받기
  +  DML 성공 여부에 따른 트랜잭션 제어 처리(commit/rollback)

 → commit/rollback에는 Connection 객체가 필요하기 때문에
     Connection 객체를 Service에서 생성 후
     Dao에 전달하는 형식의 코드를 작성하게 됨

 

[dto]

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
    private int userNo;
	private String userId;
	private String userPw;
	private String userName;
	private String enrollDate;
	// -> enrollDate는 왜 java.sql.Date가 아니라 String인가??
	//   -> DB 조회 시 날짜 데이터를 원하는 형태의 문자열로
	//      변환하여 조회할 예정 -> TO_CHAR() 이용
}

 

[common]

 package edu.kh.jdbc.common;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/* Template : 양식, 주형, 본을 뜨기 위한 틀
 *  -> "미리 만들어뒀다"를 의미
 *  
 * JDBCTemplate : 
 * 	JDBC 관련 작업을 위한 코드를
 * 	미리 작성해서 제공하는 클래스
 * 
 * - getConnection() + AutoCommit false
 * - commit() / rollback()
 * - 각종 close()
 * 
 * ***** 중요 *****
 * 어디서든 JDBCTemplate 클래스를 
 * 객체로 만들지 않고도 메서드를 사용할 수 있도록 하기 위해
 * 모든 메서드를 public static 으로 선언
 * */
public class JDBCTemplate {
	
	// 필드
	private static Connection conn = null;
	// -> static 메서드에서 사용 가능한 필드는 static 필드만 가능
	

	// 메서드
	
	/**
	 * 호출 시 Connection 객체를 생성해서 반환하는 메서드
	 * @return conn
	 */
	public static Connection getConnection() {
		
		try {
			
			// 이전에 참조하던 Connection 객체가 존재하고
			// 아직 close된 상태가 아니라면
			if(conn != null && !conn.isClosed()) {
				return conn; // 새로 만들지 않고 기존 Connection 반환
			}
			
			
			/* DB 연결을 위한 정보들을 별도 파일에 작성하여
			 * 읽어오는 형식으로 코드를 변경!!!
			 * 
			 * 이유 1 : Github에 코드 올리면 해킹하세요~ 뜻이라
			 * 			보안적인 측면에서 코드를 직접 보지 못하게함
			 * 
			 * 이유 2 : 혹시라도 연결하는 DB 정보가 변경될 경우
			 * 			Java 코드가 아닌
			 * 			읽어오는 파일의 내용을 수정하면 되기 때문에
			 * 			Java 코드 수정 x -> 추가 컴파일 필요 x
			 * 			--> 개발 시간 단축!!
			 */
			
			/* driver.xml 파일 내용 읽어오기 */
			
			// 1. Properties 객체 생성
			// - Map의 자식 클래스
			// - K, V가 모두 String 타입
			// - xml파일 입출력을 쉽게 할 수 있는 메서드 제공
			Properties prop = new Properties();
			
			// 2. Properties 메서드를 이용해서
			//    driver.xml 파일 내용을 읽어와 prop 에 저장
			
			String filePath = "driver.xml"; 
			// 프로젝트 폴더 바로 아래 driver.xml 파일
								
			// driver.xml 파일의 내용을 prop에 저장하겠다
			prop.loadFromXML(new FileInputStream(filePath));
			
			
			// prop에 저장된 값(driver.xml 에서 읽어온 값)을 이용해
			// Connection 객체 생성하기
			
			// prop.getProperty("KEY") : KEY가 일치하는 Value를 반환
			Class.forName( prop.getProperty("driver") );
			String url      = prop.getProperty("url");
			String userName = prop.getProperty("userName");
			String password = prop.getProperty("password");
			
			conn = DriverManager.getConnection(url, userName, password);
			
			// 만들어진 Connection에 AutoCommit 끄기
			conn.setAutoCommit(false);
			
		}catch (Exception e) {
			e.printStackTrace();
		}
		
		return conn;
	}
	
	
	// ----------------------------------
	
	/* 트랜잭션 제어 처리 메서드 (commit, rollback) */
	
	/**
	 * 전달 받은 커넥션에서 수행한 SQL을 COMMIT하는 메서드
	 * @param conn
	 */
	public static void commit(Connection conn) {
		try {
			if(conn != null && !conn.isClosed()) conn.commit();
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 전달 받은 커넥션에서 수행한 SQL을 Rollback하는 메서드
	 * @param conn
	 */
	public static void rollback(Connection conn) {
		try {
			if(conn != null && !conn.isClosed()) conn.rollback();
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	// ---------------------------------------------------
	
	/**
	 * 전달 받은 커넥션을 close(자원 반환)하는 메서드
	 * @param conn
	 */
	public static void close(Connection conn) {
		try {
			if(conn != null && !conn.isClosed()) conn.close();
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 전달 받은 Statement를 close(자원 반환)하는 메서드
	 * + PreparedStatement도 close 처리 가능!!
	 *   왜?? PreparedStatement가 Statement의 자식이기 때문에!!
	 *   (다형성 업캐스팅)
	 * @param stmt
	 */
	public static void close(Statement stmt) {
		try {
			if(stmt != null && !stmt.isClosed()) stmt.close();
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 전달 받은 ResultSet을 close(자원 반환)하는 메서드
	 * @param rs
	 */
	public static void close(ResultSet rs) {
		try {
			if(rs != null && !rs.isClosed()) rs.close();
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	
}

 

[service]

package edu.kh.jdbc.service;

import java.sql.Connection;

import edu.kh.jdbc.common.JDBCTemplate;
import edu.kh.jdbc.dao.UserDao;
import edu.kh.jdbc.dto.User;

// Service : 비지니스 로직 처리
// - DB에 CRUD 후 결과 반환 받기
//  +  DML 성공 여부에 따른 트랜잭션 제어 처리(commit/rollback)
//  --> commit/rollback에는 Connection 객체가 필요하기 때문에
//     Connection 객체를 Service에서 생성 후
//    Dao에 전달하는 형식의 코드를 작성하게 됨

public class UserService {

	// 필드
	private UserDao dao = new UserDao();
	
	// 메서드
	/**
	 *  전달 받은 아이디와 일치하는 User 정보 반환
	 * @param input 입력된 아이디
	 * @return 아이디가 일치하는 회원 정보, 없으면 null
	 */

	public User selectId(String input) {
		
		// 커넥션 생성
		Connection   conn = JDBCTemplate.getConnection();
		
		// Dao 메서드 호출 후 결과 반환 받기
	
		User user = dao.selectId(conn, input);
		// 다 쓴 커넥션 닫기
		JDBCTemplate.close(conn);
		
		return user; // DB 조회 결과 반환
	}
	
	
}

[dao]

package edu.kh.jdbc.dao;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;

import edu.kh.jdbc.common.JDBCTemplate;
import edu.kh.jdbc.dto.User;

// DAO(Data Access Object) : 
// 데이터가 저장된 곳에 접근하는 용도의 객체
// -> DB에 접근하여 Java에서 원하는 결과를 얻기 위해
//    SQL을 수행하고 결과 반환 받는 역할

public class UserDao {
	
	// 필드
	// - DB 접근 관련한 JDBC 객체 참조형 변수를 미리 선언
	private Statement stmt = null;
	private PreparedStatement pstmt = null;
	private ResultSet rs = null;
	
	/** 전달 받은 Connection을 이용해 DB에 접근하여
	 * 전달 받은 아이디와 일치하는 User 정보 조회하기
	 * @param conn  : Service에서 생성한 Connection 객체 
	 * @param input : View에서 입력 받은 아이디
	 * @return
	 */
	public User selectId(Connection conn, String input) {
		
		User user = null; // 결과 저장용 변수
		
		try {
			// SQL 작성
			String sql = "SELECT * FROM TB_USER WHERE USER_ID = ?";
			
			// PreparedStatement 객체 생성
			pstmt = conn.prepareStatement(sql);
			
			// ?(placeholder)에 알맞은 값 대입
			pstmt.setString(1, input);
			
			// SQL 수행 후 결과 반환 받기
			rs = pstmt.executeQuery();
			
			// 조회 결과가 있을 경우
			// -> 중복되는 아이디가 없을 경우
			//   1행만 조회되기 때문에 while보단 if를 사용하는게 효과적
			if(rs.next()) {
				
				// 각 컬럼의 값 얻어오기
				int userNo      = rs.getInt("USER_NO");
				String userId   = rs.getString("USER_ID");
				String userPw   = rs.getString("USER_PW");
				String userName = rs.getString("USER_NAME");
				
				// java.sql.Date 활용
				Date enrollDate = rs.getDate("ENROLL_DATE");
				
				
				// 조회된 컬럼값을 이용해 User 객체 생성
				user = new User(userNo, 
								userId, 
								userPw, 
								userName, 
								enrollDate.toString());
				
			}
			
		}catch (Exception e) {
			e.printStackTrace();
			
		} finally {
			// 사용한 JDBC 객체 자원 반환(close)
			JDBCTemplate.close(rs);
			JDBCTemplate.close(pstmt);
			
			// Connection 객체는 Service에서 close!!!!!!!
		}
		
		return user; // 결과 반환(생성된 User 또는 null)
		
	}
	

	

}

[run]

package edu.kh.jdbc.run;

import edu.kh.jdbc.common.JDBCTemplate;
import edu.kh.jdbc.view.UserView;

public class UserRun {
	public static void main(String[] args) {
		System.out.println(JDBCTemplate.getConnection());
		
		UserView view = new UserView();
		view.test();
		
	}
}