
다음과 같은 구조를 만든다.

main
main - BankApp
import dao.BankDAO;
import model.Account;
import java.util.List;
import java.util.Scanner;
public class BankApp {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 디비한테 데이터를 요청할 때는 /뒤에 식별자를 쓴다.
// http://bank.com/account GET 계좌 전체 줘
// http://bank.com/account/10 GET 10번(프라이머리키) 계좌 줘
// http://bank.com/account POST 계좌를 만드는 것!
// -> 이 정보만으로는 포스트 못 함
// http://bank.com/account/1 DELETE 1번(프라이머리키) 계좌 삭제해 줘!
// http://bank.com/account/1 PUT
// -> 이 정보만으로는 풋 못 함
// 겟 딜리트 요청은 http에 바디가 없다.
// 포스트, 풋 요청은 http에 바디가 없다.
// 풋, 딜리트, 업데이터는 write요청이다. -> 응답에 바디가 없다. 오케이만 해주면 됨.
System.out.println("http 메서드를 입력하세요");
String method = sc.nextLine();
System.out.println("식별자를 입력하세요");
String action = sc.nextLine();
String body = "";
BankDAO bankDAO = new BankDAO();
// GET: 조회
if (method.equalsIgnoreCase("GET")) {
if (action.equalsIgnoreCase("/account")) {
List<Account> accountList = bankDAO.selectAll();
System.out.println(accountList);
} else if (action.contains("/account/")) {
String[] actionSpl = action.split("/");
String actionNumStr = actionSpl[2];
int actionNum = Integer.parseInt(actionNumStr);
Account account = bankDAO.selectByNumber(actionNum);
System.out.println("account: " + account);
}
}
// POST: 입력
else if (method.equalsIgnoreCase("POST")) {
if (action.equalsIgnoreCase("/account")) {
System.out.println("body 데이터를 입력하세요.");
body = sc.nextLine();
System.out.println("/account 입력됨");
String[] step1 = body.split("&");
String password = step1[0].split("=")[1];
String balanceStr = step1[1].split("=")[1];
int balance = Integer.parseInt(balanceStr);
int account = bankDAO.insert(password, balance); // 왜 int로 해야 되는거지?
}
}
// PUT: 수정
else if (method.equalsIgnoreCase("PUT")) {
if (action.equalsIgnoreCase("/account")) {
System.out.println("body 데이터를 입력하세요"); // balance=70000000&number=3
body = sc.nextLine();
String[] step1 = body.split("&");
String balanceStr = step1[0].split("=")[1];
int balance = Integer.parseInt(balanceStr);
// number 찾기
String numberStr = step1[1].split("=")[1];
int number = Integer.parseInt(numberStr);
int account = bankDAO.updateByNumber(balance, number);
}
}
// DELETE: 삭제
else if (method.equalsIgnoreCase("DELETE")) {
if (action.equalsIgnoreCase("/account")) {
System.out.println("삭제하고 싶은 번호를 입력하세요.");
int deleteNum = sc.nextInt();
int account = bankDAO.deleteByNumber(deleteNum);
}
}
}
}
main - dao-BankDAO
package dao;
// 데이터 베이스에 접근하기 위한 데이터 액세스 오브젝트를 만든다. 전 세계 공통!!
import db.DBConnection;
import lombok.AllArgsConstructor;
import model.Account;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* Controller: 안내원, 라우터
* DAO: Data Access Object, 데이터베이스와 상호작용 하는 책임만 가지고 있다.
* SRP: 단일 책임의 원칙
*/
public class BankDAO {
public int deleteByNumber(int number) {
/**
* 1. 디비 소켓 가져오기
* 2. 버퍼에 쿼리 담기
* 3. 쿼리 전송
* 4. 결과 리턴
*/
Connection conn = DBConnection.getInstance(); // getInstance()는 스테이틱 메서드이기 때문에 이렇게 부를 수 있어.
try {
String sql = "delete from account_tb where number = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
// delete
pstmt.setInt(1, number);
int num = pstmt.executeUpdate(); // flush();
return num;
} catch (SQLException e) {
e.printStackTrace();
}
return -1;
}
public int insert(String password, int balance) {
Connection conn = DBConnection.getInstance();
try {
String sql = "insert into account_tb(password, balance, created_at) values(?, ?,now())";
PreparedStatement pstmt = conn.prepareStatement(sql); // 코드는 다르지만 얘가 버퍼임
// 연결된 선에다가 버퍼를 달고 쿼리를 넣는다. 그런데 그 쿼리가 완성되지 않았어.
// insert
pstmt.setString(1, password); // 몇 번째 파라미터를 완성할거냐. 1, 2, 3,... 0이 없음
pstmt.setInt(2, balance); // 몇 번째 파라미터를 완성할거냐. 1, 2, 3,... 0이 없음
int num = pstmt.executeUpdate(); // flush();
return num;
} catch (SQLException e) {
e.printStackTrace();
}
return -1;
}
public int updateByNumber(int balance, int number) {
Connection conn = DBConnection.getInstance();
try {
String sql = "update account_tb set balance = ? where number = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
// update
pstmt.setInt(1, balance);
pstmt.setInt(2, number);
int num = pstmt.executeUpdate(); // flush();
return num;
} catch (SQLException e) {
e.printStackTrace();
}
return -1;
}
public Account selectByNumber(int number) { // 계좌번호는 프라이머리키이기 때문에 하나만 있으니까 클래스에 담에서..... 요런 느낌.
Connection conn = DBConnection.getInstance();
try {
String sql = "select * from account_tb where number =?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, number);
ResultSet rs = pstmt.executeQuery(); // ResultSet: 테이블 형태의 데이터
// Account rs = pstmt.executeQuery(); // 로 하지 않은 이유!! 뭐가 어떻게 만들어질지 알고? 일단 ResultSet으로 받아야 한다.
// boolean isRow = rs.next(); // 커서 한 칸 내리기, boolean이다. 커서를 내렸는데 뭐가 있으면 true, 없으면 false
// System.out.println(isRow);
while (rs.next()){
// Account 클래스에 담는다. 그러지 않으면 테스트코드에서 또 rs어쩌구 해야함.
// 계좌가 최초로 생성될 때는 생성자로 아래의 값들을 만든다.
Account account = new Account(
rs.getInt("number"),
rs.getString("password"),
rs.getInt("balance"),
rs.getTimestamp("created_at")
);
return account;
}
// // 커서를 한 칸 옆으로 옮기는 것! 프로젝션: 컬럼을 골라내는 것
// System.out.println(rs.getInt("number"));
// System.out.println(rs.getString("password"));
// System.out.println(rs.getInt("balance"));
// System.out.println(rs.getTimestamp("created_at"));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public List<Account> selectAll() {
Connection conn = DBConnection.getInstance();
try {
String sql = "select * from account_tb order by number desc"; // 디폴트는 오름차순, 최근에 만든 것부터 보려면 내림차순! order by number desc 해줘야 함.
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery(); // ResultSet: 테이블 형태의 데이터
/**
* 와일문을 돌면 어카운트가 하나씩 만들어지는데 그것을 add하면 account는 이미 담겼기 때문에 지워져도 되지만 어카운트리스트는 계속 새로 만들어지면 안 됨.
*/
List<Account> accountList = new ArrayList<>();
while (rs.next()){
// Account 클래스에 담는다. 그러지 않으면 테스트코드에서 또 rs어쩌구 해야함.
// 계좌가 최초로 생성될 때는 생성자로 아래의 값들을 만든다.
Account account = new Account(
rs.getInt("number"),
rs.getString("password"),
rs.getInt("balance"),
rs.getTimestamp("created_at")
);
accountList.add(account);
}
return accountList;
// // 커서를 한 칸 옆으로 옮기는 것! 프로젝션: 컬럼을 골라내는 것
// System.out.println(rs.getInt("number"));
// System.out.println(rs.getString("password"));
// System.out.println(rs.getInt("balance"));
// System.out.println(rs.getTimestamp("created_at"));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
main - db - DBConnection
package db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBConnection {
public static Connection getInstance(){
String username = "root";
String password = "1234";
String url = "jdbc:mariadb://127.0.0.1:3306/cosdb2";
// 프로토콜이 적용된 소켓
try {
Connection conn = DriverManager.getConnection(url, username, password);
System.out.println("db connect success");
return conn;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
main - model - Account
package model;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
import java.sql.Timestamp;
/**
* DB에 select 한 데이터를 담기 위한 오브젝트
*/
@ToString
@AllArgsConstructor // 모든 생성자를 자동으로 만들어 준다.
@Getter
public class Account {
private int number;
private String password;
private int balance;
// java.sql의 Timestamp
// 카멜표기법 사용하기
private Timestamp createdAt;
// 데이터에서 create_at이라고 되어 있지만 createAt으로 해야함.
}
test
test - dao - BankDAOTest
package dao;
import db.DBConnection;
import model.Account;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
public class BankDAOTest {
@Test
public void deleteByNumber_test() {
// given
int number = 100;
// when
BankDAO dao = new BankDAO();
int result = dao.deleteByNumber(number);
// then
if (result == 1) {
System.out.println("삭제 성공");
} else if (result == 0) {
System.out.println(number + "번호를 찾을 수 없습니다.");
} else {
System.out.println("삭제 실패");
}
}
@Test
public void insert() {
// given
String password = "1234";
int balance = 5000;
// when
BankDAO dao = new BankDAO();
int result = dao.insert(password, balance);
// then
if (result == 1) {
System.out.println("삽입 성공");
} else if (result == 0) {
System.out.println("password를 확인해 주세요.");
} else {
System.out.println("삽입 실패");
}
}
@Test
public void updateByNumber_test() {
// given
int balance = 7000;
int number = 1;
// when
BankDAO dao = new BankDAO();
int result = dao.updateByNumber(balance, number);
// then
if (result == 1) {
System.out.println("업데이트 성공");
} else if (result == 0) {
System.out.println("계좌번호를 확인해 주세요.");
} else {
System.out.println("업데이트 실패");
}
}
@Test
public void selectByNumber_test() {
// given
int number = 3;
// when
BankDAO dao = new BankDAO();
Account account = dao.selectByNumber(number);
// then
if (account == null) {
System.out.println("조회된 값이 없습니다.");
} else {
System.out.println(account); // @ToString를 써서 자동으로 투스트링 만들어짐.
// System.out.println(account.getNumber());
// System.out.println(account.getPassword());
// System.out.println(account.getBalance());
// System.out.println(account.getCreatedAt());
}
}
@Test
public void selectAll_test() {
// given
// when
BankDAO dao = new BankDAO();
List<Account> accountList = dao.selectAll();
System.out.println(accountList.size());
// then
}
}
test - db - DBConnectionTest
package db;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBConnectionTest {
@Test
public void getInstance_test() {
// given: 파라미터(테스트에는 파라미터를 못 적는다. 그래서 여기서 파라미터를 쓴다?)
// when: 본코드 실행, 본코드의 메서드를 바로 호출한다.
Connection conn = DBConnection.getInstance(); // 리턴되는 값 conn
// then: 눈 검증
if(conn ==null){
System.out.println("실패");
} else {
System.out.println("성공");
}
}
}
Share article