====== 개발 가이드 ======
===== xDataSet 개요 =====
이 장에서는 xFrame5 솔루션의 xDataSet 기능에 대한 기술적인 개요에 대하여 설명한다.
여기에서는 xDataSet 내부 구조에 대한 개념적인 부분을 설명하며, 이 장에서 기술하는 내용은 아래와 같다.
  * xDataSet 개요
  * xDataSet 내부 아키텍처
  * xDataSet 데이터 처리 흐름 아키텍처
==== xDataSet 개요 ====
xDataSet 이란 xFrame5 솔루션에서 UI 및 서버 부분에서 데이터를 처리하기 위한 아키텍처이다.
xDataSet 아키텍처는 UI 부분에서 처리하는 부분과 서버에서 처리하는 부분이 상호 연관적인 관계를 가지고 유기적으로 데이터를 처리하기 기반을 제공한다.
전체적인 아키텍처 구조는 아래의 그림과 같다.
{{ .:development_guide:00.png?nolink |}}
위의 그림에서 데이터 흐름에 대한 설명은 아래와 같다.
|< 100% 50px - >|
^  구분  ^ 설명 ^
|  1  | 사용자 시스템에서 사용자가 트랜잭션을 발생시키기 위해서 트랜잭션 I/O 맵에 정의한 트랜잭션 ID 정보를 지정하여 트랜잭션 발생 함수를 호출한다. |
|  2  | 
  * xFrame-Viewer 내부의 xDataSet 컴포넌트가 트랜잭션 ID의 입력 맵 정보를 기준으로 데이터 셋에서 업무 서버 시스템으로 송신할 데이터를 조립한다.
  * 이때, 데이터 셋에 저장되어 있는 데이터뿐만 아니라, 화면의 메타 정보도 함께 조립하여 업무 서버 시스템으로 송신한다.
 |
|  3  | 업무 서버 시스템의 업무 어플리케이션은 사용자 시스템으로부터 수신 받은 정보를 xdataset5.jar 라이브러리를 이용하여 필요한 데이터를 추출한다. |
|  4  | 업무 서버 시스템의 업무 어플리케이션은 DBMS 와 연동하여 데이터 처리를 수행한다. |
|  5  | 업무 서버 시스템의 업무 어플리케이션은 사용자 시스템으로 송신할 데이터를 xdataset5.jar 라이브러리를 이용하여 설정한다. |
|  6  | 클라이언트로 송신될 데이터가 모두 설정된 이후에, 데이터를 사용자 시스템으로 송신하여, 업무 처리를 완료한다. |
|  7  | 사용자 시스템에서는 업무 서버로부터 수신 받은 데이터를 xDataSet 컴포넌트에 의해서 자동 분석한다. |
|  8  | 사용자 시스템의 xDataSet 시스템은 트랜잭션 ID 의 출력 맵 정보를 기준으로 데이터를 화면에 자동으로 표시한다. |
==== xDataSet 주요 기능 ====
xDataSet 의 주요 기능은 아래의 표와 같다.
|< 100% 150px - >|
^  구분  ^ 주요 기능 ^
| 사용자 시스템\\ (개발자 시스템) | 
  * 글로벌 데이터 셋 기능
  * 데이터 셋과 UI 컴포넌트간 1:N 데이터 바인딩 기능
  * Query를 이용한 데이터 셋 자동 생성 기능 및 초기 데이터 설정 기능
  * 데이터 셋을 이용한 화면 UI 컴포넌트 생성 및 자동 바인딩 기능
  * 트랜잭션 맵 기능을 통한 데이터 셋 I/O 설정 기능
  * First-Row 방식의 데이터 표시 기능
 |
| 업무 서버 시스템 | 
  * 사용자 시스템의 UI로부터 수신된 데이터의 자동 분석
  * 사용자 시스템으로 송신할 데이터에 대한 설정 기능
  * 화면에 대한 Meta 정보 추출 기능
  * 데이터 압축 송수신 기능
  * First-Row 방식으로 데이터를 사용자 시스템의 UI로 송신하는 기능
 |
==== xDataSet 내부 아키텍처 ====
사용자 시스템에서 처리되는 xDataSet 내부 아키텍처는 아래와 같다.
=== 데이터 셋 구분 ===
데이터 셋은 화면 데이터 셋과 글로벌 데이터 셋으로 구분되며, 각각의 특징은 아래와 표와 같다.
|< 100% 150px ->|
^  구분  ^ 주요 기능 ^
| 화면 데이터 셋 | 
  *각각의 개별 화면에서 정의한 데이터 셋
  *각각의 개별 화면에서만 접근 가능
 |
| 글로벌 데이터 셋 | 
  *전역적으로 정의한 데이터 셋
  *개별 화면에서 접근 가능
 |
=== 송수신 데이터 구조 ===
업무 서버로 송신되는 데이터에 대한 구조는 아래의 그림과 같다.
{{ .:development_guide:01.png?nolink |}}
송수신 데이터의 각각의 항목에 대한 설명은 아래의 표와 같다.
|< 100% 150px 50em>|
^  구분  ^ 주요 기능 ^
| 트랜잭션 URL 파라미터  | 
  *트랜잭션 맵에서 트랜잭션 URL 부분에 사용자가 지정한 파라미터 정보
  *파라미터 정보는 GET 방식의 URL 지정 방식과 동일
  *파라미터 이름 중 [XDATASET] 은 xFrame 내부에서 이용하므로 사용하면 안 됨
|
| 화면 데이터 셋 | 
  *각각의 개별 화면에서 지정한 데이터 셋
  *트랜잭션 맵에서 지정한 데이터 셋의 데이터만 송수신 됨.
|
| 글로벌 데이터 셋  | 
  *글로벌 데이터 셋으로 트랜잭션 맵에서 지정한 데이터 셋만 송수신 됨
|
| 화면 메타 정보 | 
  *화면 메타 정보는 아래의 데이터로 구성됨
  *화면 속성의 [trancode]와 [transactionheader] 프로퍼티 정보
  *화면 경로 및 이름 : 화면이 개발 툴 내에서 저장되어 있는 경로 및 이름
  *사용자 시스템 IP 주소 : 실제 사용자 IP 주소
  *트랜잭션 맵 ID : 사용자가 발생시킨 트랜잭션 ID
|
=== 내부 데이터 셋 구조 ===
=== xDataSet ID ===
각각의 xDataSet은 고유의 ID를 가지며, 각각의 ID 는 다음과 같은 제약 사항이 있다.
|< 100% 150px ->|
^  구분  ^ 주요 기능 ^
| 화면 데이터 셋  | 
  * 각각의 화면내의 xDataSet ID는 유일한 값을 가짐
  * 화면 간 xDataSet의 이름은 동일해도 상관없음
  * 화면내의 xDataSet ID는 글로벌 데이터 셋의 ID와 중복될 수 없음
|
| 글로벌 데이터 셋 | 
  * 전역적으로 유일한 값을 가짐
  * 화면내의 xDataSet ID 값과 중복될 수 없음
|
=== xDataSet 컬럼 정의 ===
xDataSet 컬럼은 다음과 같은 속성을 가진 컬럼들로 구성된다
|< 100% 150px ->|
^  구분  ^ 주요 기능 ^
| Column  | 
  * 데이터 셋의 컬럼 이름
  * 단일 데이터 셋 내에서는 중복되지 않는 값을 가짐
|
| Description | 
  * 컬럼에 대한 부가 설명
  * Query 실행기를 통해서 컬럼 정보를 설정할 경우에는, 테이블 정의 시에 지정한 컬럼의 [Comment] 값으로 설정됨
|
| Length | 
  * 컬럼에 들어갈 수 있는 데이터의 최대 길이
  * Query 실행기를 통해서 컬럼 정보를 설정할 경우에는, 테이블 정의 시에 지정한 컬럼의 [Length] 값으로 설정됨
|
=== 데이터 셋 내부 구조 ===
xFrameViewer 에서 사용하는 xDataSet 은 아래 그림과 같이 데이터 셋의 데이터 이외에도 부가적인 정보를 가지고 있다.
{{ .:development_guide:02.png?nolink |}}
위의 그림에서 예시한 데이터 셋 정보와 같이 데이터 셋 내부는 아래와 같이 데이터 부와 메타 데이터 부로 구성되며, 각 부분에 대한 설명은 아래와 같다.
|< 100% 150px 160px ->|
^  구분  |^ 주요 기능 ^
| xDataSet 데이터 부 || 
  * xDataSet에 저장되어 있는 실제 데이터
  * 데이터 셋의 컬럼별/로우별로 데이터가 저장됨
 |
| xDataSet\\ 메타 데이터 부 | ROW ID | 
  * 데이터 셋 레코드의 로우 값
 |
| ::: | RECORD_STATUS | 
  * 데이터 셋의 변경 상태 정보이며, 트랜잭션이 끝나면 모두 기본 상태의 NORMAL로 초기화됨
  * NORMAL : 기존 데이터에서 값이 변경되지 않은 상태 (기본 상태)
  * UPDATE : 기존 데이터에서 값이 변경된 레코드 상태
  * DELETE : 기존 데이터에서 값이 삭제된 레코드 상태
  * INSERT : 기존 데이터에 새롭게 추가된 데이터 레코드 상태
 |
| ::: | RECORD_KEY | 
  * 각 레코드를 구별하는 유일한 값
 |
| 상태 데이터 부 | UI 콘트롤 바인드 정보  | 
  * 데이터 셋과 BIND된 UI 콘트롤 정보 리스트
  * 하나 이상의 UI 콘트롤이 하나의 데이터 셋에 바인딩 될 수 있음
 |
| ::: | 전체 레코드 개수 | 
  * 현재 데이터 셋에 저장되어 있는 전체 레코드 개수
 |
| ::: | CURRENT_ROW | 
  * 현재 사용자가 보고 있는 레코드 위치
  * 비어있는 데이터 셋 내에 처음으로 데이터가 저장되는 경우는 첫번 째 레코드 위치로 설정
  * 데이터 셋이 그리드가 아닌 일반 텍스트성 콘트롤에 바인드 되어 있을 경우, UI 콘트롤에 표시되는 데이터는 CURRENT_ROW에 해당하는 데이터 셋의 정보가 표시됨
  * 데이터 셋이 그리드 콘트롤에 바인딩 되어 있을 경우, 이 정보는 현재 UI 콘트롤에서 사용자가 선택한 ROW가 됨
 |
=== 트랜잭션 맵 구조 ===
트랜잭션 맵은 화면에서 업무 서버 시스템과의 통신 시 송수신 데이터에 사용되는 데이터 셋의 정보와 업무 서버 시스템의 URL 정보를 관리하는 맵이다.
트랜잭션 맵은 아래와 같은 정보를 정의한다.
  * 하나의 업무 화면에서는 하나 이상의 트랜잭션을 정의할 수 있으며, 각각의 트랜잭션은 트랜잭션 ID로구분된다.
  * 트랜잭션 ID별로 업무 서버 시스템의 URL 정보와 송수신 데이터 셋의 정보를 정의한다.
  * 송수신 대상 데이터 셋은 각각의 데이터 셋의 송수신 대상 컬럼을 정의한다.
  * 데이터 셋의 송수신 대상 레코드 기준을 정의한다.
=== 업무 서버 시스템 URL 정보 설정 방법 ===
트랜잭션 ID 별로 업무 서버 시스템 URL 을 지정하는 방법은 아래와 같다.
  * 업무 서버 시스템 URL = BASE_URL + TRANSACTION_URL
BASE_URL 은 업무 서버 시스템의 기본 URL 정보를 지정하는 값으로 트랜잭션마다 반복되는 정보를 미리 정의하고,
업무 시스템의 URL 정보를 일괄적으로 적용하기 위해서 사용된다.
설정방법은 [UI 개발 환경 설정] – [UI 환경 설정] 항목을 참고한다.
=== 데이터 셋의 송수신 대상 레코드 기준 정의 ===
트랜잭션 ID 에 대한 송수신 대상 데이터 셋을 지정하는 방법은 아래의 표와 같이 입력/출력에 따라 구분되어 지정하며,
설정 값에 따라 데이터를 송수신하는 대상 데이터가 결정된다.
|< 100% 100px 100px ->|
^  구분   |^ 설명 ^
^ 입출력 구분  ^ 설정 값  |   |
| 입력 | 공백 | 트랜잭션 발생시 업무 서버로 송신되지 않는 데이터 셋 |
| ::: | ALL | 트랜잭션 발생시 업무 서버로 데이터 셋의 모든 데이터가 송신됨 |
| ::: | UPDATE | 트랜잭션 발생시 업무 서버로 데이터 셋의 데이터 중에서 [RECORD STATUS] 상태가 “UPDATE, DELETE, INSERT”로 설정된 레코드만 송신됨 |
| ::: | CHECKED | 
  * 트랜잭션 발생시 업무 서버로 데이터 셋의 레코드 상태와 무관하게 그리드 콘트롤에서 Check된 레코드만 송신됨.
  * Check 방식을 사용하기 위해서는 데이터 셋과 링크된 그리드 콘트롤의[use_checkrow] 및 [multi_checkrow] 속성을 사용함.
  * 이때, 레코드의 상태는 변경 없음.
 |
| 출력 | 공백 | 
  * 트랜잭션 발생시 업무 서버로부터 수신처리 되지 않음.
  *업무 서버에서 해당 데이터 셋에 대한 데이터를 설정한 경우에도 데이터를 처리하지 않음
 |
| ::: | UPDATE | 
  * 업무 서버로부터 수신된 데이터에서 데이터의 [RECORD KEY] 값을 기준으로 기존 데이터를 업데이트함
  * 업무 서버로부터 수신된 데이터에서 [RECORD KEY] 값에 해당하는 데이터가 기존에 없는 경우에는 데이터 셋에 새롭게 추가됨
|
| ::: | CLEAR | 기존에 저장된 데이터 셋의 모든 데이터를 삭제하고, 업무 서버로부터 수신된 데이터로 데이터 셋의 데이터를 설정함 |
==== xDataSet 데이터 처리 흐름 아키텍처 ====
===일반 데이터 처리 흐름도 ===
xDataSet 의 데이터는 업무 서버 시스템과 사용자 UI 시스템간에 데이터를 아래의 그림과 같이 처리한다.
{{ .:development_guide:03.png?nolink |}}
|< 100% 50px ->|
^  구분  ^ 설명 ^
|  1  | 사용자는 UI 이벤트(예: [조회] 버튼 클릭)를 발생시켜 업무 화면의 request_submit() 함수를 호출하여 정의된 트랜잭션 ID에 해당하는 트랜잭션을 발생시킴|
|  2  | xFrame Viewer에서 트랜잭션 ID에 해당하는 업무 서버 시스템의 URL 정보와 트랜잭션 IO 맵 정보를 기준으로 업무 서버 시스템으로 송신할 데이터를 설정|
|  3  | 
  * 송신 데이터는 데이터 셋의 데이터 이외에도 부가적인 데이터가 송신됨
  * 송신 데이터의 구조는 [xDataSet 내부아키텍처 - 송수신 데이터 구조] 참조
 |
|  4  | xdataset5.jar 라이브러리를 이용해서 입력 데이터를 얻어오고 비즈니스 업무 요건에 따라 처리|
|  5  | xdataset5.jar 라이브러리를 이용해서 출력 데이터를 설정 |
|  6  | xFrame Viewer에서 출력 데이터에 대한 수신 및 데이터 처리가 완료되면, 개발자가 정의한 트랜잭션 완료 시 처리할 비즈니스 로직을 처리하기 위해, 화면의 on_submit_complete() 함수를 호출|
===== xFrame5 개발 환경 설정 =====
이 장에서는 xFrame5 개발 환경을 설정하는 방법을 설명한다.
  * xFrame5 서버 환경 설정
  * xFrame5 UI 개발 환경 설정
==== 서버 환경 설정 ====
=== Eclipse 프로젝트 생성 ===
Eclipse 에서 다음과 같이 신규 프로젝트를 생성한다. (project name : xFrameApp)
{{ .:development_guide:04.png?nolink |}}
새로 생성된 프로젝트의 [Properties]를 선택하여 Default Output Folder를 xFrameApp/WebContent/WEBINF/classes 로 선택한다. classes 폴더가 없을 경우에는 생성한 후 설정한다.
{{ .:development_guide:33.png?nolink |}}
=== 톰캣 서버 설정 ===
[Window] – [Show View] – [Servers] 를 클릭한 후 [Servers] 탭에서 새로운 서버를 생성하고 앞서 생성한 프로젝트(xFrameApp)을 추가한다. 톰캣 서버의 버전은 해당 환경에 맞게 선택한다.
{{ .:development_guide:6.png?nolink |}}
{{ .:development_guide:7.png?nolink |}}
=== xFrame5 서버 환경 설정 ===
다음 그림을 참고로 xFrame5의 서버 환경을 구성한다.
{{ .:development_guide:08.png?nolink |}}
  * WebContent 디렉토리 하위에 project를 생성하고 그 하위에 sample 디렉토리를 생성한다.
  * C:\xFrame5 디렉토리에 xframe5.css, xframe5.html, xframe5.ico, xframe5.js 파일을 WebContent 디렉토리에 복사한다.
  * xFrame5 설치 디렉토리인 C:\xFrame5 디렉토리 하위에 xfs 디렉토리 중, css, ext, html, lib 폴더를 WebContent 디렉토리로 복사한다.
  * C:\xFrame5\jar\ 디렉토리에 xdataset5-xxxxxxxx.jar, mysql-connector-java-5.1.10-bin.jar 및 json-simple1.1.1.jar 파일을 WebContent\WEB-INF\lib\ 에 복사한다
  * WebContent 하위에 jsp 폴더를 생성한다.
=== 프로젝트 디렉토리 구조 및 파일 개요 ===
프로젝트 디렉토리 구조 및 내용은 아래와 같다.
{{ .:development_guide:09.png?nolink |}}
=== XDATASET_BASEURL 설정 ===
xframe5.js 파일 내 XDATASET_BASEURL 을 http://127.0.0.1:8080/xFrameApp/jsp/ 로 설정한다.
{{ .:development_guide:10.png?nolink |}}
==== UI 개발 환경 설정 ====
=== xFrame5 프로젝트 생성 디렉토리 확인 ===
Eclipse 에서 생성한 xFrameApp 프로젝트 내 WebContent\project\sample 폴더를 선택 후 마우스 우클릭하여 [Properties] 를 선택하여 xFrame5@DevStudio 에서 프로젝트 루트 디렉토리로 사용할 디렉토리를 확인한다.
{{ .:development_guide:11.png?nolink |}}
=== xFrame5@DevStudio 시작  ===
바탕화면에 xFrame5@DevStudio 아이콘을 더블클릭하여 DevStudio 를 실행한다.
시작 화면에서 [File]탭 > [프로젝트 생성] 탭을 선택한 후 프로젝트 생성 경로를 [xFrame5 프로젝트 생성 디렉토리 확인]에서 확인한 디렉토리를 선택한다.
프로젝트 아이디와 이름을 [sample]로 입력한 후 생성 버튼을 클릭한다.
{{ .:development_guide:12.png?nolink |}}
=== UI 환경 설정 ===
xFrame5@DevStudio [도구] 메뉴에서 [옵션]을 선택한다.
{{ .:development_guide:13.png?nolink |}}
[미리보기] 탭에서 HTML5 기본 URL 을 http://127.0.0.1:8080/xFrameApp/xframe5.html 로 입력한다.
{{ .:development_guide:14.png?nolink |}}
[기타] 탭에서 Transaction 탭 보기를 선택하고, 인코딩 방식을 UTF-8 로 선택한다.
{{ .:development_guide:15.png?nolink |}}
===== xDataSet 활용 예제 =====
이 장에서는 xDataSet 을 활용한 예제를 통해 xDataSet 의 사용법을 익힌다.
  *  예제 개요
  *  예제 DB구성
  *  예제 UI 개발 및 서버 개발
==== 예제 개요 ====
xDataSet 을 이용한 직원정보조회 예제를 따라 해보며, xDataSet 의 기본적인 사용방법을 학습한다. 이 예제를 통해 트랜잭션과 데이터 셋의 사용방법도 함께 살펴보도록 한다.
본 예제는 다음과 같은 개발 환경을 전제로 기술한다.
|< 100% 100px 100px ->|
^  구분  ^  소프트웨어  ^ 참고사이트 |
| 개발 툴 | Eclipse | https://www.eclipse.org/ |
| 웹 서버 | Tomcat | http://tomcat.apache.org/ |
| DB | MySQL | https://www.mysql.com/ |
다음은 이 예제의 최종 실행화면이다.
{{ .:development_guide:16.png?nolink |}}
==== 예제 DB 구성 ====
=== 테이블 생성 ===
=== 테이블 스키마 ===
예제에서 활용될 스키마는 아래와 같으며, [테이블 생성 스크립트] 항목을 참고로 DB 에 해당 테이블을 생성한다.
테이블 명 : EMP_INFO
|< 100% 100px 100px 60px 60px ->|
^  컬럼 명  ^  데이터 형식  ^  길이  ^  Key  ^ Comment  ^
| emp_no | CHAR | 6 |  PK  | 직원번호  |
| emp_no | VARCHAR | 20 |  -  | 직원이름  |
| emp_age | INT | - |  -  | 직원나이  |
| mail_addr | VARCHAR | 100 |  -  | 메일주소  |
=== 테이블 생성 스크립트 ===
다음 스크립트를 참고로 예제 테이블을 생성한다.
CREATE TABLE `emp_info` (
    `emp_no` CHAR(6) NOT NULL COMMENT '직원번호',
    `emp_name` VARCHAR(20) DEFAULT NULL COMMENT '직원이름',
    `emp_age` INT(3) DEFAULT NULL COMMENT '직원나이',
    `mail_addr` VARCHAR(100) DEFAULT NULL COMMENT '메일주소',
    PRIMARY KEY (`emp_no`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
=== 데이터 생성 ===
=== 데이터 입력 스크립트 ===
다음 스크립트를 참고로 예제 데이터를 입력한다.
INSERT INTO `emp_info`(`emp_no`,`emp_name`,`emp_age`,`mail_addr`) VALUES ('100111','김우섭',49,'wskim@softbase.co.kr');
INSERT INTO `emp_info`(`emp_no`,`emp_name`,`emp_age`,`mail_addr`) VALUES ('100112','곽경환',42,'khkwak@softbase.co.kr');
INSERT INTO `emp_info`(`emp_no`,`emp_name`,`emp_age`,`mail_addr`) VALUES ('100115','전시교',50,'skjeon@softbase.co.kr');
INSERT INTO `emp_info`(`emp_no`,`emp_name`,`emp_age`,`mail_addr`) VALUES ('100117','김종인',47,'jikim@softbase.co.kr');
INSERT INTO `emp_info`(`emp_no`,`emp_name`,`emp_age`,`mail_addr`) VALUES ('100118','유동균',40,'dkyou@softbase.co.kr');
INSERT INTO `emp_info`(`emp_no`,`emp_name`,`emp_age`,`mail_addr`) VALUES ('100124','임기조',35,'kjlim@softbase.co.kr');
INSERT INTO `emp_info`(`emp_no`,`emp_name`,`emp_age`,`mail_addr`) VALUES ('100133','김용진',31,'yjkim@softbase.co.kr');
INSERT INTO `emp_info`(`emp_no`,`emp_name`,`emp_age`,`mail_addr`) VALUES ('100212','김용상',36,'yskim@softbase.co.kr');
INSERT INTO `emp_info`(`emp_no`,`emp_name`,`emp_age`,`mail_addr`) VALUES ('100215','김용완',54,'ywkim@softbase.co.kr');
INSERT INTO `emp_info`(`emp_no`,`emp_name`,`emp_age`,`mail_addr`) VALUES ('100218','김지태',33,'jtkim@softbase.co.kr');
INSERT INTO `emp_info`(`emp_no`,`emp_name`,`emp_age`,`mail_addr`) VALUES ('100221','홍성일',50,'sihong@softbase.co.kr');
INSERT INTO `emp_info`(`emp_no`,`emp_name`,`emp_age`,`mail_addr`) VALUES ('100223','김경환',43,'khkim@softbase.co.kr');
INSERT INTO `emp_info`(`emp_no`,`emp_name`,`emp_age`,`mail_addr`) VALUES ('100226','정학길',28,'hkjung@softbase.co.kr');
INSERT INTO `emp_info`(`emp_no`,`emp_name`,`emp_age`,`mail_addr`) VALUES ('100312','유승한',29,'shyou@softbase.co.kr');
INSERT INTO `emp_info`(`emp_no`,`emp_name`,`emp_age`,`mail_addr`) VALUES ('100319','방인홍',36,'ihbang@softbase.co.kr');
INSERT INTO `emp_info`(`emp_no`,`emp_name`,`emp_age`,`mail_addr`) VALUES ('100325','김종욱',37,'jwkim@softbase.co.kr');
commit;
====  UI 개발 ====
=== UI 개발 환경 설정 ===
=== xFrame5 프로젝트 생성 디렉토리 확인 ===
Eclipse에서 생성한 xFrameApp 프로젝트 내 WebContent\project\sample 폴더 선택 후 마우스 우클릭하여 [Properties] 를 선택하여 xFrame5@DevStudio 에서 프로젝트 루트 디렉토리로 사용할 디렉토리를 확인한다.
{{ .:development_guide:05.png?nolink |}}
=== xFrame5@DevStudio 시작 ===
바탕화면에 xFrame5@DevStudio 아이콘을 더블클릭하여 DevStudio 를 실행한다.
시작 화면에서 [File]탭 > [프로젝트 생성] 탭을 선택한 후 프로젝트 생성 경로를 [xFrame5 프로젝트 생성 디렉토리 확인]에서 확인한 디렉토리를 선택한다.
프로젝트 아이디와 이름을 [sample]로 입력한 후 생성 버튼을 클릭한다.
{{ .:development_guide:12.png?nolink |}}
=== UI 환경 설정 ===
xFrame5@DevStudio [도구] 메뉴에서 [옵션]을 선택한다.
{{ .:development_guide:13.png?nolink |}}
[미리보기] 탭에서 HTML5 기본 URL 값으로 http://127.0.0.1:8080/xFrameApp/xframe5.html 을 입력한다.
{{ .:development_guide:14.png?nolink |}}
[기타] 탭에서 Transaction 탭 보기를 선택하고, 인코딩 방식을 UTF-8 로 선택한다.
{{ .:development_guide:15.png?nolink |}}
=== UI 화면 구성 ===
=== 새 화면 생성 ===
프로젝트 창에서 프로젝트명을 선택 후 마우스 우 클릭하고 [디렉토리 생성] 메뉴를 선택한다. 디렉토리명은 “xDataset”으로 입력하여 디렉토리를 만든다.
{{ .:development_guide:17.png?nolink |}}
[화면] -> [새 화면] 메뉴를 선택하여 새 화면을 생성한다. 속성 창에서 title, width, height 을 설정한다.
{{ .:development_guide:18.png?nolink |}}
[화면] -> [저장] 메뉴를 선택하고 [xDataset] 디렉토리를 선택한 후 “Employee” 라는 이름으로 저장한다.
{{ .:development_guide:19.png?nolink |}}
=== 데이터 셋 설정 ===
화면 하단의 [Transaction] 탭의 [xDataSet] 탭을 선택한다. xDataSet List 에 xDataSet 을 추가한 후 아래와 같이 [xDataset ID]와 [Description]을 입력한다.
{{ .:development_guide:20.png?nolink |}}
=== 데이터 셋 컬럼 정의 ===
직원 정보를 저장할 DS_EMP_INFO 데이터 셋의 컬럼을 정의한다. DB 상에 존재하는 테이블을 가져와 데이터 셋의 컬럼을 정의하기 위해서 퀴리 실행기를 이용하여 [Column]을 정의한다.
다음 그림과 같이 xDataSet List 에서 [DS_EMP_INFO]를 클릭하고 [xDataSet Column]에 있는 [쿼리 실행기]를 클릭한다.
{{ .:development_guide:21.png?nolink |}}
[쿼리 실행기]가 실행 되면 [환경 설정] 버튼을 클릭하여 현재 사용하고 있는 데이터베이스 정보를 선택 및 입력한다.
{{ .:development_guide:22.png?nolink |}}
[쿼리 실행기]에서 “select * from emp_info” 질의문을 입력하고 [Run]버튼을 클릭하면 DB 의 테이블과 값들을 가져온 것을 확인 할 수 있다.
[DS_EMP_INFO]의 [xDataSet Column]을 DB 와 동일하게 정의하기 위해서 [컬럼정보 가져오기] 버튼을 클릭한다.
참고로 [초기 데이터 가져오기] 버튼을 누르면 DB 에 저장된 데이터를 [Column Data]에 가져올 수도 있다.
{{ .:development_guide:23.png?nolink |}}
==== 트랜잭션 설정 ====
트랜잭션은 정보의 교환이나 데이터베이스 갱신 등 일련의 작업들에 대한 연속처리 단위를 의미한다. 화면에서 발생하는 트랜잭션을 정의하기 위하여 [Transaction]탭내에 [xTranMap] 탭을 선택한다.
xTranMap Info 에 트랜잭션을 추가한 후 아래와 같이 [xTranMapID], [URL], [Comment] 값을 입력한다.
{{ .:development_guide:24.png?nolink |}}
[xTranMap I/O]를 설정한다. 입력 및 출력 항목에 대한 자세한 설명은 [xDataSet 내부 아키텍처 - 내부 데이터 셋 구조]를 참고한다.
{{ .:development_guide:25.png?nolink |}}
Transaction I/O 설정
|< 100% 150px 150px 150px - >|
^ xTranMapID ^ 출력데이터 ^ 데이터 구분  ^ 설명 ^
| TR_SELECT_EMP | DS_EMP_INFO | CLEAR | 직원 정보를 저장하고 있는 데이터 셋의 데이터를 삭제하고 업무 서버로부터 수신한 데이터를 이용해서 기존 데이터로 저장한다. |
=== UI 화면 개발 ===
직원 정보 그리드는 xDataSet 과 연결 되어 서버에서 보내주는 데이터를 가져와 화면에 출력 한다.
다음 그림과 같이 xDataSet 목록 창에서 [DS_EMP_INFO]를 클릭하고 Drag & Drop 으로 그리드를 생성하고, 이벤트를 처리할 [조회] 버튼을 생성한다.
{{ .:development_guide:26.png?nolink |}}
화면 구성 컨트롤 및 속성
|< 100% 50px 100px 100px - >|
^  구분  ^컨트롤^ 속성 ^ 값 ^
|  1  | 버튼 | name | btnSelect |
|  :::  | ::: | text | 조회 |
|  2  | 그리드 | name | grdEmpList |
그리드를 더블클릭 하면 [그리드 열 속성 등록 창]이 나온다. 각 열의 [데이터부]에 [link_data] 속성을 확인 해보면 xDataSet 과 연동되는 ID 의 Column 과 연결되어 있는 것을 알 수 있다. 예를 들어, [직원번호] 열의 [link_data]는 [DS_EMP_INFO]에 있는 [emp_no] Column 과 연결되어 있다.
{{ .:development_guide:27.png?nolink |}}
==== 이벤트 처리 ====
=== 트랜잭션 발생 버튼 이벤트 처리 ===
사용자가 [조회] 버튼을 클릭할 경우, 업무 서버와의 데이터 트랜잭션이 발생한다. 이벤트를 처리할 함수를 생성하기 위해 [조회]버튼 속성에서 on_mouseup 항목을 클릭하여 다음과 같이 함수를 생성한다.
{{ .:development_guide:28.png?nolink |}}
구현할 스크립트는 다음을 참고한다.
function btnSelect_on_mouseup()
{
    screen.requestsubmit("TR_SELECT_EMP", true);
}
화면에 설정된 xTranMapID 를 기준으로 서버와 데이터를 송수신한다.
화면과 서버가 데이터를 주고받기 위해서는 screen 오브젝트의 requestsubmit API 를 사용하여 트랜잭션을발생시키며, screen.requestsubmit(strTranMapID, bProcAsync)의 파라미터는 다음 표를 참고 한다.
|< 100% 150px - >|
^ 파라미터 ^ 설명 ^
| strTranMapID | 
  * 트랜잭션을 발생시킬 트랜잭션 ID 를 지정한다. 트랜잭션 ID 는 [xTranMapInfo]에서 정의됨
  * 트랜잭션 ID 는 업무 서버의 URL 정보와 송수신될 데이터 셋의 정보를 구별함
 |
| bProcAsync | 
트랜잭션에 대한 통신 처리는 Sync 방식과 Async 방식으로 처리할 것을 지정함
  * true : 트랜잭션이 Async 방식으로 처리되고, on_submitcomplete 함수가 콜백 처리됨
  * false : 트랜잭션이 Sync 방식으로 처리되고, on_submitcomplete 함수가 콜백 처리되지 않음
|
=== Sync 방식과 Async 방식의 차이 ===
트랜잭션 발생시에 처리 방식인 Sync 방식과 Async 방식의 차이는 아래의 표와 같다.
|< 100% 200px - - >|
^ 항목 ^ Sync 방식 ^ Async 방식 ^
| 함수 리턴 시점 | 업무 서버로 데이터를 송신하고, 업무 서버로부터 데이터를 수신한 후, 수신 데이터에 대한 처리가 완료되면 함수 리턴  | 업무 서버로 데이터가 송신 완료되면 함수 리턴 |
| 트랜잭션 완료 | requestsubmit 함수 호출이 리턴되면 거래 처리 완료 | screen_on_submitcomplete 함수가 호출되면 거래 처리 완료 |
| 트랜잭션 처리 결과 정보 확인  | screen 오브젝트의 특정함수를 호출하여 결과 확인 | screen_on_submitcomplete 함수의 파라미터로 확인 |
| 특징 | 트랜잭션이 완료되기 전에 사용자는 아무런 동작을 수행할 수 없음 | 트랜잭션을 완료되기 전에 사용자가 다른 동작이나 또 다른 트랜잭션을 발생시킬 수 있음 |
=== 트랜잭션 완료 버튼 이벤트 처리 ===
트랜잭션이 완료되면 화면의 on_submitcomplete 함수가 xFrame-Viewer 에 의해서 자동으로 호출된다.
트랜잭션 완료 시에 자동으로 호출되는 screen_on_submitcomplete 함수의 역할은 트랜잭션의 정상 처리 유무에 대한 정보를 전달하기 위한 것이며, 함수의 파라미터 값은 아래의 표와 같다.
|< 100% 150px - >|
^ 파라미터 ^ 설명 ^
| mapid | 처리 완료된 트랜잭션의 ID 로 툴에서 설정한 xTranMapID 값에 해당함 |
| result | 처리 완료에 대한 정보로 ‘1’인 경우에는 정상이고, 그 이외의 경우에는 장애임  |
| recv_userheader | 업무 서버 시스템에서 setUserHeader 함수를 통해서 지정한 값 |
| recv_code | 업무 서버 시스템에서 setErrorMessage 함수를 통해서 지정한 코드 값 |
| recv_msg | 업무 서버 시스템에서 setErrorMessage 함수를 통해서 지정한 메시지 값 |
본 예제에서는 트랜잭션이 완료되었을 경우, 아래의 그림과 같이 해당 정보를 개발콘솔에 표시하도록 개발할 것이다. 화면에서 on_submitcomplete 이벤트를 선택한다.
{{ .:development_guide:29.png?nolink |}}
트랜잭션 완료 처리시에 호출되는 실제 함수 소스는 아래와 같다.
function screen_on_submitcomplete(mapid, result, recv_userheader, recv_code, recv_msg)
{
    // 처리 결과를 콘솔에 출력
    factory.consoleprint("mapid = " + mapid);
    factory.consoleprint("result = " + result);
    factory.consoleprint("recv_userheader = " + recv_userheader);
    factory.consoleprint("recv_code = " + recv_code);
    factory.consoleprint("recv_msg = " + recv_msg);
}
==== 서버 개발 ====
=== 예제 구현 ===
=== 직원 정보 조회 처리 개발 ===
WebContent\jsp 디렉토리 아래 SelectEmp.jsp를 생성하고, 다음 내용을 파일에 복사한다.
26~29 라인은 예제 테이블이 생성된 DB 환경에 알맞게 수정한다.
<%@ page import="java.sql.DriverManager" %>
<%@ page import="java.sql.Connection" %>
<%@ page import="java.sql.PreparedStatement" %>
<%@ page import="java.sql.ResultSet" %>
<%@ page import="xdataset5.XDataSet5" %>
<%
Connection conn = null;         // DB Connection Object
PreparedStatement pstmt = null; // JDBC PreparedStatement Object
ResultSet rs = null;            // Query Result Set Object
XDataSet5 xDataSet5 = null;     // XFrame XDataSet Object
try {
    // Clear out's buffer
    out.clearBuffer();
    // Create XDataSet object
    xDataSet5 = new XDataSet5(request, response);
    System.out.println("ScreenNo : " + xDataSet5.getScreenNo());
    System.out.println("IP : " + xDataSet5.getTerminalIpAddress());
    System.out.println("Map ID : " + xDataSet5.getTransactionMapId());
    System.out.println("User Header : " + xDataSet5.getUserHeader());
    // For MySQL
    String driverClass = "com.mysql.jdbc.Driver";
    String dbUrl = "jdbc:mysql://localhost:3306/xframe_data";
    String dbUserId = "xframe";
    String dbUserPasswd = "xframe";
    // Load JDBC Driver and connect to database
    Class.forName(driverClass);
    conn = DriverManager.getConnection(dbUrl, dbUserId, dbUserPasswd);
    // Create a select query for EMP_INFO table
    String sQuery =
        "SELECT " +
            "emp_name, emp_no, emp_age, mail_addr " +
        "FROM " +
            "EMP_INFO " +
        "ORDER BY " +
            "emp_name";
    // Creae a statement and execute a statement
    pstmt = conn.prepareStatement(sQuery);
    rs = pstmt.executeQuery();
    // Loop a select result records
    for(int nRow = 0; rs.next(); nRow++) {
        // Get data from resultset
        String emp_name = rs.getString("emp_name");
        if(emp_name == null) emp_name = "";
        String emp_no = rs.getString("emp_no");
        if(emp_no == null) emp_no = "";
        String emp_age = rs.getString("emp_age");
        if(emp_age == null) emp_age = "";
        String mail_addr = rs.getString("mail_addr");
        if(mail_addr == null) mail_addr = "";
        // Set output data to XDataSet object
        xDataSet5.setData("DS_EMP_INFO", "emp_name", nRow, emp_name);
        xDataSet5.setData("DS_EMP_INFO", "emp_no", nRow, emp_no);
        xDataSet5.setData("DS_EMP_INFO", "emp_age", nRow, emp_age);
        xDataSet5.setData("DS_EMP_INFO", "mail_addr", nRow, mail_addr);
    }
    // Return data to XFrame
    xDataSet5.returnData();
}
catch(Exception e) {
    try {
        if(xDataSet5 != null) {
            // Set error code and error message
            xDataSet5.setErrorMessage("XDATASET_ERROR", e.getMessage());
            System.out.println(e.getMessage());
            xDataSet5.returnData();
        }
    }
    catch(Exception ex) {
        System.out.println("Exceptino Msg = " + ex.toString());
    }
}
finally {
    // Release a database resources
    if(rs != null) { try { rs.close(); } catch(Exception ignore) {} }
    if(pstmt != null) { try { pstmt.close(); } catch(Exception ignore) {} }
    if(conn != null) { try { conn.close(); } catch(Exception ignore) {} }
}
%>
=== 예제 실행 ===
구현된 [직원정보조회] 예제를 확인해 본다.
=== 톰캣 서버 시작 ===
톰캣 시작 버튼을 클릭하여 서버를 시작한다.
{{ .:development_guide:30.png?nolink |}}
=== 예제 확인 ===
[보기] – [미리보기(HTML5)]를 클릭하여 구현한 예제를 실행한다
{{ .:development_guide:31.png?nolink |}}
[조회] 버튼을 클릭하여 직원정보가 정상적으로 조회되는 지 확인한다.
{{ .:development_guide:32.png?nolink |}}