본문 바로가기
DB/Code

CODE [day_05] DB / 07. 계좌 개설 및 입출금, 계좌 이체 프로그램 만들기 - JDBC, SELECT(WHERE, COUNT), INSERT, UPDATE

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

계좌 개설 및 입출금, 계좌 이체 프로그램 만드는 예제


** 요구사항 **


사용자는 계좌 개설이 가능하다.

계좌 계설 시
--> 1. 계좌번호, 계좌주명, 비밀번호, 잔액정보가 저장되어야 한다
--> 2. 최초 계좌 개설 시에는 초기 납입액 1000원 이상이 되어야 한다
--> 3. 계좌번호는 유일해야 하고, 시스템에서 자동 발급되도록 관리한다 (primary key, sequence)

잔액 확인 시
--> 계좌번호가 존재해야 하고, 비밀번호가 일치해야 한다.

입금액, 출금액, 계좌 이체액은 모두 0원을 초과해야 한다.

입금 시에는
--> 계좌번호, 비밀번호가 일치해야 한다.
출금 시에는
--> 계좌번호, 비밀번호, 잔액 확인 절차가 필요하다.
계좌 이체 시에는
--> 1. 송금자 및 수금자의 계좌가 존재해야 한다.
--> 2. 이체액은 0원을 초과해야한다.
--> 3. 송금자의 비밀번호가 일치해야 한다.
--> 4. 송금자의 잔액확인이 필요하다.


SQL

ACCOUNT_INST TABLE 생성

CREATE TABLE account_inst (
	account_no	NUMBER			PRIMARY KEY,
	name		VARCHAR2(100)		NOT NULL,
	password	VARCHAR2(100)		NOT NULL,
	balance		NUMBER			DEFAULT 1000
);

 

account_inst_seq SEQUENCE 생성

: cache기능을 사용하지 않겠다는 옵션을 할당

 -- > 비정상 종료 시에도 번호가 이어지도록

 

CREATE SEQUENCE account_inst_seq NOCACHE;

 


UML

UML diagram


JAVA JDBC

TestDAO class (main class)

 

step1. 계좌 개설 단위 테스트 

/TestUnit1.java

package test;

import java.sql.SQLException;

import model.AccountDAO;
import model.AccountVO;
import model.CreateAccountException;
// step1. 계좌 개설 단위 테스트 
public class TestUnit1 {
	public static void main(String[] args) {
		try {
			AccountDAO dao=new AccountDAO();			
			//개설할 계좌 정보
			AccountVO vo=new AccountVO("아이유","1234",1000);			
			//AccountVO vo=new AccountVO("장기하","4321",2000);
			try{
			dao.createAccount(vo);
			System.out.println("계좌 개설 성공");
			}catch(CreateAccountException se){
				System.out.println(se.getMessage());
			}			
		} catch (ClassNotFoundException e) {			
			e.printStackTrace();
		} catch(SQLException e){
			e.printStackTrace();
		}
	}
}

 

step2. 계좌 잔액 조회 테스트 

/TestUnit2.java

package test;

import java.sql.SQLException;

import model.AccountDAO;
import model.AccountNotFoundException;
import model.NotMatchedPasswordException;


//step2 계좌 잔액조회 테스트
public class TestUnit2 {
	public static void main(String[] args) {		
		try {
			AccountDAO dao = new AccountDAO();
			System.out.println("잔액조회:" 
			+ dao.getAccountBalance("1", "1234"));
		}catch (AccountNotFoundException e) {
				System.out.println(e.getMessage());			
		}catch (NotMatchedPasswordException e) {			
			System.out.println(e.getMessage());			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} 

	}
}

 

step3. 입금 테스트

/TestUnit3.java

package test;

import java.sql.SQLException;

import model.AccountDAO;
import model.AccountNotFoundException;
import model.NoMoneyException;
import model.NotMatchedPasswordException;
//step3 입금 테스트 
public class TestUnit3 {
	public static void main(String[] args) {		
		try {
			AccountDAO dao = new AccountDAO();
			dao.deposit("1","12345", 200);
			System.out.println("정상입금처리");
		}catch (AccountNotFoundException e) {				
			System.out.println(e.getMessage());			
		}catch (NoMoneyException e) {			
			System.out.println(e.getMessage());	
		}catch (NotMatchedPasswordException e) {
			System.out.println(e.getMessage());	
		}catch (SQLException e) {		
			e.printStackTrace();
		}catch (ClassNotFoundException e) {			
			e.printStackTrace();	
		} 
	}
}

 

step4. 출금 테스트

/TestUnit4.java

package test;

import java.sql.SQLException;

import model.AccountDAO;
import model.AccountNotFoundException;
import model.NotMatchedPasswordException;
import model.InsufficientBalanceException;
import model.NoMoneyException;
//step4 출금 테스트 
public class TestUnit4 {
	public static void main(String[] args) {		
		try {
			AccountDAO dao = new AccountDAO();
			dao.withdraw("1","1234", 2000);
			System.out.println("정상출금처리");				
		}catch (NoMoneyException e) {			
			System.out.println(e.getMessage());
		}catch (AccountNotFoundException e) {
			 System.out.println(e.getMessage());
		}catch (NotMatchedPasswordException e) {				
			System.out.println(e.getMessage());		
		}catch (InsufficientBalanceException e) {
			System.out.println(e.getMessage());	
		}catch (SQLException e) {		
			e.printStackTrace();
		}catch (ClassNotFoundException e) {			
			e.printStackTrace();	
		}
	}
}

 

step5. 계좌 이체 테스트 

/TestUnit5.java

package test;

import java.sql.SQLException;

import model.AccountDAO;
import model.NotMatchedPasswordException;
import model.AccountNotFoundException;
import model.InsufficientBalanceException;
import model.NoMoneyException;
//step5 계좌이체 테스트 
public class TestUnit5 {
	public static void main(String[] args) {		
			try {
				AccountDAO dao = new AccountDAO();
				dao.transfer("1","1234","2",10000);
				System.out.println("이체 완료");			
			} catch (NoMoneyException e) {
				System.out.println(e.getMessage());
			}  catch (AccountNotFoundException e) {
				System.out.println(e.getMessage());
			} catch (InsufficientBalanceException e) {
				System.out.println(e.getMessage());
			} catch (NotMatchedPasswordException e) {
				System.out.println(e.getMessage());
			}catch (ClassNotFoundException e) {				
				e.printStackTrace();			
			}catch (SQLException e) {				
				e.printStackTrace();
			}
	}
}

 


Common class

: DB에 접근하는데 필요한 variable들을 모아놓은 클래스

 

/DbInfo.java

package common;

public interface DbInfo {
	String DRIVER_NAME="oracle.jdbc.driver.OracleDriver";
	String URL="jdbc:oracle:thin:@127.0.0.1:1521:xe";
	String USER="scott";
	String PASS="tiger";
}

 


DAO ( Data Access Object ) class

: 데이베이스 연동 로직을 정의한 객체

하나의 Connection 내에서 여러 개의 기능을 넣을 수 있다 !

 

/AccountDAO.java

package model;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import common.DbInfo;

public class AccountDAO {
	public AccountDAO() throws ClassNotFoundException {
		Class.forName(DbInfo.DRIVER_NAME);
	}

	private Connection getConnection() throws SQLException {
		return DriverManager.getConnection(DbInfo.URL, DbInfo.USER, DbInfo.PASS);
	}

	public void closeAll(ResultSet rs, PreparedStatement pstmt, Connection con) throws SQLException {
		if (rs != null)
			rs.close();
		if (pstmt != null)
			pstmt.close();
		if (con != null)
			con.close();
	}

	public void closeAll(PreparedStatement pstmt, Connection con) throws SQLException {
		closeAll(null, pstmt, con);
	}

	/**
	 * 계좌를 개설하는 메서드 계좌번호는 시퀀스를 이용해 자동 생성해 입력하고 계좌주명과 비밀번호,초기 납입금을 데이터베이스에 입력한다 
	 * 초기 납입금이 1000원 미만이면 개설하지 않는다.
	 * 
	 * @param vo
	 * @throws CreateAccountException
	 * @throws SQLException
	 */
	public void createAccount(AccountVO vo) throws CreateAccountException, SQLException {
		if (vo.getBalance() < 1000)
			throw new CreateAccountException("초기 납입액은 1000원 이상이어야 합니다!");
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			con = getConnection();
			StringBuilder sql = new StringBuilder();
			sql.append("insert into account_inst(account_no,name,password,balance)");
			sql.append(" values(account_inst_seq.nextval,?,?,?)");
			pstmt = con.prepareStatement(sql.toString());
			pstmt.setString(1, vo.getName());
			pstmt.setString(2, vo.getPassword());
			pstmt.setInt(3, vo.getBalance());
			pstmt.executeUpdate();
		} finally {
			closeAll(rs, pstmt, con);
		}
	}

	/**
	 * 계좌번호와 비밀번호를 입력받아 잔액을 반환하는 메서드 계좌번호가 존재하지 않거나 계좌번호에 따른 비밀번호가 일치하지 않으면 예외를
	 * 발생시킨다.
	 * 
	 * @param accountNo
	 * @param password
	 * @return
	 * @throws SQLException
	 * @throws AccountNotFoundException
	 * @throws NotMatchedPasswordException
	 * 
	 */
	public int getAccountBalance(String accountNo, String password)
			throws SQLException, NotMatchedPasswordException, AccountNotFoundException {
		int balance = -1;
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			con = getConnection();
			String sql = "select password,balance from account_inst where account_no=?";
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, accountNo);
			rs = pstmt.executeQuery();
			if (rs.next()) {
				if (password.equals(rs.getString(1))) { // 비밀번호가 일치하면
					balance = rs.getInt(2);
				} else { // 비밀번호가 일치하지 않으면
					throw new NotMatchedPasswordException("비밀번호가 일치하지 않습니다!");
				}
			} else {// 계좌가 존재하지 않으면
				throw new AccountNotFoundException("계좌가 존재하지 않습니다!");
			}
		} finally {
			closeAll(rs, pstmt, con);
		}
		return balance;
	}

	/**
	 * 입금처리 메서드
	 * 
	 * @param accountNo
	 * @param money
	 * @throws NoMoneyException
	 * @throws SQLException
	 * @throws AccountNotFoundException
	 * @throws NotMatchedPasswordException
	 */
	public void deposit(String accountNo, String password, int money)
			throws NoMoneyException, SQLException, AccountNotFoundException, NotMatchedPasswordException {
		if (money <= 0)
			throw new NoMoneyException("입금액은 0원을 초과해야 합니다!");
		getAccountBalance(accountNo, password);// 계좌 존재유무와 비밀번호 확인 예외처리를 위해 호출한다
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			con = getConnection();
			String sql = "update account_inst set balance=balance+? where account_no=?";
			pstmt = con.prepareStatement(sql);
			pstmt.setInt(1, money);
			pstmt.setString(2, accountNo);
			pstmt.executeUpdate();
		} finally {
			closeAll(rs, pstmt, con);
		}
	}

	/**
	 * 출금 메서드 money는 0 초과 accountNo 존재하고 password 일치해야 한다 balance 보다 money(출금액) 은
	 * 같거나 작아야 한다.
	 * 
	 * @param accountNo
	 * @param password
	 * @param money
	 * @throws NoMoneyException
	 * @throws AccountNotFoundException
	 * @throws SQLException
	 * @throws InsufficientBalanceException
	 * @throws NotMatchedPasswordException
	 */
	public void withdraw(String accountNo, String password, int money) throws SQLException, NoMoneyException,
			InsufficientBalanceException, NotMatchedPasswordException, AccountNotFoundException {
		if (money < 1)
			throw new NoMoneyException("출금액은 0원을 초과해야 합니다");
		int balance = getAccountBalance(accountNo, password);
		if (balance < money)
			throw new InsufficientBalanceException("잔액부족하여 출금할 수 없습니다");
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			con = getConnection();
			String sql = "update account_inst set balance=balance-? where account_no=?";
			pstmt = con.prepareStatement(sql);
			pstmt.setInt(1, money);
			pstmt.setString(2, accountNo);
			pstmt.executeUpdate();
		} finally {
			closeAll(rs, pstmt, con);
		}
	}
	/**
	 * 계좌번호에 해당하는 계좌가 존재하는 지를 조회하는 메서드 계좌가 존재하면 true , 존재하지 않으면 false를 반환한다
	 * 
	 * @param accountNo
	 * @return
	 * @throws SQLException
	 */

	public boolean existAccount(String accountNo) throws SQLException {
		boolean flag = false;
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			con = getConnection();
			String sql = "select count(*) from account_inst where account_no=?";
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, accountNo);
			rs = pstmt.executeQuery();
			if (rs.next() && rs.getInt(1) > 0)
				flag = true;
		} finally {
			closeAll(rs, pstmt, con);
		}
		return flag;
	}
	/**
	 * 이체시 입금받을 메서드 ( 비밀번호 확인 과정이 없음 ) 
	 * @param accountNo
	 * @param money
	 * @throws NoMoneyException
	 * @throws SQLException
	 * @throws AccountNotFoundException
	 * @throws NotMatchedPasswordException
	 */

	public void transferDeposit(String accountNo, int money)
			throws NoMoneyException, SQLException, AccountNotFoundException, NotMatchedPasswordException {
		if (money <= 0)
			throw new NoMoneyException("이체액은 0원을 초과해야 합니다!");
		if (!existAccount(accountNo))
			throw new AccountNotFoundException("이체받을 계좌가 존재하지 않습니다");
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			con = getConnection();
			String sql = "update account_inst set balance=balance+? where account_no=?";
			pstmt = con.prepareStatement(sql);
			pstmt.setInt(1, money);
			pstmt.setString(2, accountNo);
			pstmt.executeUpdate();
		} finally {
			closeAll(rs, pstmt, con);
		}
	}
	/**
	 * 계좌이체 accountNo 에 해당하는 계좌에서 출금하여 otherAccountNo에 해당하는 계좌에 입금하는 메서드 예외상황
	  1.transferMoney가 0 이하일 경우 NoMoneyException 
	  2.accountNo 또는 otherAccountNo가
	     존재하지 않을 경우 AccountNotFoundException
	  3.accountNo 즉 출금계좌 password가 다를 경우
	    NotMatchedPasswordException 4. accountNo 즉 출금계좌의 balance(잔액) 이
	    transferMoney(이체액) 보다 작을 경우 InsufficientBalanceException
	  
	 * @param accountNo
	 * @param password
	 * @param otherAccountNo
	 * @param transferMoney
	 * @throws NoMoneyException
	 * @throws SQLException
	 * @throws AccountNotFoundException
	 * @throws InsufficientBalanceException
	 * @throws NotMatchedPasswordException
	 */
	public void transfer(String accountNo, String password, String otherAccountNo, int transferMoney)
			throws NoMoneyException, SQLException, AccountNotFoundException, InsufficientBalanceException,
			NotMatchedPasswordException {
		if (transferMoney <= 0)
			throw new NoMoneyException("이체액은 0원을 초과해야 합니다!");		
		withdraw(accountNo, password, transferMoney);
		transferDeposit(otherAccountNo, transferMoney);
	}
}

 


Exception class

: 예외상황 발생 시 대안 흐름을 생성하기 위하여 사용

 

1. 계좌가 없을 때 발생하는 예외

/AccountNotFoundException.java

package model;

public class AccountNotFoundException extends Exception {
	private static final long serialVersionUID = -2964134848203606702L;

	public AccountNotFoundException(String message) {
		super(message);		
	}
}

 

2. 계좌 생성 시 발생하는 예외

/CreateAccountException.java

package model;

public class CreateAccountException extends Exception{
	private static final long serialVersionUID = 491332526990042396L;

	public CreateAccountException(String message){
		super(message);
	}
}

 

3. 잔고액에서 출금,송금액을 빼면 -가 되는 경우에 발생하는 예외

/InsufficientBalanceException.java

package model;

public class InsufficientBalanceException extends Exception {
	private static final long serialVersionUID = 2046794047983657245L;

	public InsufficientBalanceException(String message) {
		super(message);
		// TODO Auto-generated constructor stub
	}

}

 

4. 입금/출금/송금액이 0 이하인 경우에 발생하는 예외

/NoMoneyException.java

package model;

public class NoMoneyException extends Exception {
	private static final long serialVersionUID = -4236638528117552246L;

	public NoMoneyException(String message) {
		super(message);
		// TODO Auto-generated constructor stub
	}
}

 

5. 비밀번호가 일치하지 않을 때 발생하는 예외

/NotMatchedPasswordException.java

package model;

public class NotMatchedPasswordException extends Exception{
	private static final long serialVersionUID = 5628642488426527596L;
	public NotMatchedPasswordException(String message){
		super(message);
	}
}

 


VO ( Value Object ) class

: 정보를 저장하고 (계층 간/ 원격으로)전송하기 위한 class

 

/AccountVO.java

package model;

public class AccountVO {
	private String accountNo;
	private String name;
	private String password;
	private int balance;
	public AccountVO() {
		super();		
	}	
	public AccountVO(String name, String password, int balance) {
		super();
		this.name = name;
		this.password = password;
		this.balance = balance;
	}

	public AccountVO(String accountNo, String name, String password, int balance) {
		super();		
		this.accountNo = accountNo;
		this.name = name;
		this.password = password;
		this.balance = balance;
	}
	public String getAccountNo() {
		return accountNo;
	}
	public void setAccountNo(String accountNo) {
		this.accountNo = accountNo;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public int getBalance() {
		return balance;
	}
	public void setBalance(int balance) {
		this.balance = balance;
	}
	@Override
	public String toString() {
		return "AccountVO [accountNo=" + accountNo + ", name=" + name
				+ ", password=" + password + ", balance=" + balance + "]";
	}
	
}
728x90
반응형