자바와 DB를 연동해서 CRUD 프로그램 작성하기

장경수·2023년 4월 12일

📃먼저 주제를 선정해야 한다 :

  • 편의점 상품 관리

📌주제 : 편의점 상품 관리

1) 데이터 모델링

  • 어떤 형태의 데이터를 다룰 것인지 결정한다
  • 데이터의 상세 속성과 자료형을 정의한다
  • 데이터베이스에는 테이블, 프로그램에는 DTO를 작성한다

2) 화면 구현 (main 클래스에서 만들기)

  • 기본 인터페이스의 화면을 구상한다
  • UI 프로토타이핑을 통해 어떤 화면들이 있는지 결정
  • 어떤 화면들이 어떤 순서로 연결되는지 결정

3) 기능 구현

  • 어떤 기능이 구현되어야 하는지 명시한다
  • 각 기능의 세부내용을 결정
  • 세부 내용에 따른 SQL을 작성하여 관리하는 DAO를 작성

4) 통합 구현

  • main, 화면, 기능, Database 가 연결되는 구조 작성
  • 예외 처리 및 테스트, 더미데이터 등의 작업을 수행

====================================================================================

1. 데이터 모델링

편의점 상품 관리를 하기 위해 필요한 데이터

  • 상품번호 (정수)
  • 상품이름 (문자열)
  • 가격 (정수)
  • 유통기한 (날짜)
  • 설명 (문자열)

💡 Database 테이블 구성하기

Create table product (
	idx			number,
    name		varchar2(100),
    price		number,
    expiryDate	date,
    memo		varchar2(2000)
);

💡 DTO 구성하기

// java.sql.Date는 java.util.Date를 상속받아 DB에서 사용되는 날짜 타입으로 사용된다.
// 따라서 expiryDate 필드의 타입은 java.sql.Date로 정의되어 있다.
import java.sql.Date;

public class ProductDTO {
	// 변수 선언
    private int idx;
	private String name;
	private int price;
	private Date expiryDate;
	private String memo;
	
    // 문자열 반환
    @Override
	public String toString() {
		return String.format("%s) %s \t%,d원 \t%s \t%s", idx, name, price, expiryDate, memo) ;
	}
    
    // 각 필드에 대한 Getter/Setter 메소드를 정의
    public int getIdx() {
		return idx;
	}
	public void setIdx(int idx) {
		this.idx = idx;
	}
	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 Date getExpiryDate() {
		return expiryDate;
	}
	public void setExpiryDate(Date expiryDate) {
		this.expiryDate = expiryDate;
	}
	public String getMemo() {
		return memo;
	}
	public void setMemo(String memo) {
		this.memo = memo;
	}

}

2. 화면 구현 및 통합 구현

< GUI 구현을 하지 않기 때문에 구현 순서가 바뀔 수 있음 >

import java.sql.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;

// 전체목록	(고유번호 순으로 출력이 기본값, 정렬되면 다른 순서로 출력)
// 검색		(이름으로 검색, 포함된다면 모두 출력)
// 추가		(상품등록)
// 삭제		(등록된 상품 코드 제거)
// 수정		(상품수량 및 가격 수정)
// 정렬		(날짜순 정렬, 고유번호 순 정렬, 수량 기준 정렬)
// 종료

public class Main {
	public static void main(String[] args) {
    
    Scanner sc = new Scanner(System.in);
    ProductDAO dao = new ProductDAO();
    ProductDTO tmp = null;
    ArrayList<ProductDTO> list;
    int menu, row, idx;
    String keyword, key, value;
    HashMap<String, String> map = new HashMap<String, String>();
    map.put("상품번호", "idx");
    map.put("상품이름", "name");
    map.put("상품가격", "price");
    map.put("유통기한", "expiryDate");
    map.put("상품설명", "memo");
    String order = map.get("상품번호");
    boolean desc = false;
    
    while(true) {
    	System.out.println("1. 전체 목록");
		System.out.println("2. 검색");
		System.out.println("3. 추가");
		System.out.println("4. 수정");
		System.out.println("5. 삭제");
		System.out.println("6. 정렬");
		System.out.println("0. 종료");
		System.out.print("선택 >>>> ");
		menu = Integer.parseInt(sc.nextLine());
           
        switch (menu) {
        case 1:	// 전체 목록
        	list = dao.selectAll(order, desc);
            list.forEach(dto -> System.out.println(dto));
          	break;
         case 2:	// 검색
            System.out.print("검색어를 입력하세요 : ");
            keyword = sc.nextLine();
            list = dao.select(keyword);
            list.forEach(dto -> System.out.println(dto));
           	break;
         case 3:	// 추가
         	System.out.print("신규 상품을 생성합니다");
         	tmp = useBean(sc);
         	row = dao.update(tmp);
         	System.out.println(row != 0 ? "추가 성공" : "추가 실패");   
           	break;
         case 4:	// 수정
        	 System.out.print("기존 상품을 수정합니다");
        	 tmp = useBean(sc);
        	 row = dao.update(tmp);
        	 System.out.println(row != 0 ? "수정 성공" : "수정 실패");
           	break;
         case 5:	// 삭제
        	System.out.print("삭제할 상품번호 입력 : ");
        	idx = Integer.parseInt(sc.nextLine());
        	
        	row = dao.delete(idx);
        	System.out.println(row != 0 ? "삭제 성공" : "삭제 실패");
           	break;
         case 6:	// 정렬
        	System.out.println(new ArrayList<>(map.keySet()));
        	System.out.print("정렬 기준 선택 : ");
        	key = sc.nextLine();
        	value = map.get(key);
        	if(value != null) {
        		order = value;
        	}
        	System.out.print("내림차순? (true | false) ");
        	desc = Boolean.parseBoolean(sc.nextLine());
           	break;
             
         case 0:	// 종료
           	sc.close();
            return;
         }     
     }
    
   }// end of main
   
   // 추가, 수정 부분에서 활용한다 (코드의 재활용, 함수)
	static ProductDTO useBean(Scanner sc) {
		ProductDTO dto = new ProductDTO();
		
		System.out.print("상품 번호 : ");
		dto.setIdx(Integer.parseInt(sc.nextLine()));

		System.out.print("상품 이름 : ");
		dto.setName(sc.nextLine());
		
		System.out.print("상품 가격 : ");
		dto.setPrice(Integer.parseInt(sc.nextLine()));
		
		try {
			System.out.print("유통기한 (yyyy-MM-dd) : ");
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			String inputDate = sc.nextLine();
			java.util.Date date = sdf.parse(inputDate);
			dto.setExpiryDate(new Date(date.getTime()));
			
		} catch (ParseException e) {
			e.printStackTrace();
		}
		
		System.out.print("상품 설명 : ");
		dto.setMemo(sc.nextLine());

		return dto;
	}
   
} 

3. 기능 구현

아래의 기능들을 구현한다.
1. 전체목록 (고유번호 순으로 출력이 기본값, 정렬되면 다른 순서로 출력)
2. 검색 (이름으로 검색, 포함된다면 모두 출력)
3. 추가 (상품등록)
4. 삭제 (등록된 상품 코드 제거)
5. 수정 (상품수량 및 가격 수정)
6. 정렬 (날짜순 정렬, 고유번호 순 정렬, 수량 기준 정렬)

  • Main Class의 switch-case에서 어떤 기능이 구현되어야 하는지 명시
  • ProductDTO Class는 각 기능의 세부내용에 따른 SQL을 작성, 관리하는 클래스
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import oracle.jdbc.driver.OracleDriver;

public class ProductDAO {
	
	private Connection conn;
	private PreparedStatement pstmt;
	private ResultSet rs;
	
    // 데이터베이스 연결 정보 저장
	private String url = "jdbc:oracle:thin:@192.168.1.100:1521:xe";
	private String user = "c##itbank";
	private String password = "it";
	
    // JDBC 드라이버 클래스 이름 저장
	private String className = OracleDriver.class.getName();
	
	public ProductDAO() {
		try {
			Class.forName(className);			
		} catch(ClassNotFoundException e) {
			System.err.println("DAO 생성자 예외 발생 : " + e);
		}
		
	}
	
    // 모든 상품 정보를 가져오는 메소드
	public ArrayList<ProductDTO> selectAll(String order, boolean desc) {
		ArrayList<ProductDTO> list = new ArrayList<ProductDTO>(); // 반환할 객체 생성
		String sql = "select * from product order by " + order; // SQL문장 생성
		if(desc) {
			sql += " desc";
		}
		System.out.println("SQL > " + sql);
		
		try {
			conn = DriverManager.getConnection(url, user, password);
			pstmt = conn.prepareStatement(sql); // sql을 미리 넣어둔다
			rs = pstmt.executeQuery(); // 미리 넣었으니 여기서는 sql을 지정하지 않는다
			
			while(rs.next()) {
				ProductDTO dto = new ProductDTO();
				dto.setIdx(rs.getInt("idx"));
				dto.setName(rs.getString("name"));
				dto.setPrice(rs.getInt("price"));
				dto.setExpiryDate(rs.getDate("expiryDate"));
				dto.setMemo(rs.getNString("memo"));
				list.add(dto);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try { if(rs != null)	rs.close(); }	catch(Exception e) {}
			try { if(pstmt != null)	pstmt.close(); }	catch(Exception e) {}
			try { if(conn != null)	conn.close(); }	catch(Exception e) {}
		}
		return list;
	}
	
    // 상품 이름으로 조회하는 메소드
	public ArrayList<ProductDTO> select(String keyword) {
		ArrayList<ProductDTO> list = new ArrayList<ProductDTO>(); // 반환할 객체 생성
		String sql = "select * from product where name like '%%%s%%'"; // SQL문장 생성
		sql = String.format(sql, keyword);
		try {
			conn = DriverManager.getConnection(url, user, password);
			pstmt = conn.prepareStatement(sql); // sql을 미리 넣어둔다
			rs = pstmt.executeQuery(); // 미리 넣었으니 여기서는 sql을 지정하지 않는다
			
			while(rs.next()) {
				ProductDTO dto = new ProductDTO();
				dto.setIdx(rs.getInt("idx"));
				dto.setName(rs.getString("name"));
				dto.setPrice(rs.getInt("price"));
				dto.setExpiryDate(rs.getDate("expiryDate"));
				dto.setMemo(rs.getNString("memo"));
				list.add(dto);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try { if(rs != null)	rs.close(); }	catch(Exception e) {}
			try { if(pstmt != null)	pstmt.close(); }	catch(Exception e) {}
			try { if(conn != null)	conn.close(); }	catch(Exception e) {}
		}
		return list;
	}
	
    // 상품 정보를 추가하는 메소드
	public int insert(ProductDTO dto) {
		int row = 0;
		String sql = "insert * from product values (?, ?, ?, ?, ?)";
		
		try {
			conn = DriverManager.getConnection(url, user, password);
			pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, dto.getIdx());
			pstmt.setString(2, dto.getName());
			pstmt.setInt(3, dto.getPrice());
			pstmt.setDate(4, dto.getExpiryDate());
			pstmt.setString(5, dto.getMemo());
			
			row = pstmt.executeUpdate();
			
		} catch (SQLException e) {
			e.printStackTrace();
		}

		return row;
	}
	
    // 상품 정보를 수정하는 메소드
	public int update(ProductDTO dto) {
		int row = 0;
		String sql = "update product set name=?, price=?, expireDate=?, memo=? where idx=?";
		try {
			conn = DriverManager.getConnection(url, user, password);
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, dto.getName());
			pstmt.setInt(2, dto.getPrice());
			pstmt.setDate(3, dto.getExpiryDate());
			pstmt.setString(4, dto.getMemo());
			pstmt.setInt(5, dto.getIdx());
			
			row = pstmt.executeUpdate();
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try { if(rs != null)	rs.close(); }	catch(Exception e) {}
			try { if(pstmt != null)	pstmt.close(); }	catch(Exception e) {}
			try { if(conn != null)	conn.close(); }	catch(Exception e) {}
		}
		
		return row;
	}
	
    // 상품 정보를 삭제하는 메소드
	public int delete(int idx) {
		int row = 0;
		String sql = "delete product where idx = ?";
		try {
			conn = DriverManager.getConnection(url, user, password);
			pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, idx);
			
			row = pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try { if(rs != null) 	rs.close();		}	catch(Exception e) {}
			try { if(pstmt != null) 	pstmt.close();		}	catch(Exception e) {}
			try { if(conn != null) 	conn.close();		}	catch(Exception e) {}
		}
		return row;
	}
}

코드 작성이 끝나면 SQL Developer에 들어가서 상품들을 등록

위의 SQL 코드를 실행하면 아래와 같이 테이블 생성이 완료

이제 다시 자바 코드를 실행 해서 정상적으로 연동이 되는지 확인

전체 목록을 출력해보면 DB에서 입력한 정보들이 정상적으로 출력된다.


콜라 라고 검색을 하면 콜라를 가지고 있는 이름들 출력


상품을 추가하고 전체 목록에 제대로 뜨는지 확인하고, DB에서 select * from product order by idx;를 실행하면 DB에도 저장되는 것을 확인 할 수 있다.


기존 파워에이드토레타로 수정, 전체 목록에 제대로 출력, DB에도 수정된 것을 확인 가능하다.

DB에서도 아래와 같이 수정 가능
< 4번째 상품을 스프라이트 (캔) 250ML, 가격은 1500원으로 수정한다 >


토레타를 삭제, 전체 목록에서도 지워지고 DB에서도 지워졌다.

DB에서 삭제 하는 방법
< 6번째 상품 삭제 >


정렬은 상품이름, 상품가격, 상품번호, 유통기한, 상품설명 중 하나를 선택하고 내림차순으로 할지 오름차순으로 할지 선택하면 원하는 대로 정렬을 할 수 있다.


유통기한 오름차순으로 정렬하기.

profile
coding is my life

0개의 댓글