저번에는 미니프로젝트에 사용할 DB를 만들고 마무리 했었다.
오늘은 Model에 VO클래스 (데이터를 담는 클래스) 부터 진행하도록 하겠다.
private int cpuNO; //DB에 기본 키 값
private String cpuName; //CPU 이름
private int cpuCinebench; //CPU의 시네벤치(멀티) 테스트점수
private String cpuBaseclock; //CPU의 베이스 클럭
private String cpuBoostclook; //CPU의 부스트 클럭
private String cpuPowerusage; //CPU의 최대 사용전력
private Date cpuRelease; //CPU출시일
private int cpuPrice; //CPU가격(현재가)
private String cpuMfrName; //CPU 제조사 (AMD,INTEL)
private String cpuSocket; //CPU 제조사에 따른 소켓이름 EX) AM4,,, 1700...
private int cpuStock; //CPU재고
먼저 기본적인 필드를 작성해준다.
그리고 기본적인 세팅으로 생성자, toString, getter/setter도 만들어준다.
public CPU(String cpuName, int cpuCinebench, String cpuBaseclock, String cpuBoostclook,
String cpuPowerusage, int cpuPrice, String cpuMfrName, String cpuSocket, int cpuStock, Date cpuRelease) {
super();
this.cpuName = cpuName;
this.cpuCinebench = cpuCinebench;
this.cpuBaseclock = cpuBaseclock;
this.cpuBoostclook = cpuBoostclook;
this.cpuPowerusage = cpuPowerusage;
this.cpuRelease = cpuRelease;
this.cpuPrice = cpuPrice;
this.cpuMfrName = cpuMfrName;
this.cpuSocket = cpuSocket;
this.cpuStock = cpuStock;
}
@Override
public String toString() {
return "고유번호 : " + cpuNO + ", CPU 이름 : " + cpuName + ", CPU 성능테스트 점수 : " + cpuCinebench + ", CPU 베이스 클럭 : "
+ cpuBaseclock + ", CPU 부스트 클럭 : " + cpuBoostclook + ", \nCPU 사용전력 : " + cpuPowerusage
+ ", CPU 출시일 : " + cpuRelease +", CPU 가격 : " + cpuPrice + ", CPU 제조회사 : " + cpuMfrName
+ ", CPU 소켓 : " + cpuSocket + ", CPU 재고 : " + cpuStock + "\n\n";
}
public final int getCpuNO() {
return cpuNO;
}
public final void setCpuNO(int cpuNO) {
this.cpuNO = cpuNO;
}
...
코드가 너무 길어질 수 있으니 get/set 코드들은 전부 올리지 않았다.
마찬가지로 VGA(그래픽카드에 대한 클래스도 만들었다)
private int vgaNo;
private String vgaName;
private String vgaBaseclock;
private String vgaBoostclock;
private String vgaPowerusage;
private int vgaPrice;
private String vgaMfrName;
private int vgaStock;
private String vgaZerofan;
private Date vgaRelease;
똑같이 사용하기 위해 기본적인 세팅 (생성자와 toString, get/set을 만들어주고)
public VGA(String vgaName, String vgaBaseclock, String vgaBoostclock, String vgaPowerusage, int vgaPrice,
String vgaMfrName, int vgaStock, String vgaZerofan, Date vgaRelease) {
super();
this.vgaName = vgaName;
this.vgaBaseclock = vgaBaseclock;
this.vgaBoostclock = vgaBoostclock;
this.vgaPowerusage = vgaPowerusage;
this.vgaPrice = vgaPrice;
this.vgaMfrName = vgaMfrName;
this.vgaStock = vgaStock;
this.vgaZerofan = vgaZerofan;
this.vgaRelease = vgaRelease;
}
@Override
public String toString() {
return "VGA 고유번호 : "+vgaNo + ", VGA 이름 : " + vgaName + ", VGA 베이스 클럭 : " + vgaBaseclock + ", VGA 부스트 클럭 : "
+ vgaBoostclock + ", VGA 사용전력 : " + vgaPowerusage + ",\n VGA 출시일 : " + ", VGA 가격 : "
+ vgaPrice + ", VGA 제조회사 : " + vgaMfrName + ", VGA 재고 "+vgaStock + ", 제로팬 기능여부 : " +vgaZerofan+"\n\n";
}
public int getVgaNo() {
return vgaNo;
}
public void setVgaNo(int vgaNo) {
this.vgaNo = vgaNo;
}
마찬가지로 get/set은 전부 올리지 않았다.
클래스의 소개는 이렇다
VO (데이터 보관 담당)클래스 : CPU, VGA
데이터 컨트롤, 사용자의 요청을 담당하는 : Controller
실질적으로 DB와 소통하는 유일한 클래스 : Dao
여러가지 자주 사용하는 메서드를 모아놓은 temp 클래스
사용자에게 보여지는 View를 담당하는 Menu 클래스
시작은 Menu클래스부터 구현해보자!
Scanner sc = new Scanner(System.in);
Controller c = new Controller();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); //sql에 데이터를 입력받기 위해 사용하는 메소드
temp t = new temp();
Dao d = new Dao();
public void mainMenu() { //손님과 관리자를 구분하는 메인메뉴
while(true) {
System.out.println("환영합니다, 컴퓨터가게 입니다.");
System.out.println("1. 손님");
System.out.println("2. 관리자");
System.out.println("9. 종료");
int menu = sc.nextInt();
sc.nextLine();
switch(menu) {
case 1:
this.customerMenu();
break;
case 2:
this.masterMenu();
break;
case 9:
System.out.println("시스템 종료");
return;
default:
System.out.println("잘못 입력하셨습니다. 다시 입력해주세요");
break;
}//end switch
}//end while
}//end mainMenu
제일 먼저 보여지는 메인 메뉴이다.
손님과 관리자를 분리시켜주는 역할을 하는 갈림길이다. case 1 = 손님메뉴로 갔을 때를 봐보자
# case 1 손님메뉴
public void customerMenu() {
while(true) {
System.out.println("손님 메뉴입니다.");
System.out.println("1. 컴퓨터 부품 구매");
System.out.println("2. 구매내역 삭제");
System.out.println("3. 장바구니 확인");
System.out.println("9. 종료");
int menu = sc.nextInt();
sc.nextLine();
switch(menu) {
case 1:
this.buyMenu();
break;
case 2:
break;
case 3:
break;
case 9:
System.out.println("이전 메뉴로");
break;
default:
System.out.println("잘못 입력하셨습니다. 다시 입력해주세요");
break;
}//end switch
}//end while
}//end customerMenu
손님메뉴에서 구현할 것은 세가지이다.
컴퓨터 부품을 구매하고 구매내역을 삭제하고 장바구니를 확인하는 것이다.
비어있는건 아직 미구현이기 때문에 case 1인 컴퓨터 부품 구매 클래스를 보자
#case 1 , #case 1
컴퓨터 부품 구매를 누르면 나오게되는 메뉴이다.
public void buyMenu() {
while(true) {
System.out.println("구매 메뉴입니다. 구매하실 부품을 골라주세요");
System.out.println("1. CPU");
System.out.println("2. VGA");
System.out.println("3. Mainboard");
System.out.println("9. 이전 메뉴로");
int menu = sc.nextInt();
sc.nextLine();
switch(menu) {
case 1:
t.buyParts("CPU");
break;
case 2:
t.buyParts("VGA");
break;
case 3:
break;
case 9:
System.out.println("이전 메뉴로");
break;
default:
System.out.println("잘못 입력하셨습니다. 다시 입력해주세요");
break;
}//end switch
}//end while
}//end buyMenu
여기서 1번을 선택하게 되면 CPU라는 String이 자동으로 넘어가고 실제적으로 구매하는 buyParts 메소드를 호출한다.
temp 클래스의 buyParts메소드
public void buyParts(String name) { //인자로 방금 넣어놨던 "CPU"를 받아온다.
switch(name) {
case "CPU":
c.selectCpu();
break;
case "VGA":
c.selectVga();
break;
}
System.out.print("구매하실 "+ name +"의 고유 번호를 입력해주세요 : ");
int index = sc.nextInt();
sc.nextLine();
System.out.print("구매하실 수량을 입력해주세요 : ");
int amount = sc.nextInt();
sc.nextLine();
if(amount >d.selectVga().get(0).getVgaStock()) { //DB에서 재고 값을 가져옴
System.out.println("\n재고가 부족하여 구매할 수 없습니다. 다시 입력해주세요.\n");
}else {
updateOfBuy(name, index, amount);
}
}//end buyParts
방금 입력한 1번은 CPU이고 2번은 VGA였다 무엇을 누르냐에 따라서 내가 보여 줄 값이 다르게 나오게 된다.
데이터베이스에서 재고 값을 가져와 내가 구매하려는 amount보다 재고가 적으면 구매 불가 메세지가 나온다.
재고가 있다면 마지막에 호출되는 updateOfBuy로 이동한다.
updateOfBuy 입력된 값에 따라서 Controller에 요청을 보내는 메소드, 우린 CPU 문자열을 넣어놨으니 c.buyCPU로 이동하게된다.
public void updateOfBuy(String name, int index, int amount) {
switch(name) {
case "CPU":
c.buyCPU(index, amount);
break;
case "VGA":
c.buyVGA(index, amount);
break;
}
}
Controller의 buyCPU 메소드
public void buyCPU(int index, int amount) {
int result = new Dao().buyCPU(index, amount); //index는 CPU의 고유번호, amount는 구매수량
if(result > 0) {
System.out.println("\n"+amount + "개 구매 완료되었습니다.");
}else {
System.out.println("구매에 실패했습니다.(수량이 아닌 다른 이유)");
}
}
여기서는 원래 객체로 데이터를 가공하여 Dao로 보내 DB와 직접 통신을 하게 되어있다.
하지만 기능이 단순 구매니까 DB의 재고 컬럼값만 바꿔주면 되기에 객체로 만들지는 않았다.
이 다음 코드를 예측해보자. int result는 Dao로 보내서 실행한 결과이고 실행한 DB쿼리는 UPDATE문이다.
그렇다면 우리는 반환값으로 int형 즉 쿼리가 성공적으로 실행됐다면 반환되는 메세지 = 무조건 한 줄 이상이 반환되기에 result가 0보다 크다면 DB에 성공적으로 반영됐다는 의미가 된다.
그 반대로 쿼리를 실행했지만 한 줄도 반환되지 않아 result가 0줄이 된다면 그건 DB에 반영되지 않았다는 뜻이다. = 실패
(논리오류 발생)
그럼 new Dao().buyCPU(index, amount)의 buyCPU로 이동해보자
Dao 의 buyCPU (DB와 직접 연결하여 쿼리를 주고 받는 곳)
public int buyCPU(int index, int amount) {
int result = 0;
Connection conn = null;
PreparedStatement pstmt = null;
int stock = this.selectCpu().get(0).getCpuStock(); //DB에서 재고수량을 가져오는 것
String sql = "UPDATE CPUCCC "
+ "SET C_Stock = ? "
+ "WHERE C_NO = ?";
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "DDD", "DDD");
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, stock - amount);
pstmt.setInt(2, index);
result = pstmt.executeUpdate();
if(result >0) {
conn.commit();
}else {
conn.rollback();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return result;
}
저번에 공부하여 포스팅 했던 JDBC 의 형태와 거의 흡사하다고 볼 수 있다.
처음에 성공여부를 판단할 result (성공시 한 줄 이상 반환) 과 연결에 필요한 Connection, PreparedStatement 객체를 만들어주고 세팅 한 후 DB에서 재고수량을 가져와 Stock에 저장해주고 그 값을 sql문에 얹어서 보낸다. index 값은 where에 들어가서 특정한 CPU만 재고값을 변경해주는 역할을 한다.
여기서도 성공시 한 줄 이상이 반환되는 것을 이용해 if문으로 commit을 만들어 놓았다.
정상적으로 성공했다면 result는 1 이상의 값을 가지고 리턴하여 Controller로 돌아가서 성공했다는 문장을 출력하게 될 것이다.
위 실행결과이다.
간략한 후기.
재밌다. 아직 초보라 오류도 많이뜨고 시간도 좀 걸렸지만 잡히지않던 오류를 해결하고 내가 만든 기능이 실행됐을 때의 도파민이 폭발하는 느낌은 표현하기 어렵다.
아직 구현한 것이 많이 남아있기 때문에 다음 포스팅에 이어서 작성해보도록 하겠다.
이렇게 혼자서 구현하다보니,
아 이건 나중에 좀 더 좋은 방법으로 할 수 있겠구나
아 이런건 메소드로 빼서 코드 재활용성을 높일 수 있겠구나
이건 이렇게 짜기보다 중복되는 건데 .. 리팩토링할 때 바꿔야겠구나
이런 생각들이 많이 들고 보이기 시작했다.
'미니프로젝트' 카테고리의 다른 글
간단한 홈페이지 만들어보기 (0) | 2024.03.28 |
---|---|
[초미니프로젝트] 3일차 (0) | 2024.03.04 |
[초미니프로젝트] 1일차 (0) | 2024.03.02 |