소규모의 팀프로젝트를 진행하기에 앞서, 프로젝트 전 알아두어야할 내용에 대한 정리에 대해 알아보았다. 추가로 웹크롤링을 하게 되면 두개 이상의 TableDB가 생기기 마련이다. 이때 각 테이블마다 모델(VO, DAO)가 한개씩 필요하게 되는데, 오늘은 두개의 테이블(DAO)로 작업하는 예시와 이전 내용까지의 정리를 담은 내용에 대해 포스팅 하였다.
1. 이전내용 복습
1) VO
: 멤버변수, gettter&setter, 생성자, toString로 필드가 구성되어있다. 이외에 추가되는 사항은 없도록 한다.
이때 생성자는 기본생성자를 사용할 예정이며, 자동으로 전달되는 구조이기 때문에 멤버변수가 초기화되지 않는다. 기본생성자에 setter를 더하여 새로 생성해주면 이 점의 보완이 가능하다. 이때 VO의 역할은 자료형이다. 내가 사용할 데이터의 타입의 정의한다. 즉, 다른 프로그램의 데이터(tableDB, Element<>)들을 java코드에서 다룰 수있도록 해주는 역할을 한다.
2) VO생성위치
: 샘플데이터 처리시의 VO생성 위치에 주의한다. 데이터가 넘어올때마다 초기화가 진행되어야하므로 위에서 while문 안에 들어가 있는 것을 확인할 수 있다.
3) itr의 특징
: 다음칸을 가리키며 이동하다보니 next가 되는 만큼 칸을 이동하므로, 필요 이상으로 남용되지 않도록 유의한다. 칸의 이동에 대한 설명은 이 게시글에 올 때까지 여러번 언급된 내용이기에 자세한 설명은 생략한다.
4) excute의 수행회수
: 반복문(for : each)에 담아 datas가 반복되는 만큼 수행회수를 지정한다.
5) Controller
: 컨트롤러의 생성과 동시에 dao와 view의 객체를 함께 생성하도록 작업하는데, 이는 컨트롤러의 생성자를 통해 가능하다. 컨트롤러가 하는 역할로는 입력값에 따른 분기처리(main에서 1을 누르면 목록조회 등)를 진행하고, 사용자가 요청한 데이터를 받아오고, 사용자가 요청한 화면을 보여준다.
6) Model
: CRUD수행을 위해 인자로 VO를 필수로 받아야하며, VO를 주기 위해서는 각 범위에서(핵심로직 내부에서) VO의 초기화가 필요하다. 이때, View에서 사용자가 입력한 데이터를 VO에 setter해주어야 핵심로직에 사용자의 요구가 전달된다.
샘플데이터는 프로그램이 동작할때 딱 한 번만 저장되어야하는데, DB에 연결될 예정이므로 DAO에서 구현하는것이 유리하다.
① DAO에 단 한번 호출되는 메서드를 구현(ex. startModel( ))
② DAO의 생성자에서 구현
2. 배경지식
: 설계에 들어가기 전 해당 내용을 알아두어야 설계를 진행함에 있어 무리가 없다. 우선 설계에 앞서 구현할 코드의 주제를 정하고, 그에 맞는 샘플데이터를 웹크롤링을 통해 찾아두는것이 좋다. 이때, 샘플데이터는 위의 설명처럼 DAO에서 구현하는 것이 유리함을 유의한다. 설계단계에서는 ERD, UF, LP에 대한 내용이 필수로 들어가야 하는데, 아래에서 구체적으로 알아볼 수 있도록 하였다.
내용을 확실히 파악할 수 있도록 정돈된 블로그의 링크를 각각 첨부하였다.
① ERD : ( model의 요약도 )
https://mjn5027.tistory.com/43
② UF : ( view의 요약도 )
https://brunch.co.kr/@b30afb04c9f54dc/25
③ LP : ( controller의 요약도 )
: 상단에서 언급되는 "업무 기능 분해"는 UF에 해당하고, "단위프로세스의 도출"부분이 LP에 해당한다. 허나 제대로 이해하기 위해서는 전체적으로 훑어보는 과정이 필요하다.
http://www.gurubee.net/lecture/3755
3. 실습예제
: 두개의 TableDB(DAO)를 활용하여 MVC를 나누는 방법에 대한 대략적인 예시일 뿐이라, 크롤링의 작업은 생략되었다.
1) 설계
① ERD : 데이터의 구성
- 회원
- 회원번호(pk)
- 이름
- 포인트
- 상품
- 상품번호(pk)
- 이름
- 가격
- 재고
② UF : 업무 기능의 분해
- 로그인 페이지 : 회원 id를 입력받음
- 로그인 실패 페이지 : 로그인에 실패하였습니다. 다시시도해보세요.
- 로그인 성공 페이지 : main
- 상품목록
- 상품구매 : 상품의 선택(select)후 존재한다면 구매(update)진행
- 구매 실패 페이지 : 상품 미존재 혹은 재고 부족시
- 구매 성공 페이지(포인트 부여)
- 페이지 나가기 : 로그인 페이지로 이동
③ LP : 기능의 "흐름"에 초점을 두어 로직 프로세스 도출
- UserDAO
- selectOne( ) select * from user where id=? "해당 아이디가 있는가?"
- update( ) update set user point=point+? where id=? "해당 아이디에 몇 포인드가 부여되는가?"
- ProductDAO
- selectAll( ) select * from product "목록조회"
- update( ) update set product cnt=cnt-1 where id=? "입력받은 id에 해당하는 상품의 cnt=cnt-1"
2) 구현
① TableDB & UtillClass & VO 생성
: 두개의 VO를 생성한다.
- TableDB
--내 프로그램에 존재하는 전체 테이블 조회-- select * from user_tables; --테이블 생성-- create table mem( id varchar(15) primary key, name varchar(15) not null, point int default 0 ); --초기 데이터 삽입-- insert into mem values('asdf', '김길동', 200); insert into mem(id, name) values('qwere', '박또치'); --삽입 확인-- select * from mem; --테이블 생성-- create table product( id int primary key, name varchar(50) not null, price int, cnt int default 0 ); --초기 데이터 삽입-- insert into product values(1001, '신발', 30000, 5); insert into product values(1002, '바지', 15000, 2); insert into product values(1003, '나시', 5000, 10); --삽입확인-- select * from product;
- Utill Class
package model; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; // 공통되는 로직을 따로 관리하기 위한 클래스 public class JDBCUtill { //static변수를 사용하여 자원으로 선언 static final String driverName="oracle.jdbc.driver.OracleDriver"; static final String url="jdbc:oracle:thin:@localhost:1521:xe"; static final String user="ham"; static final String passwd="1234"; // DB에 연결 == connection 확보하기에 ouput으로 설정 public static Connection connect() { Connection conn = null; try { Class.forName(driverName); conn=DriverManager.getConnection(url, user, passwd); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return conn; } // conn, stmt 닫는 메서드 public static void disconnect(PreparedStatement pstmt, Connection conn) { try { pstmt.close(); conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
- MemVO
package model; public class MemVO { private String id; private String name; private int point; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPoint() { return point; } public void setPoint(int point) { this.point = point; } @Override public String toString() { return "[" + id + "] " + name + "님, 현재 포인트는" + point + "점 입니다."; } }
- ProductVO
package model; public class ProductVO { private int id; private String name; private int price; private int cnt; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public int getCnt() { return cnt; } public void setCnt(int cnt) { this.cnt = cnt; } @Override public String toString() { return "[" + id + "] " + name + price + "원 | " + cnt + "개"; } }
② DAO 생성
: 두개의 DAO를 생성한다.
- MemDAO
package model; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class MemDAO { Connection conn; PreparedStatement pstmt; final String sql_selectOne = "select * from mem where id=?"; final String sql_update = "update mem set point=point+? where id=?"; // 로그인 public MemVO selectOne(MemVO vo) { MemVO data = null; conn = JDBCUtill.connect(); try { pstmt=conn.prepareStatement(sql_selectOne); pstmt.setString(1, vo.getId()); ResultSet rs = pstmt.executeQuery(); //로그인에 성공했다면, if(rs.next()) { data = new MemVO(); data.setId(rs.getString("id")); data.setName(rs.getString("name")); data.setPoint(rs.getInt("point")); } rs.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { JDBCUtill.disconnect(pstmt, conn); } return data; } // 해당 아이디에 포인트 부여 public boolean update(MemVO vo) { // VO는 추가될포인트, 현재 로그인한 멤버정보를 가지고 있다. conn = JDBCUtill.connect(); try { pstmt=conn.prepareStatement(sql_update); pstmt.setInt(1, vo.getPoint()); pstmt.setString(2, vo.getId()); int res=pstmt.executeUpdate(); //로그인에 성공했다면, if(res==0) { System.out.println("dao: 해당데이터 없음"); return false; } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); return false; } finally { JDBCUtill.disconnect(pstmt, conn); } return true; } }
- ProductDAO
package model; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; public class ProductDAO { Connection conn; PreparedStatement pstmt; final String sql_selectAll = "select * from product"; final String sql_update = "update product set cnt=cnt-1 where id=?"; final String sql_selectOne = "select * from product where id=?"; // 목록조회 public ArrayList<ProductVO> selectAll(ProductVO vo) { ArrayList<ProductVO> datas = new ArrayList<ProductVO>(); conn = JDBCUtill.connect(); try { pstmt=conn.prepareStatement(sql_selectAll); ResultSet rs = pstmt.executeQuery(); while(rs.next()) { ProductVO data = new ProductVO(); data.setId(rs.getInt("id")); data.setName(rs.getString("name")); data.setPrice(rs.getInt("price")); data.setCnt(rs.getInt("cnt")); datas.add(data); } rs.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { JDBCUtill.disconnect(pstmt, conn); } return datas; } // 상품 선택 후 구매:트랜잭션 public boolean update(ProductVO vo) { conn = JDBCUtill.connect(); try { conn.setAutoCommit(false); pstmt=conn.prepareStatement(sql_update); pstmt.setInt(1, vo.getId()); int res=pstmt.executeUpdate(); //pk가 들어갔다면 구매 성공 if(res==0) { System.out.println("dao: 해당데이터 없음"); return false; } pstmt=conn.prepareStatement(sql_selectOne); pstmt.setInt(1, vo.getId()); ResultSet rs = pstmt.executeQuery(); rs.next(); if(rs.getInt("cnt") < 0) { //cnt-? < 0일때 System.out.println("dao로그 : 사용자구매실패"); conn.rollback(); } else { System.out.println("dao로그 : 사용자구매성공"); conn.commit(); } conn.commit(); System.out.println("dao:사용자 구매 성공"); conn.setAutoCommit(true); rs.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); return false; } finally { JDBCUtill.disconnect(pstmt, conn); } return true; } }
③ view 생성
package view;
import java.util.ArrayList;
import java.util.Scanner;
import model.ProductVO;
public class PView {
Scanner sc = new Scanner(System.in);
String menuMsg = "1. 목록조회 \n2. 상품구매 \n3. 서비스나가기";
//회원번호 입력
public String inputMem () {
System.out.println("로그인할 아이디 입력 : ");
String id = sc.next();
return id;
}
public void printNoMem() { //회원 미존재
System.out.println("존재하지 않는 아이디입니다. 다시 시도하세요.");
}
public int printMenu() { //회원 존재
System.out.println("===메뉴===");
System.out.println(menuMsg);
System.out.println("=========");
int act = sc.nextInt();
return act;
}
// 상품 목록출력
public void printList(ArrayList<ProductVO> datas) {
for(ProductVO v : datas) {
System.out.println(v);
}
}
// 상품 선택 후 구매
public int selectPro() {
System.out.print("구매할 상품번호입력>>> ");
int id=sc.nextInt();
return id;
}
public void printPro() { //구매 성공
System.out.println("상품구매를 완료하였습니다!");
}
public void printNoPro() { //구매 실패
System.out.println("상품구매에 실패했습니다. 잠시후 다시 시도해주세요.");
}
// 서비스 종료 페이지
public void printEnd() {
System.out.println("이용해주셔서 감사합니다.");
}
}
④ Controller생성
: 주석을 꼼꼼히 살필 필요가 있다.
package controller;
import java.util.ArrayList;
import java.util.Random;
import model.MemDAO;
import model.MemVO;
import model.ProductDAO;
import model.ProductVO;
import view.PView;
public class PController {
// 두 DAO & view 객체화
MemDAO mdao;
ProductDAO pdao;
PView view;
public PController() {
mdao=new MemDAO();
pdao=new ProductDAO();
view=new PView();
}
public void startApp() {
while(true) {
// view에서 정보를 넣어주면 그게 멤버의 id
// view.inputMem을 하면 output으로 String id나옴
// 그걸 mid에 저장해서 사용
String mid=view.inputMem();
MemVO mvo = new MemVO();
mvo.setId(mid);
mvo = mdao.selectOne(mvo);
// 회원정보 없음
if(mvo==null) {
view.printNoMem();
continue; // 없으면 처음으로!
}
//로그인 성공!
while(true) {
// view에서 정보를 넣어주면 그게 act
int act = view.printMenu();
if(act==1) {
//밑에서 위로 작업! 필요한거순으로 생성하며 나열하기
ProductVO pvo = new ProductVO();
ArrayList<ProductVO> datas = pdao.selectAll(pvo);
view.printList(datas);
}else if(act==2) {
int pid = view.selectPro();
ProductVO pvo = new ProductVO();
pvo.setId(pid);
if(!pdao.update(pvo)) {
// 구매실패
view.printNoPro();
continue;
}
//구매성공 페이지(point제공)
//★★★★★★★★★★★★★★
//★이미 존재하는 객체에 대해 유의 ★
//★★★★★★★★★★★★★★
// 이 경우 mvo는 이미 상단에 존재한다.
//(로그인이 성공한 멤버의 id값)
// 따라서 초기화를 진행할 필요가 없다.
// 허나 포인트의 입력은 필요하기에 여기에서 랜덤으로 set해주기!
mvo.setPoint(new Random().nextInt(10)+1);
if(mdao.update(mvo)) {
System.out.println("성공");
}else {
System.out.println("실패");
}
}else if(act==3) {
view.printEnd();
break;
}
}
}
}
}
⑤ 실행 결과
[출력화면 ★ -> 입력]
로그인할 아이디 입력 :
qwere
===메뉴===
1. 목록조회
2. 상품구매
3. 서비스나가기
=========
1
[1001] 신발30000원 | 3개
[1002] 바지15000원 | 1개
[1003] 나시5000원 | 10개
===메뉴===
1. 목록조회
2. 상품구매
3. 서비스나가기
=========
2
구매할 상품번호입력>>> 1002
dao로그 : 사용자구매성공
dao:사용자 구매 성공
성공
===메뉴===
1. 목록조회
2. 상품구매
3. 서비스나가기
=========
1
[1001] 신발30000원 | 3개
[1002] 바지15000원 | 0개
[1003] 나시5000원 | 10개
===메뉴===
1. 목록조회
2. 상품구매
3. 서비스나가기
=========
3
이용해주셔서 감사합니다.
로그인할 아이디 입력 :
'DBMS' 카테고리의 다른 글
[Oracle] 능력단위평가 풀이 (0) | 2022.01.28 |
---|---|
[Oracle] 다양한 검색과 출력_Oracle 함수 (0) | 2022.01.28 |
[Oracle] 웹크롤링_샘플데이터처리 (0) | 2022.01.25 |
[Oracle] 웹크롤링_기초 (0) | 2022.01.24 |
[Oracle] 트랜잭션 (0) | 2022.01.22 |