본문 바로가기

Python

PyCharm - 3 tier 아키텍처를 적용(VO, Service, DAO)

# 성적처리 프로그램 v7
# 성적 데이터 추가/조회/수정/삭제 기능 제공
# 입력한 성적데이터와 처리결과는 테이블에 저장함
# 데이터베이스는 오라클 19c를 사용함
# 객체지향 프로그래밍을 이용해서 클래스 기반으로 코드 작성
# 또한, 3-tier 아키텍처를 적용해서 VO, Service, DAO로
# 세분화시켜 파일 작성
# SungJukVO
# SungJukV7Service, SungJukV7ServiceImpl
# SungJukV7DAO, SungJukV7DAOImpl

# sungjukv7 -> sungjukv7service -> sungjukv7dao

from zzyzzy.sungjuk.SungJukV7ServiceImpl import SungJukV7ServiceImpl

# 프로그램 main


# 성적 입력/조회/수정/삭제 관련 메서드가
# SungJukV7ServiceImpl 클래스에 있기 때문에
# 각 메서드를 호출하기 위해서는 객체화가 필요
sjv7srv = SungJukV7ServiceImpl()


while True:
    # 메뉴를 화면에 표시하고
    # 실행할 메뉴를 선택받아 menu 변수에 저장
    menu = sjv7srv.display_menu()

    # 입력받은 메뉴 구분
    if menu == '1': sjv7srv.add_sungjuk()
    elif menu == '2': sjv7srv.list_sungjuk()
    elif menu == '3': sjv7srv.view_sungjuk()
    elif menu == '4': sjv7srv.mdf_sungjuk()
    elif menu == '5': sjv7srv.rmv_sungjuk()
    elif menu == '0': break
    else: print('=> 잘못 입력하셨습니다~')
# 성적 데이터와 관련된 클래스

class SungJukVO:
    def __init__(self, name, kor, eng, mat):
        self.name = name
        self.kor = kor
        self.eng = eng
        self.mat = mat
        self.tot = 0
        self.avg = 0.0
        self.grd = '가'

    def __str__(self):
        result = f'{self.name} {self.kor} {self.eng} {self.mat}' \
                 f' {self.tot} {self.avg:.1f} {self.grd}'
        return result

    def print_simple(self):
        result = f'{self.name} {self.kor} {self.eng} {self.mat}'
        return result
# 성적 처리와 관련된 메서드를 추상메서드로 정의

from abc import ABCMeta, abstractmethod


class SungJukV7Service(metaclass=ABCMeta):

    # 메뉴 정의 함수
    def display_menu(self):
        main_menu = f'''
           성적 처리 프로그램 v7
        -------------------------
          1. 성적 데이터 추가
          2. 성적 데이터 조회
          3. 성적 데이터 상세조회
          4. 성적 데이터 수정
          5. 성적 데이터 삭제
          0. 프로그램 종료
        -------------------------
            powered by oracle19c
        -------------------------
        '''
        print(main_menu, end=' ')
        menu = input('=> 작업을 선택하세요 : ')

        return menu

    @abstractmethod     # 성적 입력 함수
    def add_sungjuk(self):
        pass

    @abstractmethod     # 입력받은 성적 처리 함수
    def compute_sungjuk(self, sj):
        pass

    @abstractmethod     # 성적 데이터 목록으로 출력
    def list_sungjuk(self):
        pass

    @abstractmethod     # 성적 데이터 상세 출력
    def view_sungjuk(self):
        pass

    @abstractmethod     # 성적 데이터 수정
    def mdf_sungjuk(self):
        pass

    @abstractmethod     #
    def modifying_sungjuk(self, sj):
        pass

    @abstractmethod     # 성적 데이터 삭제
    def rmv_sungjuk(self):
        pass

from zzyzzy.sungjuk.SungJukV7Service import SungJukV7Service
from zzyzzy.sungjuk.SungJukV7DAOImpl import SungJukV7DAOImpl
from zzyzzy.sungjuk.SungJukVO import SungJukVO


class SungJukV7ServiceImpl(SungJukV7Service):
    sjdao = None

    def __init__(self):
        # 성적데이터를 영속화하는 메서드는 
        # SungJukV7DAOImpl 클래스에 있음
        # 각 메서드를 호출하기 위해서는 객체화가 필요
        # 객체화는 생성자에서 실행함 - 단 한개의 객체만 생성!
        global sjdao
        sjdao = SungJukV7DAOImpl()

    def add_sungjuk(self):
        name = input('이름은?')
        kor = int(input('국어는?'))
        eng = int(input('영어은?'))
        mat = int(input('수학은?'))

        sj = SungJukVO(name, kor, eng, mat)
        self.compute_sungjuk(sj)

        # 처리된 성적데이터를 sungjuk테이블에 저장
        if sjdao.insert_sungjuk(sj):
            print('성적데이터가 성공적으로 저장됨!!')


    def compute_sungjuk(self, sj):
        sj.tot = sj.kor + sj.eng + sj.mat
        sj.avg = sj.tot / 3

        sj.grd = '가'
        if sj.avg >= 90: sj.grd = '수'
        elif sj.avg >= 80: sj.grd = '우'
        elif sj.avg >= 70: sj.grd = '미'
        elif sj.avg >= 60: sj.grd = '양'


    def list_sungjuk(self):
        hdr = '\n\t이름 \t국어 \t영어 \t수학\n'
        hdr += '\t▫▫▫▫▫▫▫▫▫▫▫▫▫▫▫▫▫▫▫▫▫▫▫▫▫▫▫▫▫'
        print(hdr)

        rows = sjdao.select_sungjuk()

        result = ''
        if rows:    # rows : SungJukVO들의 리스트
            for sj in rows:
                result += f"\t {sj.name} \t {sj.kor} "
                result += f"\t {sj.eng} \t {sj.mat}\n"
        print(result)

    def view_sungjuk(self):
        pass

    def mdf_sungjuk(self):
        pass

    def modifying_sungjuk(self, sj):
        pass

    def rmv_sungjuk(self):
        pass
# 성적데이터와 Oracle19c에 관련된 메서드를 추상메서드로 정의

from abc import ABCMeta, abstractmethod
import os
import cx_Oracle as pyorcl


class SungJukV7DAO(metaclass=ABCMeta):

    def __init__(self):
        os.putenv('NLS_LANG', '.UTF8')
        pyorcl.init_oracle_client(lib_dir=r'C:\Java\oracle_cloud')

    # 클래스 내부용 메서드 : internal
    def _open_conn(self):
        try:
            conn = pyorcl.connect(user='admin',
                                  password='Bigdata_2022',
                                  dsn='bigdata_medium')
            return conn
        except Exception as ex:
            print('open_conn()에서 오류발생!', ex)

    def _close_conn(self, cur, conn):
        cur.close()
        conn.close()

    @abstractmethod
    def insert_sungjuk(self, sj):
        pass

    @abstractmethod
    def select_sungjuk(self):
        pass

    @abstractmethod
    def selectOne_sungjuk(self, name):
        pass

    @abstractmethod
    def update_sungjuk(self, sju):
        pass

    @abstractmethod
    def delete_sungjuk(self, name):
        pass

from zzyzzy.sungjuk.SungJukVO import SungJukVO
from zzyzzy.sungjuk.SungJukV7DAO import SungJukV7DAO


class SungJukV7DAOImpl(SungJukV7DAO):
    def insert_sungjuk(self, sj):
        try:
            conn = self._open_conn()
            cur = conn.cursor()

            sql = 'insert into sungjuk values ' \
                  '(:name, :kor, :eng, :mat, :tot, :avg, :grd)'
            params = [sj.name, sj.kor, sj.eng, sj.mat,
                      sj.tot, sj.avg, sj.grd]
            cur.execute(sql, params)
            conn.commit()

            result = False
            if cur.rowcount > 0: result = True

            return result
        except Exception as ex:
            print('insert_sungjuk() 에서 오류발생!', ex)
            return False
        finally:
            try:
                self._close_conn(cur, conn)
            except: pass

    def select_sungjuk(self):
        try:
            conn = self._open_conn()
            cur = conn.cursor()

            sql = 'select name,kor,eng,mat from sungjuk'
            cur.execute(sql)
            rows = cur.fetchall()
            result = []

            for row in rows:
                sj = SungJukVO(row[0], row[1], row[2], row[3])
                result.append(sj)

            return result
        except Exception as ex:
            print('select_sungjuk() 에서 오류발생!', ex)
        finally:
            try: self._close_conn(cur, conn)
            except: pass

    def selectOne_sungjuk(self, name):
        pass

    def update_sungjuk(self, sju):
        pass

    def delete_sungjuk(self, name):
        pass