반응형

※ 데이터베이스 oracle SQL에서 전부 작성 후 commit 해주지 않으면, 자바로 데이터베이스가 넘어오지 않는다. 꼭 commit 했는지 확인하고 넘어가자.

 

- 앞으로는 이제 DAO와 VO를 자주 활용하게 된다.

 

VO와 DTO와 DAO

DTO(Data Transfer Object) : 데이터를 전달하기 위해서 만들어 지는 객체 (getter와 setter 사용)- 데이터의 수정과 조회가 모두 가능하다.- 다양한 계층 간의 데이터 교환을 용이하게 함.- 애플리케이션의

chainterior.tistory.com

 

데이터베이스 CRUD 템플릿 파일

templates.xml
0.01MB

 

 

데이터 베이스 테이블 생성 및 select로 조회 풀구성

-- 일련번호 관리객체
create sequence seq_sungjuk_idx

-- 성적테이블
create table sungjuk
(
	idx int,	-- 일련번호
	name varchar2(100) not null, -- 이름
	kor  int default 0, -- 국어
	eng  int default 0, -- 영어
	math int default 0 -- 수학
)

-- PK (항상 데이터 베이스에는 primary key가 있어야 한다.)
alter table sungjuk add constraint pk_sungjuk_idx primary key(idx);
-- Check 제약
alter table sungjuk add constraint ck_sungjuk_kor check(kor between 0 and 100);
alter table sungjuk add constraint ck_sungjuk_eng check(eng between 0 and 100);
alter table sungjuk add constraint ck_sungjuk_math check(math between 0 and 100);

-- sample data
insert into sungjuk values(seq_sungjuk_idx.nextVal,'일길동',88,99,80);
insert into sungjuk values(seq_sungjuk_idx.nextVal,'이길동',98,99,90);
insert into sungjuk values(seq_sungjuk_idx.nextVal,'삼길동',88,89,80);
insert into sungjuk values(seq_sungjuk_idx.nextVal,'사길동',98,99,99);
insert into sungjuk values(seq_sungjuk_idx.nextVal,'오길동',88,79,80);

-- table에 컬럼을 추가하지 않는 이유는 변경되는 점수마다 일일이 변경해줘야 하기 때문에 select로 조회할 때마다 조건을 달아주면 된다.
create or replace view sungjuk_view
as
select
   ss.*,
   rank() over(order by tot desc) as rank,
   case
      when avg between 90 and 100 then 'A'
      when avg between 80 and 89 then 'B'
      when avg between 70 and 79 then 'C'
      when avg between 60 and 69 then 'D'
      else 'F'
   end as grade
from
(
	select 
	   s.*,
	   (kor+eng+math) as tot,
	   round((kor+eng+math)/3,1) as avg
	from
		(select * from sungjuk) s
)ss
order by idx

select * from sungjuk_view

 

 

 

 

- DBService 생성하기

package service;

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

public class DBService {

	// OracleDriver Loading
	static {
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public Connection getConnection() throws SQLException {
		
		String url = "jdbc:oracle:thin:@localhost:1521:xe";
		String user = "test";
		String pwd = "test";
		
		Connection conn = DriverManager.getConnection(url,user,pwd);
		
		return conn;
	}
}

 

- 객체는 항상 만드는것이 아니라, 처음에 만들었던 그 한 개의 객체를 공통적으로 사용한다. (싱글톤)

single-ton pattern : 객체 1개만 생성해서 사용하자

package service;

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

public class DBService {

	// OracleDriver Loading
	static {
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	// single-ton pattern : 객체 1개만 생성해서 사용하자
	static DBService single = null;
	// 객체 : 클래스로 만든 모든 것 , 인스턴스 : 어떤 클래스의 인스턴스
	// DBService의 인스턴스 (너의 정보를 알려줄래)
	
	
	public static DBService getInstance() {
		// 없으면 생성해라
		if(single == null) {
			single = new DBService();
		}
		return single;
	}
	
	public DBService() {
		System.out.println("---DBService()---");
	}
	
	public Connection getConnection() throws SQLException {
		
		String url = "jdbc:oracle:thin:@localhost:1521:xe";
		String user = "test";
		String pwd = "test";
		
		Connection conn = DriverManager.getConnection(url,user,pwd);
		
		return conn;
	}
}
package mymain;

import java.sql.Connection;
import java.sql.SQLException;
import service.DBService;

public class MyMain_Sungjuk {

	public static void main(String[] args) {
		
		try {
			Connection conn = DBService.getInstance().getConnection();
			System.out.println("---success---");
			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}

	}
}

 

 

- 싱글톤을 설정했으면, 싱글톤을 사용해야 하는데, 아래와 같이 생성자를 또 새로만들면 무용지물이다.

 

- 그럴때는 외부에서 객체를 생성하지 못하게 생성자의 범위를 private로 제한시켜 버린다.

 

- private로 생성자를 제한시키니, main 메소드에서는 생성자를 호출해서 객체를 생성할 수가 없다.

 

 

- 싱클톤 패턴 완벽 적용

package service;

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

public class DBService {

	// OracleDriver Loading
	static {
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	// single-ton pattern : 객체 1개만 생성해서 사용하자
	static DBService single = null;
	// 객체 : 클래스로 만든 모든 것 , 인스턴스 : 어떤 클래스의 인스턴스
	// DBService의 인스턴스 (너의 정보를 알려줄래)
	
	
	public static DBService getInstance() {
		// 없으면 생성해라
		if(single == null) {
			single = new DBService();
		}
		return single;
	}
	
	private DBService() {
		System.out.println("---DBService()---");
	}
	
	public Connection getConnection() throws SQLException {
		
		String url = "jdbc:oracle:thin:@localhost:1521:xe";
		String user = "test";
		String pwd = "test";
		
		Connection conn = DriverManager.getConnection(url,user,pwd);
		
		return conn;
	}
}
package mymain;

import java.sql.Connection;
import java.sql.SQLException;
import service.DBService;

public class MyMain_Sungjuk {

	public static void main(String[] args) {
		
		try {
			Connection conn = DBService.getInstance().getConnection();
			System.out.println("---success---");
			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}

	}
}

 

 

 

- 싱클톤은 워낙 자주 사용하는 패턴이니 템플릿(Templates)에 저장해서 두고두고 사용하자

// single-ton pattern : 객체 1개만 생성해서 사용하자
	static ${primary_type_name} single = null;
	
	public static ${primary_type_name} getInstance() {
		// 없으면 생성해라
		if(single == null) {
			single = new ${primary_type_name}();
		}
		return single;
	}
	
	private ${primary_type_name}() {

	}

 

- 템플릿(Template)은 export 해서 추출이 가능하고, import로 가져오는 것이 가능하다.

singletonTemplate.xml
0.00MB

 

 

 

VO 작성하기

VO(Value Object)
1. 값을 저장관리하는 개체
2. getter/setter 생성

 

cf) 3위일체

DB Column명 = VO Property명 = 웹입력 Parameter명 (세가지는 통일되게 작성한다)

 

 

package vo;

/*
   VO(Value Object)
   1. 값을 저장관리하는 개체
   2. getter/setter 생성
   
   cf) 3위일체
   DB Column명 = VO Property명 = 웹입력 Parameter명
*/

public class SungVO {
	
	// member field, variable
	// property(속성) 프레임워크에서는 필드를 property라고 사용한다.
	int idx;;
	String name;
	int kor;
	int eng;
	int math;
	// 조회용으로 사용할 것이니 String 타입으로 받아준다.
	String tot;
	String avg;
	String rank;
	String grade;
	
	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 getKor() {
		return kor;
	}
	public void setKor(int kor) {
		this.kor = kor;
	}
	public int getEng() {
		return eng;
	}
	public void setEng(int eng) {
		this.eng = eng;
	}
	public int getMath() {
		return math;
	}
	public void setMath(int math) {
		this.math = math;
	}
	public String getTot() {
		return tot;
	}
	public void setTot(String tot) {
		this.tot = tot;
	}
	public String getAvg() {
		return avg;
	}
	public void setAvg(String avg) {
		this.avg = avg;
	}
	public String getRank() {
		return rank;
	}
	public void setRank(String rank) {
		this.rank = rank;
	}
	public String getGrade() {
		return grade;
	}
	public void setGrade(String grade) {
		this.grade = grade;
	}
	
}

 

 

 

 

DAO 작성하기

package dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import db.vo.SungVO;
import service.DBService;

/*
작성자 : 차선일
일  자 : 2024.05.31
내  용 : 성적 Data Access Object 구현
 */

public class SungDAO {

	// single-ton pattern : 객체 1개만 생성해서 사용하자
	static SungDAO single = null;

	public static SungDAO getInstance() {
		// 없으면 생성해라
		if (single == null) {
			single = new SungDAO();
		}
		return single;
	}

	private SungDAO() {

	}

	// 전체 조회
	public List<SungVO> selectList() {
		List<SungVO> list = new ArrayList<SungVO>();

		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;

		String sql = "select * from sungjuk_view";

		try {
			// 1. Connection 얻어오기
			conn = DBService.getInstance().getConnection();

			// 2. PreparedStatement
			pstmt = conn.prepareStatement(sql);

			// 3. ResultSet 얻어오기(킵해놨던 sql문 출력하기)
			rs = pstmt.executeQuery();

			while(rs.next()) {
				// rs가 가리키는 레코드의 값을 읽어온다
				int idx = rs.getInt("idx");
				String name = rs.getString("name");
				int kor = rs.getInt("kor");
				int eng = rs.getInt("eng");
				int math = rs.getInt("math");
				String tot = rs.getString("tot");
				String avg = rs.getString("avg");
				String rank = rs.getString("rank");
				String grade = rs.getString("grade");

				// 저장객체 생성 -> 레코드에서 읽은 값을 넣는다.
				SungVO vo = new SungVO();
				vo.setIdx(idx);
				vo.setName(name);
				vo.setKor(kor);
				vo.setEng(eng);
				vo.setMath(math);
				vo.setTot(tot);
				vo.setAvg(avg);
				vo.setRank(rank);
				vo.setGrade(grade);

				// ArrayList에 추가
				list.add(vo);

			}

		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		} finally {
			// 예외 처리에서 무조건 실행되는 부분
			// 마무리 작업(열린역순으로 닫기)
			// 한 번에 잡아서 try catch 하기 : alt + shift + s
			try {
				if(rs!=null)rs.close();
				if(pstmt!=null)pstmt.close();
				if(conn!=null)conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return list;
	}

	public int insert(SungVO vo) {
		// TODO Auto-generated method stub

		int res = 0;
		Connection conn = null;
		PreparedStatement pstmt = null;
		//                                                                1  2  3  4 <- parameter index
		String sql = "insert into sungjuk values(seq_sungjuk_idx.nextVal, ?, ?, ?, ?)";

		try {
			// 1. Connection 얻어오기
			conn = DBService.getInstance().getConnection();

			// 2. PreparedStatement
			pstmt = conn.prepareStatement(sql);

			// 3. pstmt parameter index 채우기
			pstmt.setString(1, vo.getName());
			pstmt.setInt(2, vo.getKor());
			pstmt.setInt(3, vo.getEng());
			pstmt.setInt(4, vo.getMath());

			// 4. DB insert
			// 업데이트 성공하면 res값이 1로 변경 / 업데이트 된 레이블 수가 올라간다. 지금은 1이네요
			res = pstmt.executeUpdate();


		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		} finally {
			// 예외 처리에서 무조건 실행되는 부분
			// 마무리 작업(열린역순으로 닫기)
			// 한 번에 잡아서 try catch 하기 : alt + shift + s
			try {
				if(pstmt!=null)pstmt.close();
				if(conn!=null)conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return res;

	}// end:insert()


	public int delete(int idx) {
		// TODO Auto-generated method stub

		int res = 0;
		Connection conn = null;
		PreparedStatement pstmt = null;
		//                                          1 <- pstmt parameter index
		String sql = "delete from sungjuk where idx=?";

		try {
			// 1. Connection 얻어오기
			conn = DBService.getInstance().getConnection();

			// 2. PreparedStatement
			pstmt = conn.prepareStatement(sql);

			// 3. pstmt parameter index 채우기
			pstmt.setInt(1, idx);

			// 4. DB delete 업데이트 된 레이블 수가 올라간다. 지금은 1이네요
			res = pstmt.executeUpdate();

		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		} finally {
			// 예외 처리에서 무조건 실행되는 부분
			// 마무리 작업(열린역순으로 닫기)
			// 한 번에 잡아서 try catch 하기 : alt + shift + s
			try {
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return res;

	}// end:delete()

	public int update(SungVO vo) {
		// TODO Auto-generated method stub

		int res = 0;
		Connection conn = null;
		PreparedStatement pstmt = null;

		String sql = "update sungjuk set name=?,kor=?,eng=?,math=? where idx=?";

		try {
			// 1. Connection 얻어오기
			conn = DBService.getInstance().getConnection();

			// 2. PreparedStatement
			pstmt = conn.prepareStatement(sql);

			// 3. pstmt parameter index 채우기
			pstmt.setString(1, vo.getName());
			pstmt.setInt(2, vo.getKor());
			pstmt.setInt(3, vo.getEng());
			pstmt.setInt(4, vo.getMath());
			pstmt.setInt(5, vo.getIdx());

			// 4. DB update
			res = pstmt.executeUpdate();

		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		} finally {
			// 예외 처리에서 무조건 실행되는 부분
			// 마무리 작업(열린역순으로 닫기)
			// 한 번에 잡아서 try catch 하기 : alt + shift + s
			try {
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return res;

	}// end:update()


	public List<SungVO> selectAvgList(int avg) {
		List<SungVO> list = new ArrayList<SungVO>();

		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;

		String sql = "select * from sungjuk_view where avg=?";

		try {
			// 1. Connection 얻어오기
			conn = DBService.getInstance().getConnection();

			// 2. PreparedStatement
			pstmt = conn.prepareStatement(sql);
			
			//2-1. pstmt parameter
			pstmt.setInt(1,avg);

			// 3. ResultSet 얻어오기(킵해놨던 sql문 출력하기)
			rs = pstmt.executeQuery();

			while(rs.next()) {
				// rs가 가리키는 레코드의 값을 읽어온다
				int idx = rs.getInt("idx");
				String name = rs.getString("name");
				int kor = rs.getInt("kor");
				int eng = rs.getInt("eng");
				int math = rs.getInt("math");
				String tot = rs.getString("tot");
				String rank = rs.getString("rank");
				String grade = rs.getString("grade");

				// 저장객체 생성 -> 레코드에서 읽은 값을 넣는다.
				SungVO vo = new SungVO();
				vo.setIdx(idx);
				vo.setName(name);
				vo.setKor(kor);
				vo.setEng(eng);
				vo.setMath(math);
				vo.setTot(tot);
				vo.setAvg(rs.getString("avg"));
				vo.setRank(rank);
				vo.setGrade(grade);

				// ArrayList에 추가
				list.add(vo);

			}

		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		} finally {
			// 예외 처리에서 무조건 실행되는 부분
			// 마무리 작업(열린역순으로 닫기)
			// 한 번에 잡아서 try catch 하기 : alt + shift + s
			try {
				if(rs!=null)rs.close();
				if(pstmt!=null)pstmt.close();
				if(conn!=null)conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return list;

	}
}

 

 

 

Main (Console) User 사용자 호출

package mymain;

import java.util.List;
import java.util.Scanner;

import dao.SungDAO;
import db.vo.SungVO;

public class MyMain_Sungjuk {
	
	static void display() {
		// DB -> 데이터 가져오기
		List<SungVO> list = SungDAO.getInstance().selectList();
		System.out.println("-----------------------------------------------------");
		System.out.println("번호   이름  국어  영어  수학  총점  평균  등수  평점");
		System.out.println("-----------------------------------------------------");
		for(SungVO vo : list) {
			System.out.printf("%3d%5s%6d%6d%6d%5s%6s%6s%6s\n",
					vo.getIdx(),vo.getName(),vo.getKor(),
					vo.getEng(),vo.getMath(),vo.getTot(),
					vo.getAvg(),vo.getRank(),vo.getGrade()
					);
		}
		System.out.println("-----------------------------------------------------");
	}
	
	static void insert(Scanner sc) {
		System.out.println("---[성적추가하기]---");
		String name;
		int kor;
		int eng;
		int math;
		System.out.print("이름 :");
		name = sc.next().trim();
		System.out.print("국어 :");
		kor = sc.nextInt();
		System.out.print("영어 :");
		eng = sc.nextInt();
		System.out.print("수학 :");
		math = sc.nextInt();
		
		// 입력 값을 SungVO에 포장
		SungVO vo = new SungVO(name,kor,eng,math);
		
		// SungDAO에게 insert 요청
		int res = SungDAO.getInstance().insert(vo);
		
		if(res==1) {
			System.out.println("추가성공 했습니다.");
		} else {
			System.out.println("추가실패 했습니다.");
		}
		
	}
	
	static void update(Scanner Letsgo) {
		System.out.println("                    ㈜수정하기㈜");
		display();
		System.out.print("수정번호입력:");
		int idx = Letsgo.nextInt();
		
		System.out.print("이름:");
		String name = Letsgo.next();
		
		System.out.println("국어/영어/수학:");
		int kor = Letsgo.nextInt();
		int eng = Letsgo.nextInt();
		int math = Letsgo.nextInt();
		
		// 입력 값을 SungVO에 포장
		SungVO vo = new SungVO(idx,name,kor,eng,math);
		
		int res = SungDAO.getInstance().update(vo);
		
		if(res==1) {
			System.out.println("수정성공 했습니다.");
		} else {
			System.out.println("수정실패 했습니다.");
		}
	}
	
	static void delete(Scanner scanner) {
		System.out.println("                    ㈜삭제하기㈜");
		display();
		System.out.print("삭제번호입력:");
		int idx = scanner.nextInt();
		
		//삭제처리
		int res = SungDAO.getInstance().delete(idx);
		if(res==1) {
			System.out.println("삭제성공 했습니다.");
		} else {
			System.out.println("삭제실패 했습니다.");
		}
		
	}
	
	static void search_avg(Scanner sc) {
		System.out.println("                    ㈜검색하기㈜");
		System.out.print("검색할 평균:");
		int avg = sc.nextInt();
		List<SungVO> list = SungDAO.getInstance().selectAvgList(avg);
		
		System.out.println("-----------------------------------------------------");
		System.out.println("번호   이름  국어  영어  수학  총점  평균  등수  평점");
		System.out.println("-----------------------------------------------------");
		for(SungVO vo : list) {
			System.out.printf("%3d%5s%6d%6d%6d%5s%6s%6s%6s\n",
					vo.getIdx(),vo.getName(),vo.getKor(),
					vo.getEng(),vo.getMath(),vo.getTot(),
					vo.getAvg(),vo.getRank(),vo.getGrade()
					);
		}
		System.out.println("-----------------------------------------------------");
		
	}

	public static void main(String[] args) {

		int menu;
		Scanner scanner = new Scanner(System.in);
		
		while(true) {
			
			System.out.print("1. 조회  2. 추가  3. 수정  4. 삭제 5. 평균  0. 종료 : ");
			menu = scanner.nextInt();
			
			if(menu==0) break;
			switch(menu) {
			case 1 : display(); break;
			case 2 : insert(scanner); break;
			case 3 : update(scanner); break;
			case 4 : delete(scanner); break;
			case 5 : search_avg(scanner); break;
			}
			
		}// end : while;
		
		System.out.println("---End---");
	}
}

 

반응형