본문 바로가기

파이어몽키

"나의 도서관 앱" 개발 따라하기 - (2) 데이터베이스 만들기, 실제 데이터 연결

업데이트

  • 2015-02-25 : "2. 프로젝트 소스에서 데이터베이스와 연결"에서 Fields를 생성해 자동증가 속성을 주도록 변경


이번 글에서는 감명깊게 읽은 도서 정보, 리뷰를 기록할 수 있는 "나의 도서관 앱" 개발과정의 두번째 따라하기를 진행합니다.

첫번째 사용자화면 만들기와 기능 구현하기를 먼저 진행하시기 바랍니다.

따라하기 2 - 데이터베이스 만들기, 실제 데이터 연결

  1. "나의 도서관"앱에서 사용할 데이터베이스 만들기 
  2. 프로젝트 소스에서 데이터베이스와 연결 
  3. 데이터와 화면요소 연결하기 
  4. 데이터 입력, 수정, 삭제 기능 구현하기 
  5. 데이터베이스 파일과 라이선스파일 배포 등록하기 
  6. 원하는 모바일 디바이스에 배포하고 실행! 끝~

1, "나의 도서관"앱에서 사용할 데이터베이스 만들기

앱에서 사용할 데이터베이스를 생성합니다. 데이터베이스는 엠바카데로 제품 중 무료로 사용할 수 있는 IBLite 기반으로 진행합니다.

  1. IB Console을 실행(시작 > 프로그램 > Embarcadero InterBase XE3)합니다.
  2. Database > Create Database 메뉴 선택 후 아래 정보를 입력 후 OK 버튼을 눌러 데이터베이스 생성합니다.
    • File Name : 프로젝트 파일 하위에 "DB" 폴더 생성 후 지정(파일명은 반드시 "BOOKLOG.GDB"(확장자 입력)로 지정)
    • Default Character Set :UTF8(한글입력 시 필수)
    • Password of user : masterkey
  3. 데이터베이스 접속 창이 표시되면 위에서 입력한 "masterkey" 비밀번호를 입력 후 Connect 버튼을 눌러 접속합니다.
    (Display Character Set은 UTF8로 설정되었는지 확인)
  4. Tool > Interactive SQL 메뉴를 선택 하고 아래의 쿼리 입력 후 실행(Query > Execute, F5)하여 테이블과 트리거를 생성합니다.

    /* 테이블 생성 */
    CREATE TABLE "BOOK_LOG" (
      "BOOK_SEQ"		INTEGER NOT NULL,
      "BOOK_TITLE"		VARCHAR(50) NOT NULL,
      "BOOK_AUTHOR"		VARCHAR(30) NOT NULL,
      "BOOK_PUBLISHER"	VARCHAR(30),
      "BOOK_PHONE"		VARCHAR(20),
      "BOOK_WEBSITE"	VARChAR(100),
      "BOOK_COMMENT"	VARCHAR(1000),
      "BOOK_THUMB"		BLOB SUB_TYPE 0 SEGMENT SIZE 80,
      "BOOK_IMAGE"		BLOB SUB_TYPE 0 SEGMENT SIZE 80,
      CONSTRAINT "BOOK_SEQ_PK" PRIMARY KEY ("BOOK_SEQ")
    );
    
    /* BOOK_SEQ 자동증가 */
    CREATE GENERATOR "BOOK_SEQ_GEN";
    CREATE TRIGGER "SET_BOOK_SEQ" FOR "BOOK_LOG"
    ACTIVE BEFORE INSERT POSITION 0 AS
    BEGIN
        new.BOOK_SEQ = gen_id(BOOK_SEQ_GEN, 1);
    END;
create_script.sql

2, 프로젝트 소스에서 데이터베이스와 연결

데이터 연결 컴포넌트를 이용해 프로젝트에서 앞에서 만든 BOOKLOG.GDB와 연결합니다

데이터 연결 작업은 DataAccessModule.pas에서 진행합니다.

데이터 연결 컴포넌트 설정

  1. 데이터 모듈에 TFDConnection을 추가합니다.
  2. 추가된 FDConnection1을 더블클릭 해 FireDAC Connection Editor를 표시하고 아래와 같이 설정합니다.
    • Drive ID : IB
    • Database : 앞에서 생성한 BOOKLOG.GDB 선택택
    • User_Name : sysdba
    • Password : masterkey
    • CharacterSet : UTF8
  3. Test 버튼을 눌러 연결을 확인하고 OK 버튼을 눌러 창을 닫습니다.
  4. FDConnection1LoginPrompt 속성을 False로 설정합니다.
  5. Connected 속성을 True로 설정합니다.

데이터 질의(Query) 컴포넌트 설정

  1. 데이터 모듈에 TFDQuery 컴포넌트를 추가합니다.
  2. FDQuery1의 Connection속성을 FDConnection1으로 설정(확인)합니다.
  3. CachedUpdates 속성을 True로 설정합니다.
  4. FDQuery1 컴포넌트를 더블클릭 후 아래 쿼리문을 설정합니다.
    • SQL Command : SELECT * FROM BOOK_LOG
    • Execute 버튼 클릭 해 쿼리문 확인
    • OK 버튼 클릭
  5. Active 속성을 True로 변경합니다.

    데이터 질의(Query) 컴포넌트 필드 추가 / 자동증가 필드 설정

    1. FDQuery1 선택 후 오른쪽 마우스 메뉴에서 Fields Editor... 메뉴를 실행합니다.
    2. Fields Editor 창의 오른쪽 마우스 메뉴에서 Add all fields 메뉴를 실행 해 모든 필드를 추가합니다.
    3. BOOK_SEQ(FDQuery1BOOK_SEQ)항목 선택 후 AutoGenerateValue 속성을 arAutoInc로 선택합니다.

    화면 구성시 샘플데이터로 사용했던 PrototypeBindSource1을 데이터 모듈에서 삭제(선택 후 Delete 키)합니다.


    3, 데이터와 화면요소 연결하기

    View > LiveBindings Designer 메뉴를 통해 라이브 바인딩 디자이너를 표시하고, 아래 그림을 참고해 화면요소에 데이터를 연결합니다. (지금은 데이터베이스에 데이터가 없으므로 연결을 해도 화면의 변화가 없습니다.)

    도서목록

    도서 상세보기

    새로운 도서추가

    4, 데이터 입력, 수정, 삭제 기능 구현하기

    화면에서 입력받은 데이터를 입력, 수정, 삭제하는 기능을 구현합니다.


    데이터 모듈에 데이터 처리 메소드 추가

    1. DataAccessModule.pas으로 이동 후 FDConnection1 컴포넌트의 BeforeConnect 이벤트에 아래의 코드를 입력합니다.
      procedure TDataModule1.FDConnection1BeforeConnect(Sender: TObject);
      begin
      // 윈도우가 아닌 경우 데이터베이스 경로를 배포경로로 조정
      {$IFNDEF MSWINDOWS}
        FDConnection1.Params.Values['Database'] := TPath.Combine(TPath.GetDocumentsPath, 'BOOKLOG.GDB');
      {$ENDIF}
      end;
    2. DataAccessModule.pas의 코드 에디터 창을 표시합니다.(폼 디자이너에서 F12)
    3. 상단 uses절에 FMX.Graphics, System.IOUtils를 추가합니다.
    4. 선언부 public 영역에 아래의 코드를 입력합니다.
        public
          { Public declarations }
          procedure Connect; // 데이터베이스 연결
          procedure AppendMode; // 입력 모드로 변경
          procedure EditMode; // 수정 모드로 변경
          procedure SetImage(ABitmap: TBitmap); // 이미지저장(본문, 목록의 썸네일 이미지)
          procedure SaveItem; // 항목 저장(입력/수정)
          procedure CancelItem; // 입력/수정 모드 취소
          procedure DeleteItem; // 선택항목 삭제
        end;
    5. 구현부(선언부에 입력 후 Ctrl + Shift + C 누르면 구현부 자동 생성)에 아래의 코드를 입력합니다.
      // 입력/수정 모드 취소
      procedure TDataModule1.CancelItem;
      begin
        if FDQuery1.UpdateStatus = TUpdateStatus.usInserted then
          FDQuery1.Cancel;
      end;
      
      // 데이터베이스 연결
      procedure TDataModule1.Connect;
      begin
      {$IFNDEF MSWINDOWS}
        FDConnection1.Params.Values['Database'] := TPath.Combine(TPath.GetDocumentsPath, 'BOOKLOG.GDB');
      {$ENDIF}
        FDConnection1.Connected := True;
        FDQuery1.Active := True;
      end;
      
      // 현재항목 삭제
      procedure TDataModule1.DeleteItem;
      begin
        FDQuery1.Delete;
        FDQuery1.ApplyUpdates(0);
        FDQuery1.CommitUpdates;
        FDQuery1.Refresh;
      end;
      
      // 수정모드
      procedure TDataModule1.EditMode;
      begin
        FDQuery1.Edit;
      end;
      
      // 입력모드
      procedure TDataModule1.AppendMode;
      begin
        FDQuery1.Insert;
      end;
      
      // 항목 저장
      procedure TDataModule1.SaveItem;
      begin
        FDQuery1.Post;
        FDQuery1.ApplyUpdates(0);
        FDQuery1.CommitUpdates;
        FDQuery1.Refresh;
      end;
      
      // 이미지 저장(본문이미지와 목록에 표시할 썸네일)
      procedure TDataModule1.SetImage(ABitmap: TBitmap);
      var
        Thumbnail: TBitmap;
        ImgStream, ThumbStream: TMemoryStream;
      begin
        if FDQuery1.UpdateStatus = TUpdateStatus.usUnmodified then
          FDQuery1.Edit;
      
        ImgStream := TMemoryStream.Create;
        ThumbStream := TMemoryStream.Create;
        try
          ABitmap.SaveToStream(ImgStream);
          Thumbnail := ABitmap.CreateThumbnail(100, 100);
          Thumbnail.SaveToStream(ThumbStream);
      
          (FDQuery1.FieldByName('BOOK_IMAGE') as TBlobField).LoadFromStream(ImgStream);
          (FDQuery1.FieldByName('BOOK_THUMB') as TBlobField).LoadFromStream(ThumbStream);
        finally
          ImgStream.Free;
          ThumbStream.Free;
        end;
      end;

    화면 기능과 데이터 처리 메소드 연결

    1. 폼 디자이너로 돌아와 아래의 코드를 참고해 데이터 처리기능을 추가합니다.

      procedure TForm1.FormCreate(Sender: TObject);
      begin
        TabControl1.TabPosition := TTabPosition.None;
        TabControl1.TabIndex := 0;
      
        OverflowMenu.Visible := False;
      
        vsbEditFocus.OnCalcContentBounds := CalcContentBoundsProc;
      
        DataModule1.Connect; // 데이터베이스 연결
      end;
      
      procedure TForm1.btnNewItemClick(Sender: TObject);
      begin
        DataModule1.AppendMode; // 입력 모드로 변경
        GotoNew;
      end;
      
      // 수정
      procedure TForm1.lstItemModifyClick(Sender: TObject);
      begin
        OverflowMenu.Visible := False;
        DataModule1.EditMode; // 수정 모드로 변경
        GotoNew;
      end;
      
      // 삭제
      procedure TForm1.lstItemDeleteClick(Sender: TObject);
      begin
        OverflowMenu.Visible := False;
      
        MessageDlg('해당 정보를 삭제하시겠습니까?', TMsgDlgType.mtWarning,
          [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0, procedure(const AResult: TModalResult)
          begin
            if AResult = mrYes then
            begin
              DataModule1.DeleteItem; // 선택항목 삭제
              GotoList;
            end;
          end);
      end;
      
      procedure TForm1.btnCancelClick(Sender: TObject);
      begin
        DataModule1.CancelItem; // 입력/수정 모드 취소
        GotoList;
      end;
      
      procedure TForm1.btnSaveItemClick(Sender: TObject);
      begin
        DataModule1.SaveItem; // 현재항목 저장
        GotoList;
      end;
      
      procedure TForm1.ChangeImageEvent(Image: TBitmap);
      begin
        imgNewItem.Bitmap.Assign(Image);
        DataModule1.SetImage(Image); // 이미지 저장
      end;

    5, 데이터베이스 파일과 라이선스파일 배포 등록하기

    이제 모든 개발이 완료되었습니다. IBLite 데이터베이스를 이용한 경우에는 IBLite 데이터베이스 파일과 IBLite 라이선스 파일과 라이브러리를 앱 배포시 함께 배포해야 합니다.


    IBLite 데이터베이스 파일 배포 등록하기

    1. Project > Deployment 메뉴를 선택해 배포 관리자 화면을 표시합니다.
    2. Add files 버튼을 누르고 1단계에서 만든 BOOKLOG.GDB 파일을 선택해 추가합니다.
    3. 설정선택 콤보박스를 Android platform과 iOS Device platform으로 선택하고 각각 아래를 참고해 Remote Path를 수정합니다.
      • Android platform - assets\internal\
      • iOS Device platform - StartUp\Documents\

    IBLite 라이선스 파일과 라이브러리 배포 등록하기

    1. IBLite, IBTOGO 테스트 라이선스 배포방법 페이지를 참고해 reg_iblite.txt 파일을 다운로드 합니다.
      1. https://reg.codegear.com/srs6/activation.do 페이지 이동
      2. 제품구매(또는 트라이얼 다운로드) 시 받은 라이선스 메일을 참고해 Serial Number와 Registration Code 입력 후 Next 버튼 클릭
      3. 하단에서 파일 다운로드 기능을 이용해 C:\Users\Public\Documents\Embarcadero\InterBase\redist\InterBaseXE3 경로에 파일 다운로드
      4. 다운로드된 텍스트파일(reg_XXXXXXX.txt)를 "reg_iblite.txt"로 이름 변경
    2. 배포 관리자 화면에서 Add Featured Files 버튼 클릭 후 Interbase TOGO 라이브러리 선택
      1. InterBase ToGo > iOSDevice 항목 선택 > reg_ibtogo.txt 선택해제
      2. InterBase ToGo > Android 항목 선택 > reg_ibtogo.txt 선택해제

    (옵션)앱 이름을 바꾸고 아이콘으로 단장하기

    앱의 이름 바꾸기

    1. Project > Option 메뉴 선택 후 Version Info 메뉴 선택 합니다.
    2. 상단의 타겟 플랫폼을 선택 후 플랫폼에 맞는 항목을 입력합니다.
      • 안드로이드 : label
      • iOS(아이폰) : CFBundleDisplayName
    3. 각각 '나의 도서관' 입력 후 OK 버튼으로 저장합니다.

    앱의 아이콘/스플래쉬 이미지 바꾸기

    1. Project > Option  메뉴 선택 후 Application 항목을 선택합니다.
    2. 상단의 Target에서 플랫폼을 선택 후 목록에 있는 아이콘과 스플래쉬 이미지를 지정합니다.
      (목록의 이미지 크기에 맞는 이미지를 준비해야 합니다. 샘플아이콘 다운로드)

    6, 원하는 모바일 디바이스에 배포하고 실행! 끝~

    • 배포를 원하는 플랫폼을 선택하고 Run > Run Without Debugging 메뉴를 통해 배포 및 실행합니다.
      (안드로이드 개발환경 설정은 앱메소드 튜토리얼 동영상을 통해 확인할 수 있습니다.)

    개발도구

    참고








    • 더스틴 2014.11.12 11:22

      안녕하세요. 좋은 내용 올려주셔서 감사합니다.
      소스중에 아래 부분은 C++빌더로는 어떻게 표현되는 것인지요?
      (FDQuery1.FieldByName('BOOK_IMAGE') as TBlobField).LoadFromStream(ImgStream);

      • Favicon of https://blog.hjf.pe.kr BlogIcon 험프리.김현수 2014.11.12 16:47 신고

        아래 링크를 참고하시면 도움이 되실것 같네요.^^(제가 C++ 문법이 짧아서요^^)
        http://codeback.net/cbuilder/using-tblobfield-and-tblobstream-in-cbuilder
        해결되시면 해결하신 내용 좀 남겨주세요. 제가 C++빌더로 컨버전해보고 싶네요.(가능하시면 소스코드 보내주시면 감사하겠습니다^^)

    • 더스틴 2014.11.12 23:43

      위에 제가 질문 드린 내용은 해결되었습니다. 아래와 같이 하면 잘되더군요. ^^
      dynamic_cast<TBlobField*>(FDQuery1->FieldByName("BOOK_IMAGE"))->LoadFromStream(ImgStream);
      아무튼 빠른 피드백 감사합니다.
      김현수님의 블로그 내용이 많은 도움 됩니다. 정말 감사드려요.

    • 아이리스 2015.03.23 11:51

      죄송한데 계속 ibconsol애서요. Bad parameters on attach or create database
      CHARACTER SET UTF8 is not defined 이런문구가 뜨면서 데이터베이스 생성이 안됩니다. 캐릭터셋을 none
      하면 만들어지기는 하는데 이번에 델파이에서는 type mismatch for field ' BOOK_TITLE', expecting: WideString actual:String. 이런 에러 문구가 떠서 엑티브를 할수가 없군요. 문자형셋이 안맞아서 그런거 같은데 해결법좀요

    • 하이길동 2015.05.26 10:11

      안녕하세요 다름이 아니오라 db관련으로 궁금한것이 있어 이렇게 문의드립니다
      interbase 나 firebird로 된 sql문을 sqlite로 바꾸려면
      어떻게 해야 되는지 알고 싶어 문의드립니다
      sqlite에 없는 것 같은 generator 같은것(????)
      sqlite로 작성하니 여기서부터 에러가 계속 나서 ~
      "BOOK_THUMB" BLOB SUB_TYPE 0 SEGMENT SIZE 80,
      "BOOK_IMAGE" BLOB SUB_TYPE 0 SEGMENT SIZE 80,
      CONSTRAINT "BOOK_SEQ_PK" PRIMARY KEY ("BOOK_SEQ")
      );

      /* BOOK_SEQ 자동증가 */
      CREATE GENERATOR "BOOK_SEQ_GEN";
      CREATE TRIGGER "SET_BOOK_SEQ" FOR "BOOK_LOG"
      ACTIVE BEFORE INSERT POSITION 0 AS
      BEGIN
      new.BOOK_SEQ = gen_id(BOOK_SEQ_GEN, 1);
      END;

      • Favicon of https://blog.hjf.pe.kr BlogIcon 험프리.김현수 2015.05.26 14:45 신고

        자동증가 필드를 지원하는 방식은 DB마다 다른데요.
        구글에서 "sqlite 자동증가"로 검색해 보시면 첫번째 링크인 볼랜드 포럼에서 다음 내용을 참고할 수 있네요.
        http://interbase.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=835

    • 이성열 2015.06.18 14:37

      너무나 많은 도움 받고 갑니다.
      나도 모르게 북마크에 추가하게 되네요.