2020년 11월 17일

업데이트:


JDBCRun.java

import com.kh.jdbc.view.JDBCView;

public class JDBCRun {
	public static void main(String[] args) {
		new JDBCView().displayMain();
	}
}



JDBCView.java

import java.util.InputMismatchException;
import java.util.Scanner;
import com.kh.jdbc.member.mode.vo.Member;
import com.kh.jdbc.member.model.service.MemberService;

/** JDBCProject View
 * @author 이한솔
 *
 */
public class JDBCView {
	
	private Scanner sc = new Scanner(System.in);
	private MemberService mService = new MemberService();
	private Member loginMember = null; // 로그인된 회원의 정보를 저장
	
	
	
	// alt + shift + j
	/**
	 * 메인 메뉴 View
	 * 작성자 : 이한솔
	 */
	public void displayMain() {
		int sel = 0;
		
		do {
			try {
				if(loginMember == null) { // 로그인이 되어있지 않은 경우
					System.out.println("★☆★☆★☆★☆★☆ JDBC PROJECT ★☆★☆★☆★☆★☆");
					System.out.println("====================================");
					System.out.println("1. 로그인");
					System.out.println("2. 회원가입");
					System.out.println("0. 프로그램 종료");
					System.out.println("====================================");
					
					System.out.print("메뉴 선택 >> ");
					sel = sc.nextInt();
					sc.nextLine();
					
					System.out.println();
					
					switch(sel) {
					case 1 : login(); break;
					case 2 : signUp(); break;
					case 0 : System.out.println("프로그램 종료."); break;
					default : System.out.println("잘못 입력하셨습니다.");
					}
				} else {
					System.out.println("====================================");
					System.out.println("[메인 메뉴]");
					System.out.println("1. 회원 기능");
					System.out.println("9. 로그아웃");
					System.out.println("0. 프로그램 종료");
					System.out.println("====================================");
					
					System.out.print("메뉴 선택 >> ");
					sel = sc.nextInt();
					sc.nextLine();
					
					System.out.println();
					
					switch(sel) {
					case 1 :  break;
					case 9 : loginMember = null;  // 회원 정보를 없앰
							 System.out.println("로그아웃 되었습니다.");
							 break;
					case 0 : System.out.println("프로그램 종료."); break;
					default : System.out.println("잘못 입력하셨습니다.");
					}
				}
			} catch (InputMismatchException e) {
				System.out.println("숫자만 입력해주세요.");
				sel = -1;
				sc.nextLine(); // 버퍼에 남아있는 문자열 제거
			}
		}while(sel != 0);
	}

	/**
	 * 회원가입용 View
	 */
	private void signUp() {
		System.out.println("[회원 가입]");
		System.out.print("아이디 : ");
		String memId = sc.nextLine();
		System.out.print("비밀번호 : ");
		String memPw = sc.nextLine();
		System.out.print("이름 : ");
		String memNm = sc.nextLine();
		System.out.print("전화번호 : ");
		String phone = sc.nextLine();
		System.out.print("성별 : ");
		char gender = sc.nextLine().toUpperCase().charAt(0); 
		
		// 입력받은 값을 하나의 Member 객체에 저장
		Member newMember = new Member(memId, memPw, memNm, phone, gender);
		
		// 입력받은 회원 정보를 DB에 삽입하기 위한 service 호출
		try {
			System.out.println();
			int result = mService.signUp(newMember);
			
			if(result > 0) {
				System.out.println("회원 가입 성공 !!!!!!!!!!!!!!");
			}else {
				System.out.println("회원 가입 실패.......");
			}
		} catch (Exception e) {
			System.out.println("회원 가입 과정에서 오류 발생");
			e.printStackTrace();
		}
	}
	

	/**
	 * 로그인용 View
	 */
	private void login() {
		System.out.println("[로그인]");
		System.out.print("아이디 : ");
		String memId = sc.nextLine();
		System.out.print("비밀번호 : ");
		String memPw = sc.nextLine();
		
		// 아이디, 비밀번호를 하나의 Member 객체에 저장
		Member member = new Member();
		member.setMemId(memId);
		member.setMemPw(memPw);
		
		//입력받은 ID, PW를 이용하여 로그인 서비스 수행
		// -> 반환 받은 결과를 loginMember에 저장
		try {
			loginMember = mService.login(member);
			
			// 로그인이 성공한 경우
			if(loginMember != null) {
				System.out.println("***** " + loginMember.getMemNm() + "님 환영합니다. *****");
			} else {
				System.out.println("아이디 또는 비밀번호가 일치하지 않거나, 탈퇴한 회원입니다.");
			}
		} catch (Exception e) {
			System.out.println("로그인 과정에서 오류가 발생했습니다.");
			e.printStackTrace();
		}
	}
}



MemberService.java

//static import : 특정 static 필드, 메소드 호출 시 클래스명을 생략할 수 있게 하는 구문
import static com.kh.jdbc.common.JDBCTemplate.*;

import java.sql.Connection;
import com.kh.jdbc.common.JDBCTemplate;
import com.kh.jdbc.member.mode.vo.Member;
import com.kh.jdbc.member.model.dao.MemberDAO;

//Service
// 1. 요청, 응답 데이터의 가공 처리
// 2. 여러 DAO 메소드를 호출하여 DML 진행 후 수행된 DML을 하나의 트랜잭션으로 묶어 처리하는 역할
// ***** 트랜잭션 처리를 위해 Connection 객체의 생성과 반환을 Service에서 진행해야 함 *****

public class MemberService  {

	private MemberDAO mDAO = new MemberDAO();
	
	public int signUp(Member newMember) throws Exception {
		
		// Connection 생성 == JDBCTemplate에서 커넥션 얻어오기
		Connection conn = getConnection();
		
		// 요청을 처리할 수 있는 알맞은 DAO 메소드를 호출하여
		// 커넥션과 매개변수 전달하고 결과를 반환 받음
		int result = mDAO.signUp(conn, newMember);
		
		// result 값에 따른 트랜잭션 처리
		if(result > 0) commit(conn);
		else rollback(conn);
		
		
		// conn 반환
		close(conn);
		
		
		return result;
	}

	public Member login(Member member) throws Exception{
		// 커넥션 객체 얻어오기
		Connection conn = getConnection();
		
		// 얻어온 커넥션과 매개변수를 DAO 메소드로 전달.
		Member loginMember = mDAO.login(conn, member);
		
		// Select는 트랜잭션 처리가 필요없으므로 바로 커넥션 반환
		close(conn);
		
		// DB 조회 결과인 loginMember 반환
		return loginMember;
	}
}



Member.java

import java.sql.Date;

public class Member {
	private int memNo; // 회원번호
	private String memId; 	//아이디
	private String memPw; // 비밀번호
	private String memNm; // 이름
	private String phone; //전화번호
	private char gender; //성별
	private Date hireDt; // 가입일
	private char scsnFl; //탈퇴여부
	
	public Member() { } // 기본생성자

	
	public Member(String memId, String memPw, String memNm, String phone, char gender) {
		super();
		this.memId = memId;
		this.memPw = memPw;
		this.memNm = memNm;
		this.phone = phone;
		this.gender = gender;
	}
	
	

	// 로그인용 생성자
	public Member(int memNo, String memId, String memNm, String phone, char gender, Date hireDt) {
		super();
		this.memNo = memNo;
		this.memId = memId;
		this.memNm = memNm;
		this.phone = phone;
		this.gender = gender;
		this.hireDt = hireDt;
	}


	public Member(int memNo, String memId, String memPw, String memNm, String phone, char gender, Date hireDt,
			char scsnFl) {
		super();
		this.memNo = memNo;
		this.memId = memId;
		this.memPw = memPw;
		this.memNm = memNm;
		this.phone = phone;
		this.gender = gender;
		this.hireDt = hireDt;
		this.scsnFl = scsnFl;
	}

	public int getMemNo() {
		return memNo;
	}

	public void setMemNo(int memNo) {
		this.memNo = memNo;
	}

	public String getMemId() {
		return memId;
	}

	public void setMemId(String memId) {
		this.memId = memId;
	}

	public String getMemPw() {
		return memPw;
	}

	public void setMemPw(String memPw) {
		this.memPw = memPw;
	}

	public String getMemNm() {
		return memNm;
	}

	public void setMemNm(String memNm) {
		this.memNm = memNm;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public char getGender() {
		return gender;
	}

	public void setGender(char gender) {
		this.gender = gender;
	}

	public Date getHireDt() {
		return hireDt;
	}

	public void setHireDt(Date hireDt) {
		this.hireDt = hireDt;
	}

	public char getScsnFl() {
		return scsnFl;
	}

	public void setScsnFl(char scsnFl) {
		this.scsnFl = scsnFl;
	}

	@Override
	public String toString() {
		return "Member [memNo=" + memNo + ", memId=" + memId + ", memPw=" + memPw + ", memNm=" + memNm + ", phone="
				+ phone + ", gender=" + gender + ", hireDt=" + hireDt + ", scsnFl=" + scsnFl + "]";
	}
}



MemberDAO.java

import static com.kh.jdbc.common.JDBCTemplate.close;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;

import com.kh.jdbc.member.mode.vo.Member;

public class MemberDAO {

	// DAO에서 자주 사용하는 JDBC 객체 참조 변수를 멤버 변수로 선언
	private Statement stmt = null;
	private PreparedStatement pstmt = null;
	private ResultSet rset = null;
	
	// 외부 xml 파일에 저장된 SQL 구문을 읽어들일 Properties 변수 선언
	private Properties prop = null;
	
	public MemberDAO() {
		// 기본 생성자를 통한 객체 생성 시 xml 파일을 읽어오게 함.
		try {
			prop = new Properties();
			prop.loadFromXML(new FileInputStream("member-query.xml"));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	/** 회원가입용 DAO
	 * @param conn
	 * @param newMember
	 * @return result
	 * @throws Exception
	 */
	public int signUp(Connection conn, Member newMember) throws Exception{
														// 예외를 view에서 처리하기위해 던져줌
		/*
		 * 이전 DAO에서 하던 역할
		 * 1) JDBC 드라이버 등록
		 * 2) DB 연결 커넥션 생성
		 * 3) SQL 수행
		 * 4) 트랜잭션 처리
		 * 5) JDBC 객체 반환
		 * 6) sql 수행 결과 반환
		 * 
		 * --> 지금은 3, 5, 6번 수행
		 */
		
		int result = 0; //DML 수행 결과 저장용 변수
		try {
			
			String query = prop.getProperty("signUp");
			
			// SQL 구문을 DBdp 전달할 준비
			pstmt = conn.prepareStatement(query);
			
			pstmt.setString(1,  newMember.getMemId());
			pstmt.setString(2,  newMember.getMemPw());
			pstmt.setString(3,  newMember.getMemNm());
			pstmt.setString(4,  newMember.getPhone());
			pstmt.setString(5,  newMember.getGender() + "");
			// char 데이터에 빈문자열("")을 더하여 String 형태로 형변환
			
			// SQL 수행 수 결과를 반환받아 result에 저장
			result = pstmt.executeUpdate();
		} finally {
			// catch가 없어도 finally 작성 가능
			// DB 자원 반환
			close(pstmt);
		}
		return result;
	}


	public Member login(Connection conn, Member member) throws Exception {
		Member loginMember = null; // 로그인된 회원 정보를 저장할 임시변수
		
		try {
			
			// member-query.xml 파일에서 키값이 "login"인 태그의 값을 얻어옴
			String query = prop.getProperty("login");
			
			// DB 전달을 위한 pstmt 생성
			pstmt = conn.prepareStatement(query);
			
			// SQL 구문의 위치홀더에 알맞는 값을 배치
			pstmt.setString(1, member.getMemId());
			pstmt.setString(2, member.getMemPw());

			// SQL 수행 후 결과를 ResultSet으로 반환 받음
			rset = pstmt.executeQuery();
			
			// 조회 결과가 있는지 확인하는 if문 작성
			if(rset.next()) {
				// 조회 결과가 있을 경우 Member 객체를 만들어 로그인 정보를 저장
				loginMember = new Member(rset.getInt("MEM_NO"), 
										 rset.getString("MEM_ID"),
									 	 rset.getString("MEM_NM"),
									 	 rset.getString("PHONE"),
									 	 rset.getString("GENDER").charAt(0),
									 	 rset.getDate("HIRE_DT"));
			}
		}finally {
			// DB 자원 반환
			close(rset);
			close(pstmt);

		}
		// 조회 결과가 담긴 loginMember 반환
		return loginMember;
	}

}



JDBCTemplate.java

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

public class JDBCTemplate {
	// 1. 반복되는 Connection 객체의 생성을 간소화
	// 2. 트랜잭션 처리, close() 처리의 간소화
	
	// ** 싱글톤(singleTon) 패턴
	// 프로그램 구동 시 메모리 상에 딱 하나의 객체만 기록되게 하는 디자인 패턴
	// 대표적인 예시로 java.lang.Math가 있음.
	
	// 모든 필드, 메소드를 static으로 선언하여 프로그램 구동 시 static 메모리 영역에
	// 모든 클래스 내용을 로드하여 하나의 객체 모양을 띄게 함.
	
	// 하나의 공용 커넥션 참조변수 선언
	// public으로 접근제한자를 설정하면 null 값을 가진 커넥션을 참조할 수도 있으므로 private으로 제한을 건다.
	private static Connection conn = null;
	//private 선언 이유 : 직접 접근 시 null 값이나 닫혀진 커넥션 객체를 가져갈 수 있는 확률이 있어서 이를 미연에 차단한다
	
	
	// 해당 클래스의 내용은 모두 static에서 객체의 모양을 이루기 때문에
	// 추가적인 객체 생성을 막기 위해 private을 사용
	private JDBCTemplate() { }
	
	// DB 연결을 위한 Connection 객체를 간접적으로 얻어가는 메소드 생성
	public static Connection getConnection() {
		
		try {
			if(conn == null || conn.isClosed()) { // 커넥션이 없거나, 닫혀있는 경우
												  // -> 새로운 커넥션을 생성하여 반환
				/* DB 연결을 위한 Driver 정보나
				 * DB URL, 계정 정보는 상황에 따라 언제든지 바뀔 가능성이 높음.
				 * --> 코드를 직접 수정하게 되는 경우 유지보수에 좋지 않음
				 * --> 외부파일에 해당 정보들을 기입하여 읽어오는 형태로 변환
				 * --> 내부 코드에 변화가 없으므로 재컴파일이 필요없음
				 * 		--> 유지보수성 향상
				 */
				Properties prop = new Properties();
				
				// driver.xml 파일에 작성된 entry를 prop에 저장함
				prop.loadFromXML(new FileInputStream("driver.xml"));
				
				
				// JDBC 드라이버 등록 및 커넥션 얻어오기
				Class.forName(prop.getProperty("driver"));
				conn = DriverManager.getConnection(prop.getProperty("url"),
												   prop.getProperty("user"),
												   prop.getProperty("password"));
				
				// 자동 commit 비활성화
				conn.setAutoCommit(false);
			}
			
		}catch (Exception e) {
			e.printStackTrace();
		}
		return conn;
	}
	
	
	// 트랜잭션 처리(commit, rollback)도 공통적으로 사용함
	// static으로 미리 선언으로 코드 길이 감소 효과 + 재사용성
	public static void commit(Connection conn) {
		try {
			if (conn != null && !conn.isClosed()) {
				// 참조하고 있는 커넥션이 닫혀있지 않은 경우
				conn.commit();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void rollback(Connection conn) {
		try {
			if (conn != null && !conn.isClosed()) {
				// 참조하고 있는 커넥션이 닫혀있지 않은 경우
				conn.rollback();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	// DB 연결 자원 반환 구문도 static으로 작성
	public static void close(Connection conn) {
		try {
			if (conn != null && !conn.isClosed()) {
				// 참조하고 있는 커넥션이 닫혀있지 않은 경우
				conn.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	public static void close(ResultSet rset) {
		try {
			if (rset != null && !rset.isClosed()) {
				// 참조하고 있는 커넥션이 닫혀있지 않은 경우
				rset.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	// Statement, PreparedStatement 두 객체를 반환하는 메소드
	// 어떻게? PreparedStatement는 Statement의 자식이므로
	// 매개변수 stmt에 다형성이 적용되어서 자식 객체인 PreparedStatement를 참조 가능
	public static void close(Statement stmt) {
		try {
			if (stmt != null && !stmt.isClosed()) {
				// 참조하고 있는 커넥션이 닫혀있지 않은 경우
				stmt.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}



TestProperties.java

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Properties;

public class TestProperties {
	public static void main(String[] args) {
		// Map<K, V> --> 키와 값에 모든 자료형이 가능함
		// Map<String, String> == Properties 
		
		// Properties 클래스
		// 키와 값이 모두 String인 컬렉션
		// + 외부 파일 입출력이 간단하게 구현되어 있음.
		
		
		Properties prop = new Properties();
		
		/*
		// 값 세팅
		prop.setProperty("driver", "oracle.jdbc.driver.OracleDriver");
		prop.setProperty("url", "jdbc:oracle:thin:@localhost:1521:xe");
		prop.setProperty("user", "jdbc");
		prop.setProperty("password", "jdbc");
		
		// 꺼내 쓰는 법
		//System.out.println(prop.getProperty("driver"));
		
		// 세팅한 Properties 객체를 외부파일(XML)로 출력
		// XML의 장점 : 모든 프로그래밍 언어에서 입출력 가능한 파일
		try {
			
			prop.storeToXML(new FileOutputStream("driver.xml"), "driver information");
			
		}catch (Exception e) {
			e.printStackTrace();
		}
		*/
		
		
		// 외부 xml 파일 읽어오기
		try {
			prop.loadFromXML(new FileInputStream("driver.xml"));
			System.out.println(prop.getProperty("driver"));
			System.out.println(prop.getProperty("url"));
			System.out.println(prop.getProperty("user"));
			System.out.println(prop.getProperty("password"));
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
}



driver.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>driver information</comment>
<entry key="user">jdbc</entry>
<entry key="password">jdbc</entry>
<entry key="url">jdbc:oracle:thin:@localhost:1521:xe</entry>
<entry key="driver">oracle.jdbc.driver.OracleDriver</entry>
</properties>



member-query.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<!-- member 관련 SQL 구문을 작성하는 xml 파일 -->
<entry key="signUp">
INSERT INTO TB_MEMBER 
VALUES(SEQ_MNO.NEXTVAL, ?, ?, ?, ?, ?, DEFAULT, DEFAULT)
</entry>

<entry key="login">
SELECT MEM_NO, MEM_ID, MEM_NM, PHONE, GENDER, HIRE_DT
FROM TB_MEMBER WHERE MEM_ID = ? AND MEM_PW = ? 
AND SCSN_FL = 'N'
</entry>
</properties>

태그: ,

카테고리:

업데이트:

댓글남기기