Anyframe Gen

Version 1.2.0

본 문서의 저작권은 삼성SDS에 있으며 Anyframe 오픈소스 커뮤니티 활동의 목적하에서 자유로운 이용이 가능합니다. 본 문서를 복제, 배포할 경우에는 저작권자를 명시하여 주시기 바라며 본 문서를 변경하실 경우에는 원문과 변경된 내용을 표시하여 주시기 바랍니다. 원문과 변경된 문서에 대한 상업적 용도의 활용은 허용되지 않습니다. 본 문서에 오류가 있다고 판단될 경우 이슈로 등록해 주시면 적절한 조치를 취하도록 하겠습니다.


I. Overview
1. Introduction
1.1. 개요
1.2. 기술 지원
1.3. 유지 보수
1.4. 시스템 사양
2. Key Features
2.1. 주요 특징
2.2. Anyframe Gen의 구조
2.3. 프로젝트 중심의 개발
2.4. CRUD 코드 생성
2.5. 테스트 코드 생성
II. Installation
3. 설치
4. [UPGRADE] 1.2.0 버전으로 업그레이드 하는 방법
III. Command Line Interface
5. 환경 설정
5.1. Anyframe Gen 환경 변수 설정
5.2. Anyframe Gen 도움말
5.3. DB 구동
6. Commands for Project
6.1. 프로젝트 생성
6.2. Anyframe 플러그인 설치 및 제거
6.3. Domain Class 생성
6.4. CRUD 소스 코드 생성
6.4.1. Business Layer 코드 생성
6.4.2. Presentation Layer 코드 생성
6.4.3. Business Layer와 Presentation Layer 코드 함께 생성
6.5. DB 정보 변경
7. 어플리케이션 및 프로젝트 빌드
7.1. 어플리케이션 빌드
7.1.1. 예시1) 어플리케이션 빌드 후 클래스 배포
7.1.2. 예시2) 어플리케이션 빌드 후 JAR 파일 배포
7.1.3. 예시3) 어플리케이션 빌드 후 WAR 파일 배포
7.2. 프로젝트 빌드
8. 어플리케이션 빌드 및 실행
8.1. 어플리케이션 빌드 및 웹 어플리케이션 실행
IV. Eclipse Plugin
9. Installing Anyframe Gen Plugin
9.1. Anyframe Gen 플러그인 설치
10. Preferences
10.1. Eclipse 설정
10.2. DB 구동
11. New Project Creation
11.1. Create new project
11.2. 프로젝트 생성 시 발생할 수 있는 에러 해결 Tip
11.2.1. Out of memory
11.2.2. Project Clean & JSP Validation Error
12. Domain Generation
13. CRUD Generation
14. Configuration
15. JDBC Setting
16. Anyframe Plugin Installation
17. Project/Application Build
17.1. Project Build
17.2. Application Build
V. Templates Extensions
18. 프로젝트 템플릿 확장
18.1. Web 타입 프로젝트 템플릿 확장
18.2. Service 타입 프로젝트 템플릿 확장
19. 소스 코드 템플릿 확장
19.1. 템플릿 폴더 생성
19.2. 템플릿 파일 목록 작성(template.config)
19.3. 템플릿 파일(*.ftl) 수정
19.4. 템플릿 파일(*.ftl) 변수
19.5. 변경된 템플릿 파일(*.ftl) 적용

I.Overview

Anyframe Gen은 Anyframe 기반의 프로젝트 개발 시 기존 개발 방식보다 훨씬 쉽고 빠르게 개발을 시작할 수 있도록 Scaffolding, 코드 생성 기능 등을 제공하는 개발 툴이다.

개요에서는 툴을 통해 제공되는 기능, 특징, 자동 생성된 코드를 통해 재사용될 수 있는 공통 기능 등에 대해 설명하고 있다. 이밖에 기술 지원 방법 및 유지 보수 그리고 시스템 사양 등에 대한 사항도 제시하고 있다. 또한 Anyframe Gen의 주요 특징, 구조, 프로젝트 중심 개발에 대해 소개하고 있다.

1.Introduction

Anyframe Gen은 최신 오픈소스(Anyframe)를 바탕으로 기존 방식보다 훨씬 쉽고 빠르게 개발을 시작할 수 있도록 Scaffolding, 코드 생성 기능 등을 제공한다.

1.1.개요

  • Anyframe Gen 설치를 통해 기존의 복잡한 설치 및 설정 작업을 최소화한다. Anyfame Gen의 설치로 Anyframe 설치, 프로젝트 구조 생성, 단위 모듈 생성, 소스코드 생성, 빌드/테스트/패키지 스크립트 생성 등이 가능하다.

  • Web 타입, Service 타입으로 프로젝트 타입을 선택할 수 있어 프로젝트 중심의 개발이 가능하다.

  • 엔티티 클래스(JPA)와 기본 템플릿(FreeMarker)을 이용한 도메인 객체 중심의 CRUD 기본 코드가 생성되고, 자동으로 단위/통합 테스트 케이스가 작성된다. 템플릿은 프로젝트의 개발표준에 따라 변경이 가능하다.

  • 템플릿을 이용해 생성된 CRUD 소스는 default 템플릿의 경우 Anyframe Generic Service 를 기반으로 작성된 코드이며(상속 혹은 참조), miplatform 템플릿의 경우 Anyframe MiPlatform 쿼리서비스(MiPQueryService)를 기반으로 작성된 코드이다.

  • 코드 생성 시, 다음과 같은 공통기능이 제공된다.

    표 1.1. generated common functions

    function
    Generic Service/DAO
    Search (Primary Keys, Required Fields)
    Paging (Paging Navigation Bar)
    Exception / Message Handling
    User Defined Template

  • DB 테이블에 해당하는 도메인 클래스를 생성하고, 해당 도메인 클래스를 기반으로 CRUD 소스 코드를 생성하는 데 이때 DB 테이블에 맞는 테스트 데이터까지 함께 생성해주고 있다. DB는 기본적으로 HSQL DB를 샘플 DB로 제공하고 있으나 Oracle, MySQL, Sybase DB 등 DB 정보를 변경하여, 프로젝트에서 사용하는 DB 기반 코드 생성 기능을 사용할 수 있게 하고 있다. 이때, 각 DB 별 제공되는 테이블 컬럼 타입이 다양하므로 도메인 클래스 생성 시 혹은 CRUD를 위한 테스트 데이터 생성 시 지원되지 않는 타입 정보로 인한 오류가 생길 수 있다. 이 때에는 DB 컬럼 타입 별 매핑되는 자바 타입 정보를 설정해주는 파일 내용을 변경하여 지원해주도록 한다.

1.2.기술 지원

Anyframe Gen에 대한 기술 지원은 Anyframe 오픈소스 커뮤니티 사이트( http://www.anyframejava.org/ )의 포럼 메뉴를 통해 이루어지며, 단순 질의 응답에서부터 소스 코드에 대한 구체적인 가이드 및 해결책을 제시한다. 특정 프로젝트를 위한 기술 컨설팅 지원이 필요한 경우 Anyframe 오픈소스 커뮤니티 사이트의 연락처 를 통해 요청할 수 있다. 또한, 이슈관리시스템인 JIRA( http://dev.anyframejava.org/jira/ )를 통해, Bug Fix, Improvements, New Features 에 대한 이슈들을 요청할 수 있다. 자세한 사용방법은 이곳 을 참조하도록 한다.

1.3.유지 보수

Anyframe 오픈소스 커뮤니티 사이트( http://www.anyframejava.org/ )를 통해 릴리즈된 최신버전 및 이전 버전에 해당하는 라이브러리, 매뉴얼 등을 제공받을 수 있으며 패치 및 업그레이드되는 실시간 파일의 경우 Reuse Repository 를 통해 제공된다. 자세한 사용방법은 이곳 을 참조하도록 한다.

1.4.시스템 사양

하드웨어와 소프트웨어 요구 사항은 다음 테이블에 작성되어 있다. 아래 작성된 하드웨어 사양 이하의 시스템에서도 Anyframe Gen을 사용할 수 있으나, 빠른 성능을 위해서는 아래 사양을 권고한다. 또한 아래 작성된 Storage의 경우, Anyframe Gen 전체 설치 파일에서부터 Eclipse, Tomcat, MiPlatform 등 모든 관련 파일 설치를 합하여 작성된 것으로 Anyframe Gen 만으로는 1GB 이하의 용량을 차지하고 있다. 소프트웨어 요구 사항은 반드시 충족시켜줘야 한다.

표 1.2. System Requirements(HW)

Hardware RequirementsDescription
Memory 1024MB RAM 이상
Storage 1GB 하드 디스크 공간

표 1.3. System Requirements(SW)

Software RequirementsDescription
JDK 1.5.x Version
Eclipse IDE Eclipse 3.3.x Version 이상 지원(Europa/Ganymede/Galileo)

2.Key Features

Anyframe Gen은 어플리케이션 프레임워크인 Anyframe 기반으로 프로젝트를 개발할 때 Anyframe 설치, 프로젝트 생성 및 코드 생성 기능을 통해 개발 편의성을 제공해주는 개발 툴로 CLI(Command Line Interface) 혹은 Eclipse Plugin 툴을 통해 Scaffolding과 코드 생성 기능을 제공한다. 아래 그림에서와 같이 Anyframe 설치에서부터 프로젝트 구조, 코드 생성, 빌드 수행에 이르기까지 개발 프로세스 전반에 걸쳐 개발에 도움을 준다.

2.1.주요 특징

Anyframe Gen은 다음과 같은 주요 특징을 가지고 있다.

  • 개발 대상 프로젝트에 대한 프로젝트 구조 및 단위 모듈, 빌드 스크립트 생성한다.

  • 도메인 클래스를 중심으로 CRUD 기본 코드 생성하고 자동으로 테스트 코드와 테스트 데이터를 생성한다.

  • 프로젝트 개발 시 프로젝트 전체 구조 및 모듈, 소스 코드 생성 기능 및 프로젝트 단위 별 빌드 기능을 제공함으로써 신속한 개발 환경 구성을 가능하게 한다.

  • Anyframe을 사용하여 개발 시 직면하게 되는 복잡한 설정 파일로 인한 잦은 오류 발생 상황을 줄일 수 있다.

  • 개발 초기 공통 개발 템플릿을 따로 구성하여 배포하고 각 개발자들은 배포된 개발 템플릿 소스를 참조하여 수정해서 사용해야 하는 이러한 반복적인 작업을, Anyframe Gen에서 제공하는 코드 생성 기능을 이용하면 하지 않게 된다.

  • Best Practice에 해당하는 샘플 소스 코드를 자동 생성시켜줌으로써 Anyframe을 활용한 개발 시 참조하기 용이하다.

  • 단위 테스트 케이스 및 통합 테스트 케이스를 자동 생성시켜줌으로써 개발 진행 시 테스트를 통한 코드 품질을 향상시킬 수 있다.

  • Anyframe Gen은 자바의 Generic Type 및 JPA Annotation 설정 등의 기능을 이용하므로 JDK 5 이상의 환경에서 사용할 수 있다.

2.2.Anyframe Gen의 구조

Anyframe Gen 설치를 통해 Anyframe, 템플릿, 빌드 도구, 사용되는 모든 라이브러리 설치가 완료된다. 개발 프로젝트의 생성 위치는 꼭 applications 하위로 지정하지 않아도 무방하다.

2.3.프로젝트 중심의 개발

프로젝트별 Eclipse 연계 및 샘플 코드 생성이 가능하며 단위 빌드 기능이 제공된다. 어플리케이션 빌드의 경우 클래스 혹은 war 파일로 패키징 처리된다.

2.4.CRUD 코드 생성

Anyframe Gen을 통해 생성된 도메인 클래스에 대해 CRUD 생성이 가능하다.

2.5.테스트 코드 생성

jMock을 사용하여 단위/통합 테스트 케이스가 자동생성된다. Foreign Key Data 와 같은 복합 키 데이터 처리 관련한 테스트도 가능하다.

II.Installation

Anyframe Gen을 개발 환경에 맞게 설치하도록 한다. 설치 프로그램을 이용하여 손쉽게 설치할 수 있다.

3.설치

Anyframe Gen은 압축파일로 배포되며, 다음과 같은 순서에 의하여 설치한다. Anyframe Gen 설치 시 Anyframe 도 함께 설치가 된다. 따라서, Anyframe Gen을 설치하면 Anyframe 을 따로 설치할 필요가 없다.

  1. Anyframe Gen을 설치하기 위한 [시스템 사양]을 확인한다.

  2. Anyframe Gen의 최신 배포판을 http://www.anyframejava.org/project/gen#downloads 에서 확인한다.

  3. Anyframe Gen의 최신 배포판("Anyframe-gen-x.x.x.x-bin.zip")을 사용자의 컴퓨터에 내려받는다.

  4. 내려받은 최신 배포판의 압축을 원하는 폴더에 푼다.

  5. 압축을 풀면 다음과 같은 파일들이 보인다.

    • licenses : Anyframe Gen을 통해 배포되는 3rd party 라이브러리들에 대한 라이센스 본문과 정리된 목록

    • plugins : Eclipse 플러그인 패키지 (Anyframe Common, Anyframe Gen)

    • Anyframe-gen-x.x.x.x-setup.jar : Anyframe Gen 설치 파일(JAR 파일을 실행시킨다)

    • changelog.txt : 버전 별 변경 사항 로그

    • license.txt : Anyframe Gen 라이센스(Apache License)

    • readme.txt : Anyframe Gen 소개 및 기본 사항

  6. Anyframe Gen 설치를 위해 Anyframe-gen-x.x.x.x-setup.jar 파일을 실행시킨다.

    jar파일 연결 프로그램이 JAVA Platform 인 경우, 해당 파일을 더블클릭하여 실행시킨다. 만약 알집등의 압축프로그램으로 연결이 되어 있는 경우는 해당 프로그램의 지원 확장자에서 *.jar를 빼거나, command 창에서 java 명령어를 통해 실행시킬 수 있다. command 창 실행 후, "java -jar Anyframe-gen-x.x.x.x-setup.jar" 명령어를 수행한다.

  7. 다음 순서대로 설치를 진행한다.

    Apache License에 동의하고 Next 버튼 클릭하면 Anyframe Gen 을 설치할 경로를 지정할 수 있는 창이 조회된다. Anyframe Gen을 설치하고자 하는 폴더를 선택한 후 Next 선택하여 설치를 완료한다. 이때 이 installation path 항목으로 입력된 정보가 Anyframe Gen이 설치된 root 경로 가 되며 이후 매뉴얼 내용에서 [Gen Home] 이라 통칭하도록 한다.

  8. Anyframe Gen이 정해진 경로에 제대로 설치되어 있는지 확인해본다. 아래 그림과 같은 구조로 설치되어 있으면 정상이다. 설치 과정이 모두 완료되면 Anyframe에서 제공하는 모든 라이브러리들과 빌드 도구인 Ant, 프로젝트 및 코드 생성 템플릿, 공통 빌드 스크립트, 샘플 HSQL DB등이 모두 함께 설치 완료된다.

4.[UPGRADE] 1.2.0 버전으로 업그레이드 하는 방법

이전 버전의 Anyframe Gen 1.1.1을 사용하고 있었다면 아래 URL에서 업그레이드 가이드 파일을 다운로드 받은 뒤, 압축을 풀어서 Gen 1.2.0 업그레이드 가이드.ppt 문서를 참조하여 업그레이드를 수행하도록 한다.

  1. Anyframe Gen 1.2.0 으로의 업그레이드를 위해서 Anyframe Portal 사이트의 [Gen 1.1.1 버전에서 1.2.0 버전으로 업그레이드 할 수 있는 가이드 다운로드하기] 를 다운로드 받는다.

  2. 압축 파일을 푼 뒤, Gen 1.2.0 Upgrade Guide.ppt 문서를 따라 진행하도록 한다.

III.Command Line Interface

Command Line Interface를 사용하여 프로젝트 생성, Domain 클래스 및 CRUD 소스 코드 생성, 빌드 및 실행 등의 작업을 할 수 있다. 이때 [빌드]와 [빌드 및 실행]에서 수행하는 빌드가 중복되는 작업이므로 [빌드 및 실행]을 수행시키는 경우 [빌드] 단계는 수행시키지 않는다. CLI(Command Line Interface) 기반의 command를 실행하여 작업하는 경우, 아래 매뉴얼에서 정의한 command arguments 이외의 값 설정 혹은 반드시 필요한 arguments 생략 시 올바르게 동작하지 않을 수 있으므로 유의하도록 한다.

5.환경 설정

Command Line Interface을 사용하기 위한 환경 설정 및 도움말에 대해 알아보자.

5.1.Anyframe Gen 환경 변수 설정

Anyframe Gen 설치 폴더 하위의 bin 폴더에서 command 창을 실행 시킨 다음 env 명령어를 입력하여 env.bat 파일을 실행시킨다.(Windows 환경에서는 env.bat 파일을, Unix 환경에서는 env.sh 파일을 실행시킨다.) GEN_HOME, ANT_HOME, PATH, CLASSPATH, MAINCLASS 등의 환경 변수 설정이 수행된다.

주의 사항

Windows 환경에서는 env.bat 파일을 CLI 상에서 실행시키고, Unix 환경(ex. Mac OS 등)에서는 우선 bin 폴더 하위의 파일들에 대해서 실행 권한을 부여(chmod 755 *)한 후, env.sh 파일을 실행(source env.sh)시킨다. 수행시켜야 할 command는 각 내용의 괄호안을 참고하도록 한다.

5.2.Anyframe Gen 도움말

Command를 통한 작업 시, 사용 가능한 command가 아래 그림과 같으며 이는 gen -help 라는 명령어를 통해 확인 가능하다. gen -help를 통해 확인할 수 있는 명령어는 Anyframe과 Anyframe Gen에서 제공하는 command가 함께 보이는 것이며, Anyframe Gen에서 제공하는 command를 중심으로 확인해본다. Anyframe에서 제공하는 command는 추후 제공되는 Anyframe의 매뉴얼을 참고하도록 한다.

5.3.DB 구동

현재 Anyframe Gen은 샘플 DB로 HSQL DB를 제공하고 있다. [Gen Home]\db\scripts\hsqldb\ 하위의 start.cmd 파일을 실행시켜서 DB를 구동한다. 탐색기로 해당 경로 이동 후, start.cmd 파일을 더블 클릭하면 hsqldb가 구동된다. 만약 Oracle과 같은 다른 DB를 사용한다면 DB를 구동시키고, 프로젝트 생성 후에 DB 정보를 build.properties 파일에 입력해주도록 한다.

주의 사항

Windows 환경에서는 start.cmd 파일을 CLI 상에서 실행시키고, Unix 환경(ex. Mac OS 등)에서는 우선 hsqldb 폴더 하위의 파일들에 대해서 실행 권한을 부여(chmod 755 *)한 후, start.sh 파일을 실행(./start.sh)시킨다.

6.Commands for Project

command를 활용하여 프로젝트 생성, Domain Class 및 CRUD 소스 코드 생성, 그리고 DB 정보 변경 등의 작업을 할 수 있다.

6.1.프로젝트 생성

Command Line Interface를 이용해 프로젝트를 생성해본다.

  1. env를 통해 환경 변수 정보가 설정된 command 창에서 프로젝트 생성을 위해 다음 command를 입력한다. 프로젝트가 생성되는 위치는 command의 옵션에 의해 변경될 수 있다. 여기서는 default인 Gen Home 하위의 applications 폴더에 프로젝트를 생성한다.

  2. 다음의 프로젝트 생성 command를 입력한다.

    gen create-project [-options]
    • ex) gen create-project -pjtname myproject -package com.sds.emp

    • 위 예제는 myproject라는 프로젝트명을 가진 com.sds.emp 패키지의 프로젝트를 생성하는 command로 아래와 같은 option 정보를 추가하여 프로젝트 정보를 변경할 수 있다.

      표 6.1. create-project options

      optiondescriptiondefault value
      -pjtname 프로젝트 이름을 지정할 수 있는 옵션으로 이름을 지정하지 않는 경우 default value에 해당하는 프로젝트가 생성된다. myproject
      -pjttype web or service 타입 프로젝트를 지정한다. 지정하지 않는 경우 web 타입 프로젝트로 생성된다.

      *web: dynamic 웹 프로젝트

      *service : java 프로젝트

      web
      -apphome 프로젝트가 생성될 위치를 설정한다. 옵션값을 설정하지 않으면 기본적으로 [Gen Home] 디렉토리 하위의 applications 폴더 아래에 생성된다. [Gen Home]\applications\
      -package 프로젝트의 대표 패키지명을 입력한다. 차후 소스 코드 생성 시 기준이 되는 소스 패키지명이 된다. 프로젝트명으로 -pjtname에 지정한 값
      -repo [Anyframe에서만 사용되는 옵션] 프로젝트에서 참조하는 라이브러리 파일들을 프로젝트 내로 가져오기 위해 바라보는 Repository 정보를 지정하는 옵션으로 Anyframe Gen을 사용할 경우 모든 참조 라이브러리 파일들이 [Gen Home] 폴더 하위의 repo 폴더에 존재하므로 해당 옵션은 따로 사용하지 않는다. N/A

  3. 프로젝트 생성이 정상적으로 되었는지 확인한다. Web 타입 프로젝트일 경우 dynamic 웹 프로젝트로 생성되고, Service 타입 프로젝트일 경우 자바 프로젝트로 생성된다.

    Web 타입 프로젝트가 생성되면 eclipse 프로젝트 관련 파일들(.project, .classpath)과 Anyframe Foundation 샘플 및 테스트 코드, 빌드 파일(build.xml), 프로젝트 설정 파일(build.properties), 설치된 Anyframe 플러그인 관련 폴더(.metadata) 등이 생성된다.

    Service 타입 프로젝트가 생성되면 eclipse 프로젝트 관련 파일들(.project, .classpath)과 Anyframe Foundation 라이브러리 및 Aspect등 공통 클래스, 설정 파일, 빌드 파일(build.xml), 프로젝트 설정 파일(build.properties), 설치된 Anyframe 플러그인 관련 폴더(.metadata) 등이 생성된다.

    생성된 프로젝트 설정 파일(Properties)을 수정하면, 이후 Domain 클래스 생성 및 CRUD 소스코드 생성 등의 기능에서 수정된 설정 값을 통해 생성되도록 할 수 있다. 아래 표에 설명된 항목별 내용을 보고 DAO Framework, Template type 설정을 비롯하여 다양한 공통 속성 값을 변경시킬 수 있다. DB 관련한 설정 파일 설명에 대해서는 [DB 정보 변경]에 상세하게 설명되어 있다.

    표 6.2. build.properties(프로젝트 정보)

    Property NameDescriptionRequiredDefault Value
    gen.homeAnyframe Gen을 설치한 루트 폴더Y[Gen Home]
    project.name프로젝트 명Ymyproject
    project.version프로젝트 버전Y1.0.0
    project.home프로젝트 루트 폴더 경로Y[Gen Home]\applications\[프로젝트명]
    package.name프로젝트 대표 패키지 명Y프로젝트명
    dao.frameworkDAO Framework 선택(query, hibernate 중 택일)Yquery
    emma.enabled프로젝트 빌드 시 emma를 이용하여 코드 커버리지 리포트 결과 생성 여부Ytrue
    template_type프로젝트 및 CRUD 소스 코드 생성 시 기반이 되는 Template 형태(ex. default, miplatform 등)Ydefault
    project.type프로젝트 타입Yweb
    web.context.pathjetty run 으로 실행시킬때 사용되는 WebContext Path명Y프로젝트 명

6.2.Anyframe 플러그인 설치 및 제거

프로젝트를 생성한 후, Anyframe 에서 제공하는 다음 command 들을 통해 Anyframe 플러그인을 설치 또는 제거할 수 있다.

service 타입 프로젝트는 플러그인의 라이브러리 파일만 설치/제거 할 수 있는 install-lib, uninstall-lib command 만 사용가능하고, web 타입 프로젝트는 라이브러리 파일 설치 뿐만 아니라 샘플도 함께 설치할 수 있는 command도 모두 사용가능하다. Anyframe 플러그인은 해당 플러그인과 관련된 라이브러리와 샘플로 구성되어 있으며, 샘플은 선택적으로 설치될 수 있다.

Anyframe Gen CLI를 통해서 생성할 소스코드의 DAO Framework 또는 Template Type을 디폴트로 지정된 값 이외의 값으로 설정하고 싶은 경우, 이와 관련한 Anyframe 플러그인이 설치되어 있어야 생성된 프로젝트가 정상적으로 동작할 수 있다. 예를 들어, DAO Framework의 디폴트 설정은 Query Service로 되어 있지만 Hibernate/JPA 를 사용하고 싶은 경우, 프로젝트 설정 파일(build.properties)의 dao.framework 의 값을 hibernate으로 변경하는 것 이외에, Anyframe 의 hibernate 플러그인을 설치하여야 한다. 프로젝트 설정 파일과 관련한 설명은 [프로젝트 생성]을 참조하도록 한다.

  • Anyframe 플러그인(라이브러리+샘플코드) 설치

    1. 프로젝트가 생성된 폴더 하위로 이동한다. (예를 들어, myproject 라는 프로젝트를 생성시켰다면 myproject 폴더 하위에서 command를 실행시키도록 한다.)

    2. Anyframe 플러그인 설치(라이브러리+샘플코드) command를 입력한다.

      gen install PLUGIN_NAME [-options]
      • ex) gen install hibernate -package com.sds.emp

      • 위 예제는 hibernate 플러그인에 대한 샘플과 라이브러리를 설치하는 command로 설치되는 샘플의 패키지는 com.sds.emp로 설정된다.

        표 6.3. install options

        optiondescriptiondefault value
        -package플러그인 설치 시 함께 설치되는 샘플 소스 코드의 패키지를 지정하는 옵션으로 지정하지 않았을 경우 src/main/java 밑에 상위패키지 없이 설치된다. N/A
        -repo프로젝트에서 참조하는 라이브러리 파일들을 프로젝트 내로 가져오기 위해 바라보는 Repository 정보를 지정하는 옵션으로 Anyframe Gen을 사용할 경우 모든 참조 라이브러리 파일들이 [Gen Home] 폴더 하위의 repo 폴더에 존재하므로 해당 옵션은 따로 사용하지 않는다.N/A

    3. Anyframe 플러그인(라이브러리+샘플코드)이 정상적으로 설치되었는지 확인한다.

      Anyframe 플러그인(라이브러리+샘플코드)이 정상적으로 설치되었다면, 지정한 패키지 경로에 설치한 플러그인 샘플 소스 코드가 생성되어 있고, src/main/webapp/WEB-INF/lib에 플러그인 관련 라이브러리가 설치되어 있다.

  • Anyframe 플러그인(라이브러리+샘플코드) 제거

    1. 프로젝트가 생성된 폴더 하위로 이동한다. (예를 들어, myproject라는 프로젝트를 생성시켰다면 myproject 폴더 하위에서 command를 실행시키도록 한다.)

    2. Anyframe 플러그인 제거(라이브러리+샘플코드) command를 입력한다.

      gen uninstall PLUGIN_NAME [-options]
      • ex) gen uninstall hibernate

      • 위 예제는 hibernate 플러그인에 대한 샘플과 라이브러리를 제거하는 command이다.

        표 6.4. uninstall options

        optiondescriptiondefault value
        -excludes플러그인 제거시 제외하고 싶은 파일명을 입력한다. 예를 들어, context-hibernate-services.xml 을 hibernate 플러그인 삭제 시 삭제되지 않게 하기 위해서는 -excludes context-hibernate-services.xml 로 옵션을 설정해준다. N/A
        -repo프로젝트에서 참조하는 라이브러리 파일들을 프로젝트 내로 가져오기 위해 바라보는 Repository 정보를 지정하는 옵션으로 Anyframe Gen을 사용할 경우 모든 참조 라이브러리 파일들이 [Gen Home] 폴더 하위의 repo 폴더에 존재하므로 해당 옵션은 따로 사용하지 않는다.N/A

    3. Anyframe 플러그인(라이브러리+샘플코드)이 정상적으로 제거되었는지 확인한다.

      Anyframe 플러그인(라이브러리+샘플코드)이 정상적으로 제거되었다면, 플러그인 샘플 소스 코드 및 관련 라이브러리가 제거된다.

  • Anyframe 플러그인(라이브러리) 설치

    1. 프로젝트가 생성된 폴더 하위로 이동한다. (예를 들어, myproject라는 프로젝트를 생성시켰다면 myproject 폴더 하위에서 command를 실행시키도록 한다.)

    2. Anyframe 플러그인(라이브러리) 설치 command를 입력한다.

      gen install-lib PLUGIN_NAME [-options]
      • ex) gen install-lib hibernate

      • 위 예제는 hibernate 플러그인에 대한 라이브러리를 설치하는 command이다.

        표 6.5. install-lib options

        optiondescriptiondefault value
        -pjtname라이브러리 설치 할 프로젝트명을 지정하는 옵션이다.command를 실행시키는 위치의 프로젝트명
        -target설치할 라이브러리가 위치할 파일 경로를 지정하는 옵션이다.[프로젝트 폴더]/src/main/webapp/WEB-INF/lib
        -metadata플러그인 정보가 있는 metadata 파일의 위치를 지정하는 옵션이다. 프로젝트 폴더 하위
        -repo프로젝트에서 참조하는 라이브러리 파일들을 프로젝트 내로 가져오기 위해 바라보는 Repository 정보를 지정하는 옵션으로 Anyframe Gen을 사용할 경우 모든 참조 라이브러리 파일들이 [Gen Home] 폴더 하위의 repo 폴더에 존재하므로 해당 옵션은 따로 사용하지 않는다.N/A

    3. Anyframe 플러그인(라이브러리)이 정상적으로 설치되었는지 확인한다.

      Anyframe 플러그인(라이브러리)이 정상적으로 설치되었다면, src/main/webapp/WEB-INF/lib에 플러그인 관련 라이브러리가 설치되어 있다.

  • Anyframe 플러그인(라이브러리) 제거

    1. 프로젝트가 생성된 폴더 하위로 이동한다. (예를 들어, myproject라는 프로젝트를 생성시켰다면 myproject 폴더 하위에서 command를 실행시키도록 한다.)

    2. Anyframe 플러그인(라이브러리) 제거 command를 입력한다.

      gen uninstall-lib PLUGIN_NAME [-options]
      • ex) gen uninstall-lib hibernate

      • 위 예제는 hibernate 플러그인에 대한 라이브러리를 제거하는 command이다.

        표 6.6. uninstall-lib options

        optiondescriptiondefault value
        -target삭제할 라이브러리가 위치한 파일 경로를 지정하는 옵션이다.[프로젝트 생성 폴더]/src/main/webapp/WEB-INF/lib
        -metadata플러그인 정보가 있는 metadata 파일의 위치를 지정하는 옵션이다. 프로젝트 생성 폴더 하위
        -repo프로젝트에서 참조하는 라이브러리 파일들을 프로젝트 내로 가져오기 위해 바라보는 Repository 정보를 지정하는 옵션으로 Anyframe Gen을 사용할 경우 모든 참조 라이브러리 파일들이 [Gen Home] 폴더 하위의 repo 폴더에 존재하므로 해당 옵션은 따로 사용하지 않는다.N/A

    3. Anyframe 플러그인(라이브러리)이 정상적으로 제거되었는지 확인한다.

      Anyframe 플러그인(라이브러리)이 정상적으로 제거되었다면, 플러그인 관련 라이브러리가 제거된다.

6.3.Domain Class 생성

Command Line Interface를 이용해 Domain Class를 생성해본다. 이때, 반드시 DB를 구동하여 다음 command를 수행한다. DB가 구동되지 않은 상태에서 Domain Class를 생성하는 경우 socket creation error가 발생한다. 기본적으로 DB 정보는 HSQL로 설정되나 이를 변경하고 싶은 경우 다음 [DB정보 변경] 을 참조한다.

  1. Domain Class 생성 command를 입력한다.

    gen create-model [-options]
    • ex) gen create-model -table "*" -basepackage com.sds.emp.domain

    • 위 예제는 모든 테이블에 대해 Domain Class를 프로젝트 생성 시 지정한 대표 패키지(ex. com.sds.emp) 하위의 domain 패키지 내에 생성하는 command로 아래와 같은 option 정보를 이용하여 Domain Class 생성 대상 및 패키지 정보를 변경할 수 있다.

      표 6.7. create-model options

      optiondescriptiondefault value
      -table Domain Class를 생성하려는 대상 DB 테이블을 선정한다. 테이블에 대한 option 을 따로 설정하지 않는 경우 default로 모든 DB 테이블로부터 Domain Class를 생성하고 있다. 명시적으로 모든 DB Table에 대해서 Domain Class를 생성하기 위해서는 "*" 로 옵션 값을 설정한다. 특정 테이블만 대상으로 Domain Class를 생성하고 싶은 경우 대상 DB 테이블명을 지정하면 된다. 여러 개의 테이블을 대상으로 할 때에는 "," 기호를 이용하여 작성하도록 한다.

      * 이때 테이블명에 대해 대소문자를 구분하므로 유의하여 테이블명을 입력하도록 한다.

      ex) gen create-model -table BOARD,BOARD_MASTER -basepackage com.sds.emp.domain

      "*" (모든 테이블 대상)
      -basepackage DB 테이블로부터 Domain Class를 생성 시 어느 소스 코드 패키지 하위에 생성시킬 지 결정하는 옵션으로, default로 프로젝트 생성 시 설정한 대표패키지 + ".domain" 패키지 경로가 Domain Class 패키지 경로가 된다. 프로젝트 생성 시 지정한 대표 패키지.domain

  2. Domain Class 가 정상적으로 생성되었는지 확인한다.

    Domain Class 생성 시 지정한 -basepackage 값에 해당하는 패키지에 -table 값에 해당하는 Domain Class가 있으면 정상이다. 아래는 생성된 Board.java 코드의 일부분이다.

    @Entity
    @Table(name = "BOARD", schema = "PUBLIC")
    public class Board implements Serializable {
        private BoardId id;
        private BoardMaster boardMaster;
        private String boardName;
        중략...
        public BoardId getId() {
            return this.id;
        }
        public void setId(BoardId id) {
            this.id = id;
        }
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "BOARD_MASTER_ID", nullable = false, 
                    insertable = false, updatable = false)
        public BoardMaster getBoardMaster() {
            return this.boardMaster;
        }
        public void setBoardMaster(BoardMaster boardMaster) {
            this.boardMaster = boardMaster;
        }
        @Column(name = "BOARD_NAME", nullable = false, length = 150)
        public String getBoardName() {
            return this.boardName;
        }
        public void setBoardName(String boardName) {
            this.boardName = boardName;
        }	  
    }

6.4.CRUD 소스 코드 생성

위에서 생성한 Domain Class를 기반으로 CRUD 소스 코드를 생성할 수 있다. 이때 Business Layer와 Presentation Layer 별로 구분하여 소스 코드를 생성할 수도 있고 함께 생성해낼 수도 있다. 각각의 경우로 나누어서 아래에 설명하고 있다. 아래 예제는 default 템플릿 타입으로 설정되어 있는 경우에 해당하며, 이 때 생성된 CRUD 소스코드는 annotation 기반으로 되어 있다.

6.4.1.Business Layer 코드 생성

  1. Business Layer 코드 생성 command를 입력한다.

    gen create-crud ENTITY [-options]
    • ex) gen create-crud Board -package board -scope service

    • 위 예제는 Board Domain class를 기반으로 CRUD 소스 코드 생성 시 대표 패키지(ex. com.sds.emp) + ".board" 패키지 하위에 business layer 코드를 생성시키는 command로 아래와 같은 option 정보를 이용하여 CRUD 소스 코드 생성 시 필요한 타켓 프로젝트와 패키지 경로 위치 그리고 생성 범위 등을 변경할 수 있다.

      표 6.8. create-crud options

      optiondescriptiondefault value
      -package CRUD 소스 코드가 생성될 패키지명을 정하는 옵션으로, 프로젝트 생성 시 지정한 대표 패키지 뒤에 붙게 된다. Domain Class명(소문자)형태
      -scope 생성할 코드가 business layer일 경우 service로 설정하고, presentation layer일 경우 web으로 설정한다. 두 layer에 대한 소스 코드 모두를 함께 생성할 경우 all로 설정한다. all

  2. Business Layer 코드가 정상적으로 생성되었는지 확인한다.

    서비스인터페이스, 서비스구현클래스, DAO인터페이스, DAO구현클래스와 매핑쿼리문등이 생성된다.

    아래는 생성된 자바코드와 속성파일, 매핑쿼리문의 일부분이다. 서비스인터페이스, 서비스구현클래스, DAO인터페이스, DAO구현클래스는 Generic Service를 상속받아 구현되었으므로, 자세한 내용은 Generic Service를 참조한다.

    • 서비스인터페이스 (src/main/java/[대표패키지]/[-package 값]/service/[Entity 클래스명]Service.java)

      public interface BoardService extends GenericService<Board, BoardId> {
          Page getPagingList(SearchVO searchVO) throws Exception;        
      }
    • 서비스구현클래스 (src/main/java/[대표패키지]/[-package 값]/service/impl/[Entity 클래스명]ServiceImpl.java)

      @Service("boardService")
      @Transactional(rollbackFor = {Exception.class}, propagation = Propagation.REQUIRED)
      public class BoardServiceImpl extends GenericServiceImpl<Board, BoardId> 
                          implements BoardService {
      	    
          @Resource
          private BoardDao boardDao;
      	
          @PostConstruct
          public void initialize(){
              super.setGenericDao(boardDao);
          }
          
          /** {@inheritDoc} */
          public Page getPagingList(SearchVO searchVO) throws Exception {
              return super.getGenericDao().getPagingList(searchVO);
          }        
      }
    • DAO인터페이스 (src/main/java/[대표패키지]/[-package 값]/dao/[Entity 클래스명]Dao.java)

      public interface BoardDao extends GenericDao<Board, BoardId> {
          Page getPagingList(SearchVO searchVO) throws Exception;
      }
    • DAO구현클래스 (src/main/java/[대표패키지]/[-package 값]/dao/impl/[Entity 클래스명]Dao[DAO Framework 명]Impl.java)

      @Repository("boardDao")
      public class BoardDaoQueryImpl extends GenericDaoQuery<Board, BoardId> 
                          implements BoardDao {
      
          @Resource
          IQueryService queryService;
          @Resource
          IPropertiesService propertiesService;
      	
          public BoardDaoQueryImpl() {
              super(Board.class);
          }
          
          @PostConstruct
          public void initialize(){
              super.setQueryService(queryService);
              super.setPropertiesService(propertiesService);
          }
          
          /** {@inheritDoc} */
          public Page getPagingList(SearchVO searchVO) throws Exception {
              int pageIndex = searchVO.getPageIndex();
              int pageSize = super.getPropertiesService().getInt("PAGE_SIZE");
              int pageUnit = super.getPropertiesService().getInt("PAGE_UNIT");
              중략...
              return super.findListWithPaging(ClassUtils.getShortName(getPersistentClass()), 
                              args, pageIndex, pageSize, pageUnit);
          }    
      }
    • 매핑쿼리문 (src/main/resources/query/mapping-query-[Entity 클래스명].xml)

      <queryservice>
        <queries>
          <query id="createBoard">
            <statement>
              INSERT INTO BOARD (BOARD_ID, BOARD_DESC, BOARD_MASTER_ID, BOARD_NAME, 
                     BOARD_ORDER, BOARD_TOPICS, REG_DATE) 
              VALUES (:vo.id.boardId, :vo.boardDesc, :vo.id.boardMasterId, :vo.boardName, 
                     :vo.boardOrder, :vo.boardTopics, :vo.regDate)
            </statement>
          </query>
          중략...
        </queries>
      </queryservice>
    • MessageSoruce (src/main/resources/message/message-generation.properties)

      # -- Board-START
      board.id.boardId=Board Id		
      board.id.boardMasterId=Board Master Id		
      board.boardDesc=Board Desc
      board.boardName=Board Name
      board.boardOrder=Board Order
      board.boardTopics=Board Topics
      board.regDate=Reg Date
      
      # -- success messages -- 
      success.board.create=Board has been added successfully.
      success.board.update=Board has been updated successfully.
      success.board.delete=Board has been deleted successfully.
      
      # -- error messages --
      error.boardserviceimpl.create=Board data not created
      error.boardserviceimpl.create.solution=Enter correct data for mandatory field 
      or enter data according to formats means date format as yyyy-mm-dd
      error.boardserviceimpl.create.reason=Entered incorrect data for Board
      중략...
    • 통합테스트케이스 (src/test/java/[대표패키지]/[-package 값]/dao/[Entity 클래스명]DaoTest.java)

      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration(locations = { "classpath*:/spring/context-*.xml" })
      public class BoardDaoTest{
      
          @Resource(name="boardDao")
          private BoardDao boardDao;
      
          @Test	    
          public void testAddAndRemoveBoard() throws Exception {
              Board board = new Board();            
              BoardId id = new BoardId();
              id.setBoardId(new Integer(1732013925));            	
              id.setBoardMasterId(new Integer(1681092908));            	
              board.setId(id);
              중략...
          }
      }
    • 단위테스트 케이스 (src/test/java/[대표패키지]/[-package 값]/service/impl/[Entity 클래스명]ServiceImplTest.java)

      @RunWith(JMock.class)
      public class BoardServiceImplTest{
          private BoardServiceImpl service = null;
          private BoardDao dao = null;
          private Mockery context = new JUnit4Mockery();
      
          @Before
          public void setUp() {
              System.setProperty("log4j.configuration", "log4j-test.xml");
              this.dao = context.mock(BoardDao.class);
              this.service = new BoardServiceImpl();        
              ObjectUtil.setField(this.service, "boardDao", this.dao);
              this.service.initialize();
          }
      
          @After
          public void tearDown() {
              service = null;
          }
      
          @Test
          public void testGetBoard() throws Exception {
              log.debug("testing get...");
      		
              final BoardId id = new BoardId();
              id.setBoardId(257077485);	        
              id.setBoardMasterId(555604496);	        
              final Board board = new Board();
      
              // set expected behavior on dao 
              context.checking(new Expectations() {{
                  one(dao).get(with(equal(id)));
                  will(returnValue(board));
              }});
      
              Board result = service.get(id);
              assertSame(board, result);
          }
      중략...

참고

build.properties 에서 dao.framework 값을 변경하지 않았을 경우 기본 DAO Framework 은 Query Service 로 설정되어 있다. 위의 경우는 Query Service로 설정되어 있는 경우에 해당한다.

build.properties 에서 dao.framework 값을 hibernate 으로 설정하여 DAO Framework 으로 Hibernate 을 사용하는 경우, CRUD 소스코드 생성시 DAO구현 클래스는 BoardDaoHibernateImpl.java 로, 매핑쿼리문은 hibernate/dynamic/dynamic-hibernate-board.xml 형태로 생성된다.

6.4.2.Presentation Layer 코드 생성

  1. Presentation Layer 코드 생성 command를 입력한다.

    gen create-crud ENTITY [-options]
    • ex) gen create-crud Board -package board -scope web

    • 위 예제는 Board Domain class를 기반으로 CRUD 소스 코드 생성 시 대표 패키지(ex. com.sds.emp) + ".board" 패키지 하위에 presentation layer 코드를 생성시키는 command이다.

      표 6.9. create-crud options

      optiondescriptiondefault value
      -package CRUD 소스 코드가 생성될 패키지명을 정하는 옵션으로, 프로젝트 생성 시 지정한 대표 패키지 뒤에 붙게 된다. Domain Class명(소문자)형태
      -scope 생성할 코드가 business layer일 경우 service로 설정하고, presentation layer일 경우 web으로 설정한다. 두 layer에 대한 소스 코드 모두를 함께 생성할 경우 all로 설정한다. all

  2. Presentation Layer 코드가 정상적으로 생성되었는지 확인한다.

    서비스와 통신을 하기 위한 컨트롤러 파일, UI파일(JSP 또는 MiPlatform 용 XML파일) 등이 생성된다.

    • 컨트롤러 (src/main/java/[대표패키지]/[-package 값]/web/[Entity 클래스명]Controller.java)

      @Controller
      @RequestMapping("/board.do")
      public class BoardController {
      
          /**
           * Resource Injection on BoardService
           */
          @Resource(name="boardService")
          private BoardService boardService;
      
          중략...    
      
          /**
           * Display Board list.
           * @param searchVO form object with request parameters bound onto it
           * @param model model containing control data
           * @return the prepared Board list view
           * @throws Exception in case of getting Board paging list
           */ 
          @RequestMapping(params = "method=list")  
          public String list(@ModelAttribute("search") SearchVO searchVO, Model model) throws Exception 
          {
              Page resultPage = boardService.getPagingList(searchVO);
      
              model.addAttribute("boardList", resultPage.getList());
              model.addAttribute("resultPage", resultPage);
      		        
              return "generation/board/listBoard";        
          }
      }
    • UI JSP 파일 (src/main/webapp/WEB-INF/jsp/[프로젝트명]/*.jsp)

      <%@ include file="/sample/common/taglibs.jsp"%>
      <html>
      <head>
          <%@ include file="/sample/common/meta.jsp" %>
          <title><fmt:message key="boardList.title"/></title>
          <meta name="heading" content="<fmt:message key='boardList.heading'/>"/>    
          <link rel="stylesheet" href="<c:url value='/sample/css/admin.css'/>" 
              type="text/css">
      	
          <script type="text/javascript" 
              src="<c:url value='/sample/javascript/CommonScript.js'/>"></script>    
          <script language="JavaScript">
              function fncAddBoardView() {
                  document.location.href="<c:url value='/board.do?method=addView'/>";
              }	
              function fncSearchBoard(arg) {
                  var conditions = ["boardId","boardMasterId","boardTopics"]	
      중략...
    • 단위테스트케이스 (src/test/java/[대표패키지]/[-package 값]/web/[Entity 클래스명]ControllerTest.java)

      @RunWith(JMock.class)
      public class BoardControllerTest {
      
          private BoardController controller;
          private String SUCCESS_ADDVIEW = "generation/board/viewBoard";
          private String SUCCESS_ADD = "redirect:/board.do?method=list";
          private String SUCCESS_GET = "generation/board/viewBoard";
          private String SUCCESS_UPDATE = "forward:/board.do?method=list";
          private String SUCCESS_LIST = "generation/board/listBoard";
          private String SUCCESS_DELETE = "redirect:/board.do?method=list";
          private Mockery context = new JUnit4Mockery();
          private BoardService mockService = null;
      	
          @Before   
          public void setUp() throws Exception {
              System.setProperty("log4j.configuration", "log4j-test.xml");
      
              this.mockService = context.mock(BoardService.class);                
              this.controller = new BoardController();
              this.controller.setBoardService(this.mockService);       
          }
          
          public void setBoardController(BoardController controller) {
              this.controller = controller;
          }
              
          @Test
          public void testAddView() throws Exception{
              String viewName = this.controller.addView(new ExtendedModelMap());
              
              assertEquals("returned correct view name", SUCCESS_ADDVIEW, viewName);
         }
         중략...

6.4.3.Business Layer와 Presentation Layer 코드 함께 생성

  1. Business Layer 와 Presentation Layer 코드 생성 command를 입력한다.

    gen create-crud ENTITY [-options]
    • ex) gen create-crud Board -package board -scope all

    • 위 예제는 Board Domain class를 기반으로 CRUD 소스 코드 생성 시 대표 패키지(ex. com.sds.emp) + ".board" 패키지 하위에 business layer 코드와 presentation layer 코드를 함께 생성시키는 command이다.

      표 6.10. create-crud options

      optiondescriptiondefault value
      -package CRUD 소스 코드가 생성될 패키지명을 정하는 옵션으로, 프로젝트 생성 시 지정한 대표 패키지 뒤에 붙게 된다. Domain Class명(소문자)형태
      -scope 생성할 코드가 business layer일 경우 service로 설정하고, presentation layer일 경우 web으로 설정한다. 두 layer에 대한 소스 코드 모두를 함께 생성할 경우 all로 설정한다. all

  2. Business Layer, Presentation Layer 코드가 정상적으로 생성되었는지 확인한다. dao,service,web 폴더가 존재하여야 하며, 각각 business layer, presentation layer 생성 시 결과 화면을 참조하여 확인해보도록 한다.

6.5.DB 정보 변경

Command Line Interface를 이용하여 build.properties 파일에 변경한 DB 설정 정보를 프로젝트 내 관련 파일들에 모두 반영되도록 한다. default로 HSQL DB를 사용하는 sampledb를 제공하고 있다. 해당 프로젝트에서 HSQL DB가 아닌 다른 DB를 사용하는 경우 build.properties 파일을 수정해준 뒤, DB 정보 변경 command를 실행시켜준다.

  1. build.properties파일(생성한 프로젝트 폴더 하위에 위치)을 열어 DB 설정 정보를 수정한다.

    표 6.11. build.properties I (DB 정보)

    property namedescriptionrequireddefault value
    db_type DB 정보(HSQL, Oracle, MySQL, Sybase 등) Y HSQL
    db_name Database 명 Y sampledb
    schema schema 명 N PUBLIC
    username DB 사용자 명 Y sa
    password DB 사용자 패스워드 N
    server DB에 접근하기 위한 server 정보 (ex.70.7.105.123) Y localhost
    port DB에 접근하기 위한 port 번호 Y -1
    driver_class DB의 드라이버 클래스를 설정한다. Default Value로는 HSQL의 드라이버 클래스 값이며, DB에 맞는 값을 찾아 설정하면 된다.

    ex. Oracle: oracle.jdbc.driver.OracleDriver

    ex. MySQL: com.mysql.jdbc.Driver

    ex. Sybase: com.sybase.jdbc3.jdbc.SybDataSource

    Y org.hsqldb. jdbcDriver
    driver_jar _path DB에 접근하기 위한 driver jar 파일 경로를 설정한다. Default Value로는 HSQL의 driver jar파일 경로 값이며, DB에 맞는 driver jar 파일을 찾아 경로를 설정하면 된다.

    ex. Oracle: ojdbc-XX.jar

    ex. MySQL: mysql-connector-java-X.X.XX-bin.jar

    ex. Sybase: jconnX.jar

    Y [Gen Home]/repo/ hsqldb/hsqldb/ 1.8.0.10/ hsqldb- 1.8.0.10.jar
    url DB에 접근하기 위한 Access URL Y jdbc: hsqldb:hsql: //localhost /sampledb

    표 6.12. build.properties II (DB 관련 정보)

    property namedescriptionrequireddefault value
    dialect DB별 Hibernate Dialect 클래스를 설정한다. Default Value로는 HSQL의 dialect값이며, DB에 맞는 값을 찾아 설정하면 된다.

    ex. Oracle: org.hibernate.dialect. OracleDialect(10g의 경우 org.hibernatedialect. Oracle10gDialect)

    ex. MySQL: org.hibernate.dialect. MySQLDialect

    ex. Sybase: org.hibernate.dialect. SybaseDialect

    Y org.hibernate.dialect. HSQLDialect
    paging _generator [Query Service에서 사용] 목록 조회 시 페이징 처리를 지원하기 위한 SQL 생성 클래스명을 설정한다. Default Value로는 HSQL의 paging generator 값이며, DB에 맞는 값을 설정하면 된다. MySQL과 Sybase는 현재 지원되지 않는다.

    ex. Oracle: anyframe.core.query.impl. jdbc.generator.OraclePagingSQLGenerator

    N anyframe.core.query. impl.jdbc.generator. HSQLPaging SQLGenerator
    lobhandler [Query Service에서 사용] BLOB,CLOB과 같은 Large Data Type을 핸들링하는 클래스명을 설정한다. Default Value로는 HSQL의lobhandler 값이며, HSQL은 lob type을 지원하지 않으므로 공란으로 비워둔다. 각 DB에 맞는lobhandler 값을 찾아 설정한다.

    ex. Oracle: org.springframework.jdbc.support. lob.OracleLobHandler

    ex. MySQL: org.springframework.jdbc.support. lob.DefaultLobHandler

    ex. Sybase: org.springframework.jdbc.support. lob.DefaultLobHandler

    N N/A

  2. DB 변경 command를 입력한다. build.properties 파일의 DB 정보를 참조로 하여 DB 설정 내용을 반영한다.

    gen change-db
  3. DB 정보가 정상적으로 변경되었는지 확인한다.

    프로젝트 코드 내 DataSource Service 설정 정보 및 Hibernate, Query Service 관련 정보들이 변경되었는지 확인한다. (ex. src/main/resources/spring/context-datasource.xml)

참고

현재 Anyframe Gen에서는 5개의 DB를 지원하고 있다.(HSQL, Oracle, MySQL, Sybase, DB2) 프로젝트에서 작업하려는 DB가 이 5가지 중 하나라면 [Gen Home]/db/jdbc.config 파일을 열어서 사용하려는 DB 정보가 등록되었는지 확인한다. ※ Gen 이클립스 플러그인 UI에서는 4개의 DB 목록(HSQL, Oracle, MySQL, Sybase)을 제공하고 있다.

<list>
  <jdbcType>
   <type>Oracle</type>
   <driver>oracle.jdbc.driver.OracleDriver</driver>
   <dialect>
      <string>org.hibernate.dialect.Oracle10gDialect</string>
      <string>org.hibernate.dialect.Oracle9iDialect</string>
      <string>org.hibernate.dialect.Oracle8iDialect</string>            
   </dialect>
   <port>1521</port>
   <pagingGenerator>anyframe.core.query.impl.jdbc.generator.
                    OraclePagingSQLGenerator</pagingGenerator>
   <lobHandler>org.springframework.jdbc.support.lob.OracleLobHandler
   </lobHandler>
  </jdbcType>
  중략...

만약 이외의 다른 DB를 사용하려면 Anyframe 이슈 관리 시스템 에 등록해주시기 바랍니다.

7.어플리케이션 및 프로젝트 빌드

Command Line Interface를 이용해 생성된 프로젝트에서 어플리케이션 및 프로젝트에 대해 빌드를 할 수 있다. 빌드 단계에서는 소스 코드 컴파일, 테스트 케이스 수행, 패키징, 코드 품질 검사, 배포 파일 생성 등 빌드 프로세스를 수행하는데 어플리케이션 빌드와 프로젝트 빌드 두 가지 형태로 크게 구분할 수 있다.

프로젝트 단위로 빌드를 수행하여 프로젝트 배포 파일을 생성해낸다.

7.1.어플리케이션 빌드

Command Line Interface를 이용해 어플리케이션을 빌드해본다.

  1. 프로젝트가 생성된 폴더 하위로 이동한다. (예를 들어, myproject 라는 프로젝트를 생성시켰다면 myproject 폴더 하위에서 command를 실행시키도록 한다.)

  2. 다음의 어플리케이션 빌드 command를 입력한다.

    gen build [-options]
    • 프로젝트가 생성된 폴더 하위의 dist폴더에 프로젝트 명으로 된 배포폴더가 생성되고, 옵션에 따라 배포형태 및 war 파일 생성유무 등이 결정된다.

    • ex)gen build -deploy jar

    • 위 예제는 jar 파일 형태로 프로젝트를 패키징하여 배포 파일을 생성하는 command이다.

      표 7.1. build options

      optiondescriptiondefault value
      -deploy 프로젝트 배포 형태를 정의할 수 있다. "class" 혹은 "jar"를 입력한다.

      - WEB-INF/classes 폴더 하위에 클래스 형태로 배포할 때 class로 설정

      - WEB-INF/lib 폴더 하위에 jar 파일 형태로 배포할 때 jar로 설정

      class
      -war true일 때 프로젝트가 생성된 폴더 하위의 dist 폴더에 프로젝트명.war 파일을 생성 한다. false
      -clean true일 때 프로젝트가 생성된 폴더 하위의 dist 폴더 전체를 삭제 한 후 빌드를 수행한다. false

7.1.1.예시1) 어플리케이션 빌드 후 클래스 배포

어플리케이션 전체 빌드 후, WEB-INF/classes 폴더 하위에 프로젝트 소스 코드 컴파일 결과를 class 파일 형태로 배포하는 경우에 사용한다.

gen build -deploy class

빌드된 결과를 WEB-INF/classes 에서 확인하며,WEB-INF/classes 아래에 컴파일된 자바코드, 설정파일, 매핑쿼리문 등이 생성된다.

7.1.2.예시2) 어플리케이션 빌드 후 JAR 파일 배포

어플리케이션 전체 빌드 후, WEB-INF/lib 폴더 하위에 프로젝트 소스 코드 컴파일 결과를 jar 파일 형태로 배포하는 경우에 사용한다.

gen build -deploy jar

빌드된 결과를 WEB-INF/lib 에서 확인하며, 하나의 프로젝트 이름(예를 들면 myproject)으로 jar 파일이 생성된다.

7.1.3.예시3) 어플리케이션 빌드 후 WAR 파일 배포

어플리케이션 전체 빌드 후, war 파일을 생성하는 경우에 사용한다.

gen build -war true

빌드된 결과를 프로젝트가 생성된 폴더/dist/ 폴더 하위에서 확인한다. 프로젝트가 생성된 폴더/dist 폴더에는 프로젝트 명으로 된 war 파일이 생성된다.( 예)myproject.war)

참고

현재 Anyframe Gen에서는 어플리케이션 빌드 관련된 빌드 스크립트를 [Gen Home]/cli/scripts/application-build.xml 파일에서 관리하고 있다. 이 빌드 파일 내에서 target명이 "build"인 경우가 어플리케이션 빌드에 해당된다.

<target name = "build" depends = "clean, dist, war"/>
중략...

만약 어플리케이션 빌드 프로세스 내용 중 일부를 변경시키고자 한다면 application-build.xml 파일 내용을 변경하도록 한다.

7.2.프로젝트 빌드

Command Line Interface를 이용해 프로젝트에 대한 빌드를 수행한다.

  1. 빌드 대상 프로젝트 폴더 하위로 이동한다. (예를 들어, myproject 라는 프로젝트를 생성시켰다면 myproject 폴더 하위에서 command를 실행시키도록 한다.)

  2. ant를 실행하기 위한 build.xml, build.properties 파일이 있는지 확인한다.

  3. 다음의 프로젝트 빌드 command를 입력한다.

    ant [targets]
    • ex) ant all

    • 위 예제는 프로젝트에 대해서 all이라는 target을 실행시키는 ant command로 아래와 같은 target 중 하나를 선택하여 프로젝트 빌드 프로세스를 수행시킬 수 있다. target을 입력하지 않고 ant만 실행시킨 경우 default target인 "default"가 수행된다.

      표 7.2. ant targets

      targetdescription
      default 프로젝트에 대해서 초기화, 컴파일, 패키징 등의 기본 빌드 프로세스를 수행한다.
      deploy default target을 수행한 후 web type 프로젝트의 경우 war 파일 압축이 풀려진 형태의 폴더를 dist 폴더 하위에 배포한다.
      all 위에 설명한 "default" target에서 수행하는 빌드 프로세스 작업 외에 테스트 케이스 수행, 소스 코드 커버리지, CheckStyle/JDepend/FindBugs/Code Duplication 등의 코드 품질 검사 리포팅까지의 작업을 추가로 더 수행한다.
      그외 "clean", "init", "resources", "compile", "test-resources", "test-compile", "package", "emma-jars", "test", "report", "deploy" 등 빌드 프로세스 작업 내역 하나 별로 하나의 ant target이 구성되어 있으므로 위에서 설명한 "default"와 "all" target 이외의 작업 별 빌드를 수행해야 할 필요가 있으면 사용하도록 한다.

참고

현재 Anyframe Gen에서는 프로젝트 빌드 스크립트를 [Gen Home]/cli/scripts/project-build.xml 파일에서 관리하고 있다. (project-build.properties 함께 제공) 이 빌드 파일 내 target명들 앞에 prefix로 "shared:"가 붙어있어서 실제 생성한 프로젝트 내 빌드 파일(build.xml)에서는 이 공통 프로젝트 빌드 파일(project-build.xml)의 target명을 호출하여 실제 프로젝트 빌드를 수행하게 되며, 각 프로젝트 별로 특화된 빌드 프로세스를 추가해넣을 수도 있다.

만약 공통 프로젝트 빌드 파일을 변경하여 나머지 모든 프로젝트 내 빌드 프로세스 내용을 변경시키고자 한다면 project-build.xml 파일 내용을 변경하도록 한다.

8.어플리케이션 빌드 및 실행

Command Line Interface를 이용해 어플리케이션 전체 빌드를 수행하고 웹 어플리케이션까지 실행시킬 수 있다. 즉, command를 통해 프로젝트 빌드와 배포를 수행한 후 Jetty를 이용하여 웹 어플리케이션을 구동시킴으로써 어플리케이션의 기능 확인이 가능하다.

8.1.어플리케이션 빌드 및 웹 어플리케이션 실행

Command Line Interface를 이용해 어플리케이션을 빌드하고 웹 어플리케이션을 실행시켜본다.

  1. 프로젝트가 생성된 폴더 하위로 이동한다. (예를 들어, myproject 라는 프로젝트를 생성시켰다면 myproject 폴더 하위에서 command를 실행시키도록 한다.)

  2. 다음의 어플리케이션 빌드 및 웹 어플리케이션 실행 command를 입력한다.

    gen run [-options]
    • 앞에서 설명된 어플리케이션 빌드 과정을 동일하게 수행한 후 웹 어플리케이션을 구동시켜주는 역할을 담당한다.

    • ex) gen run

    • 위 예제는 추가 옵션 정보 없이 해당 어플리케이션을 빌드하고 Jetty로 실행시키는 command이다.

      표 8.1. build-app options

      optiondescriptiondefault value
      -deploy 프로젝트 배포 형태를 정의할 수 있다. "class" 혹은 "jar"를 입력한다.

      - WEB-INF/classes 폴더 하위에 클래스 형태로 배포할 때 class로 설정

      - WEB-INF/lib 폴더 하위에 jar 파일 형태로 배포할 때 jar로 설정

      class
      -war true일 때 프로젝트가 생성된 폴더 하위의 dist 폴더에 프로젝트명.war 파일을 생성 한다. false
      -clean true일 때 프로젝트가 생성된 폴더 하위의 dist 폴더 전체를 삭제 한 후 빌드를 수행한다. false

  3. 웹 어플리케이션 실행 결과를 웹 브라우저를 띄워서 확인하도록 한다. 요청 URL에서 Port 정보가 8090 인 것에 유의하도록 한다. (Jetty의 기본 Port 정보가 8090임)

    예제의 경우 요청 URL은 http://localhost:8090/myproject 가 되며, 이 때, 설치된 플러그인 목록이 조회된다. http://localhost:8090/myproject/index.jsp 로 접속하면 Gen 을 통해 생성한 메뉴를 확인할 수 있다.

  4. Jetty 폴더를 확인한다.

    프로젝트 dist 폴더 하위에 jetty-temp라는 폴더가 생성되어 Jetty가 구동되게 된다. 배포 이후에 클래스나 JAR 파일, JSP 파일 등을 반영하고 Jetty로 재확인하고 싶다면 이 폴더의 해당 위치에 배포하도록 한다.

IV.Eclipse Plugin

Anyframe Gen Eclipse Plugin을 사용하여 프로젝트 생성, Domain 클래스 및 CRUD 소스 코드 생성, Configuration, JDBC Setting, Anyframe 플러그인 install/uninstall 등의 작업을 할 수 있다. 프로젝트는 Wizard를 통해서 생성하며, 그 밖의 작업은 Anyframe Gen Editor를 이용한다.

9.Installing Anyframe Gen Plugin

9.1.Anyframe Gen 플러그인 설치

Anyframe Gen은 압축파일로 배포되며, 설치방법은 [Anyframe Gen 매뉴얼의 설치]를 참고하도록 한다.

  1. Anyframe Gen 플러그인 설치는 Anyframe Plugin Update Site를 통해서 설치할 수 있다. 외부 인터넷 연결이 안되거나 네트웍에 문제가 있는 경우 아래의 노트 [Update Site를 이용하지 않고 Anyframe Gen Eclipse Plugin 설치하기] 내용을 참고하여 설치하도록 한다.

    1. Eclipse의 Help > Install New Software... 메뉴를 선택한다.

    2. [Available Software] 화면: 우측 상단의 Add...버튼을 클릭하여 Anyframe Plugin Update Site를 추가하도록 한다. 이때 Name에는 Anyframe Plugin Update Site를, Location에는 http://dev.anyframejava.org/update를 입력한다.

    3. [Available Software] 화면: 중앙에 Anyframe Plugin Update Site 를 루트로 하는 Plugin Tree가 나타난다. (Anyframe Common, Anyframe Gen, Anyframe Oden, Anyframe Query Manager 목록 조회됨) 여기서 하단 항목 중 "Contact all update sites during install to find required software" 체크 박스를 해제하여 다른 Plugin이 함께 설치되는 것을 방지한다.

    4. [Available Software] 화면: Plugin Tree 중 Anyframe Gen을 선택하고 하단의 Next 버튼을 클릭한다.

    5. [Install Details] 화면: Anyframe Gen하위로 Anyframe Common plugin이 보이게 된다. Anyframe Gen 사용 시 Anyframe Common이 필요하므로 참조관계에 의해 함께 설치된다. 확인 후 Next 버튼을 클릭한다.

    6. [Review Licenses] 화면: 좌측의 Plugin을 선택하면 우측에 License text가 나온다. Anyframe Common과 Anyframe Gen에 대해서 우측 하단의 "I accept the terms of the license agreements" 구문에 동의하고 Finish 버튼을 클릭한다.

    7. [Security Warning] 화면: 팝업창에서 설치 진행 여부 물을 때 OK 버튼을 선택한다.

    8. [Software Updates] 화면: 팝업창이 뜨고, "Would you like to restart now?" 질문에 Yes 버튼을 선택한다.

    Anyframe Plugin Update Site를 이용한 설치 전 주의 사항

    Anyframe Gen Plugin이 설치하려고 하는 Eclipse의 dropins 혹은 addins 폴더에 이미 설치되어 있다면 Update Site를 통해 설치될 Plugin과 중복되어 문제를 일으킬 수 있으므로 반드시 dropins 혹은 addins 폴더에 Anyframe Gen Plugin이 설치되어 있는지 확인하고 설치되어 있다면 제거한 후, Update Site를 통해 설치하도록 한다. Update Site를 통해 설치한 경우 물리적인 Anyframe Gen Plugin 파일은 plugins 폴더 하위에 위치하게 된다.

  2. "Help > About Eclipse Platform (또는 About Eclipse SDK) > Plug-in Details"를 통해 정상적으로 설치되었는 지 확인한다.

    ☞ About Eclipse Platform (또는 About Eclipse SDK) 메뉴는 Windows용 Eclipse의 경우 Help 메뉴에서, Mac OS X용 Eclipse의 경우 Eclipse 메뉴에서 확인할 수 있다.

    ☞ Eclipse 루트 폴더 하위의 plugins 폴더 내로 anyframe.common.eclipse.core_xxx.jar와 anyframe.gen.eclipse.core_xxx.jar 파일이 설치되어있는지 확인해볼 수 있다.

  3. Anyframe Gen 플러그인을 포함한 전체 Anyframe Gen의 설치가 완료되었다. Anyframe Gen의 기능을 사용하여 개발하기 이전에 반드시 [Preferences] 내용을 참고하여 환경 설정을 모두 끝마치도록 한다.

Update Site를 이용하지 않고 Anyframe Gen Eclipse Plugin 설치하기

Anyframe Gen 플러그인 설치는 plugins 폴더내에 있는 2개의 플러그인 패키지 파일들(anyframe.[제품명].eclipse[.*]_x.x.x.jar)를 "[eclipse 설치 폴더]/dropins/anyframe/eclipse/plugins" 로 복사시키면 된다. plugins 폴더에는 다음 두가지 플러그인 패키지가 존재한다.

  • anyframe.common.eclipse.core_x.x.x.jar : Anyframe plugins의 공용 라이브러리 및 공통 메뉴 제공

  • anyframe.gen.eclipse.*_x.x.x.x.jar : Anyframe Gen 플러그인

☞ 현재 Anyframe Common 플러그인의 경우, Anyframe Gen 설치 파일 내에 함께 배포되어 손쉽게 설치할 수 있도록 제공하고 있다. 하지만 Anyframe Common 플러그인은 독립적으로 배포되고 사용될 수 있는 플러그인이므로 추후 Anyframe Common 플러그인 버전이 업데이트되고, 업데이트된 버전을 사용하고자 한다면 Anyframe Gen에서 배포한 구버전 Anyframe Common 플러그인을 제거하고 업데이트된 플러그인 패키지를 설치하도록 한다.

10.Preferences

10.1.Eclipse 설정

Anyframe Gen 을 이용하여 생성한 프로젝트 실행을 위해 필요한 환경설정을 한다. Anyframe Gen의 환경설정은 Eclipse Preferences 창을 통해 수행한다.

  • ClassPath 설정 : Anyframe Library 를 인식하도록 ClassPath를 설정한다.

    Window >> Preferences >> Java >> Build Path >> Classpath Variables 에서 New 클릭

    Name : GEN_REPO

    Path : [Gen Home]\repo [Folder..]

  • Server 설정 : 어플리케이션이 구동될 WAS로 Tomcat v6.0을 사용한다.

    Window >> Preferences >> Server >> Runtime Environments 에서 Add..클릭

    Name : Apache Tomcat v6.0

    Tomcat Installation directory : [Tomcat 이 설치된 root 경로]

    JRE : Workbench default JRE

  • Ant Home 설정 : 설치된 Ant 를 인식하도록 Ant Home을 변경하거나 Ant Home Entries에 jdepend-X_X.jar파일을 추가한다.

    • Ant Home 변경 : Window >> Preferences >> Ant >> Runtime >> Classpath Tab >> 우측 하단의 Ant Home.. 버튼 클릭

      path : [Gen Home]\ant

    • Ant Home Entries 파일 추가 : Window >> Preferences >> Ant >> Runtime >> Classpath Tab >> 우측 의 Add External JARs... 버튼 클릭

      path : [Gen Home]\ant\lib\jdepend-2.9.jar 파일 선택

환경설정을 통해 Anyframe Gen으로 생성된 프로젝트가 정상적으로 실행이 된다.

10.2.DB 구동

  • 샘플 DB를 구동 시킨다.

    현재 Anyframe Gen은 샘플 DB로 HSQL DB를 제공하고 있다. [Gen Home]\db\scripts\hsqldb 하위의 start.cmd 파일을 실행시켜서 DB를 구동한다.

    탐색기로 해당경로 이동 후, start.cmd 파일을 더블클릭하면 hsqldb가 구동된다. 만약 Oracle과 같은 다른 DB를 사용한다면 DB를 구동시킨 후, [Gen Home]\db\scripts\[DB명]\sampledb-[DB명].sql 파일의 스크립트를 실행해준다. 현재는 Oracle(sampledb-oracle.sql), MySQL(sampledb-mysql.sql), Sybase(sampledb-sybase.sql)에 대한 샘플쿼리문이 제공되고 있으며, Anyframe Gen 에서 자동으로 설치되는 샘플이 정상적으로 동작하기 위해 필요한 것이다.

    구동된 DB에 대한 JDBC 설정은 프로젝트를 생성하면서 반영하거나, Anyframe Gen JDBC Setting 탭을 통해서 반영이 가능하다. 자세한 내용은 [New Project Creation]또는 [JDBC Setting]을 참고하도록 한다. JDBC Setting 탭은 Domian Type 프로젝트 생성 후에 사용이 가능하다.

11.New Project Creation

Anyframe Gen 을 이용해 프로젝트를 생성 할 수 있다.

11.1.Create new project

  1. File >> New >> Other.. >> Anyframe >> Project 을 선택

  2. 열린 창에서 프로젝트 생성을 위해 다음과 같은 내용을 입력한다. 아래 항목을 문제없이 기입하는 경우 Next 버튼과 Finish 버튼이 활성화 되며, Next 버튼을 클릭하면 DB정보를 구성할 수 있는 화면으로 연결된다.

    • Project Name: 프로젝트 이름으로, 예제의 경우 emarketplace로 설정하였다.

    • Gen Home: Anyframe Gen을 설치하기 위해 설치 시 선택했던 경로

    • Base Location: 프로젝트 생성 위치로, default로 지정되는 경로를 꼭 사용할 필요 없이 원하는 경로로 변경 가능하다.

    • Package Name: 패키지 이름으로, 예제의 경우 com.sds.emp로 지정하였다.

    • Web: Web 타입 프로젝트 생성하는 경우 선택한다. Dynamic Web 프로젝트가 생성되며 Anyframe foundation 플러그인이 샘플과 함께 설치된다.

    • Service: Service 타입 프로젝트 생성하는 경우 선택한다. Java 프로젝트가 생성되며 Anyframe foundation 플러그인 라이브러리만 설치되고 샘플은 설치되지 않는다. annotation 기반으로 자바코드를 생성할 수 있는 Anyframe Gen 아키타입이 설치된다.

  3. DB정보를 구성하기 위해 위 화면에서 Next 버튼을 클릭하였다면 다음과 같은 JDBC Configuration 화면이 제공된다.

    Finish 버튼을 누르면 프로젝트가 생성된다.

    • Database Type: Database 타입으로, HSQL, Oracle, MySQL, Sybase를 제공하고 있다.

    • Database Name: Database 의 이름

    • Schema: 스키마의 이름

    • User Name: DB 유저 이름

    • Password: 패스워드

    • Server: DB가 설치된 서버 ip 정보, 로컬에서 사용하는 경우 localhost

    • Port: HSQL의 경우 -1, Oracle의 경우 1521, MySQL의 경우 3306, Sybase는 3000

    • Hibernate Dialect: Hibernate에서 쿼리 수행 시, DBMS에 최적화된 기능을 제공하기 위해 사용되는 것이 SQL Dialect 이며, 이 Dialect 프로퍼티를 사용하여 해당 DB 별 Dialect 정보를 설정할 수 있다. 각 DB 별 Dialect 클래스가 따로 존재하여 HSQL DB를 선택한 경우, 디폴트로 org.hibernate.dialect.HSQLDialect값이 선택된다.(Oracle, MySQL, Sybase Dialect 도 제공함)

    • Driver Class Name: DB의 드라이버 클래스를 설정해 주기 위한 값으로, HSQL의 경우 org.hsqldb.jdbcDriver 값으로 설정된다. Database Type 선택 시 해당 DB에 맞는 값이 셋팅된다.

    • Driver Jar Path : Anyframe Gen 설치 시 샘플 DB를 위한 HSQL DB Driver Jar 파일이 제공되므로 디폴트로 설정된다. 만약 다른 DB를 사용한다면 해당 DB의 Driver jar 파일로 연결시켜준다.

  4. 프로젝트 생성이 완료되면 Eclipse 내에 프로젝트가 정상적으로 생성되어 Import 되었는지 확인해본다. Web 타입 프로젝트일 경우 dynamic 웹 프로젝트로 생성되고, Service 타입 프로젝트일 경우 자바 프로젝트로 생성된다.

  5. 서버를 실행하여 프로젝트를 실행해본다.

    • Web 타입 프로젝트일 경우, 서버를 실행하여 프로젝트를 실행해본다. 프로젝트를 선택한 후 마우스 우측 버튼 클릭 >> Run As >> Run On Server 메뉴를 선택하고 이때 기존에 설정되어있던 Tomcat Server(6.0 Version 사용)가 없는 경우 등록해주고 실행하도록 한다.

      Web 타입 프로젝트의 경우 서버를 start 했을 때 열리는 웹 페이지는 설치된 플러그인 목록이 보이는 화면이다. 프로젝트 생성 이후에 Anyframe Gen Editor의 CRUD Generation 기능을 통해 생성되는 화면은 /src/main/webapp/index.jsp를 선택한 후 마우스 우측 버튼 클릭하여 Run As 함으로써 확인할 수 있다.

    • 프로젝트를 생성을 통해 만들어진 프로젝트 설정 파일(Properties)을 수정하여, 수정된 설정 값을 통해 소스가 생성되도록 할 수 있다. 아래 표에 설명된 항목별 내용을 보고 DB 설정을 비롯하여 다양한 공통 속성 값을 변경시킬 수 있다. 현재 DB 속성 정보들의 디폴트 값은 HSQL 샘플 DB에 대한 속성 값으로 설정되어 있다.

      • 표 11.1. build.properties I (프로젝트 정보)

        Property NameDescriptionRequiredDefault Value
        gen.homeAnyframe Gen을 설치한 루트 폴더Y[Gen Home]
        project.name프로젝트 명Ymyproject
        project.version프로젝트 버전Y1.0.0
        project.home프로젝트 루트 폴더 경로Y[Gen Home] \applications\ [프로젝트명]
        package.name프로젝트 대표 패키지 명Y프로젝트명
        dao.frameworkDAO Framework 선택(query, hibernate 중 택일)Yquery
        emma.enabled프로젝트 빌드 시 emma를 이용하여 코드 커버리지 리포트 결과 생성 여부Ytrue
        template_type프로젝트 및 CRUD 소스 코드 생성 시 기반이 되는 Template 형태(ex. default, miplatform 등)Ydefault
        project.type프로젝트 타입Yweb
        web.context.pathjetty run 으로 실행시킬때 사용되는 WebContext Path명Y프로젝트 명

        표 11.2. build.properties Ⅱ(DB 정보)

        Property NameDescriptionRequiredDefault Value
        db_name[DB] Database 명Ysampledb
        dialect[DB] DB별 Hibernate Dialect 클래스 설정Yorg.hibernate. dialect. HSQLDialect
        driver_class[DB] DB의 드라이버 클래스 설정Yorg.hsqldb. jdbcDriver
        schema[DB] schema 명YPUBLIC
        username[DB] DB 사용자 명Ysa
        password[DB] DB 사용자 패스워드NN/A
        url[DB] DB에 접근하기 위한 Access URLYjdbc:hsqldb:hsql://localhost/sampledb
        lobhandler[DB]BLOB,CLOB과 같은 Large Data 타입에 대한 핸들링NN/A
        port[DB] DB에 접근하기 위한 portY-1
        driver_jar_path[DB] DB에 접근하기 위한 driver jar파일의 경로YC\:\\Gen-1.2.0\\repo\\hsqldb\\hsqldb\\1.8.0.10\\hsqldb-1.8.0.10.jar
        server[DB] DB에 접근하기 위한 server정보Ylocalhost
        db_type[DB] DB 정보(HSQL, Oracle, MySQL, Sybase)YHSQL
        paging_generator[DB] DB에 따른 페이징 처리 SQL GeneratorNanyframe.core. query.impl. jdbc.generator. HSQLPaging SQLGenerator

11.2.프로젝트 생성 시 발생할 수 있는 에러 해결 Tip

11.2.1.Out of memory

프로젝트 생성 시 다음과 같은 out of memory 에러가 발생할 경우 다음과 같이 조치한다.

  1. 실행하고 있는 eclipse가 설치되어 있는 폴더로 이동한다.

  2. root 폴더 하위의 eclipse.ini 파일의 내용에서 launcher.XXMaxPermSize값(ex. 256M)을 높여서 재설정해준다. 필요 시 메모리 사용 최소값(-Xms)과 최대값(-Xmx)을 증가시켜서 사용하도록 한다. 다음은 Eclipse 3.5.0(Galileo) 버전의 eclipse.ini 파일 예이다.

    -clean
    -startup
    plugins/org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar
    --launcher.library
    plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.0.200.v20090519
    -product
    org.eclipse.epp.package.jee.product
    --launcher.XXMaxPermSize
    256M
    -showsplash
    org.eclipse.platform
    --launcher.XXMaxPermSize
    128m
    -vmargs
    -Dosgi.requiredJavaVersion=1.5
    -Xms400m
    -Xmx512m
    

11.2.2.Project Clean & JSP Validation Error

  • 프로젝트 생성 시 다음과 같이 생성된 프로젝트에 표시가 뜨는 경우, 프로젝트를 clean을 하거나 해당 프로젝트를 close 한 후 다시 open하면 표시가 사라진다.

    ☞ Project >> Clean... 수행

    ☞ 프로젝트 선택 후 오른쪽 마우스 클릭 >> Close Project 후 프로젝트 선택 후 오른쪽 마우스 클릭 >> Open Project

  • Problems 에 JSP Validation 에러가 나오는 경우, 실제로 error는 아니지만 eclipse에서 인식을 에러로 하는 것으로 다음과 같이 validation 설정을 변경해주면 된다. Eclipse 내 프로젝트에서 Validation 기능을 사용하게 되면 시간이 많이 소요될 수 있다. 반드시 필요한 경우가 아니고, 속도 향상을 위해서라면 Validation 설정을 모두 Disable All 버튼을 선택하여 사용하지 않는 것으로 설정할 수도 있다.

    ☞ Window >> Preferences... >> Validation >> JPA Validator, JSP Syntax Validator 의 Build 항목 체크 해제 후 Apply

12.Domain Generation

Anyframe Gen을 이용해 Domain Class 를 생성해본다.

DB 테이블 기반으로 Domain Class를 생성시키기 때문에 JDBC 설정이 제대로 되었는지 [JDBC Configuration 설정방법]을 참조하여 확인 한 후, Domain Class를 생성하도록 한다.

  1. 프로젝트를 선택한 후 우 클릭 >> Anyframe Gen 메뉴를 선택한다. 이때 해당 Service 프로젝트가 Domain 타입 프로젝트가 아닌 경우, Anyframe Gen 메뉴는 비활성화되어 보여진다.

  2. Anyframe Gen Editor에서 Domain Generation Tab을 선택한다. Refresh 버튼을 수행하면 현재 선택 가능한 DB Table들과 소스 코드 패키지가 트리 형태로 조회된다. 이때 Domain Class로 생성하고자 하는 Table을 선택하고, Domain Class를 어느 소스 코드 패키지 하위로 생성시킬 것인지를 선택한 후 Generate 버튼을 클릭한다.

    참조관계에 있는 테이블의 경우 해당 테이블을 동시에 선택하여 Domain Class를 생성 해야 하며, 이를 통해 참조관계에 관한 정보가 제공된다.

    • Choose Tables: JDBC 구성에 따라 연결된 DB의 테이블 목록이 조회된다.

    • Choose a package: 해당 프로젝트에 있는 소스 코드 패키지 경로가 조회된다.(src/main/java 소스 폴더에 한함)

  3. Domain Class 가 제대로 생성되었는지 확인해 본다. 원하는 패키지 하위로 Domain Class들이 위치하고 있는지 확인한다.

    생성된 Domain Class는 JPA Annotation 설정을 통해 DB Table, Column 정보들을 가지고 있다.

    @Entity
    @Table(name = "BOARD", schema = "PUBLIC")
    public class Board implements Serializable {
        private BoardId id;
        private BoardMaster boardMaster;
        private String boardName;
        중략...
        @EmbeddedId
        @AttributeOverrides({@AttributeOverride(name = "boardId",column = 
               @Column(name = "BOARD_ID",nullable = false)
            )
            , @AttributeOverride(name = "boardMasterId",column = 
               @Column(name = "BOARD_MASTER_ID",nullable = false)
            )
        })
        public BoardId getId() {
            return this.id;
        }
        public void setId(BoardId id) {
            this.id = id;
        }
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "BOARD_MASTER_ID", nullable = false, 
                    insertable = false, updatable = false)
        public BoardMaster getBoardMaster() {
            return this.boardMaster;
        }
        public void setBoardMaster(BoardMaster boardMaster) {
            this.boardMaster = boardMaster;
        }
        @Column(name = "BOARD_NAME", nullable = false, length = 150)
        public String getBoardName() {
            return this.boardName;
        }
        public void setBoardName(String boardName) {
            this.boardName = boardName;
        }
    }

참고

위에서 설명한 기능 수행 도중에는 프로젝트 생성, 코드 생성 및 DB 변경 등과 같은 Anyframe Gen의 기능을 동시에 수행시킬 수 없으므로 유의하도록 한다. (Background 실행을 통한 기능 수행 시)

13.CRUD Generation

Anyframe Gen을 이용해 CRUD를 생성해본다.

Domain Class를 중심으로 CRUD에 대한 기본 코드를 생성하고 자동으로 테스트 코드와 테스트 데이터를 생성해줌으로써 생성된 코드의 기능 확인까지 손쉽게 할 수 있다. 따라서, CRUD Generation 기능을 사용하기 전에 Domain Generation 기능을 이용하여, 연결된 DB 테이블 기반의 Domain Class를 먼저 생성하도록 한다.

  1. 프로젝트를 선택한 후 우 클릭 >> Anyframe Gen 을 선택한다.

  2. Anyframe Gen Editor에서 CRUD Generation Tab을 선택한다. Refresh 버튼을 수행하면 현재 선택 가능한 Domain Class들과 타겟 프로젝트로 지정된 프로젝트 목록이 조회된다.

  3. CRUD 기능을 구현하고 싶은 Domain Class를 선택하고, CRUD Project Configuration 내용을 입력한다.

    • CRUD Service: CRUD 기능이 구현될 서비스 명으로 Default로 이름이 지정되며 조회만 가능하다.

    • Package: CRUD가 생성될 패키지 이름이며, 특정 서브 시스템 하위로 코드를 생성하고 싶다면 중간 패키지 정보를 함께 입력하면 된다. (ex. sub.categories)

    • Project Name: 프로젝트명으로 조회만 가능하다.

    • Web source code generation: 비즈니스 레이어에 해당하는 소스 뿐 아니라 프리젠테이션 레이어 소스 코드들도 함께 생성하고자 한다면 체크 박스에 체크하도록 한다. Service 타입 프로젝트의 경우, 이 체크박스는 활성화 되지 않는다.

  4. Generate 버튼을 클릭한 후, CRUD 코드가 정상적으로 생성되었는지 확인해본다. 타겟 프로젝트로 지정한 프로젝트에는 Domain Class에 대한 비즈니스 서비스 인터페이스,구현 클래스, DAO 인터페이스, DAO 구현 클래스, Spring 설정 파일들, 테스트 코드, 테스트 데이터 등이 생성된다. Web 타입 프로젝트에는 Spring MVC Controller 클래스, Spring MVC 설정 파일, 테스트 코드, JSP 페이지 등이 생성된다. 참고로, CRUD 생성 후 소스파일에 표시가 뜨는 경우는, test 플러그인이 없기 때문이다. Anyframe Gen Editor의 Installation 탭에서 test 플러그인을 다운받아 설치하면 해결된다.

    • 서비스인터페이스 (src/main/java/[대표패키지]/[-package 값]/service/[Entity 클래스명]Service.java)

      public interface BoardService extends GenericService<Board, BoardId> {
          Page getPagingList(SearchVO searchVO) throws Exception;        
      }
    • 서비스구현클래스 (src/main/java/[대표패키지]/[-package 값]/service/impl/[Entity 클래스명]ServiceImpl.java)

      @Service("boardService")
      @Transactional(rollbackFor = {Exception.class}, propagation = Propagation.REQUIRED)
      public class BoardServiceImpl extends GenericServiceImpl<Board, BoardId>
                          implements BoardService {
      	    
          @Resource
          private BoardDao boardDao;
      	
          @PostConstruct
          public void initialize(){
              super.setGenericDao(boardDao);
          }
          
          /** {@inheritDoc} */
          public Page getPagingList(SearchVO searchVO) throws Exception {
              return super.getGenericDao().getPagingList(searchVO);
          }        
      }
    • DAO인터페이스 (src/main/java/[대표패키지]/[-package 값]/dao/[Entity 클래스명]Dao.java)

      public interface BoardDao extends GenericDao<Board, BoardId> {
          Page getPagingList(SearchVO searchVO) throws Exception;
      }
    • DAO구현클래스 (src/main/java/[대표패키지]/[-package 값]/dao/impl/[Entity 클래스명]Dao[DAO Framework 명]Impl.java)

      @Repository("boardDao")
      public class BoardDaoQueryImpl extends GenericDaoQuery<Board, BoardId>
                          implements BoardDao {
      
          @Resource
          IQueryService queryService;
          @Resource
          IPropertiesService propertiesService;
      	
          public BoardDaoQueryImpl() {
              super(Board.class);
          }
          
          @PostConstruct
          public void initialize(){
              super.setQueryService(queryService);
              super.setPropertiesService(propertiesService);
          }
          
          /** {@inheritDoc} */
          public Page getPagingList(SearchVO searchVO) throws Exception {
              int pageIndex = searchVO.getPageIndex();
              int pageSize = super.getPropertiesService().getInt("PAGE_SIZE");
              int pageUnit = super.getPropertiesService().getInt("PAGE_UNIT");
              중략...
              return super.findListWithPaging(ClassUtils.getShortName(getPersistentClass()), 
                              args, pageIndex, pageSize, pageUnit);
          }   
      }
    • 매핑쿼리문 (src/main/resources/query/mapping-query-[Entity 클래스명].xml)

      <queryservice>
        <queries>
          <query id="createBoard">
            <statement>
              INSERT INTO BOARD (BOARD_ID, BOARD_DESC, BOARD_MASTER_ID, BOARD_NAME, 
                     BOARD_ORDER, BOARD_TOPICS, REG_DATE) 
              VALUES (:vo.id.boardId, :vo.boardDesc, :vo.id.boardMasterId, :vo.boardName, 
                     :vo.boardOrder, :vo.boardTopics, :vo.regDate)
            </statement>
          </query>
          중략...
        </queries>
      </queryservice>
    • MessageSoruce (src/main/resources/message/message-generation.properties)

      # -- Board-START
      board.id.boardId=Board Id		
      board.id.boardMasterId=Board Master Id		
      board.boardDesc=Board Desc
      board.boardName=Board Name
      board.boardOrder=Board Order
      board.boardTopics=Board Topics
      board.regDate=Reg Date
      
      # -- success messages -- 
      success.board.create=Board has been added successfully.
      success.board.update=Board has been updated successfully.
      success.board.delete=Board has been deleted successfully.
      
      # -- error messages --
      error.boardserviceimpl.create=Board data not created
      error.boardserviceimpl.create.solution=Enter correct data for mandatory field 
      or enter data according to formats means date format as yyyy-mm-dd
      error.boardserviceimpl.create.reason=Entered incorrect data for Board
      중략...
    • 통합테스트케이스 (src/test/java/[대표패키지]/[-package 값]/dao/[Entity 클래스명]DaoTest.java)

      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration(locations = { "classpath*:/spring/context-*.xml" })
      public class BoardDaoTest{
      
          @Resource(name="boardDao")
          private BoardDao boardDao;
      
          @Test	    
          public void testAddAndRemoveBoard() throws Exception {
              Board board = new Board();            
              BoardId id = new BoardId();
              id.setBoardId(new Integer(1732013925));            	
              id.setBoardMasterId(new Integer(1681092908));            	
              board.setId(id);
              중략...
          }
      }
    • 단위테스트 케이스 (src/test/java/[대표패키지]/[-package 값]/service/impl/[Entity 클래스명]ServiceImplTest.java)

      @RunWith(JMock.class)
      public class BoardServiceImplTest{
          private BoardServiceImpl service = null;
          private BoardDao dao = null;
          private Mockery context = new JUnit4Mockery();
      
          @Before
          public void setUp() {
              System.setProperty("log4j.configuration", "log4j-test.xml");
              this.dao = context.mock(BoardDao.class);
              this.service = new BoardServiceImpl();        
              ObjectUtil.setField(this.service, "boardDao", this.dao);
              this.service.initialize();
          }
      
          @After
          public void tearDown() {
              service = null;
          }
      
          @Test
          public void testGetBoard() throws Exception {
              log.debug("testing get...");
      		
              final BoardId id = new BoardId();
              id.setBoardId(257077485);	        
              id.setBoardMasterId(555604496);	        
              final Board board = new Board();
      
              // set expected behavior on dao 
              context.checking(new Expectations() {{
                  one(dao).get(with(equal(id)));
                  will(returnValue(board));
              }});
      
              Board result = service.get(id);
              assertSame(board, result);
          }
      중략...
    • 컨트롤러 (src/main/java/[대표패키지]/[-package 값]/web/[Entity 클래스명]Controller.java)

      @Controller
      @RequestMapping("/board.do")
      public class BoardController {
      
          /**
           * Resource Injection on BoardService
           */
          @Resource(name="boardService")
          private BoardService boardService;
      
          중략...    
      
          /**
           * Display Board list.
           * @param searchVO form object with request parameters bound onto it
           * @param model model containing control data
           * @return the prepared Board list view
           * @throws Exception in case of getting Board paging list
           */ 
          @RequestMapping(params = "method=list")  
          public String list(@ModelAttribute("search") SearchVO searchVO, 
                                  Model model) throws Exception 
          {        
              Page resultPage = boardService.getPagingList(searchVO);
      
              model.addAttribute("boardList", resultPage.getList());
              model.addAttribute("resultPage", resultPage);
      		        
              return "generation/board/listBoard";        
          }
      }
    • UI JSP 파일 (src/main/webapp/WEB-INF/jsp/[프로젝트명]/*.jsp)

      <%@ include file="/sample/common/taglibs.jsp"%>
      <html>
      <head>
          <%@ include file="/sample/common/meta.jsp" %>
          <title><fmt:message key="boardList.title"/></title>
          <meta name="heading" content="<fmt:message key='boardList.heading'/>"/>     
          <link rel="stylesheet" href="<c:url value='/sample/css/admin.css'/>" 
              type="text/css">
      	
          <script type="text/javascript" 
              src="<c:url value='/sample/javascript/CommonScript.js'/>"></script>    
          <script language="JavaScript">
              function fncAddBoardView() {
                  document.location.href="<c:url value='/board.do?method=addView'/>";
              }	
              function fncSearchBoard(arg) {
                  var conditions = ["boardId","boardMasterId","boardTopics"]	
          중략...
    • 단위테스트케이스 (src/test/java/[대표패키지]/[-package 값]/web/[Entity 클래스명]ControllerTest.java)

      @RunWith(JMock.class)
      public class BoardControllerTest {
      
          private BoardController controller;
          private String SUCCESS_ADDVIEW = "generation/board/viewBoard";
          private String SUCCESS_ADD = "redirect:/board.do?method=list";
          private String SUCCESS_GET = "generation/board/viewBoard";
          private String SUCCESS_UPDATE = "forward:/board.do?method=list";
          private String SUCCESS_LIST = "generation/board/listBoard";
          private String SUCCESS_DELETE = "redirect:/board.do?method=list";
          private Mockery context = new JUnit4Mockery();
          private BoardService mockService = null;
      	
          @Before   
          public void setUp() throws Exception {
              System.setProperty("log4j.configuration", "log4j-test.xml");
      
              this.mockService = context.mock(BoardService.class);                
              this.controller = new BoardController();
              this.controller.setBoardService(this.mockService);       
          }
          
          public void setBoardController(BoardController controller) {
              this.controller = controller;
          }
              
          @Test
          public void testAddView() throws Exception{
              String viewName = this.controller.addView(new ExtendedModelMap());
              
              assertEquals("returned correct view name", SUCCESS_ADDVIEW, viewName);
         }
              중략...

참고

위에서 설명한 기능 수행 도중에는 프로젝트 생성, 코드 생성 및 DB 변경 등과 같은 Anyframe Gen의 기능을 동시에 수행시킬 수 없으므로 유의하도록 한다. (Background 실행을 통한 기능 수행 시)

14.Configuration

Anyframe Gen을 사용하기 위해 Project Location 확인 및 DAO Frameworks, Template 정보를 설정한다.

프로젝트는 기본적으로 Query Service DAO Framework 을 사용하도록 설정되어 있으며, Hibernate/JPA으로 DAO Frameworks 설정을 변경하고 싶을 경우 Installation Tab에서 Hibernate 플러그인을 설치해야 한다. Hibernate/JPA 플러그인이 설치되어 있지만 예외적으로 Template이 MiPlatform으로 되어 있는 경우는 Hibernate/JPA Framework을 사용할 수 없다.

Template은 기본적으로 default만 제공되고, Installation Tab에서 MiPlatform 플러그인을 설치한 경우 추가적으로 선택할 수 있다.

  1. 프로젝트를 선택한 후 우 클릭 >> Anyframe Gen 을 선택한다.

  2. Anyframe Gen Editor에서 Configuration Tab을 선택하고 프로젝트 경로 확인 및 DAO Framework, Template 정보를 구성한다.

    • Project Location: 현재 프로젝트가 생성된 위치정보가 보인다.

    • DAO Frameworks: Query Service, Hibernate/JPA 중에 하나를 선택할 수 있고, Hibernate/JPA는 Hibernate 플러그인을 설치한 이후에 선택이 가능하다. map, miplatform Template의 경우 Query Service만 지원된다.

    • Template Selection: 기본적으로 default, map 템플릿이 지원되며, default 템플릿은 Annotation 기반의 Spring/SpringMVC 등으로 구성된 소스 코드 템플릿이 제공된다. MiPlatform 플러그인을 설치한 경우 MiPlatform Template도 선택할 수 있다. MiPlatform 의 경우 PID(Presentation Interface Developer)가 설치되어 있어야 생성된 소스가 정상적으로 동작한다.

  3. 입력정보 작성이 끝나면 반드시 Apply 버튼을 클릭하여 Configuration 정보가 저장되도록 한다. 구성한 정보가 정상적으로 반영되었는지 확인하기 위해서는 탐색기에서 선택한 프로젝트 경로로 이동하여, build.properties 파일내의 dao.framework(DAO Frameworks), template_type(Template Type) 항목의 값을 확인해본다. 정상적으로 반영이 되었다면, 해당 항목의 값이 입력한 값들로 변경되어 보일 것이다. 참고로, project.home 은 프로젝트 경로 정보이다.

15.JDBC Setting

Anyframe Gen의 Domain Class 를 생성 기능을 사용하기 위해서 DB 연결정보를 설정한다.

  1. 프로젝트를 선택한 후 우 클릭 >> Anyframe Gen 을 선택한다.

  2. Anyframe Gen Editor에서 JDBC Setting Tab을 선택하고 JDBC 연결정보를 입력한다.

    • Database Type: Database 타입으로 HSQL, Oracle, MySQL, Sybase 를 제공하고 있다.

    • Database Name: Database의 이름

    • User Name: DB 유저 이름

    • Schema: DB 스키마의 이름

    • Password: 패스워드

    • Server: DB가 설치된 서버 ip 정보, 로컬에서 사용하는 경우 localhost

    • Port: HSQL의 경우 -1, Oracle의 경우 1521, MySQL의 경우 3306, Sybase는 3000

    • Hibernate Dialect: Hibernate에서 쿼리 수행 시, DBMS에 최적화된 기능을 제공하기 위해 사용되는 것이 SQL Dialect 이며, 이 Dialect 프로퍼티를 사용하여 해당 DB 별 Dialect 정보를 설정할 수 있다. 각 DB 별 Dialect 클래스가 따로 존재하여 HSQL DB를 선택한 경우, 디폴트로 org.hibernate.dialect.HSQLDialect값이 선택된다.(Oracle, MySQL, Sybase Dialect 도 제공함)

    • Driver Class Name: DB의 드라이버 클래스를 설정해 주기 위한 값으로, HSQL의 경우 org.hsqldb.jdbcDriver 값으로 설정된다. Database Type 선택 시 해당 DB에 맞는 값이 셋팅된다.

    • Driver Jar Path: Anyframe Gen 설치 시 샘플 DB를 위한 HSQL DB Driver Jar 파일이 제공되므로 디폴트로 설정된다. 만약 다른 DB를 사용한다면 해당 DB의 Driver jar 파일로 연결시켜준다.

  3. 입력정보 작성이 끝나면 반드시 Apply 버튼을 클릭하여 JDBC Configuration 정보가 저장되도록 한다.

    Schema 정보를 리스트에서 선택하지 않고 Apply 버튼을 클릭할 경우, Schema 를 선택하라는 메시지가 출력된다. Schema 를 제외한 나머지 JDBC Configuration 정보가 정상적인 경우 Schema 정보를 얻어올 수 있으며, 얻어온 리스트에서 Schema 를 선택하여 Apply 하면 Configuration 정보가 반영된다.

    JDBC 환경 설정 정보가 정상적으로 구성되어 DB와 잘 연결되는지 확인하기 위해서는 Domain Generation Tab으로 이동하여 Refresh 버튼을 클릭해본다. 이때 정상적으로 연결이 잘 되는 경우라면 해당 DB의 Table들이 조회될 것이다.

참고

위에서 설명한 기능 수행 도중에는 프로젝트 생성, 코드 생성 및 DB 변경 등과 같은 Anyframe Gen의 기능을 동시에 수행시킬 수 없으므로 유의하도록 한다. (Background 실행을 통한 기능 수행 시)

16.Anyframe Plugin Installation

Anyframe Gen에서 Anyframe에서 제공하는 플러그인 을 Install/Uninstall 하기 위해서 사용한다. 플러그인을 설치하면 해당 플러그인과 연관된 라이브러리가 설치되며, 일부 플러그인의 경우 샘플코드를 제공하고 있다. 제공되는 샘플코드를 라이브러리와 함께 설치하고 싶은 경우, "Install or uninstall plugins with sample"에 체크한다.

  1. 프로젝트를 선택한 후 우 클릭 >> Anyframe Gen 을 선택한다.

  2. Anyframe Gen Editor에서 Installation Tab을 선택하면 다음과 같은 항목이 보인다.

    • !: Install/Uninstall 할 대상을 체크하는 부분으로, foundation 플러그인은 Anyframe 사용을 위한 기본 플러그인이므로, Install/Uninstall 대상에서 제외된다.

    • Plugin Type: 플러그인 타입

    • Group Id: 플러그인 Library의 Group 명

    • Artifact Id: 플러그인 Library 명

    • Version: 플러그인 버전

    • Sample: 샘플코드 존재여부로 샘플코드가 있으면 O, 라이브러리만 존재하는 플러그인은 X 로 표시

    • Installed: 플러그인이 설치되었는지 여부로 플러그인을 설치하면 O로 표시

    • Install or uninstall plugins with sample: 샘플코드를 라이브러리와 함께 설치/삭제하고 싶은 경우 체크박스에 체크하며,Service 타입 프로젝트에서는 비활성화 된다.

  3. 설치 또는 제거할 플러그인 항목을 체크한 후, Install 혹은 Uninstall 버튼을 클릭한다.

    Install/Uninstall 할 경우 tomcat은 stop 시킨 상태에서 수행하도록 한다. 그렇지 않은경우, 동작은 정상적으로 수행되나, 아래 4번 내용과 같은 에러가 발생하게 된다.

    플러그인 이 설치되었으면 Installed 항목에서 O표시가, 제거되었으면 X표시가 되며, 현재 설치되어 있는 플러그인 다음과 같은 방법으로 확인할 수 있다.

    Web타입 프로젝트의 경우 해당 플러그인과 샘플이 함께 설치되며, 해당 플러그인 적용된 샘플은 프로젝트를 실행시켜봄으로써 확인할 수 있다. Service 타입 프로젝트의 경우 해당 플러그인의 라이브러리만 설치된다.

    샘플 실행방법은[ New Project Creation]의 프로젝트 실행방법 내용을 참조한다.

    아래는 플러그인 설치 및 제거와 관련하여 정상적으로 반영되었는지 확인하는 방법이다.

    • metadata 정보확인: 프로젝트폴더 >> .metadata폴더>> anyframe-plugins-metadata.mf 파일에 list로 관리한다.

      foundation=anyframe,anyframe.plugin.foundation,4.2.0,com.sds.emp,sample,true
      miplatform=anyframe,anyframe.plugin.miplatform,4.2.0,,com.sds.emp,false
    • Web 타입 프로젝트: 플러그인 추가/삭제 시 관련된 라이브러리는 프로젝트 Web App Libraries에 추가/삭제

    • Service 타입 프로젝트: Service 타입 프로젝트의 .classpath에 설치된 플러그인 정보가 표시된다. 아래는 Service 타입 프로젝트의 .classpath일부분이다.

      중략...
      <!--hibernate here -->
      <!--hibernate-START-->
          <classpathentry exported="true" kind="var" 
              path="GEN_REPO/antlr/antlr/2.7.7/antlr-2.7.7.jar" />
          <classpathentry exported="true" kind="var" 
              path="GEN_REPO/anyframe/anyframe.hibernate/4.0.0/
              anyframe.hibernate-4.0.0.jar" />
          <classpathentry exported="true" kind="var" 
              path="GEN_REPO/dom4j/dom4j/1.6.1/dom4j-1.6.1.jar" />
          <classpathentry exported="true" kind="var" 
              path="GEN_REPO/net/sf/ehcache/ehcache/1.6.2/ehcache-1.6.2.jar" />
          중략...
      <!--hibernate-END-->
  4. 플러그인 Install/Uninstall 시에 다음 그림과 같은 메시지가 뜨는 경우는 tomcat이 실행된 상태에서 tomcat이 인식하고 있는 파일에 변경이 있는 경우에 발생하는 것이다.

    아래와 같은 메시지는 플러그인 Install/Uninstall 전에 tomcat 동작을 stop 시킬 경우에는 뜨지 않는다.

참고

위에서 설명한 기능 수행 도중에는 프로젝트 생성, 코드 생성 및 DB 변경 등과 같은 Anyframe Gen의 기능을 동시에 수행시킬 수 없으므로 유의하도록 한다. (Background 실행을 통한 기능 수행 시)

17.Project/Application Build

Anyframe Gen 을 이용해 단위 프로젝트 별 빌드 혹은 어플리케이션 전체 빌드를 수행할 수 있다.

각각의 단위 프로젝트 생성 시에 빌드 스크립트 파일이 함께 생성되어, 빌드를 수행할 수 있다. 빌드 도구로 Ant를 사용하며 디폴트 타겟 빌드 수행 시 컴파일, 테스트, 패키징, 배포 등의 공통적인 빌드 프로세스 단계를 수행해주고 있다.

아래의 두 가지 경우로 나누어서 살펴보자.

17.1.Project Build

  1. 프로젝트 내 build.xml 확인

    프로젝트 내부로 자동 생성되어진 build.xml 파일이 존재한다. 빌드 스크립트 내에는 빌드 수행을 위한 compile, test, package등 공통적으로 사용되는 빌드 타겟들이 존재한다. 실제 구동 내역을 가지고 있는 공통 스크립트는 [Gen Home]\cli\scripts\project-build.xml 파일 내에 작성되어 있다. 프로젝트 별로 변경해야 하는 일이 생기면 공통 스크립트를 수정하면 된다. 또한 각 프로젝트 단위 별로 공통 빌드 내역 외에 특화된 빌드 내용을 추가해야 하는 경우에는 해당 빌드 타겟을 확장하여 추가해 넣을 수 있다.

    다음은 Web 타입 프로젝트에 생성된 build.xml 의 일부분이다.

    <project name="Build module" default="default" basedir=".">		
        <property file = "build.properties"/>
        <import file = "${gen.home}/cli/scripts/project-build.xml"/>
    	
        <target name="clean" depends = "shared:clean" />
        <target name="init" depends = "shared:init" />
        <target name="resources" depends = "shared:resources" />
        <target name="compile" depends = "shared:compile" />
        <target name="test-resources" depends = "shared:test-resources" />
        <target name="test-compile" depends = "shared:test-compile" />
        <target name="package" depends = "shared:package" />
        <target name="extract" depends = "shared:extract" />
        <target name="emma-jars" depends = "shared:emma-jars" />
        <target name="test" depends = "shared:test" />
        <target name="report" depends = "shared:report" />
    
        <target name = "default" depends = "init, resources, compile, package"/>
        <target name = "deploy" depends = "default, extract"/>
        <target name = "all" depends = "clean, init, resources, compile, 
                   test-resources, test-compile, package, emma-jars, test, report"/>
    </project>
  2. 프로젝트 내 build.xml 선택 후 >> Run As >> Ant Build 을 선택

    디폴트 타겟이 수행되어 다음과 같은 빌드 프로세스를 거치게 된다. 최종 결과물인 프로젝트 바이너리 파일은 repo 폴더 하위에 존재하게 된다.

    init -> resources -> compile -> package -> deploy

  3. 프로젝트 내 build.xml 선택 후 >> Run As >> Ant Build... 을 선택

    디폴트 타겟이 아닌 리포팅 결과물을 생성해내는 타겟을 실행시켜 본다. 빌드 시 코드 분석 리포트, 테스트 수행 결과 리포트, 코드 커버리지 리포트 등을 생성시킨다. 리포트 결과물은 프로젝트 내 output 폴더에 생성되므로 빌드가 모두 완료된 뒤 확인해보도록 한다.

    clean -> init -> resources -> test-resources -> test-compile -> package -> emma-jars -> test -> report

17.2.Application Build

프로젝트가 생성된 폴더 경로로 이동한 후 Command Prompt 창을 열고, 빌드를 수행한다. (CLI(Command Line Interface)이용)

이때 gen 이라는 command를 이용하여 빌드를 수행할 것이기 때문에 [Gen Home]\bin 폴더 하위에 있는 env.bat 파일을 해당 Command Prompt 창에서 먼저 실행해준다.

어플리케이션을 빌드하는 방법은 다음과 같이 2가지가 있으며, 해당 command 는 프로젝트가 생성된 경로로 이동하여 실행한다.

  • 어플리케이션 빌드 후 WEB-INF/classes 폴더 하위에 CLASS 형태로 배포하는 방법

    gen build -deploy class
  • 어플리케이션 빌드 후 WEB-INF/lib 폴더 하위에 JAR 파일 형태로 배포하는 방법

    gen build- -deploy jar

V.Templates Extensions

Anyframe Gen 툴을 통해 자동 생성되는 프로젝트 구조와 소스 코드는 각 개발자 혹은 프로젝트 상황에 맞게 확장하여 사용할 수 있는 구조를 제공한다. 템플릿 파일들의 배포 위치는 [Gen Home] 폴더 하위의 templates 폴더이며 Anyframe Gen 설치 시 기본적으로 default, map, miplatform 템플릿을 제공하고 있다.

기본적으로 제공되는 각각의 템플릿에 대해서 살펴본 후, 필요한 템플릿에 대해서 확장해보도록 한다.

표 21. 기본 템플릿

template namedescription
default 가장 기본이 되는 템플릿으로 spring/spring mvc 기반으로 Business Layer와 Presentation Layer 간의 데이터 통신을 DTO(Data Transfer Object) 객체를 이용하여 구현하며, 화면은 JSP 페이지로 구성되어 있다.
map spring 기반으로 Business Layer와 Presentation Layer 간의 데이터 통신을 Map(java.util.Map) 객체를 이용하도록 Business Layer 코드, Presentation Layer 코드를 생성해준다. 또한 DAO 코드는 Query Service를 이용하여 생성해주고 있다. Hibernate를 이용한 DAO 코드는 생성하지 않는다.
miplatform spring/spring mvc 기반으로 Business Layer와 Presentation Layer 간의 데이터 통신을 MiPlatform의 객체(DatasetList,VariableList)를 이용하여 구현하며, 화면은 MiPlatform을 이용한 UI로 구성되어 있다.

18.프로젝트 템플릿 확장

[Gen Home] 폴더 하위의 templates 폴더를 살펴보면 default, map, miplatform 폴더가 존재하고 그 하위로 각각 project와 source 폴더가 존재하고 있음을 확인할 수 있다.

프로젝트 템플릿을 확장한다는 것은 Anyframe Gen을 통해 생성되는 프로젝트 구조를 포함하여 샘플 코드, 프로젝트 내부 빌드 파일 등을 각 개발자 혹은 프로젝트 상황에 맞게 수정하여 사용할 수 있다는 것으로 여기서는 Maven의 Archetype을 작성함으로써 프로젝트 템플릿을 확장할 수 있다. Archetype에 대한 자세한 내용은 Introduction to Archetypes 을 참조하도록 한다.

어플리케이션의 프로젝트 구조가 Web 타입 인지 Service 타입 인지에 따라 Project Template 확장 방법이 다르므로 유의하도록 한다.

18.1.Web 타입 프로젝트 템플릿 확장

Web 타입 프로젝트의 경우, 기본적인 프로젝트 구조 및 샘플 코드가 Anyframe의 Foundation Plugin(anyframe.plugin.foundation-4.2.0.jar)으로부터 생성된다.

Anyframe Gen을 통해서는 샘플 코드 일부와 빌드 스크립트가 생성되므로 이 매뉴얼에서는 Anyframe Gen을 통해 변경될 수 있는 부분을 설명하겠다. Anyframe Foundation Plugin에 대한 설명은 Anyframe 매뉴얼을 참고하도록 한다.

아래 나열한 순서에 따라서 확장해보도록 한다. 아래에서는 message source 파일(properties)을 더 추가해보는 예제로 구성되어 있다.

  1. Anyframe source code repository(Subversion)으로부터 anyframe.gen.archetype.singleconfig 프로젝트(SVN URL:http://dev.anyframejava.org/subv/anyframe-opensource/gen/tags/gen-1.2.0/dev/archetype/anyframe.gen.archetype.singleconfig)를 내려받는다. Subversion에 Access하는 자세한 방법은 이곳(Subversion 연결) 을 참고하도록 한다.

  2. Eclipse에 anyframe.gen.archetype.singleconfig 프로젝트를 Import한 후, 프로젝트 명을 변경시킨다. 이때 이름은 반드시 anyframe.gen.archetype.singleconfig로 시작 하는 이름이어야 한다.

    예를 들어, anyframe.gen.archetype.singleconfig.ext로 프로젝트 명을 변경시켜보자.

    • Eclipse Project 명 변경: 프로젝트 선택 후 마우스 우측 버튼 선택 > Refactor > Rename...> anyframe.gen.archetype.singleconfig.ext 입력 > OK

    • Maven Project 명 변경: 프로젝트 하위에 있는 pom.xml 파일을 Open하여 아래와 같이 groupId, artifactId, version 정보를 원하는 정보로 변경하도록 한다.

      <groupId>templates.project.ext</groupId>
      <artifactId>anyframe.gen.archetype.singleconfig.ext</artifactId>
      <version>1.0.0</version>
    • Project 폴더명까지 모두 anyframe.gen.archetype.singleconfig.ext으로 변경하여 기존의 anyframe.gen.archetype.singleconfig 프로젝트와 혼동되지 않도록 관리한다.

  3. anyframe.gen.archetype.singleconfig.ext 프로젝트 하위의 src/main/resources/archetype-resources 폴더 내 파일들을 변경 및 추가할 수 있다.

    샘플 코드 혹은 빌드 스크립트 파일을 변경할 수 있다. 샘플 코드는 src/main/resources/archetype-resources/src 폴더 하위에, 빌드 스크립트 파일(build.xml)은 src/main/resources/archetype-resources/pjt 폴더 하위에 위치하고 있다.

  4. 신규 message resource 파일을 추가하여, 프로젝트 생성 시 나타나도록 message-ext.properties 파일을 추가한다.

    그러므로 src/main/resources/archetype-resources/src/main/resources/message 폴더 하위에 message-ext.properties 파일을 추가한다.

  5. 수정 및 추가한 정보에 의해 부가적으로 변경되어야 하는 파일이 존재하는 경우, 함께 수정하도록 한다.

    message resource 파일이 추가되면, spring messageSource bean에 properties 파일을 추가 설정해주도록 한다. 즉, src/main/resources/archetype-resources/src/main/resources/spring/context-common.xml 파일에 다음과 같이 value 태그를 추가해넣는다.

    <bean id="messageSource" 
    	class="org.springframework.context.support.ResourceBundleMessageSource">	
    	<property name="basenames">
    		<list>
    			<value>message/message-ext</value>					
    			<value>message/message-generation</value>					
    			<value>message/message-productmgmt</value>
    			<value>anyframe/core/properties/messages/properties</value>
    			중략...							
    		</list>
    	</property>
    </bean>
  6. 확장된 anyframe.gen.archetype.singleconfig.ext 프로젝트를 패키징한다.

    Maven으로 프로젝트를 빌드하여 jar 파일로 패키징하도록 한다. Maven 빌드를 하기 위해서는 Maven을 먼저 설치해야 하는데 이는 Anyframe 매뉴얼 중 Maven 설치 및 환경 설정 부분을 참고하도록 한다. Maven 설치 및 환경 설정 한 이 후 "mvn package" command를 수행시킨다. 그 결과 패키지 파일은 anyframe.gen.archetype.singleconfig.ext 프로젝트 하위의 target 폴더에 anyframe.gen.archetype.singleconfig.ext-1.0.0.jar 파일로 생성된다.

    mvn package
  7. 확장된 anyframe.gen.archetype.singleconfig.ext 배포 파일을 [Gen Home] 폴더 하위의 templates 폴더에 위치시키는데 이때, 새로운 템플릿으로 명명하여 사용할 것이므로 templates 폴더 하위에 ext와 같이 템플릿명을 나타내는 폴더를 생성한 뒤 다음과 같이 ext 폴더 하위로 project 폴더를 두고, anyframe.gen.archetype.singleconfig.ext-1.0.0.jar 파일을 배포한다.

    즉, [Gen Home]/templates/default 폴더 전체를 복사하여 [Gen Home]/templates/ext 폴더에 위치시킨 후 기존의 anyframe.gen.archetype.singleconfig-1.0.0.jar 파일을 project 폴더에서 삭제하고 새로 패키징한 anyframe.gen.archetype.singleconfig.ext-1.0.0.jar 파일을 위치시킨다.

  8. Web 타입 프로젝트 생성 기능을 수행시켜서 위에서 추가한 message-ext.properties 파일이 자동생성되어 구성되는지 확인해보도록 한다.

    CLI상에서 Web 타입 프로젝트 생성 시 build.properties 파일의 template_type 항목의 값을 ext로 변경하고 생성하도록 한다. Eclipse Plugin을 이용하여 Web 타입 프로젝트 생성 시에는 AnyframeGen Editor의 Configuration Tab 내에서 template을 ext로 변경하고 생성하도록 한다.

18.2.Service 타입 프로젝트 템플릿 확장

Service 타입 프로젝트의 경우, 자바 프로젝트 구조가 구성되어 생성된다.

다음 표와 같이 여러 종류의 Archetype이 있으므로 확장하고 싶은 Archetype에 대해 작업하도록 한다.

표 18.1. Service 타입 Projects Archetypes

archetypedescription
anyframe.gen.archetype.service.annotation 프로젝트의 구조를 생성시켜주는 archetype으로 Aspect 클래스 및 spring 설정 파일 그리고 빌드 스크립트(build.xml)를 제공한다.

아래 나열한 순서에 따라서 확장해보도록 한다.

  1. Anyframe source code repository(Subversion)으로부터 archetype 프로젝트를 내려받도록 한다. (SVN URL은 다음 표를 참조한다.) Subversion에 Access하는 자세한 방법은 이곳(Subversion 연결) 을 참고하도록 한다.

    표 18.2. Archetype SVN URL

    archetypeSVN URL
    anyframe.gen.archetype.service.annotation http://dev.anyframejava.org/subv/anyframe-opensource/gen/tags/gen-1.2.0/dev/archetype/anyframe.gen.archetype.service.annotation

  2. Eclipse에 archetype 프로젝트를 Import한 후, 프로젝트 명을 변경시킨다. 이때 이름은 반드시 anyframe.gen.archetype.service로 시작 하는 이름이어야 한다.

    예를 들어, anyframe.gen.archetype.service.annotation.ext로 프로젝트 명을 변경시켜보자.

    • Eclipse Project 명 변경: 프로젝트 선택 후 마우스 우측 버튼 선택 > Refactor > Rename...> anyframe.gen.archetype.service.annotation.ext 입력 > OK

    • Maven Project 명 변경: 프로젝트 하위에 있는 pom.xml 파일을 Open하여 아래와 같이 groupId, artifactId, version 정보를 원하는 정보로 변경하도록 한다.

      <groupId>templates.serviceproject.ext</groupId>
      <artifactId>anyframe.gen.archetype.service.annotation.ext</artifactId>
      <version>1.0.0</version>

    • Project 폴더명까지 모두 anyframe.gen.archetype.service.annotation.ext으로 변경하여 기존의 anyframe.gen.archetype.service.annotation 프로젝트와 혼동되지 않도록 관리한다.

  3. anyframe.gen.archetype.service.annotation.ext 프로젝트 하위의 src/main/resources/archetype-resources 폴더 내 파일들을 변경 및 추가할 수 있다.

    샘플 코드 혹은 빌드 스크립트 파일을 변경할 수 있다. 샘플 코드는 src/main/resources/archetype-resources/src 폴더 하위에, 빌드 스크립트 파일(build.xml)은 src/main/resources/archetype-resources/pjt 폴더 하위에 위치하고 있다.

  4. LoggingAspect 클래스에 afterLogging 메소드를 추가한다.

    아래와 같이 src/main/java/common/aspect/LoggingAspect.java 파일을 열어서 afterLogging 메소드를 추가해넣는다. 메소드 호출 후에도 로깅을 남기도록 수정한다.

    private MessageSource messageSource;
    public void setMessageSource(MessageSource messageSource) {
    	this.messageSource = messageSource;
    }
    public void afterLogging(JoinPoint thisJoinPoint) {
    	Class clazz = thisJoinPoint.getTarget().getClass();
    	String className = clazz.getName();
    	String classSimpleLowerName = thisJoinPoint.getTarget().getClass().
    	                              getSimpleName().toLowerCase();
    	String methodName = thisJoinPoint.getSignature().getName();
    	String methodLowerName = methodName.toLowerCase();
    	
    	StringBuffer buf = new StringBuffer();
    	buf.append("\n** After Logging Aspect : executed " + methodName + "() in "
    			+ className + " Class.");
    	buf.append("\n*******************************************\n");
    	buf.append(messageSource.getMessage("success." + classSimpleLowerName + "."
    			+ methodLowerName, new String[] {}, "no messages", Locale.getDefault()));
    	buf.append("\n*******************************************\n");
    	
    	Log logger = LogFactory.getLog(clazz);
    	if (logger.isDebugEnabled())
    		logger.debug(buf.toString());	
    }
  5. 수정 및 추가한 정보에 의해 부가적으로 변경되어야 하는 파일이 존재하는 경우, 함께 수정하도록 한다.

    Aspect 클래스에 메소드가 추가되고 이를 반영하기 위해 src/main/resources/archetype-resources/src/main/resources/spring/context-aspect.xml 파일에 다음과 같이 aop:after 태그를 추가해넣는다.

    <aop:config>
    	<aop:pointcut id="loggingMethod" expression="execution(* *..*Service+.*(..))" />
    	<aop:aspect ref="methodLoggingAspect" >
    		<aop:before method="beforeLogging" pointcut-ref="loggingMethod"/>
    		<aop:after method="afterLogging" pointcut-ref="loggingMethod" />
    	</aop:aspect>	 
    </aop:config>
  6. 확장된 anyframe.gen.archetype.service.annotation.ext 프로젝트를 패키징한다.

    Maven으로 프로젝트를 빌드하여 jar 파일로 패키징하도록 한다. Maven 빌드를 하기 위해서는 Maven을 먼저 설치해야 하는데 이는 Anyframe 매뉴얼 중 Maven 설치 및 환경 설정 부분 을 참고하도록 한다. Maven 설치 및 환경 설정한 이후 "mvn package" command를 수행시킨다. 그 결과 패키지 파일은 anyframe.gen.archetype.service.annotation.ext 프로젝트 하위의 target 폴더에 anyframe.gen.archetype.service.annotation.ext-1.0.0.jar 파일로 생성된다.

    mvn package
  7. 확장된 anyframe.gen.archetype.service.annotation.ext 배포 파일을 [Gen Home] 폴더 하위의 templates 폴더에 위치시키는데 이때, 새로운 템플릿으로 명명하여 사용할 것이므로 templates 폴더 하위에 ext와 같이 템플릿명을 나타내는 폴더를 생성한 뒤 다음과 같이 ext 폴더 하위로 project 폴더를 두고, anyframe.gen.archetype.service.annotation.ext-1.0.0.jar 파일을 배포한다.

    즉, [Gen Home]/templates/default 폴더 전체를 복사하여 [Gen Home]/templates/ext 폴더에 위치시킨 후 기존의 anyframe.gen.archetype.service.annotation-1.2.0.jar 파일을 project 폴더에서 삭제하고 새로 패키징한 anyframe.gen.archetype.service.annotation.ext-1.0.0.jar 파일을 위치시킨다.

  8. Service 타입 프로젝트 생성 기능을 수행시켜서 위에서 추가한 LoggingAspect.java 파일이 자동생성되어 구성되는지 확인해보도록 한다.

    CLI상에서 Service 타입 프로젝트 생성 시 build.properties 파일의 template_type 항목의 값을 ext로 변경하고 생성하도록 한다. Eclipse Plugin을 이용하여 Service 타입 타입 프로젝트 생성 시에는 AnyframeGen Editor의 Configuration Tab 내에서 template을 ext로 변경하고 생성하도록 한다.

19.소스 코드 템플릿 확장

[Gen Home] 폴더 하위의 templates 폴더를 살펴보면 아래와 같이 default,map, miplatform 폴더가 존재하고 그 하위로 각각 project와 source 폴더가 존재하고 있음을 확인할 수 있다.

소스 코드 템플릿을 확장한다는 것은 Anyframe Gen을 통해 생성되는 도메인 클래스, CRUD 소스 코드에 대해서 각 개발자 혹은 프로젝트 상황에 맞게 수정하여 사용할 수 있다는 것으로 여기서는 FreeMarker Template을 수정함으로써 소스 코드 템플릿을 확장할 수 있다. FreeMarker에 대한 자세한 내용은 FreeMarker 사이트 를 참조하도록 한다.

프로젝트가 Web타입 인지 Service타입 인지에 상관없이 소스 코드 템플릿 확장 방법은 동일하다.

19.1.템플릿 폴더 생성

FreeMarker Template(*.ftl) 파일들을 수정하여 자동 생성되는 소스 코드에 대한 템플릿을 확장해보도록 한다.

default 템플릿을 확장하여 ext 템플릿을 구성해보자. 이때 프로젝트 템플릿은 확장하지 않고 소스 코드 템플릿만 확장해본다. 프로젝트 템플릿 확장하는 방법은 [프로젝트 템플릿 확장 매뉴얼] 을 참고하도록 한다.

[Gen Home]/templates/default 폴더 전체를 복사한 후 이름을 ext로 변경시켜서 [Gen Home]/templates/ext 폴더를 만들고 [Gen Home]/templates/ext/source 폴더 하위의 template.config 파일이 있는지 확인한다.

19.2.템플릿 파일 목록 작성(template.config)

template.config 파일을 열고 소스 코드 생성에 필요한 템플릿 파일 목록을 작성한다.

template.config 파일 내 작성되는 정보는 소스 코드 생성 시 필요한 코드 템플릿 목록 정보로 default 템플릿을 통해 제공되는 템플릿 정보는 다음 표와 같다.

타입 별 템플릿 파일에 대한 설명으로, template.config 파일 내 템플릿 목록으로 작성되어야 CRUD 소스 코드 생성 시 결과 코드로 생성된다. service 타입 템플릿은 Business Layer 코드 생성 시 사용되는 템플릿이고, web 타입 템플릿은 Presentation Layer 코드 생성 시 사용된다.

template.config 파일 내 템플릿 정보 등록 시 아래와 같은 항목 내용을 작성하도록 한다.

  • type: service, web 타입

  • ftl: freemarker template 파일

  • src: 생성될 소스 코드 파일 명

    • {basepkg-name} : 대표패키지

    • {class-name} : 엔티티 클래스 명

  • share: sample db data 공유 여부를 true, false로 설정

  • dao: hibernate, query 중 dao framework 설정

  • description: 템플릿 설명

표 19.1. Service Type template configuration

typeftlsrcsharedaodescription
service dao/sample-data.ftl src/test/resources/{class-name}-sample-data.xmlfalseN/Atest sample db data
service dao/dao-test.ftl src/test/java/{basepkg-name}/dao/{class-name}Dao Test.java trueN/Adao class test case
service dao/dao.ftl src/main/java/{basepkg-name}/dao/{class-name}Dao.java falseN/Adao class
service dao/dao-bean.ftl src/main/resources/{class-name}Dao-bean.xml falseN/Adao class spring bean configuration xml 파일
service service/service-test.ftl src/test/java/{basepkg-name}/service/impl/{class-name}Service ImplTest.java falseN/Aservice implementation class에 대한 test case
service service/service.ftl src/main/java/{basepkg-name}/service/{class-name} Service.java falseN/Aservice interface class
service service/service-impl.ftl src/main/java/{basepkg-name}/service/impl/{class-name}Service Impl.java falseN/Aservice implementation class
service dao/hibernate/dao-impl.ftl src/main/java/{basepkg-name}/dao/impl/{class-name} DaoHibernate Impl.java falsehibernatehibernate dao implementation class
service dao/hibernate/dynamic-hibernate.ftl src/main/resources/hibernate/dynamic/dynamic-hibernate-{class-name}.xml falsehibernatehibernate dynamic hql mapping xml file
service dao/query/dao-impl.ftl src/main/java/{basepkg-name}/dao/impl/{class-name}Dao QueryImpl.java falsequeryquery dao implementation class
service dao/query/mapping-query.ftl src/main/resources/query/mapping-query-{class-name}.xml falsequeryquery service mapping xml file
service web/Application Resources.ftl src/main/resources/{class-name}-Application Resources .properties falseN/Amessage source properties 파일

표 19.2. Web Type template configuration

typeftlsrcsharedaodescription
web web/spring/controller-test.ftl src/test/java/{basepkg-name}/web/{class-name}Controller Test.java falseN/Aspring mvc controller class test case
web web/spring/controller.ftl src/main/java/{basepkg-name}/web/{class-name} Controller.java falseN/Aspring mvc controller class
web web/spring/list-view.ftl src/main/webapp/WEB-INF/jsp/sample/{class-name}/list{class-name}.jsp falseN/Alist view jsp page
web web/spring/form-view.ftl src/main/webapp/WEB-INF/jsp/sample/{class-name}/view{class-name}.jsp falseN/Adetail view jsp page
web web/menu.ftl src/main/webapp/common/{class-name}-menu.jsp falseN/Amenu jsp page

19.3.템플릿 파일(*.ftl) 수정

[Gen Home]/templates/ext/source 폴더 하위에서 확장하고 싶은 ftl 파일들을 선정하여 수정하도록 한다.

source 폴더 하위에 있는 ftl 파일들은 원하는 폴더로 묶어서 관리할 수 있다. 현재에는 다음 표와 같이 4개의 폴더(model, service, dao, web)로 구분되어 있다. 자유롭게 변경할 수 있다. 단, 폴더명과 ftl 파일 명 변경 시 위에서 설명한 template.config 파일 내 ftl 항목 내용도 반드시 변경시켜줘야 한다.

표 19.3. template folder

folder namedescription
model 도메인 클래스 생성 시 사용되는 ftl들 존재
service service 클래스/테스트 케이스 및 Spring bean 설정 파일 ftl들 존재
dao 샘플 데이터, hibernate/query dao 클래스/테스트 케이스 및 Spring bean 설정 파일 ftl들 존재
web 메뉴, message resource, spring mvc 클래스/테스트 케이스 및 Spring bean 설정 파일, JSP ftl들 존재

예를 들어 service 생성 시 기본 CRUD 메소드 외 다른 메소드를 추가해보자.

  • [Gen Home]/templates/ext/source/service/service.ftl 파일을 열어 다음과 같이 getProcedureList 메소드를 추가한다.

    getProcedureList의 리턴 타입이 List 이므로 클래스 상단에 import 구문을 추가해줘야 함에 유의하도록 한다.

    package ${basepackage}.service;
    
    import java.util.List;
    
    import anyframe.common.Page;
    import anyframe.common.util.SearchVO;
    import ${appfusepackage}.service.GenericService;
    import ${pojo.packageName}.${pojo.shortName};
    <#if c2j.isComponent(pojo.identifierProperty) >
    import ${pojo.packageName}.${pojo.getJavaTypeName(pojo.identifierProperty, jdk5)};
    </#if>
    
    public interface ${pojo.shortName}Service extends 
    	GenericService<${pojo.shortName}, 
    	               ${pojo.getJavaTypeName(pojo.identifierProperty, jdk5)}> {
    
    	public Page getPagingList(SearchVO searchVO) throws Exception;     
    	public List getProcedureList(SearchVO searchVO) throws Exception;   
    }

    이 ftl 구문 내에서 클래스, 메소드 등의 이름을 변경하거나 내용을 수정할 수 있다. service interface(service.ftl) 클래스에 대한 내용 수정 시 service implementation(service-impl.ftl) 클래스에 대한 내용도 함께 수정해줘야 함에 유의하도록 한다.

  • [Gen Home]/templates/ext/source/service/service-impl.ftl 파일을 열어 다음과 같이 getProcedureList 메소드를 추가한다.

    getProcedureList의 리턴 타입이 List 이므로 클래스 상단에 import 구문을 추가해줘야 함에 유의하도록 한다.

    <#assign pojoNameLower = pojo.shortName.substring(0,1).toLowerCase()+
    	pojo.shortName.substring(1)>
    package ${basepackage}.service.impl;
    
    import java.util.List;
    import anyframe.common.Page;
    import anyframe.common.util.SearchVO;
    import ${basepackage}.dao.${pojo.shortName}Dao;
    import ${pojo.packageName}.${pojo.shortName};
    <#if c2j.isComponent(pojo.identifierProperty) >
    import ${pojo.packageName}.${pojo.getJavaTypeName(pojo.identifierProperty, jdk5)};
    </#if>
    import ${basepackage}.service.${pojo.shortName}Service;
    import ${appfusepackage}.service.impl.GenericServiceImpl;
    
    public class ${pojo.shortName}ServiceImpl extends 
      GenericServiceImpl<${pojo.shortName}, 
                         ${pojo.getJavaTypeName(pojo.identifierProperty, jdk5)}> 
      implements ${pojo.shortName}Service {
      
        ${pojo.shortName}Dao ${pojoNameLower}Dao;
    
        public ${pojo.shortName}ServiceImpl(${pojo.shortName}Dao ${pojoNameLower}Dao) {
            super(${pojoNameLower}Dao);
            this.${pojoNameLower}Dao = ${pojoNameLower}Dao;
        }
        
    	public Page getPagingList(SearchVO searchVO) throws Exception {
    		return this.${pojoNameLower}Dao.getPagingList(searchVO);
    	}        
    	
    	public List getProcedureList(SearchVO searchVO) throws Exception{
    	중략...
    	}
    	   
    }

19.4.템플릿 파일(*.ftl) 변수

템플릿 파일(*.ftl)을 수정하기 위해서는 일반 문자열 자체를 변경하여 클래스나 메소드 명을 변경시킬 수도 있으나 템플릿 파일 내 사용되는 변수(${변수명})를 이용하여 수정 시 좀더 다양하게 템플릿을 확장시킬 수 있다.

다음은 템플릿 파일 내에서 자주 사용되는 변수에 대한 설명을 표로 나타낸 것이다.

표 19.4. FTL 파일 내 변수 목록

namedescription
pojo.shortName CRUD 대상이 되는 도메인 클래스명(ex. Board)
pojoNameLower CRUD 대상이 되는 도메인 클래스명의 소문자 형태(ex. board)
pojo.packageName CRUD 대상이 되는 도메인 클래스의 패키지명
basepackage 소스 코드 생성 시 생성되는 클래스의 상위 패키지로 어플리케이션 대표 패키지명
appfusepackage anyframe.core.generic 패키지
pojo.identifierProperty.name 도메인 클래스의 Primary Key에 해당하는 속성명

다음은 아래와 같이 사용되는, 템플릿 파일 내에서 FreeMarker 구문을 통해 사용되는 로직에 대한 설명을 표로 나타낸 것이다. <#구문 내에서 사용된다.

foreach, if, lt, assign 등과 같은 FreeMarker 문법에 대한 내용은 FreeMarker 사이트 를 참조하도록 한다.

<#foreach field in pojo.getAllPropertiesIterator()>    
    <#foreach column in field.getColumnIterator()>
        <#if field.equals(pojo.identifierProperty) && !column.nullable 
            && !c2h.isCollection(field) && !c2h.isManyToOne(field) 
            && !c2j.isComponent(field)>
            <#lt/><form:option value="${field.name}">
            <anyframe:message code="${pojoNameLower}.${field.name}"/>
            </form:option>     
        </#if>
    </#foreach>    
    <#if field.equals(pojo.identifierProperty) && !c2h.isCollection(field) 
 	    && !c2h.isManyToOne(field) && c2j.isComponent(field)>
       <#lt/>       
       <#assign pojoIdentifier = pojo.identifierProperty.getValue() >       		
       <#foreach idfield in pojoIdentifier.getPropertyIterator()>               		 	
           <#lt/><form:option value="${field.name}.${idfield.name}">
           <anyframe:message code="${pojoNameLower}.${field.name}.${idfield.name}"/>
           </form:option>            	
       </#foreach>     		
    </#if>
</#foreach>

표 19.5. FTL 파일 내 로직

logicdescription
pojo.getAllPropertiesIterator() 도메인 클래스의 모든 속성 정보를 얻어냄
c2j.isComponent(pojo.identifierProperty) 도메인 클래스의 Primary Key에 해당하는 속성이 Composite Key 클래스로 구성되었는지 여부를 리턴함
c2j.isComponent(field) 도메인 클래스의 해당 field 속성이 primitive type이 아닌 클래스로 구성되었는지 여부를 리턴함
c2h.isCollection(field) 도메인 클래스의 해당 field 속성이 Collection 클래스로 구성되었는지 여부를 리턴함
c2h.isManyToOne(field) 도메인 클래스의 해당 field 속성이 many to one 관계에 있는지 여부를 리턴함
dbdata.getSampleDataSet(pojo) DB 테이블 별 컬럼값에 해당하는 샘플 데이터 값을 얻어냄

참고

pojo(POJOClass), c2j(Cfg2JavaTool), c2h(Cfg2HbmTool), data(AnyframeDataHelper), dbdata(AnyframeDBData), util(StringUtils) 등은 템플릿 파일 내에서 각 클래스의 메소드를 호출하여 로직을 수행할 수 있도록 해주는 변수들로 Anyframe Gen 툴 내에서 설정해주고 있다. 현재 제공되는 템플릿 파일내에서 사용되고 있는 모습을 참조하여 작성하도록 한다.

19.5.변경된 템플릿 파일(*.ftl) 적용

확장된 ftl 파일을 실제 CRUD 소스 코드 생성 시 사용해본다.

CLI 혹은 Eclipse Plugin 툴을 이용하여 CRUD 소스 코드를 생성시켜서 변경된 템플릿 파일이 정상적으로 반영되었는지 확인한다. 소스 코드 생성 시 에러가 발생하지 않고, 실제 어플리케이션을 구동시켜서 정상적으로 동작해야 한다.