레이블이 Java Web App인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Java Web App인 게시물을 표시합니다. 모든 게시물 표시

2009년 7월 28일 화요일

Teamcity 설치

지속적인 통합에 대한 필요성이 증가하면서 최근에 많은 지속적 통합 툴이 등장하고 있다. 오픈 소스 기반으로 개발되는 지속적 통합 툴은 CruiseControl과 Hudson이 가장 많이 사용되고 있다. 최근에 등장한 Hudson도 설치와 설정이 편리하고 다양한 플러그인을 지원하여 많은 개발자들이 사용하고 있다. 상용 지속적 통합 툴로는 Atlassian에서 개발한 Bamboo와 JetBrains에서 개발한 Teamcity가 가장 많이 사용되고 있다. 오픈 소스로 개발하는 CruiseControl과 Hudson도 좋은 툴이지만 여기서는 Teamcity를 이용하여 지속적 통합을 하는것을 예로 보여주겠다. Teamcity는 무료로 20명의 사용자까지 무료로 사용할 수 있으며, 설치와 설정이 쉽고 피드백 기능을 다양하게 지원하고 있어 여러모로 많이 편리하다.

Teamcity 다운로드
Teamcity 무료버전은 아래 주소로 가서 다운로드 받으면 되겠다.
http://www.jetbrains.com/teamcity/download
위주소로 가서 Free Professional Edition을 다운로드 받으면 된다.

Teamcity 설치하기
다운로드 받은 Teamcity 바이너리 설치파일을 더블 클릭하여 설치한다.

Teamcity 설치 환영 화면에서 'Next'버튼을 누른다.



Teamcity 라이선스 정책에 동의하는 화면에서 'I Agree' 버튼을 누른다.



Teamcity 서버를 설치할 경로를 선택한 다음 'Next' 버튼을 누른다.



윈도우 서비스에 Teamcity Build Agent와 Teamcity 서버를 등록할지의 여부를 결정한다. 기본은 Build Agent와 서버를 모두 서비스에 등록할 수 있게 체크된 상태이다.'Next' 버튼을 눌러 다음 화면으로 이동한다. 여기서 주의할점은 Teamcity WAS 서버가 기본으로 TOMCAT 서버를 사용함으로 만약 기존에 TOMCAT이 서버에 깔린 상태라면 충돌이 일어날수 있다. 충돌이 일어나지 않도록 기존에 톰캣 Listening포트를 변경하는것이 필요하겠다.




Teamcity에서 관리할 프로젝트와 각 프로젝트별 설정 정보를 관리하는 디렉토리를 선택한다. 디렉토리를 선택한 다음 'Next' 버튼을 누르면 설치가 시작된다.
마지막으로 Teamcity 서버가 사용할 포트를 설정한다. 기본값으로 설정된 7000을 그냥 사용하여 보자.

이로써 Teamcity 설치가 완료된다. 설치완료후 기본 정보 설정이 필요한데 원하는 정보를 기입하고 저장한다. 기본으로 Admin계정을 생성하여야 할것이다.

참고문헌: 자바 프로젝트 필수 유틸리티

2009년 7월 21일 화요일

Trac 설치 및 기본 플러그인 설치와 설정

Trac은 미국항공우주국의 분사추진 연구소에서 사용할 정도로 전 세계적으로 널리 사용되고 있다. Trac은 아래와 같은 특점이 있음으로 하여 많은 프로젝트를 진행하는 개발자들이 애용한다.

  1. 오픈 소스로 작성되었기 때문에 언제든지 사용자가 소스를 수정하여 사용할 수있다. 참고로 Trac은 Python이라고 불리우는 언어로 만들어졌다.
  2. Trac은 문서, SVN, WBS 등 모든것을 웹 기반으로 관리할 수 있다. 웹 브라우저로 프로젝트 정보에 언제 어디서든 접근할 수 있으며, 누구라도 수정할 수 있다. 히스토리 관리가 가능하기 때문에 변경사항을 추적하기 쉽다.
  3. SVN, VSS, CVS 등 여러 버전 관리 시스템과 연동할 수 있다.

Trac의 설치
Trac은 Python으로 만들어져 있기 때문에 Python언어를 잘 모르는 개발자들한테는 아주 생소한 존재일지도 모른다. Trac을 설치하려면 Apache, Python, mod_python, pysqlite 와 같이 여러 개의 소프트웨어를 함께 설치해야 하기에 좀 번거롭다.

1. 아파치 서버 설치
Apache 웹 서버 설치는 가장 무난하므로 여기서는 생략 하겠다. 단 집고 넘어갈 점이라면 Apache 서버 설치경로 인데 나의 경우 D 드라이버로 정했다.

2. Python 설치
Trac은 Python으로 개발했으므로 Python을 설치해야 한다.
  • 사이트: http://www.python.org
  • 다운로드: http://www.python.org/download/
  • 다운로드 할 파일: Python 2.5.4 Windows installer (Windows binary -- does not include source)
  • 설치 파일: python-2.5.4.msi
Python 설치 파일을 클릭하면 Python 프로그램의 사용자를 지정하는 화면이 나타난다. 모든 사용자가 사용할 수 있게 Install for all users를 선택한 다음 'Next' 버튼을 눌러 다음 화면으로 이동한다.



Python을 설치할 디렉토리를 지정하는 화면에서 C:\Python25를 선택한 다음 'Next'버튼을 누른다.



설치 할 Python의 구성 요소를 선택하는 화면이다. 기본 설정을 그대로 사용한다. 기본값으로 Register Extensions, Tcl/Tk, Documentation, Utility Scripts, Test suite 등을 그대로 설치한다. 'Next' 버튼을 누르면 Python설치가 진행된다. 몇초간 걸리므로 내심하게 기다려주면 되겠다.



오케이, 아래와 같은 창이 뜨면 설치가 성공한것이다. 잊지 말것은 이것은 Windows, DOS용 Python이다. Linux용은 다른 방식으로 설치가 될것이다.(시간나면 Linux용 설치방법까지 업데이트 할 계획이다.) 'Finish'를 기분좋게 클릭하고 설치를 완료하자.



3. mod_python 설치
Apache에서 Python코드를 실행하는 방법은 CGI방식과 Apache 모듈 방식이 있다. (이점은 PHP와 흡사하다, PHP와 Apache를 연동하였던 분이라면 쉽게 무난하게 이해가 가능할 것이다.) 그러나 CGI방식은 속도가 느리므로 크게 권장하지 않고 일반적으로 mod_python Apache모듈을 설치해 모듈 방식으로 Python 코드를 실행한다. 그러기 위헤서는 mod_python을 설치하는 과정이 필요하다. 결국 이 과정자체가 설치이면서 Python과 Apache를 연동하는 과정이기도 하다.
  • 사이트: http://www.modpython.org
  • 다운로드: http://httpd.apache.org/modules/python-download.cgi
  • 설치 파일: mod_python-3.3.1.win32-py2.5-Apache2.2.exe
위에 링크에는 Apache 2.2.용 mod python을 명시했는데 사실상 Apache버전에 마추어 적당한 mod python을 다운로드 받어야 한다.

mod_python 설치 파일을 실행하면 설치 화면이 나타난다. 다음을 눌러 이동한다.



Python이 설치되어 있다면 Python이 설치된 디렉토리 경로를 확인할 수 있다. 레지스터리에 Python설치관련 정보가 남아있으므로 무난히 찾을수가 있겠다. 모듈이 설치 될 기본 경로는 Python Installation Path/Lib/site-packages 이다.



설치 준비 화면이다. 다음을 누르면 설치가 진행된다.



mod_python을 설치하는 중 Apache가 설치된 경로를 지정하는 다이얼로그박스가 뜰것이다. 앞에서 Apache를 설치한 디렉토리를 정해주고 '마침' 버튼을 누르면 모든 설치가 무난히 완료 될것이다.
mod_python을 설치한 후 Apache 설정 파일에 mod_python.so 모듈을 추가해야 한다. Apache를 동적 모듈 로드 모드로 설치를 했으면 이 부분도 무난히 진행이 될것이다. 아파치 설치 디렉토리/conf/httpd.conf 파일을 메모장을 열고 다음과 같이 mod_python.so 파일을 설정한다. httpd.conf 파일을 보면 이미 Dynamic Shared Object(DSO)파일이 설정이 되어진것을 확인 할 수가 있겠다. 그 아래에 우리가 넣은 라이브러리만 추가해주면 된다.



Apache 서비스를 재시작해주고 Apache 서비스가 정상적으로 시작되면 mod_python이 성공적으로 설치가 되었음을 의미한다.

4. Genshi 설치
Genshi는 PHP진영에서 사용되는 smarty나 JAVA진영에서 사용되는 Velocity와 같은 템플릿 엔진이다. 단 Genshi는 Python언어 용이라는 점이다. 우리가 설치할 Trac의 버전(0.11) Genshi는 디자인 템플릿 엔진으로 사용함으로 Trac을 돌리기 위해서는 필수로 설치를 해줘야만 한다.
  • 사이트: http://genshi.edgewall.org/
  • 다운로드: http://genshi.edgewall.org/wiki/Download
  • 설치 파일: Genshi-0.5.1.win32-py2.5.exe
Genshi 설치 파일을 클릭하면 Genshi 설치 화면이 나타난다. '다음' 버튼을 눌러 이동한다.



mod python을 설치했을 때 처럼 python경로를 설정해주는 창이 뜰것인데 기본으로 설정된 사항을 묵인하고 '다음' 버튼을 누른다. 그다음도 몇몇 창이 뜰것인데 모두 묵인으로 '다음' 버튼을 클릭하여 설치를 진행한다.



5. pysqlite 설치
Trac은 sqlite DBMS를 사용한다. pysqlite는 Python언어환경에서 sqlite DBMS접근을 지원하도록 만들어진 라이브러리이다. JAVA에서 놓고보면 sqlite용 jdbc driver인 셈이다. Trac을 사용하려면 필수적으로 pysqlite를 설치해야만 한다. (참 필요로 하는 라이브러리가 참 많네...)
  • 사이트: http://trac.edgewall.org/wiki/PySqlite
  • 다운로드: http://oss.itsystementwicklung.de/trac/pysqlite/wiki#Downloads
  • 설치 파일: pysqlite-2.5.5.win32-py2.5.exe
pysqlite 설치 파일을 클릭하면 pysqlite 설치 화면이 나타난다. '다음' 버튼을 눌러 이동한다.



mod python을 설치했을 때 처럼 python경로를 설정해주는 창이 뜰것인데 기본으로 설정된 사항을 묵인하고 '다음' 버튼을 누른다. 그다음도 몇몇 창이 뜰것인데 모두 묵인으로 '다음' 버튼을 클릭하여 설치를 진행한다.



6. setuptools 설치
setuptools는 Python언어로 만들어진 툴인데 Python으로 만들어진 프로그램들을 자동으로 다운로드 + 설치 해준다. setuptools는 Trac관련 plugins를 설치할 때 "아주" 유용함으로 필히 설치를 해두도록 하자.
  • 사이트: http://peak.telecommunity.com/DevCenter/setuptools
  • 다운로드: http://peak.telecommunity.com/dist/ez_setup.py
  • 설치 파일: ez_setup.py
다운로드 받은 파일에서부터 알수 있다 싶이 이 프로그램은 python으로 만들어진 프로그램이라 확장자가 py로 되어있다. 이렇게 py확장자를 가진 파일들은 python 을 이용하여 실행해야 한다. Python설치 디렉토리의 bin폴더에 가서
python.exe ez_setup.py
하면 되겠다. 만약 python 기본디렉토리를 path에 잡아 놓은 상태라면 구지 python설치경로/bin까지 가지 않아도 되겠다. 아래 그림에서처럼 메시지가 뜨면 설치가 성공한것이다.



7. Trac 설치
지금까지 설치한것은 이번에 설치하게 될 Trac을 설치하기 위하 초기작업이라고 보면 되겠다.(Trac이라는 녀석 참 까탈스럽기도 하다.ㅡㅡ;) 본격적으로 Trac 설치를 해보자~
  • 사이트: http://trac.edgewall.org
  • 다운로드: http://trac.edgewall.org/wiki/TracDownload
  • 설치 파일: Trac-0.11.4.win32.exe
Trac 설치 파일을 실행하면 Trac 설치 화면이 나타난다. '다음' 버튼을 눌러 설치를 진행한다.



mod python을 설치했을 때 처럼 python경로를 설정해주는 창이 뜰것인데 기본으로 설정된 사항을 묵인하고 '다음' 버튼을 누른다. 그다음도 몇몇 창이 뜰것인데 모두 묵인으로 '다음' 버튼을 클릭하여 설치를 진행한다.



8. 새 프로젝트 생성
샘플용으로 새 프로젝트를 생성해 보자. 새로 생성할 프로젝트명을 sample로 정하고 생성을 시도하겠다. Trac에서 새로운 프로젝트를 생성하려면 PYTHON_설치디렉토리\Scripts\trac-admin.exe 프로제트_REPOSITORY initenv 명령어를 실행한다. 우선 먼저 Trac 프로젝트를 관리하는 디렉토리를 생성한다. 나의 경우는 sample이라는 이름으로 E:\Trac\sample 이라는 경로에 빈 폴더를 만들고 Trac 프로젝트를 관리하겠다. 디렉토리를 생성한 후 sample 프로젝트는 trac-admin.exe의 initenv 명령을 실행하여 생성한다. 명령 프롬프트에서 아래 명령을 실행하여 sample 프로젝트를 생성한다.
PYTHON_설치디렉토리\Scripts\trac-admin.exe E:\Tracsample initenv
위 명령어를 실행하면 다음과 같은 과정으로 sample프로젝트가 생성된다.



연결할 데이터베이스를 설정한다. 기본 설정을 사용하므로 엔터를 누른다.



사용할 버전 관리 시스템의 종류를 설정한다. 나의 경우는 SVN을 사용할 것이기 때문에 그냥 엔터를 치고 넘어간다.



버전 관리 시스템의 저장소를 설정한다. sample 프로젝트의 저장소는 E:\Repository\sample로 설정한다. 버전 관리 시스템의 저장소로 설정한 E:\Repository\sample 디렉토리는 자동으로 생성되지 않는다. 이 디렉토리는 SVN 저장소를 다룰 때 생성한다.



위 네가지 설정을 완료하면 Trac에서 사용할 sample 프로젝트가 생성된다. sample 프로젝트가 정상적으로 생성되면 E:\Trac\sample 디렉토리 아래에 여러가지 Trac에 관련된 디렉토리와 파일들이 생성되겠다.

Apache에 VirtualHost 추가하기
sample 프로젝트를 생성한 다음에 설정할 부분은 Apache에서 sample 프로젝트를 인식할 수 있게 VirtualHost를 추가하는 것이다. Trac으로 생성하는 모든 프로젝트를 관리하려면 VirtualHost를 추가해야 한다. Apache 서버의 httpd-vhosts.conf 파일에 다음 설정을 추가한다.

<VirtualHost *:80>
    <Location /trac>
        SetHandler mod_python
        PythonHandler trac.web.modpython_frontend
        PythonOption TracEnvParentDir E:\Trac
        PythonOption TracUriRoot /trac
    </Location>
    <LocationMatch "/trac/[^/]+/login">
        AuthType Basic
        AuthName "Trac"
        AuthUserFile E:\Repository\htpasswd
        Require valid-user
    </LocationMatch>
</VirtualHost>

위 Apache 설정을 보면 첫 번째 <Location /trac> 엘리먼트는 /trac URL로 접근할 때 앞에서 설치한 mod_python 모듈을 사용했으며, E:\Trac 디렉토리를 기본 디렉토리로 설정하였다.

두번째 <LocationMatch "/trac/[^/]+/login"> 엘리먼트는 /trac/sample/login 과 같은 URL에 대한 요청은 인증이 필요하다고 설정한다. E:\Repository\htpasswd 파일은 인증할 때 사용할 파일로 설정하였다. htpasswd를 생성하는 방법은 아래에 언급할것이니 내심하게 쭉 내려보기 바란다.

그리고 httpd.conf파일중에서 httpd-vhosts.conf 파일 로드 해주는 라인중 앞 주석문을 제거한다. 제거후 형태는 아래와 같이 되겠다.

# Virtual hosts
Include conf/extra/httpd-vhosts.conf

Apache 설정을 완료한 다음 Apache Service를 다시 시작한다.

참고문헌: 자바 프로젝트 필수 유틸리티

2009년 7월 16일 목요일

Eclipse(MyEclipse) 언어팩 다운로드 주소

Eclipse (MyEclipse) 언어팩 다운로드 주소...

Eclipse 3.4 ganymede LP 업데이트 주소
http://download.eclipse.org/technology/babel/update-site/ganymede/

Eclipse 3.5 galileo LP 업데이트 주소
http://download.eclipse.org/technology/babel/update-site/galileo/


2009년 5월 13일 수요일

Ant 빌드 사용기 1 - Ant 소개 및 설치



Java관련 프로젝트를 진행할 때 가장 머리 아픈 것이 소스 빌드이다. PHP나 ASP언어로 된 프로젝트 진행할때는 언어자체가 웹 기반이고 인터프리터 언어이기때문에 별도의 빌더가 필요없다. 하지만 Java 이 녀석은 다르다. 컴파일 언어이기때문에 별도의 빌드 과정이 필요하다. 하지만 Java파일 하나 작성할때마다 새롭게 컴파일하는것은 아주 비효율적이다. 만약 한 프로젝트에 포함된 파일이 몇백개이라고 할때 수정된 파일을 일일이 컴파일하는것도 여간 짜증나는 일이 아닐수 없다. 그래서 나온것이 Ant Builder이다. 앤트 빌더는 UNIX상 Make와 비슷한 방식으로 특정된 소스폴더속에 있는 소스파일들을 일일이 자동 컴파일 해준다. 뿐만아니라 웹프로젝트를 진행할 때 Source와 Configuration및 Binary파일을 판단하여 빌드하고 파일 종류에 따라 서로 다른 폴더에로 아웃풋도 가능하다. 또한 Maven처럼 따라야 하는 폴더구조가 너무 엄격하지 않기 때문에 여러모로 쉽게 접근하여 사용할 수 있다.

1. Ant 설치하기
Ant를 설치하기 위하여서는 우선 ant공식 사이트에 가서 최신버젼 ant를 받아온다. 사실 MyEclipse를 깔면 기본으로 ant에 관련된 라이브러리들을 끌어오긴 하지만 수동으로 설치해보겠다. http://ant.apache.org 에 가서 최신버젼 ant를 받아온다. 이 글을 쓰는 시점에서 출시된 최신버젼이 1.7.1이므로 이 버젼 바이너리 파일을 받아온다. 아카이브를 압축풀면 아래 그림에서와 같이 폴더가 구성되었음을 볼수 있다.



우리가 일단 Eclipse에서 Ant의 Lib폴더를 등록해준다. Windows->Preferences->Ant->Runtime에 가보면 이미 Ant Home Entries에 Ant 라이브러리들이 등록이 되었음을 볼수 있다. 잠시 이 라이브러리들을 제거하고 우리가 다운로드한 Ant Lib를 classpath에 잡아준다. Add External JARs를 통하여 이 작업을 할 수 있다. 여기서는 세세히 설명하지 않도록 하겠다.
톰캣하고 연동하기 위하여 별도의 작업이 필요하다. Tomcat 이 설치된 디렉토리에 가보면 lib폴더가 보일것인데 거기서 catalina-ant.jar파일을 classpath에 등록한다. 또한 JDK lib중 tools.jar파일도 등록한다. 이로써 ant설치는 끝난다.

2. Ant 설정하기
Ant 설치된 후 실제 우리가 원하는 프로젝트를 원하는 방식에 따라서 빌드하기 위하여 여러가지 설정이 필요하다. 실제 설정파일에 대한 설명을 할라치면 복잡하고 또 모두 알아야만 빌드를 할수 있는 것도 아니므로 여기서는 템플릿 파일을 가져와 몇군데를 고치는것으로 진행하겠다.
Ant빌드파일을 다운로드 한 샘플에서 가져올수도 있지만 우리는 Tomcat컨테이너와 연동하여 빌드를 해야하기 때문에 Tomcat에서 제공해주는 샘플파일을 쓰겠다.
TOMCAT_HOME->webapps->docs->appdev->sample에서 가보면 build.xml파일이 보일것이다. 이파일을 복사하여 생성한 프로젝트 root에 넣는다. 다음 build.properties 파일을 새로 생성하고 tomcat 의 manager과 연동하기 위한 유저 id와 password를 적는다.







다음 build.xml파일을 열고서 아래와 같은 프로퍼티에 적절한 값을 입력해 넣는다.

<property name="app.name"      value="프로젝트 명"/>
<property name="app.path"      value="/${app.name}"/>
<property name="app.version"   value="0.1-dev"/>
<property name="build.home"    value="톰캣경로/webapps/프로젝트 명"/>
<property name="catalina.home" value="톰캣경로"/>
<property name="dist.home"     value="${basedir}/dist"/>
<property name="docs.home"     value="${basedir}/docs"/>
<property name="manager.url"   value="http://localhost:8080/manager"/>
<property name="src.home"      value="${basedir}/src"/>
<property name="web.home"      value="${basedir}/WebRoot"/>

정확히 설정하였으면 빌드를 시작해보자. 별도로 Java파일을 생성하고 build.xml파일을 연 상태에서 오른쪽 outline의 compile target을 클릭한다.


2009년 1월 13일 화요일

테이블 죠인을 안한 상태에서 Projection을 세팅할때

Criteria를 사용할때 제목에 명시한 경우라면 아래 글이 조금이나마 도움이 될것입니다.

Criteria를 이용하여 projection을 설정하면 쿼리를 사용하는것보담은 보다 더 유연하게 원하는 필드의 데이타를 Fetch해올 수 가 있습니다.

하지만 보통은 여러테이블내의 데이타를 죠인하여 가져오는 경우에 대하여 테이블 죠인시 매 테이블 마다 개개의 별칭을 달아줍니다. 저 또한 이런 식으로 많이 코딩을 해왔었습니다.

하지만 DAO를 리펙터링 하는 도중 이상한 문제에 봉착했었습니다.
분명히 테이블 선언시 "a" 라는 별칭을 부여하였었는데 a.property 이런식으로 원하는 속성을 fetch하려니 존재하지 않는 속성이라는 에러가 자꾸 뜨지 뭡니까?

디버깅을 열심히 하는 도중 hibernate이 내부적으로 싱글테이블인 경우 자동으로 a라는 별칭을 무시하고 this라는 포인터를 통하여 POJO의 각 속성들을 접근할 수 있게끔 처리를 하고 있음을 알게 되었습니다.

이것땜에 삽질 반시간 정도는 했네요... ㅜㅜ

2008년 3월 4일 화요일

2008년 3월 3일 월요일

DWR 사용시 Session 값 얻기

DWR 사용중 Session 객체 얻기

Java로 웹프로그래밍 하다보면 Session값을 가끔식 필요로 할 때가 있습니다.
일반적인 경우에는 doPost나 doGet 메소드를 구현함으로써 쉽게 Session값을 얻을 수가 있습니다.

HttpSession session = request.getSession();

보통 위 같은 방식으로 session을 많이 얻어옵니다.
하지만 DWR를 사용할 경우 어떤 방식으로 session값을 얻어올가요?
결국 request 인스턴스만 가질수 있으면 session은 쉽게 얻을 수 있지 말입니다.

DWR 샘플들을 살펴보던중 WebContext 라는 클래스를 알게 되었습니다.
사실 DWR를 이용하여 JS에서 Java 메소드를 콜할시 결국 request를 보내게 됩니다.
이 request를 얻을려면 별도로 webContext라는 인스턴스를 얻어야만 하는데
WebContextFactory.get() 로 쉽게 얻을 수가 있습니다.

WebContext wctx = WebContextFactory.get();
HttpServletRequest request = wctx.getHttpServletRequest();
HttpSession session = request.getSession();

이것땜에 반나절 삽질을 했네요.ㅜㅜ

2008년 1월 27일 일요일

OSGi를 위한 Spring Dynamic Modules 릴리즈

OSGi를 위한 Spring Dynamic Modules 릴리즈 되었네요.

OSGi ... 예전 모바일 자바에서 많이 들었었던 용어인데, 이렇게 Spring에서까지 언급이 되어지니 다시금 자료를 찾아보는 시간을 갖게 만드네요.
OSGi : Open Service Gateway Initiative 약자로써 "가전제품이나 보안시스템 등의 장치들을 인터넷에 접속하는 표준방식에 관한 산업계의 계획입니다" 라고 정의 되어있기는 하지만 저는 단순히 기존에 서비스를 서버에서 내리지 않고도 실시간으로 설정파일에 대한 변경사항을 시스템에 적용시켜줄 수 있는 일종의 메커니즘이라고 생각합니다.

Spring 공식 웹사이트에서 읽어본데 의하면
"이런방식(OSGi 방식)으로 쓰여진 코드는 각 모듈에 대한 분리를 더 철처히 할 수 있도록 하며 또한 작동중인 시스템에 동적으로 모듈을 추가, 삭제, 업뎃 할 수 있게끔 한다. 이를 제외하고도 동시에 여러버전의 모듈을 디플로이 해주는 기능을 갖고 있다." 라고 하네요.

한마디로 여러모듈로 이루어진 F/W상에서 실시간으로 또는 동적으로 필요한 모듈을 올리고 내릴수 있다고 보면  될것 같습니다.
 
아직까지는 버젼이 1.0 이라 직접 프로젝트에 투입하여 사용하기는 시기상조라는 느낌이 들긴 하지만 지금까지 프로젝트를 해오면서 이런 기능들을 제공해주는 먼가가 있지 않을가 하는 생각도 많이 하게 되었습니다. 결국 OSGi (예전에도 많이 들어왔던 개념) 에 대한 Spring Dynamic Modules의 릴리즈로 이 모든 것이 가능 하게 되겠군요.

Spring DM 1.0 다운로드 링크
Spring DM 1.0 참고문서
Spring DM 1.0 JavaDOC
Spring DM 1.0 샘플 서비스들

2008년 1월 8일 화요일

Projection 설정시 결과를 Entity로 리턴받기

Critera에서 받아온 데이타를 자동으로 POJO에 매핑시켜 봅니다.

NativeSQL이나 HQL이나 모두 데이타를 쿼리하여 가져올수 있지만 조건에 따라 복잡한 쿼리문은 Criteria 로 작성하는것이 더욱 직관적이고 이해가 쉽습니다.

하지만 단일 테이블이 아닌 연관 테이블일 경우 (*)를 이용하여 전체 필드의 값을 쿼리해 오는것은 오버헤드가 많이 걸립니다. 그래서 업무에서는 페이지에 필수로 표시시켜줄 몇가지 항목들만 쿼리문속에 Projection을 이용하여 쿼리를 하게 됩니다.

하지만 Criteria를 사용하여본 분들은 알수 있겠지만 단순히 Projection 만 세팅하게 되면 디비에서 Fetch한 데이타를 Object 배열을 통하여 리턴하게 됩니다. 사실 Projection 설정시 순서만 정확히 설정해주고 Object 배열속의 데이타를 그 순서에 따라 View에 표시시켜주면 그뿐이지만 좀 특수한 데이타 타입일 경우 (예하면 Date 타입)에는 원하는 타입으로 정확히 매핑을 시켜주지 않습니다.

하이버넷 매뉴얼을 읽어보는던중 우연히 위 문제를 해결할수 있는 절묘한 방법을 찾을수 있었습니다.

또한 Criteria의 ResultTransformer 가 PassThroughResultTransformer로 변환되므로 결과치는 우리가 원하는 결과하고 많이 차이가 날수 있습니다. 그래서 궁극적으로 c.setResultTransformer(new AliasToBeanResultTransformer()); 이 문구를 이용하여 리턴받을 List속의 인스턴스는 개개의 Entity라고 명시를 해주어야 합니다. (seResultTransformer를 이용하여 세팅을 해주지 않으면 Object[] 로 결과를 리턴하게 됩니다.)
실제 사용되는 예제코드를 첨부합니다.

  ProjectionList projList = Projections.projectionList();
  projList.add(Projections.property("i.sqEmlrcv"), "sqEmlrcv");
  projList.add(Projections.property("o.name"), "name");
  projList.add(Projections.property("i.emlRcpnt"), "emlRcpnt");
  projList.add(Projections.property("s.dtReg"), "dtReg");
  projList.add(Projections.property("i.stSendI"), "stSendI");
  projList.add(Projections.property("i.cdEmlerr"), "cdEmlerr");
  projList.add(Projections.property("i.onRcpt"), "onRcpt");
  projList.add(Projections.property("i.onReply"), "onReply");
  cri.setProjection(projList);

  cri.setResultTransformer(new AliasToBeanResultTransformer(SentMailV.class));

2007년 12월 27일 목요일

Spring에서 Gmail SMTP서버를 이용하여 메일 보내기

Spring에서 Gmail SMTP서버를 이용한 메일 발송 구현하기

단순 텍스트 메일이 아닌 MIME타입의 메일을 보내기 위해서는 오로지 Spring만으로 구현이 불가능 합니다. 여러가지 문서를 참고한 결과 Java Mail과 Spring을 적절히 활용하면 MIME 타입의 메일을 쉽게 보낼수가 있음을 파악할수 있었습니다.
Spring 클래스들을 살펴보면 JavaMail과의 연동 및 확장가능성을 지원해주기 위하여
JavaMailSenderImpl 과 MimeMessageHelper 등과 같은 다양한 클래스들을 지원해주고 있습니다.

일단 AbstractMailSender라는 추상화 메일 센더 클래스를 만듭니다.

import javax.mail.MessagingException;

import org.springframework.mail.javamail.JavaMailSender;

/**
 * @author Leegun
 *
 */
public abstract class AbstractMailSender
{
 protected JavaMailSender sender;
 
 public void setSender(JavaMailSender sender) {
  this.sender = sender;
 }
 
 public abstract void sendMail( String to, String from,
      String subject, String text ) throws MessagingException;
 

}

다음은 메일 인증을 담당하고 있는 JavaMailAuthenticator 클래스를 만듭니다.
기존에 Java에서 지원해주고 있는 메일 인증 모듈을 그대로 사용하기 위하여 JavaMailSenderImpl 클래스를 상속받아서 구현을 시도합니다.

import java.util.Properties;

import org.springframework.mail.javamail.JavaMailSenderImpl;

/**
 * @author Leegun
 *
 */
public class JavaMailAuthenticator extends
JavaMailSenderImpl
{
 public JavaMailAuthenticator()
 {
  super();
  Properties props = new Properties();
  props.put("mail.smtp.starttls.enable", "true");
  props.put("mail.smtp.auth", "true");
  this.setJavaMailProperties(props);
 }
}

마지막으로 실제 전송해야 할 메일 내용및 To, From 과 같은 기본 사항들을 설정해줍니다.
MIME타입의 메일을 보내기 위하여 MimeMessageHelper 클래스를 사용합니다.

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import org.springframework.mail.javamail.MimeMessageHelper;

/**
 * @author Leegun
 *
 */
public class MimeMailSender extends AbstractMailSender
{
 // 메일 전송시 오류가 발생하면 MessagingException을 던진다.
 public void sendMail( String to, String from,
      String subject, String text ) throws MessagingException
 {
  MimeMessage msg = sender.createMimeMessage();
 
  // true를 세팅함으로써 메일 포맷의 다양화를 지원하겠다는것을 명시적으로 세팅해준다.
  MimeMessageHelper helper = new MimeMessageHelper(msg, true, "utf-8");
 
  helper.setTo(to);
  helper.setFrom(from);
  helper.setSubject(subject);
  helper.setText(text);
 
  sender.send(msg);
 }
}

마지막으로 ApplicationContext 에 관련 빈들을 설정해줍니다.

<beans>
 <bean id="javaMailSender" class="mypackage.JavaMailAuthenticator">
  <property name="host" value="smtp.gmail.com" />
  <property name="port" value="465" />
  <property name="protocol" value="smtps" />
  <property name="username" value="
계정아이디@gmail.com">
  <property name="password" value="비밀번호"/>
 </bean>
 
 <bean id="mimeMailSender" class="mypackage.MimeMailSender">
  <property name="sender">
   <ref bean="javaMailSender"/>
  </property>
 </bean>
</beans>

실제 사용은 아래와 같이 하면 됩니다.

ApplicationContext ctx = new ClassPathXmlApplicationContext( new String[] {"applicationContext.xml"});
MimeMailSender sender = (MimeMailSender) ctx.getBean("mimeMailSender");
 
  try {
   sender.sendMail("받는 사람 메일주소", "보내는 사람 메일 주소", "핼러우 스프링", "핼러우 스프링? 응?");
  } catch (MessagingException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

Spring 에서 Java Mail 사용시 에러문

Spring에서 Java Mail을 이용하여 메일 데몬을 작성시 이상한 에러문구가 떴었다.


ApplicationContext에서는 아래와 같이 설정을 했었다.


<beans>
<bean id="javaMailSender"
  class="com.nanumsem.nnserp.common.util.AuthenticatedJavaMailSender">
  <property name="host">
   <value>smtp.xxxx.com</value>
  </property>
  <property name="username">
   <value>xxxxx</value>
  </property>
  <property name="password">
   <value>xxxxx</value>
  </property>
</bean>

<bean id="mimeMailSender" class="com.nanumsem.nnserp.common.util.MimeMailSender">
  <property name="sender">
   <ref bean="javaMailSender"/>
  </property>
</bean>
</beans>

그런데 실제 Tomcat 기동시
java.lang.NoClassDefFoundError: javax/mail/MessagingException
이런 에러 문구가 뜨면서 javaMailSender 빈인스턴스 생성시 실패하게 된다.

분석한 결과 Spring내에는 실제 Mail처리 관련 jar파일이 포함이 되어있지 않다는것이다.
Spring에서 Mail관련 기능을  구현하기 위해서는 별도로 J2EE 에 포함된 mail.jar를 필요로 하고 있다.

sun에서 mail.jar를 다운로드 받아 WEB-INF/lib 속에 넣고 다시 빌드를 했더니 그제야 정상적으로 빈을 생성하면서 기동되였다.

2007년 11월 14일 수요일

JSValidate - Form Validation Library

JSValidate는 Prototype과 Script.aculo.us을 기반으로 한 심플한 라이버리이며 사용자들로 하여금 폼 유효성체크를 쉽게 할수 있도록 도와줍니다.

라이브러리는 http://www.jsvalidate.com/ 에서 다운로드 받으실수 있습니다.

실제 사용자는 특정된 CSS 클래스를 만들고 이에 관련되여 Form속의 필드에 Annotate를 추가하는것으로만 놀라운 Validation 효과를 만들수가 있습니다.

폼에 사용되여질수 있는 Annotate들은 다음과 같습니다.

  • jsrequired - 필드가 일렬의 값을 필요로 할때(필수입력사항).
  • jsvalidate_number - 모든 인티져 (정수 + 부수)
  • jsvalidate_digits - 오로지 숫자만 허용
  • jsvalidate_alpha - 오로지 알파벳만 허용
  • jsvalidate_alphanum - 알파벳, 숫자만 허용
  • jsvalidate_email - 유효한 메일 주소
  • jsvalidate_uscanzip - 미국과 캐나다의 우편번호만 허용
  • jsvalidate_usstate - 미국 주 이니셜
  • jsvalidate_usphone - 미국 전화번호
  • jsvalidate_creditcard - Validates VISA, MasterCard, American Express 을 허용
  • jsvalidate_ssn - 샘플 포맷으로 열거한 포맷만 허용 - XXXXXXXXX, XXX XX XXXX, or XXX-XX-XXXXX
  • select-notfirst - 콤보박스에서 첫 항목에 대한 선택을 허용않함
2007/11/13 - [분류 전체보기] - Javascript Utility Version 2
2007/02/26 - [자바 어플리케이션/기타 프레임웍들] - Prototype을 위한 퀵 가이드

2007년 11월 13일 화요일

나의 iText 사용기...

iText 사용기...

1.  iText를 시작하면서...
프로젝트를 진행하면서 출력 결과물을 PDF로 작성해야할 필요성으로 하여 PDF 레포트를 생성시켜주는 자바 라이브러리인 - iText를 사용하였습니다. 실제 iText를 이용하면 서버사이드에서 Jsp나 JavaBean을 이용하여 여러가지 형식의 PDF 레포트를 만드실수가 있습니다.

2. iText에 대한 간단한 소개
iText 유명한 오픈소스 배포사이트인 sourceforge에서 진행하고 있는 프로젝트중의 하나로써, PDF 문서를 만들어주는 Java 라이브러리입니다. iText를 이용하여 PDF 문서는 물론 RTF 문서도 만드실수가 있습니다. 또한 XML, HTML 문서도 PDF문서로 컨버팅 하실수도 있습니다.

3. iText를 이용하여 생성된 나의 첫 PDF 문서
iText를 이용하여 PDF 문서를 생성하는데는 모두 5가지 절차가 필요합니다.

① com.lowagie.text.Document 클래스 인스턴스를 생성합니다.

Document document = new Document();

② Writer와 Document 사이의 연관을 맺어줍니다. Writer를 이용하여 문서를 하드디스크 상에 써넣을 수 가 있습니다.
PDFWriter.getInstance(document, new FileOutputStream("Helloworld.PDF"));

③ 문서를 오픈합니다.
document.open();

④ 문서에 내용을 첨부합니다.
document.add(new Paragraph("Hello World"));

⑤ 문서를 닫습니다.
document.close();

위 다섯가지 절차를 거치면 Helloworld.PDF 문서를 생성하실 수가 있습니다.

그럼 Document 클래스에 대하여 좀 더 자세히 알아볼가요?

com.lowagie.text.Document 인스턴스를 생성하는 방법은 모두 3가지가 있는데 그것들로는

public Document();
public Document(Rectangle pageSize);
public Document(Rectangle pageSize, int marginLeft, int marginRight, int marginTop, int marginBottom);

생성자 메소드 파라미터 pageSize는 생성한 문서의 페이지 크기이고, 실제 사이즈는 A4용지에 최적화 되여있습니다.
세번째 생성자 메소드 파라미터 marginLeft、marginRight、marginTop、marginBottom 는 좌, 우, 상, 하의 페이지 여백입니다.

그러면 Writer 객체는 멀가요?

일단 document인스턴스가 만들어지면 이 문서를 실제 하드디스크 상에 쓸 라이터가 필요합니다. 실제 이런 라이터를 거쳐 만들어진 문서를 우리가 원하는 포맷으로 하드디스크 상에 써 넣을수가 있습니다. 예하면 com.lowagie.text.PDF.PDFWriter 는 문서를 PDF포맷으로 저장시킬수가 있고 com.lowagie.text.html.HtmlWriter 는 문서를 HTML 포맷으로 저장시킬수가 있습니다.

그렇다면 문서의 속성을 어떻게 지정할수 있을가요?

실제 문서를 오픈 하기전에 문서의 속성을 지정하실수가 있습니다. 문서의 속성들을 여러가지 펙터들이 있는데 그것들로는 타이틀, 주제, 저자, 키워드, 배포방식, 생성자, 프로듀서, 생성일자 등입니다.

실제 이런 속성들을 세팅해주기 위하여 아래와 같은 메소드가 필요합니다.

public boolean addTitle(String title)
public boolean addSubject(String subject)
public boolean addKeywords(String keywords)
public boolean addAuthor(String author)
public boolean addCreator(String creator)
public boolean addProducer()
public boolean addCreationDate()
public boolean addHeader(String name, String content)

그중 addHeader 은 PDF문서에서는 무효하고 HTML 문서에 한해서만 그 유효합니다.

또한 새페이지를 만들기전 페이지의 크기, 북마크, 헤더와 푸터 등도 설정할수가 있습니다. 위 속성들을 세팅하기 위하여 호출이 되여질 메소드들은

public boolean setPageSize(Rectangle pageSize)
public boolean add(Watermark watermark)
public void removeWatermark()
public void setHeader(HeaderFooter header)
public void resetHeader()
public void setFooter(HeaderFooter footer)
public void resetFooter()
public void resetPageCount()
public void setPageCount(int pageN)

위 메소드들은 실제 위 속성이 세팅될 페이지를 만들기 전에 호출이 되여져야 합니다.

4. 텍스트 처리

iText에서는 Chunk, Phrase, Paragraph 등 을 이용하여 텍스트 처리를 하고 있습니다.
Chunk는 텍스트 처리상 가장 작은 단위로써 글자체, 색상, 크기 등 속성을 포함한 문자열로 구성이 되여져 있습니다. 아래 코드를 실행하면 글자체가 HELVETICA이고 크기가 10 이며 밑줄이 달린 텍스트를 그려줍니다.

Chunk chunk = new Chunk("This text is underlined", FontFactory.getFont(FontFactory.HELVETICA, 12, Font.UNDERLINE));

Phrase는 하나 또는 그 이상의 Chunk로 이루어 지며 Phrase에서도 실제 문자열의 폰트스타일이나 크기를 설정하실수가 있습니다. 단 이렇게 되면 Chunk속에 설정되여있던 폰트는 무시되게 됩니다. 실제 아래와 같은 식으로 Phrase에 Chunk를 넣을수가 있습니다.

phrase.add(chunk);

Paragraph는 하나 또는 그 이상의 Chunk나 Phrase로 이루어 지며 이 역시 단락중의 폰트스타일이나 크기를 세팅할수가 있습니다. 이걸 제외하고도 단락의 인덴테이션, 정열방식등도 설정 하실수가 있습니다.

5. 테이블 처리

iText에서 제공하는 테이블 클래스는 여러가지가 있습니다. 그중 늘 사용하는것들로는 com.lowagie.text.Table, com.lowagie.text.PDF.PDFPTable 이 두가지입니다. 그중에서도 com.lowagie.text.Table 이 클래스는 좀 단순한 형태의 테이블을 그릴때 사용이 되여지구요, 좀 더 복잡한 형태의 테이블을 구성할려면 com.lowagie.text.PDF.PDFPTable 이 클래스를 사용하여야 합니다.

그렇다면 먼저 간단한 com.lowagie.text.Table 부터 살펴 보도록 하지요.

클래스 com.lowagie.text.Table에는 모두 세가지 생성자가 있는데 그것들로는

①Table (int columns)
②Table(int columns, int rows)
③Table(Properties attributes)

파라미터 속성들에 대하여 알아보면 columns는 테이블 컬럼 갯수이고, rows는 테이블의 행 갯수이며 attributes는 테이블의 속성입니다.

테이블 클래스 속성을 아주 많으므로 일일이 소개를 못 드리겠습니다. 하지만 실제 사용이 되여지는 예제를 하나 선정하여 구체적으로 각 단계마다 멀 하고 있는지를 설명드리도록 하겠습니다.

1:Table table = new Table(3);
2:table.setBorderWidth(1);
3:table.setBorderColor(new Color(0, 0, 255));
4:table.setPadding(5);
5:table.setSpacing(5);
6:Cell cell = new Cell("header");
7:cell.setHeader(true);
8:cell.setColspan(3);
9:table.addCell(cell);
10:table.endHeaders();
11:cell = new Cell("example cell with colspan 1 and rowspan 2");
12:cell.setRowspan(2);
13:cell.setBorderColor(new Color(255, 0, 0));
14:table.addCell(cell);
15:table.addCell("1.1");
16:table.addCell("2.1");
17:table.addCell("1.2");
18:table.addCell("2.2");
19:table.addCell("cell test1");
20:cell = new Cell("big cell");
21:cell.setRowspan(2);
22:cell.setColspan(2);
23:table.addCell(cell);
24:table.addCell("cell test2");

1 - 5 까지는 새로운 테이블을 만드는 부분입니다.
두번째 라인에서 알수있다싶이 이 테이블의 테두리 두께는 1이고
세번째 라인에서는 테이블 테두리 색상을 파란색으로 설정해 두었네요.
네번째 다섯번째 라인에서는 각각 테이블 세페이싱과 패딩을 주었네요.

코드 6 - 10 까지에서는 테이블의 헤더를 정의하고 있겠습니다.
라인 7에서 cell.setHeader(true); 이렇게 세팅이되여져 있는데 이것은 새로 만든 셀을 테이블의 헤더로 설정하는 작용을 합니다.
라인 8에서는 셀이 몇개의 Row를 병합할건지를 설정하고 있으며 라인 10에서는 헤더가 끝나는 위치를 정해주고 있습니다. 이렇게 되면 여러페이지가 있을 경우 첫페이지가 아닌 두번째, 세번째 페이지에서도 똑같은 셀로 구성된 헤더를 그릴수가 있게 됩니다.

6. 이미지 처리
iText에서 이미지를 처리해주는 클래스는 com.lowagie.text.Image 입니다.
현재 iText에서 지원해주는 이미지 포맷들로는 GIF, Jpeg, PNG, WMF 등이 있습니다. 부동한 이미지들에 대하여 iText는 동일한 생성자 메소드를 사용하여 자동으로 인식을 해주고 있습니다. 아래 코드를 이용하여 GIF, JPG, PNG 인스턴스를 만드실수가 있습니다.

Image gif = Image.getInstance("vonnegut.gif");
Image jpeg = Image.getInstance("myKids.jpg");
Image png = Image.getInstance("hitchcock.png"); 

이미지 정열방식은 public void setAlignment(int alignment) 메소드를 이용하여 세팅할수가 있습니다.
파라미터로 들어오는 값들은 실제 Emu타입닌데 Image.RIGHT, Image.MIDDLE, Image.LEFT 등이 있습니다.
만약 텍스트를 이미지 옆으로 배치하고 싶으시다면 Image.TEXTWRAP, Image.UNDERLYING
속성을 세팅하면 됩니다. 위 정열방식중 여러가지를 결합하여 사용할려면 | 기호로 구분시켜서 세팅하면 됩니다. 예, setAlignment(Image.RIGHT|Image.TEXTWRAP)

7. 한글 처리
iText.jar 만 이용하여 한글이나 중문 처리를 할수 없습니다. 영문이 아닌 다른 언어를 지원할려면 iTextAsian.jar 를 별도록 프로젝트에 포함시켜야 합니다.

실제 PDF 보고서 출력폼에서 많이 사용이 되여지고 있는 폰트 "명조체" 인스턴스를 만드는것을 예로 들어서 설명하드록 하겠습니다.

String fontFace = "HYGoThic-Medium";
String fontName = "UniKS-UCS2-H";
BaseFont bf = BaseFont.createFont( fontFace, fontName, BaseFont.NOT_EMBEDDED );
Font font = new Font( bf, 12 );
Paragraph pragraph=new Paragraph("안녕하세요.", font );

끝으로 iText.jar, iTextAsian.jar를 첨부하도록 하겠습니다.




2007/11/07 - [분류 전체보기] - iText를 이용하여 원 문자를 PDF에 출력하기
2007/11/07 - [자바 어플리케이션/기타 프레임웍들] - iText로 Table을 만들기

2007년 11월 7일 수요일

iText를 이용하여 원 문자를 PDF에 출력하기

원 문자를 PDF에 출력하기

원형 문자를 PDF에 출력하는데는 여러가지 방법이 있을 수 있습니다.
가장 무식하면서도 간단한 방법은 숫자를 쓰고 숫자 밖에 원을 그리는 것입니다.
하지만 이런 방식으로 하면 미관상 문제가 있고 처리상에서도 약간한 번거로움이 있습니다.

그래서 소개합니다. 이 모든것을 아주 쉽게 처리해주는 폰트 - CombiNumerals Pro 4.0...
하지만 Pro버젼은 라이센스가 있고 별도로 구입해야 하므로 CombiNumerals 폰트를 예제에서 사용하도록 하겠습니다.

CombiNumerals 는 http://www.fontsite.com/Pages/FFDownloads.html 에서 얻을수가있습니다. 사이트 접속이 않될때를 대비하여 첨부파일로 폰트를 올립니다.

CombiNumerals 폰트를 이용하여 원문자를 출력하는것은 아주 쉽습니다.
만약 단일 원숫자를 표시하고싶을때면 폰트를 CombiNumerals 로 바꾸고 숫자만 출력하면 됩니다.
두자리 원숫자를 표시하려면 별도로 작업을 해주셔야 하는데 두가지 키의 조합이라고 보시면 됩니다. 일단 첫 자리 수 즉 십이자리수는 기입한 수의 첫번째 숫자를 사용하고 일이자리수는 기입한 숫자의 두번째 자리 숫자를 Shirt 키를 누른채 기입하면 됩니다.
예를 들면 88을 기입하고 싶으면 실제 8*를 기입하면 됩니다.
이를 쉽게 사용하기 위하여 아래와 같은 맵을 만듭니다.

String [] charMap1 = { ")","!","@","#","$","%","^","&","*","(" };

세자리 이상되는 숫자는 별도로 처리를 해주어야 하는데 CombiNumerals pro에서만 지원하기 때문에 여기서 실제 결과를 보여줄수는 없네요. 하지만 그 처리 방법을 간단히 살펴 본다면 첫번째 자리 및 마지막 자리는 위에서 설명을 드린 두자리 수 처리 방식과 동일하면 가운데 숫자 즉 첫자리수, 마지막자리수를 제외한 기타 자리수는 zxcvbnm,./ 문자로 매핑하여 사용하시면 됩니다.
이를 쉽게 사용하기 위하여 아래와 같은 맵을 만듭니다.

String [] charMap2 = { "/","z","x","c","v","b","n","m",",","." };

실제 숫자만 입력받아서 원문자를 Chunk에 담아 리턴시켜주는 함수를 구현하였는데 아래에 첨부를 합니다. 소스가 쉬우니깐 별도로 분석을 해드리지는 않겠습니다.

소스열기

아래는 실제 위에 첨부한 메소드를 이용하여 원모양 숫자를 출력한 결과입니다.

사용자 삽입 이미지





2007/11/07 - [자바 어플리케이션/기타 프레임웍들] - iText로 Table을 만들기

iText로 Table을 만들기

Create new Table by using iText Library

HtmlWriter나 RtfWriter2 를 이용하지 않고 테이블을 만들고 렌더링할려면 iText의 PdfPTable을 사용하는 것이 가장 무난하다.

아래에 그럼 가장 간단한 예로부터 차츰차츰 PdfPTable에 대하여 알아보도록 하자.

가령 아래 그림에서와 같은 Table을 만들려면 어떻게 코드가 구성되여야 할가?

사용자 삽입 이미지

실제 윗 그림에서와 같은 테이블을 만들기 위하여 드는 노력은 그다지 많지 않다..
아래에 그럼 실제 소스를 첨부하도록 하겠다.

소스열기

PdfPTable을 만들기 위하여 사용자는 필히 테이블에 들어가는 최대 컬럼의 갯수를 파라미터로 넘겨주어야 한다. 만약 컬럼 갯수가 0이면 RuntimeException이 발생한다.

테이블 넓이 및 정열방식 세팅하기
윗 소스 기초하에 아래는 테이블의 넓이와 정열방식을 변경해보도록 하자.
보다싶이 Table속의 Cell들의 정열방식중에서 왼쪽 정열방식이 기본정열 방식이다.
만약 정열을 Center로 바꾸고 싶으면 Element.ALIGN_CENTER를 이용하여 설정할 수가 있다.

table.setHorizontalAlignment(Element.ALIGN_CENTER);

테이블 넓이를 세팅함에 있어서 념두해 두어야 할 점은 테이블 넓이는 상대 넓이와 절대 넓이가 있다는 것이다.
테이블 절대 넓이를 세팅할려면 아래 두 메소드를 사용하면 된다.

PdfPTable table = new PdfPTable(3);
table.setTotalWidth(216f);
table.setLockedWidth(true);

실제 setTotalWidth에서 받는 값은 Float값이므로 뒤에 f를 써주어야 한다. 또한 절대 넓이이므로 꼭 LockedWidth를 true로 세팅해주어야 한다.

만약 테이블을 만들때 셀들의 넓이를 미리 알고 지정해주려면 어떻게 할것인가?
모두 두가지 방법이 있는데 하나는 셀을 만들고 나서 다시 넓이를 세팅하는 방식이고 다른 하나는 Table을 만들시 직접 셀의 갯수 및 매 셀의 넓이를 지정시켜서 만드는 방식이다.
첫 번째 방식은 쉬우므로 여기서 예제는 스킵하련다.
두 번째 방식에 대한 소스는 아래에 첨부하였다.

float[] widths1 = { 1f, 1f, 2f };
PdfPTable table = new PdfPTable(widths1);

여기서 1f, 1f, 2f 는 바로 셀 3개의 넓이를 미리 지정해 준것으로써 그 값은 퍼센테이지로 환산할 수 있다.즉 전체 테이블  넓이가 100%라면 첫 cell은 1/4 이므로 25%가 될것이고 두번째 셀 역시 25% 마지막 셀은 50%가 되겠다.

사용자 삽입 이미지

만약 테이블 처리 도중 셀의 넓이를 바꾸고 싶으면 setWidths 메소드를 사용하면 된다.

float[] widths2 = { 2f, 1f, 1f };
table.setWidths(widths2);

위 메소드를 실행하여 테이블을 만든 결과는 다음과 같다.

사용자 삽입 이미지

테이블 Border 및 다양한 스타일을 주기
실제 PdfPTable을 사용하다보면 좀 갑갑한 점 있다. 기존에 iText에서 지원하는 테이블류 클래스는 모두 3가지가 있다. 그것들로는 PdfPTable, Table, SimpleTable 인데 그중에서 PdfPTable이 실제 PDF에 가장 최적화 되여 만들어진 클래스이다. 하지만 PdfPTable 클래스를 살펴보면 이 클래스가 Element 인터페이스를 구현한것을 볼수 있다. 사실 여러가지 스타일을 테이블에 무난히 적용시키 위해서는 Table 클래스를 사용해야 한다. 하지만 Table 클래스는 PDF 문서에 최적화된 스타일의 테이블을 만들어주지 못하며 아직도 여러가지 버그가 존재한다. 때문에 아래는 Table 클래스가 아닌 PdfPTable 클래스를 이용하여 여러가지 스타일시트를 적용해보겠다.

PdfPTable 클래스를 살펴보면 Border를 세팅해주는 메소드자체가 없다. 그렇다면 어떻게 PdfPTable 클래스을 이용하여 Border가 2인 테이블을 만들것인가?
이를 가능하게 하기 위하여 우리는 별도의 Template이 필요하다. 또한 이런 Template을 우리는 PdfPTableEvent 인터페이스를 구현한 클래스에 넣어주어야 한다.
PdfPtableEvent 인터페이스를 보면

public void tableLayout(PdfPTable table, float widths[][], float heights[], int headerRows, int rowStart, PdfContentByte[] canvases);

tableLayour 메소드 하나만 달랑 있다. 사실상 이메소드는 테이블 렌더링이 끝나고 나서 호출이 되여진다. 실제 이 메소드를 통하여 추가한 텍스트와 그래프들은 테이블 렌더링이 끝난후 canvases 를 포함하고 있는 PdfContentByte속에 저장이 되여진다.
그럼 실제 PdfPTableEvent 인터페이스를 구현하여 테이블에 여러가지 모양을 내보자.

테이블 외곽에 두께가 1.5인 테두리를 넣어주는 것을 예로 들겠다.

먼저 PdfPTableEvents 라는 클래스를 하나 만들어보자.

소스열기

여기서 살펴 볼 곳은 딱 세곳이다.
첫째는 PdfPTableEvent 인터페이스를 구현했다는것이고, 둘째는 두께를 1.5로 설정한것이며 마지막 Border색상을 검정색으로 정한것이다.

다음 만든 PdfPTableEvents 클래스를 인스턴스화하여 실제 PdfPTable에 세팅한다.

PdfTableEvents event = new PdfTableEvents();
table.setTableEvent(event);


이러고 나면 실제 두께가 1.5인 테두리가 그려진 테이블을 볼수가 있다.

사용자 삽입 이미지

위 코드를 좀 더 개진하여 실제 굵기를 설정하려는 ROW의 인덱스 번호만 넣으면 굵기를 세팅해주는 기능을 추가할 수가 있다.

소스열기

그리고 위 클래스 인스턴스에서 필요한 인덱스 값만 배열로 넣으면 우리가 원하는 라인의 굵기를 재 설정할 수 가 있다.

실제 처리된 결과는 다음과 같다.

사용자 삽입 이미지

2007년 11월 6일 화요일

Spring 과 iText를 연동하여 PDF 생성하기

Spring MVC와 iText 를 이용하여 PDF 문서를 생성해보도록 하겠습니다.


실제 Spring MVC를 이용하지 않고 iText만 이용하여 고품질의 PDF문서를 생성할 수 있다.
하지만 이미 프로젝트내에 Spring MVC를 도입하여 사용을 하고 있는 상황이라면 별도로 MVC를 구성하는것 보다는 아예 Spring MVC를 이용하는것이 편하다.

Spring MVC와 iText를 연동하는데 아래와 같이 4가지 단계가 필요하다.

  1. web.xml에서 서블릿 선언 및 서블릿 맷핑을 한다.
  2. pdf-servlet.xml 에서 viewController와 실제 PDF 를 엑세스할 URL을 매퍼를 선언한다.
  3. viewController 클래스를 만든다.
  4. pdfView 클래스를 만든다.

web.xml에서 아래와 같이 pdf용 서블릿을 선언하고 서블릿 맵핑을 한다.

[code xml] <!-- PDF Servlet Definition --> <servlet> <servlet-name>config/pdf</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>2</load-on-startup> </servlet> <!-- Servlet Mapping For PDF DispatcherServlet --> <servlet-mapping> <servlet-name>config/pdf</servlet-name> <url-pattern>*.pdf</url-pattern> </servlet-mapping>[/code] 서블릿 명을 config/pdf로 설정하였으므로 우리가 만들어야 할 pdf 서블릿 설정 파일명은 pdf-servlet.xml이 되겠다.


pdf-servlet.xml에서는 실제 pdf 페이지를 요청하였을때 호출할 컨트롤러를 매핑해주는 urlMapping 빈 및 호출될 컨트롤러를 선언해준다. [code xml] <beans> <bean id="beanNameViewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver" /> <bean id="viewController" class="org.prototype.common.controller.MultiDocumentController" /> <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/viewPDF.pdf">viewController</prop> </props> </property> </bean> </beans> [/code] viewController 클래스는 실제 MultiActionController를 상속 받고 있는데 이렇게 함으로써 하나의 Controller로써 다양한 문서의 출력이 가능하다.
[code java] public class MultiDocumentController extends MultiActionController { public ModelAndView viewPDF( HttpServletRequest request, HttpServletResponse response ) throws Exception { List<String> list = new ArrayList<String>(); Map<String, List<String>> model = new HashMap<String, List<String>>(); model.put( "list",list ); BasePdfView pdfView = new BasePdfView(); return new ModelAndView( pdfView, model ); } }[/code] 마지막으로 BasePdfView 클래스에서 실제 출력할 PDF 에 대한 코딩을 해주고 있음을 알수 있다.
[code java] public class BasePdfView extends AbstractPdfView { @SuppressWarnings("unchecked") protected void buildPdfDocument(Map model, Document document, PdfWriter writer, HttpServletRequest request, HttpServletResponse response) throws Exception {} }[/code]

2007년 10월 25일 목요일

Spring 컨테이너가 아닌곳에서도 Service 사용하기

Service를 Spring 컨테이너가 아닌 일반 서블릿에서도 사용가능하다!!!

프로젝트를 하다보면 간혹가다가 서블릿으로 일부 어플리케이션을 만들어야 할 필요가 있다.
특히나 파일 다운로드를 구현하다보면 더욱 그러하다.
또한 일반 서블릿을 제외하고도 라이브러리나 기타 다른 클래스에서 직접 특정된 어플리케이션의 서비스인스턴스를 받아서 처리하려면 여간 힘들지 않다.

이런 경우 보통은 ApplicationContext를 ThreadLocal 변수에 저장시켰다가 다른 곳에도 호출하면서 사용한다. 하지만 한가지 단점은 ThreadLocal 변수를 초기화하지 않은채 특정된 어플리케이션을 호출하면 ApplicationContext 인스턴스를 가져올수가 없게 된다.

사실 서블릿 컨텍스트에는 ApplicatioinContext 인스턴스를 가지고 있다. 하지만 이 경우 나의 관심사는 다른 여타의 빈즈보다는 특정된 서비스이다. 솔직히 말해서 아래에 첨부한 소스를 조금 변경하면 서비스 인스턴스가 아닌 다른 인스턴스도 가져올수 있다.

먼저 그럼 소스부터 첨부하겠다.

소스열기

위에서와 같이 ServiceHelper 클래스를 만들었다면 bean으로 선언된 서비스 인스턴서를 받어오려면 아래와 같이 호출 하면된다.

SysUpfileService sysUpfileService = SysUpfileServiceHelper.getBoardService(getServletContext());

getBoardService 메소드가 static으로 선언되였으므로 별도로 SysUpfileServiceHelper 를 인스턴스화 할 필요는 없다.
위 소스에 대하여 간단하게나마 설명을 하자면 실제 Servlet에서 bean을 접근 할수가 없므로 WebApplicationContext 인스턴스를 통하여 접근을 시도한다.
WebApplicationContext 인스턴스를 받게 되면 우리가 접근하려고 하는 bean 네임만 주고 실제 bean 인스턴스를 리턴받아 온다. 사실 이 루틴은 아예 이런 빈을 사용하려는 클래스에 포함시켜서 사용할 수 있다. 하지만 여러 곳에서 이런 서비스를 빈을 필요로 하는 경우가 존재하기때문에 별도로 serviceHelper라는 클래스로 추출하였었다. 사용자는 실제 자신의 상황에 마추에 이부분 코딩을 해주면 된다.

2007년 10월 22일 월요일

Commons-upload 를 이용하여 파일 업로드를 구현해보자

Commons-upload를 이용하여 파일 업로드를 구현하였다.

Commons-upload 는 java용 파일 업로드 라이브러리이며 jakarta project의 sub project중의 하나이다.

실제 구현시 사용한 commons-upload jar파일 버젼은 1.2이다.

소스열기

그러면 아래에 윗 소스를 설명하면서 commons-upload에 대하여 알아보도록 하자.
파일을 업로드 하기 위하여서 Client Side에서 필히 POST방식으로 데이타를 Server Side에 전송하여야 한다. 우리는 Client에서 파일을 전송하는데 필요한 폼을 이미 구성하였다는 가정하여 Server Side소스만 살펴보자.
파일을 업로드 받는데 필수적 요소는 모두 3가지가 있다.

첫째, 파일소스 (즉 클라이언트에서 전송받은 파일이다.)
둘째, 파일을 저장 할 경로
셋째, 업로드 받을 파일의 최대 사이즈

위 세가지 요소를 제외하고도 사실 고려해야할 사항들이 많지만 여기서 우리는 위 요소들만 고려하여 실제 구현된 소스를 살펴보자.

1.2 이전 버젼을 사용하였다면 아마도 DiskFileUpload upload = new DiskFileUpload(); 이런 식으로 업로드 객체를 만들었었을것이다.
1.2 버젼을 업그레드 되면서 DiskFileUpload 클래스는 Deprecated되였으며 아마 1.3버젼부터는 삭제되여 질 수도 있다. Commons-upload API를 읽어보면 DiskFileUpload 대신 DiskFileItemFactory과 ServletFileUpload를 사용할것을 적극 권장하고 있었다.
자, 그럼 먼저 멀티파일을 업로드 받기 위하여 복수개 FileItem를 구성해야하는데 실제 우리는 request에서 넘어온 멀티 파일을 고려할 필요가 없이 아주 쉽게 이부분을 구현할 수 있다.
DiskFileItemFactory를 통하여 factory인스턴스를 만든다.

DiskFileItemFactory factory = new DiskFileItemFactory();

다음 factory 사이즈 계수를 설정해주어야 한다.

factory.setSizeThreshold(10485760);

여기서는 최대 10MB만 업로드 받을수 있게 숫치 10485760 을 입력한다.
다음 업로드 받을 파일의 경로를 적는다.

factory.setRepository( new java.io.File( currentDirPath ) );

currentDirPath는 사실 업로드될 파일의 경로이다.
만약 지정된 디렉토리가 만들어 지지 않았으면 아래에서 처럼 자동으로 생성해줄 수 도 있다.

File currentDir = new File(currentDirPath);
if ( !currentDir.exists() ) currentDir.mkdir();

factory에 대한 설정이 끝났으면 upload 객체를 만들어보자.

ServletFileUpload upload = new ServletFileUpload(factory);

위에서 만든 factory객체를 통함으로써 아주 쉽게 upload객체를 만들수가 있다.
다음 request를 통하여 넘어온 파일들을 파싱하여 생성된 실제 파일데이타들을 List에 쌓아둔다.
실제 여기서 미리 Generic을 이용하여 List에 저장된 데이타타입을 지정할수도 있지만 소스에서는 그렇게 구현을 하지 않았다.

List<?> items = upload.parseRequest(request);

또한 넘겨받은 필드가 폼필드인지를 검사하여 만약 폼필드인 경우에만 fields에 해당 값들을 쌓아두었다.

if (item.isFormField())
fields.put(item.getFieldName(),item.getString());
else
fields.put(item.getFieldName(),item);

2007년 10월 19일 금요일

P6SPY Configuration...

Common Property File Settings


먼저 spy.properties 의 간단한 샘플을 첨부하겠다.


설정파일 열기


module
module.xxx는 시스템 시작시 자동으로 로딩되는 특수한 모듈로서 매 모듈마다 여러가지 기능들을 수행하고 있다. 이러한 모듈의 주석문 체크를 해제하면 시스템 시작시 자동으로 메모리에 적재가 되여지며 그 생존주기는 시스템이 종료되기 전까지이다.
P6SPY에서는 아래와 같은 두가지 모듈을 지원하고 있다.

module.log=com.p6spy.engine.logging.P6LogSpyDriver
module.outage=com.p6spy.engine.outage.P6OutageSpyDriver


module.log는 로깅할때 꼭 필요한 모듈이다.
module.outage는 로깅정보를 출력할때 꼭 필요한 모듈이다.

realdriver
실제 p6spy는 WAS에서 들어오는 모든 database 요청들을 가로채고 결과를 log파일로 찍는다. 사실 이 과정에서 사용자는 코드에 전혀 손 댈 필요가 없으며 단순히 p6spy설정파일에 realdriver를 설정해주고 WAS에 wrapped 데이타베이스 driver만 설정해주면 끝난다.

filter, include, exclude
P6Spy는 사용자들로 하여금 특정된 테이블, 특정된 statement 타입들에 대하여 모니터링할수 있게 한다. 간단히 filter=true 라는 세팅만으로 log에 찍힐 모든 내용들을 필터링할수 있다.
Include는 콤마로 분할된 표현식 리스트를 받아 들이는데 실제 로그파일에는 include 리스트에 포함되여있는 문자열들만 log파일에 찍게 된다.

가령 모든 select문을 출력하되 테이블에대한 정열문을 제외하고 싶다면 아래와 같이 세팅하면 된다.

filter = true
# comma separated list of tables to include
include = select
# comma separated list of tables to exclude
exclude = orders

stringmatcher (Custom Filtering)
P6SPY를 이용하여 좀 더 융통적인 로깅정보를 획득하고 싶다면 include,exclude 대신 정규표현식을 사용할수 있다. P6SPY에서 지원하는 RegExp는 두가지가 있는데 하나는 GNU RegExp이고 다른 하나는 Jakarta RegExp이다.

# Use GNU Regex Matching for Filtering
stringmatcher =com.p6spy.engine.common.GnuRegexMatcher
# Use Apache Jakarta Regex Matching for Filtering
stringmatcher =com.p6spy.engine.common.JakartaRegexMatcher

appender

Appenders는 사용자로 하여금 출력될 로그가 어디에 저장될건지 또한 어떤식으로 저장될건지를 설정해주는 작용을 한다. 기존에 p6spy버젼은 3가지 방식의 appender을 지원하는데 그것들로는 log4j, stout, csv text파일 등이다.

CSV 파일 포맷으로 로깅을 하고 싶을때 아주 간단히 appender=com.p6spy.engine.logging.appender.FileLogger 앞의 코멘트 기호를 삭제해주면 된다.

#appender=com.p6spy.engine.logging.appender.Log4jLogger
#appender=com.p6spy.engine.logging.appender.StdoutLogger
appender=com.p6spy.engine.logging.appender.FileLogger

# name of logfile to use, note Windows users should make sure to use forward slashes in their pathname(e:/test/spy.log) (used for file logger only)
logfile = spy.log

# append to the p6spy log file. if this is set to false the
# log file is truncated every time. (file logger only)
append=true

Using StdOut—Uncomment the StdoutLogger as follows and all output will be sent to stdout in a CSV format:
#appender=com.p6spy.engine.logging.appender.Log4jLogger
appender=com.p6spy.engine.logging.appender.StdoutLogger
#appender=com.p6spy.engine.logging.appender.FileLogger

Using Log4J—To output to log4j, make sure log4j is in your path, uncomment the log4j appender, and specify the desired log4j settings:
appender=com.p6spy.engine.logging.appender.Log4jLogger
#appender=com.p6spy.engine.logging.appender.StdoutLogger
# appender=com.p6spy.engine.logging.appender.FileLogger

#The following are for log4j logging only
log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender
log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout
log4j.appender.STDOUT.layout.ConversionPattern=p6spy - %m%n

#log4j.appender.CHAINSAW_CLIENT=org.apache.log4j.net.SocketAppender
#log4j.appender.CHAINSAW_CLIENT.RemoteHost=localhost
#log4j.appender.CHAINSAW_CLIENT.Port=4445
#log4j.appender.CHAINSAW_CLIENT.LocationInfo=true

log4j.logger.p6spy=INFO,STDOUT

If for some reason log4j cannot be initialized, the logging will go to a file called log4jaux.log.