'분류 전체보기'에 해당되는 글 2491건

  1. 2009.02.25 버전관리 프로그램 Tortoise SVN
  2. 2009.02.25 TortoiseSVN 사용법 정리
  3. 2009.02.25 Tortoise SVN 사용법
  4. 2009.02.24 윈도우에서 Subversion 서버 운영하기
  5. 2009.02.24 SVN 간단 설치법
  6. 2009.02.23 [JAVA] java환경변수 & Tomcat환경변수 & Servlet 설정
  7. 2009.02.23 Struts2 강좌
  8. 2009.02.23 Struts2, Spring, iBatis 사용 3
  9. 2009.02.23 Apache Struts 2 Framework (강추)
  10. 2009.02.23 struts2 제대로 된 튜토리얼
  11. 2009.02.23 'Development/Java'
  12. 2009.02.23 Struts 2 Tutorial
  13. 2009.02.23 Struts2 Framework 의 기본적인 동작순서
  14. 2009.02.23 초보을 위한 스트럿츠(struts) 기초 강좌 - 1부
  15. 2009.02.23 java transaction 처리
  16. 2009.02.23 GlassFish + 이클립스 설정기 - Missing classpath entry \lib\appserv-rt.jar
  17. 2009.02.23 GlassFish Project - v2.1 FinalBuild
  18. 2009.02.23 glassfish
  19. 2009.02.18 MultipartRequest 파일 업로드
  20. 2009.02.18 파라미터값 모를때
  21. 2009.02.18 downloadFile.jsp
  22. 2009.02.18 MS SQL Server 2000 용 JDBC 드라이버
  23. 2009.02.18 자바스크립트 튜토리얼
  24. 2009.02.18 Eclipse 플러그인으로 코드 품질높이기
  25. 2009.02.18 개발자가 놓치기 쉬운 자바의 기본원리
  26. 2009.02.18 "AJAX Programming” 온라인 강좌(10주 과정)
  27. 2009.02.18 [강좌] 프레임웤없이 "IBatis 처음 사용하기" 슈퍼 초보용 강좌
  28. 2009.02.16 Continue to crx/store demo
  29. 2009.02.11 [Velocity] [번역중.. ] Developer's Guide
  30. 2009.02.11 이클립스 설치후 깔아야할 플러그인들 ..
98..Etc/SVN2009. 2. 25. 00:37
반응형

개요..

 


소스세이프(Source Safe)보다 좋은 버전관리 프로그램 Tortoise SVN 을 소개해드립니다.


홈페이지 : http://tortoisesvn.net/



버전관리를 통한 소스 관리의 중요성


프로그래머, 개발자라면 반드시 소스의 버전관리를 해야 합니다. (선택이 아니라 필수입니다.)


소스관리 소프트웨어를 사용하는 대표적인 이유는 다음과 같습니다.


- 백업

- 팀 프로젝트 (팀원과 공통 소스 개발)

- 잘못 만들어진 소스 복구



저(Kyuseo) 역시 예전에는 MS 사의 소스세이프(Source Safe)를 10년 가까이 사용하였으나 최근 3년간 Tortoise SVN을 사용해본 결과 이제는 소스세이프를 사용하는 프로젝트는 손까락도 대기 싫습니다. 업무 효율상 20%~30% 이상 이득을 보았다고 생각합니다.


특히 프로그래머, 팀장님들은 꼭!!! SVN 을 적극 활용하시기를 권해드립니다.



tortoise( 터틀스, 거북이) SVN 을 사용해야하는 이유


- 2명 이상의 작업자가 코드 수정이 가능

- 지능적인 자동 Marge

- 무료 공개 소스 프로그램

- 지속적인 업데이트

- 한글 지원

- 탐색기 기반

- 모든 프로그램 호환 (소스코드 뿐만이 아니라 그래픽, 기획자도 사용하기 편리함)

- 프로그램의 안정성

- 세세한 옵션 조정 가능

- 전폭적인 업데이트 로그 관리



스크린샷




Posted by 1010
98..Etc/SVN2009. 2. 25. 00:33
반응형
 
TortoiseSVN 사용법 정리

1. 저장소를 생성한다. ex) d:\RepositoryDir\Project1 에 생성 !

사용자 삽입 이미지

2. SVN 관련 설정 파일들의 설정을 바꾼다.

3. 프로젝트 폴더로 가서 필요한 부분의 파일과 폴더를 임포트한다.

* 주의할 것은 eclpise 로 테스트 해보았는데.. 자칫 모든 것을 한꺼번에 import 하게 되면 컴파일러가 .svn또는 _svn 폴더로 인하여 에러를 나타내는 경우가 있으므로 컴파일러에 맞추어서 import를 해준다.
ex)) Project1\res\layout, Project1\res\value, Project1\src\  폴더와 하위 파일들을 임포트하였다.

사용자 삽입 이미지


4. 저장소 보기를 통해서 svn에 접속.

5. 관련 파일에 관련된 디렉토리 생성.

사용자 삽입 이미지

 
¨Trunk
-프로젝트의 중심이 되는 폴더
-실제 개발 진행은 이곳에서 진행
¨Branches
-Trunk에서 뻗어나온 하나의 프로젝트로서 메인 프로젝트에서 분기하여 따로 개발을 진행
¨Tags
-버전 업이나 특정 시점에서 프로젝트 전체를 복사하여 보관하는

6. Project1_CheckOut 폴더와 같이 체크아웃용 폴더를 만들어서 그 곳의 폴더는 버전관리 프
로젝트에 쓰일 곳으로 하고 만든다.

7. 관련 디렉토리를 생성해주고, 관련 파일들을 체크 아웃을 해줘서 저장소에 있는 것을 그 곳에 복사시켜준다.
* 복사할 때에 _svn 폴더가 생기기 때문에 그 폴더가 생겨도 지장(컴파일러 에러) 없는 곳에다가 체크 아웃을 시켜준다.

8. 소스 하나만 바뀔 때에는 업데이트를 이용해주는 것이 적은 용량을 사용하므로 빠르다.

9. 프로그램이 많이 바뀔 때마다 커밋을 해주어서 적절한 코멘트와 함께 수정한 내역을 알려서 프로젝트에서 바뀐 부분을 알수 있게 해준다.

10. 파일 하나만 바뀌는 경우에는 업데이트 명령어를 해서 그 파일 하나만 저장소에서 빼와서 복사시킨다. 빠른 속도로 바꿀 수 있는 장점이 있다.

Posted by 1010
98..Etc/SVN2009. 2. 25. 00:25
반응형

Tortoise SVN 사용법

이 글은 Tortoise SVN(거북이 SVN)에 대한 간단한 매뉴얼로써 활용될 수 있습니다. 설치부터 시작해 체크아웃, 갱신 등의 전반적인 사용법까지 다루겠습니다.

SVN 이란?

SVN이란 버전관리 시스템의 하나입니다. 여기서 버전 관리 시스템이란 구성원들간의 프로젝트 소스 코드의 공유, 버전 관리(옛날 버전의 소스 코드를 조회 가능함) 그리고 소스 코드의 백업 등의 용도로 사용되는 시스템을 말하며 CVS와 SVN 등이 잘 알려져 있습니다.
참고 : Tong - Zard님의 Eclipse통

Tortoise SVN이란?

SVN을 제공하는 오픈 소스의 강력한 버전 관리 툴입니다.

설치
1.
Tortoise SVN 홈페이지(http://tortoisesvn.net/)에 접속합니다.

사용자 삽입 이미지

http://tortoisesvn.net/

2. 좌측의 메뉴 중 Download에 접근해 Current Version을 확인합니다.
사용자 삽입 이미지

The current version 1.4.3.

3. 그 아래의 Download Application에서 자신의 운영 플랫폼에 맞는 것을 찾아 클릭합니다.
사용자 삽입 이미지

Download Application.

4. 설치 파일을 다운로드 받습니다.
사용자 삽입 이미지

사용자 삽입 이미지

다운로드 완료.

5. 다운로드 받은 설치 파일을 실행시킵니다.

사용자 삽입 이미지

거북이 SVN 설치 시작.

6. 라이센스에 관한 설명을 확인한 후 동의 하신다면 위쪽 라디오 버튼을 선택하고 NEXT 버튼을 클릭합니다.

사용자 삽입 이미지

라이센스 설명.

7. 설치 요소와 설치 경로를 설정한 후 NEXT 버튼을 누릅니다. (그냥 기본값에서  NEXT 버튼을 클릭해도 상관 없습니다.)

사용자 삽입 이미지

설치 요소 선택/경로 변경

8. 설정한 인스톨 옵션에 이상이 없다면 INSTALL 버튼을 클릭합니다.

사용자 삽입 이미지

설치 전 마지막 확인.

9. 설치를 완료한 후 FINISH 버튼을 누릅니다.
사용자 삽입 이미지

설치 중.

사용자 삽입 이미지

설치 완료.

10. 시스템을 재시작 합니다.

사용자 삽입 이미지

재시작을 한다.

11. 마찬가지로 Tortoise SVN 홈페이지 다운로드 메뉴의 하단에 위치한 Languages packs에서 Korean 언어 팩을 찾아 설치합니다.

사용자 삽입 이미지

언어팩 설치 완료.

12. 설치를 확인합니다.

사용자 삽입 이미지

설치 확인.

13. 이제 부터 언어 설정을 한국어로 설정합니다. 설치가 완료되었다면 마우스 오른쪽 버튼을 클릭하였을 시 나오는 팝업 메뉴에 관련 메뉴가 추가되어 있을 것입니다. 일단, 이 중에서 TortoiseSVN -> Settings를 클릭해 보십시오.

사용자 삽입 이미지

Settings.

14. 일반 탭에 위치한 Language 설정을 한국어로 선택하고 확인을 누릅니다.

사용자 삽입 이미지
15. 바르게 설정이 되었는지 확인합니다.

사용자 삽입 이미지

한글화된 메뉴


Tortoise SVN 사용법 - 체크아웃

Tortoise SVN 사용법

이 글은 Tortoise SVN(거북이 SVN)에 대한 간단한 매뉴얼로써 활용될 수 있습니다. 설치부터 시작해 체크아웃, 갱신 등의 전반적인 사용법까지 다루겠습니다.

체크아웃이란?

SVN은 특정한 '저장소(Repository)'에 기록된 정보들을 통해 소스 코드의 버전을 관리합니다. 이 체크아웃이라는 것은 이러한 '저장소'에 접근해 소스 코드와 버전관리를 위한 파일들을 받아 오는 행위를 의미합니다.

체크아웃을 하는 방법

1.
체크아웃받을 폴더를 새로 하나 생성합니다.

사용자 삽입 이미지

I4 Studio

2. 생성된 폴더를 연 후에 그 안에서 마우스 오른쪽 버튼을 클릭해봅니다.

사용자 삽입 이미지

마우스 오른쪽 버튼.

3. 보이는 메뉴들 중 SVN 체크아웃(K)를 찾아 클릭합니다.

사용자 삽입 이미지

체크아웃.

4. '저장소 URL :'라벨 바로 밑에 위치한 입력폼에 'svn://(저장소 주소)'를 입력합니다.

사용자 삽입 이미지

svn://svn.i4studio.net/

5. 입력이 완료되었다면 확인을 눌러봅니다. 해당 저장소에 접근을 하는데 인증정보가 필요하다면 아래와 같은 대화상자가 뜹니다.

사용자 삽입 이미지

인증 대화상자

6. 사용자명과 암호를 입력하신 후 확인을 누릅니다. 일반적으로 체크아웃시 인증 절차가 필요하다면 대부분의 다른 동작에서도 인증 절차가 필요합니다. 반복적인 작업을 피하기 위해 인증 정보의 저장을 원하시는 경우엔 인증 정보 저장 체크박스를 체크합니다.

사용자 삽입 이미지

인증 정보.

7. 성공적으로 인증 절차가 끝났다면 아래와 같은 상태가 됩니다. 만약 그렇지 않고 오류창 따위가 뜬다면 서버 관리자에게 문의하여 봅니다.

사용자 삽입 이미지

체크아웃 완료.

8. 위의 창에서 확인 버튼을 누르고 1번에서 생성한 폴더의 상태를 확인해봅니다. 폴더 아이콘의 위로 초록색의 체크 아이콘이 추가된 것을 볼 수 있습니다. 그 다음 폴더의 내용을 확인해봅시다. 접근한 저장소에 공유된 파일이 있었다면 빈 폴더에 여러가지 폴더/파일들이 생성된 것을 볼 수 있습니다.

사용자 삽입 이미지

초록색 체크 아이콘.

사용자 삽입 이미지

추가된 폴더/파일.

Posted by 1010
98..Etc/SVN2009. 2. 24. 23:59
반응형
Posted by 1010
98..Etc/SVN2009. 2. 24. 23:52
반응형
Posted by 1010
01.JAVA/Java2009. 2. 23. 18:16
반응형
내 컴퓨터 -> 속성 -> 고급 -> 환경변수 -> 시스템 변수

1.JAVA_HOME 새로만들기클릭
      변수이름 : JAVA_HOME
      변수값 : 자바 jdk 를 설치한 위치를 지정 예) C:\Program Files\Java\jdk1.5.0_09

2.CLASSPATH 새로만들기클릭
      변수이름 : CLASSPATH
     변수값 : .;%JAVA_HOME%\lib\tools.jar


3.PATH 기존변수수정
      변수이름 : Path
     변수값 : java 가 설치된 디렉토리 밑의 bin 디렉토리 예) C:\Program Files\Java\jdk1.5.0_09\bin;

다 했으면 확인을 누르고 창을 닫자.

이제 설정이 잘 되었는지 확인할 차례

윈도우키+ R 을 누르면 "실행" 다이얼로그가 뜬다.
cmd를 타이핑 하고 엔터.
까만바탕의 커멘드 콘솔이 뜬다.

path를 입력해보자.
조금전에 수정한 path가 뜨면 일단 제대로 설정은 된것.
java를 입력해보자.
뭐라고 주루룩 뜨면 성공.

이제 준비는 끝났다.

시스템변수(S)에서 설정
1. 변수값    : path(맨끝에)    : 수정
   변수값    : ;%JAVA_HOME%\bin

2. 변수이름    : CLASSPATH    : 생성
   변수값    : .;%JAVA_HOME%\lib\tools.jar
   ※ 앞에 .; <= 주의할것 빼먹지말것

3. 변수이름    : JAVA_HOME    : 생성
   변수값    : C:\Program Files\Java\jdk1.5.0_15

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

TOMCAT 환경변수 설정 (tomcat은 설치하는거 없이 압축풀면 설치끝)

시스템변수(S)에서 설정

   변수이름    : CATALINA_HOME    - 생성
   변수값        : d:\www\apache-tomcat-5.5.26
   톰캣Start    : apache-tomcat-5.5.26\bin\startup.bat
   톰캣Shutdown    : apache-tomcat-5.5.26\bin\shutdown.bat

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

Servlet 설정 (web.xml 수정)

   Tomcat이 설치된 폴더 => \conf\web.xml
     ex> apache-tomcat-5.5.26\conf\web.xml
   ※ 기본적으로 보안상 Servlet은 막혀있으므로 Servlet개발을 위해서
       주석을 제거하여 사용 환경을 만든다.

  1. "invoker" 찾기

########################################################
# <!--                                #
#    <servlet>                            #
#       <servlet-name>invoker</servlet-name>                #
#       <servlet-class>                        #
#           org.apache.catalina.servlets.InvokerServlet            #
#          </servlet-class>                        #
#          <init-param>                        #
#             <param-name>debug</param-name>                #
#             <param-value>0</param-value>                #
#       </init-param>                        #
#       <load-on-startup>2</load-on-startup>                #
#    </servlet>                            #
# -->                                #
########################################################
        [▲ 이부분을 찾는다]
  2. 주석제거 <!--, --> 이것만 삭제할것
########################################################
#    <servlet>                            #
#       <servlet-name>invoker</servlet-name>                #
#       <servlet-class>                        #
#           org.apache.catalina.servlets.InvokerServlet            #
#          </servlet-class>                        #
#          <init-param>                        #
#             <param-name>debug</param-name>                #
#             <param-value>0</param-value>                #
#       </init-param>                        #
#       <load-on-startup>2</load-on-startup>                #
#    </servlet>                            #
########################################################
        [▲ 이렇게 만들면 됨]
  3. Servlet Mapping의 주석도 제거("invoker" 찾기)

########################################################
#    <!-- The mapping for the invoker servlet -->            #
# <!--                                #
#    <servlet-mapping>                        #
#       <servlet-name>invoker</servlet-name>                #
#       <url-pattern>/servlet/*</url-pattern>                #
#    </servlet-mapping>                        #
# -->                                #
########################################################
     [▲ 이부분을 찾아서 주석제거,  ▼ 이렇게 만든다]
########################################################
#    <!-- The mapping for the invoker servlet -->            #
#                                #
#    <servlet-mapping>                        #
#       <servlet-name>invoker</servlet-name>                #
#       <url-pattern>/servlet/*</url-pattern>                #
#    </servlet-mapping>                        #
#                                #
########################################################
  4. web.xml을 저장하고 닫는다.
   ※ Servlet를 작성하기위해 API를 연결한다.
      여기서는 Tomcat에 있는 servlet-api.jar파일을 이용한다.
      EJB를 개발한다면 JavaEE를 설치하는게 좋다.
  5. tomcat\common\lib\
     위의 경로에서 servlet-api.jar파일을 복사하여
     Program Files/Java/jdk/lib/
     위의 lib폴더에 복사

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

Servlet 환경변수 설정

시스템변수(S)에서 설정
1. 변수값    : CLASSPATH        : 지금까지 설정되있는것
   변수값    : .;%JAVA_HOME%\lib\tools.jar

2. jar파일 복사
    원본파일 : 톰캣경로\common\lib\servlet-api.jar (복사)
    사본파일 : C:\Program Files\Java\jdk1.5.0_16\lib\servlet-api.jar (여기에 복사할것)

3. 변수값    : CLASSPATH(맨끝에)    : 수정
   변수값    : .;%JAVA_HOME%\lib\tools.jar;C:\Program Files\Java\jdk1.5.0_15\lib\servlet-api.jar
   위치 : 톰캣경로\common\lib\servlet-api.jar

   ※ 뒤에 servlet-api파일의 경로만 넣어주면된다.
      ;C:\Program Files\Java\jdk1.5.0_15\lib\servlet-api.jar

   ※ tomcat이설치된 경로\webaps\ROOT\WEB-INF\
      classes란 폴더를 만든다. (WEB-INF 폴더아래에)

   ※ Servlet은 웹 어플리케이션 폴더 아래에
      WEB-INF\classes폴더가 존재해야함

   ※ sevlet가 잘돌아가는지 확인하는것은
      classes폴더에 servlet파일을 넣고
      웹브라우저에 http://127.0.0.1/servlet/서블릿파일(확장자빼고)
      실행되는지 볼것 ( servlet도 java기반이기때문에 대소문자 구분.. 조심!! )

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

Eclipse 설치

http://www.eclipse.org/downloads
Posted by 1010
51.Struts22009. 2. 23. 17:36
반응형

   Struts2 강좌  

  •  uychoi66
  • 2008년 1월 22일 am 12:27

문서설명 : Struts2에 대한 tip에서 부터 간단한 강좌까지를 정리합니다.

태그: 없음

평가점수 (5 표) : 
좋습니다.
 
로그인하세요.

조회수 4234 , 즐겨찾기수 0 

회원 (4) :
rkdq98d, coolbyj, ykkim, yhlee

포함된 문서 목록

-

Struts-result 

uychoi66 2008년 2월 22일, 조회수 995 , 덧글수 0

태그: 없음

 즐겨찾기에 추가 이메일 보내기 문서꾸러미에 추가 그룹에 추가

Struts-parameter 

uychoi66 2008년 2월 22일, 조회수 1113 , 덧글수 0

태그: 없음

 즐겨찾기에 추가 이메일 보내기 문서꾸러미에 추가 그룹에 추가

Struts-action 

uychoi66 2008년 2월 22일, 조회수 1302 , 덧글수 0

태그: 없음

 즐겨찾기에 추가 이메일 보내기 문서꾸러미에 추가 그룹에 추가

Struts2_theme 

uychoi66 2008년 2월 22일, 조회수 915 , 덧글수 0

태그: 없음

 즐겨찾기에 추가 이메일 보내기 문서꾸러미에 추가 그룹에 추가

Struts-result-stream 

uychoi66 2008년 2월 22일, 조회수 1115 , 덧글수 0

태그: 없음

 즐겨찾기에 추가 이메일 보내기 문서꾸러미에 추가 그룹에 추가

스트러츠2 

uychoi66 2008년 1월 9일, 조회수 3587 , 덧글수 0

태그: 없음

 즐겨찾기에 추가 이메일 보내기 문서꾸러미에 추가 그룹에 추가

Posted by 1010
51.Struts22009. 2. 23. 15:47
반응형

Struts2, Spring, iBatis 사용

1. 다운로드

1-0. Mysql 다운로드

URL : http://dev.mysql.com/get/Downloads/MySQL-5.0/mysql-5.0.67-win32.zip/from/pick#mirrors

1-1. Spring 다운로드 : spring-framework-2.5.5.zip

URL : http://www.springframework.org/download
(2008년 9월 현재 최신버젼 2.5.5)

spring-framework-2.5.5-with-dependencies.zip (82M) 라이브러리 + 문서 + common-lib 포함
spring-framework-2.5.5-with-docs.zip (36M) 문서포함
spring-framework-2.5.5.zip (6M) 라이브러리

1-2. iBatis 다운로드 : ibatis-2.3.3.720.zip

URL : http://ibatis.apache.org/javadownloads.cgi
(2008년 9월 현재 최신버젼 2.3.3)

ibatis-2.3.3.720.zip (1.9M) 라이브러리

1-3. Struts 다운로드 : struts-2.0.11.2-lib.zip

URL : http://struts.apache.org/downloads.html
(2008년 9월 현재 최신버젼 2.0.11.2 )

struts-2.0.11.2-all.zip (91M) Full Distribution
struts-2.0.11.2-apps.zip (23M) Example Applications
struts-2.0.11.2-lib.zip (4M) Essential Dependencies Only

1-4. Mysql-Connector 다운로드 : mysql-connector-java-5.0.8.zip

URL : http://dev.mysql.com/downloads/connector/j/5.1.html

mysql-connector-java-5.0.8.tar.gz (8.4M) tar 압축(일반적으로 리눅스)
mysql-connector-java-5.0.8.zip (8.4M) zip 압축

2. 이클립스 프로젝트 생성

  • 환경
    이클립스 3.4 WTP
  • 새 프로젝트 작성
    File >> New >> Project >> Ohter >> Dyanmic Web Project
    Project Name : devTest 입력 >> Finish
  • Output폴더 변경
    Propterties >> Java Build Path >>Source탭 >> 제일 밑에 Default output folder 이 있다.
    Default output folder : devTest/WebContent/WEB-INF/classes

3. 설치

3-0. Mysql 설치

알아서 설치~^^; 윈도우용이라면 .exe 파일을 실행하셔서.
"다음", "다음".... 클릭신공 발휘!!

3-1. Spring 설치

  • (V) 표시가 되어있는 파일을 이클립스 프로젝트의 /devTest/WebContent/WEB-INF/lib 안에 넣는다.
    (파일을 복사하게 되면 자동으로 이클립스가 라이브러리를 Java Resources: src/Libraries/Web App Libraries 에 등록한다.신기 _!)
    spring-framework-2.5.5
        │  changelog.txt
        │  license.txt
        │  notice.txt
        │  readme.txt
        │  
        └─dist
            │  (V) spring.jar
            │  
            ├─modules
            │      (V) spring-aop.jar
            │      (V) spring-beans.jar
            │      (V) spring-context-support.jar
            │      (V) spring-context.jar
            │      (V) spring-core.jar
            │      (V) spring-jdbc.jar
            │      (V) spring-jms.jar
            │      (V) spring-orm.jar
            │      (V) spring-test.jar
            │      (V) spring-tx.jar
            │      (V) spring-web.jar
            │      (V) spring-webmvc-portlet.jar
            │      (V) spring-webmvc-struts.jar
            │      (V) spring-webmvc.jar
            │      
            ├─resources
            │      spring-aop-2.0.xsd
            │      spring-aop-2.5.xsd
            │      spring-beans-2.0.dtd
            │      spring-beans-2.0.xsd
            │      spring-beans-2.5.xsd
            │      spring-beans.dtd
            │      spring-context-2.5.xsd
            │      spring-form.tld
            │      spring-jee-2.0.xsd
            │      spring-jee-2.5.xsd
            │      spring-jms-2.5.xsd
            │      spring-lang-2.0.xsd
            │      spring-lang-2.5.xsd
            │      spring-tool-2.0.xsd
            │      spring-tool-2.5.xsd
            │      spring-tx-2.0.xsd
            │      spring-tx-2.5.xsd
            │      spring-util-2.0.xsd
            │      spring-util-2.5.xsd
            │      spring.ftl
            │      spring.tld
            │      spring.vm
            │      
            └─weaving
                    spring-agent.jar
                    spring-aspects.jar
                    spring-tomcat-weaver.jar

3-2. iBatis 설치

  • (V) 표시가 되어있는 파일을 이클립스 프로젝트의 /devTest/WebContent/WEB-INF/lib 안에 넣는다.
    ibatis-2.3.3.720
    │  jar-dependencies.txt
    │  license.txt
    │  notice.txt
    │  release.txt
    │  
    ├─doc
    │      dev-javadoc.zip
    │      user-javadoc.zip
    │      
    ├─lib
    │      (V) ibatis-2.3.3.720.jar
    │      
    ├─META-INF
    │      MANIFEST.MF
    │      
    ├─simple_example
    │  │  README.TXT
    │  │  
    │  └─com
    │      └─mydomain
    │          ├─data
    │          │      Account.xml
    │          │      SimpleExample.java
    │          │      SqlMapConfig.xml
    │          │      
    │          └─domain
    │                  Account.java
    │                  
    └─src
            ibatis-src.zip

3-3. Struts 설치

  • (V) 표시가 되어있는 파일을 이클립스 프로젝트의 /devTest/WebContent/WEB-INF/lib 안에 넣는다.
    struts-2.0.11.2
        │  LICENSE.txt
        │  NOTICE.txt
        │  
        └─lib
                antlr-2.7.2.jar
                commons-beanutils-1.6.jar
                commons-chain-1.1.jar
                (V) commons-logging-1.0.4.jar
                commons-logging-api-1.1.jar
                commons-validator-1.3.0.jar
                (V) freemarker-2.3.8.jar
                (V) ognl-2.6.11.jar
                oro-2.0.8.jar
                struts-core-1.3.5.jar
                struts2-codebehind-plugin-2.0.11.2.jar
                struts2-config-browser-plugin-2.0.11.2.jar
                (V) struts2-core-2.0.11.2.jar
                struts2-jasperreports-plugin-2.0.11.2.jar
                struts2-jfreechart-plugin-2.0.11.2.jar
                struts2-jsf-plugin-2.0.11.2.jar
                struts2-pell-multipart-plugin-2.0.11.2.jar
                struts2-plexus-plugin-2.0.11.2.jar
                struts2-sitegraph-plugin-2.0.11.2.jar
                struts2-sitemesh-plugin-2.0.11.2.jar
                struts2-spring-plugin-2.0.11.2.jar
                struts2-struts1-plugin-2.0.11.2.jar
                struts2-tiles-plugin-2.0.11.2.jar
                tiles-api-2.0.4.jar
                tiles-core-2.0.4.jar
                tiles-jsp-2.0.4.jar
                (V) xwork-2.0.5.jar

3-4. Mysql-Connector 다운로드 : mysql-connector-java-5.1.6.zip

  • 압축을 풀고 mysql-connector-java-5.1.6-bin.jar 파일을 JRE_HOME/lib 안에 복사한다.

4. HelloWorld!! HelloWorld!! HelloWorld!! HelloWorld!! HelloWorld!! HelloWorld!!

4-1. HelloWorld!! Spring!!

Spring을 사용하는 이유? 10가지!!

1. Spring Provides Better Leverage
적은 노력을 하고도 많은 결과를 줄 수 있다.
2. Spring Provides Better Leverage
적은 노력을 하고도 많은 결과를 줄 수 있다.
3. Spring Provides Better Leverage
적은 노력을 하고도 많은 결과를 줄 수 있다.
4. Spring Provides Better Leverage
적은 노력을 하고도 많은 결과를 줄 수 있다.
5. Spring Provides Better Leverage
적은 노력을 하고도 많은 결과를 줄 수 있다.
6. Spring Enables POJO Programming
Spring은 POJO프로그래밍을 가능하게 한다.
7. Spring Enables POJO Programming
Spring은 POJO프로그래밍을 가능하게 한다.
8. Dependency Injection Helps Testability
DI는 테스트를 용이하게 해준다.
9. Inversion of Control Simplifies JDBC
IoC는 JDBC를 단순화한다.
10. Spring's Community Thrives
Spring 커뮤니티의 번영

4-1-1. Controller + Model 생성 및 테스트

  • hello1 패키지 생성
  • hello1.HelloWorld.java 인터페이스 생성
    HelloWorld.java
    package hello1;
    
    public interface HelloWorld {
    	public String sayHello(String message);
    }
  • hello1.HelloWorldImpl.java 클래스 생성
    hello1.xml에서 message를 설정
    HelloWorldImpl.java
    package hello1;
    
    public class HelloWorldImpl implements HelloWorld {
    
     
        private String message;
    
        public HelloWorldImpl() {
        }
    
        public HelloWorldImpl(String message) {
                this.message = "From Constructor" + message;
        }
    
        public String sayHello(String message) {
                return this.message + message;
        }
    
        public void setMessage(String a) {
                message = a;
        }
    }
  • /src/hello1.xml 생성
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
       <!--  bean 설정 -->
    	<bean id="hello" class="hello1.HelloWorldImpl">
    		<property name="message">
    			<value>HelloWorld!! Spring!!</value>
    		</property>
    	</bean>
    </beans>
    친절한 클립스씨

    이클립스에서 컴파일시 자동으로 /devTest/WebContent/WEB-INF/hello1.xml로 옴겨준다. '친절한것..^^'

  • 테스트를 위한 HelloClient.java 생성
    HelloClient 테스트 (hello1.xml과 HelloWorld연동 테스트)
    package hello1;
    
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.xml.XmlBeanFactory;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.core.io.Resource;
    
    public class HelloClient {
            public static void main(String[] args) {              
                    Resource res = new ClassPathResource("hello1.xml"); // 리소스를 읽어온다.
                                
                    BeanFactory factory = new XmlBeanFactory(res); // 스프링 컨테이너.
                    
                    HelloWorld bean1 = (HelloWorld)factory.getBean("hello"); // hello1.xml에서 입력한 beanID
                    
                    String str = bean1.sayHello("I need you!");
                    
                    System.out.println(str);                
            }
    }
    <결과>
    
    HelloWorld!! Spring!!I need you!

4-1-2. WAS 연동 : 웹으로 사용해보자.

  • HelloWorldServlet.java 생성
    package hello1;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.xml.XmlBeanFactory;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.core.io.Resource;
    
    public class HelloWorldServlet extends HttpServlet {
            public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
                    res.setContentType("text/html; charset=euc-kr");
                    req.setCharacterEncoding("KSC5601");
                    PrintWriter out = res.getWriter();
                    String text = req.getParameter("message");
                    
                    try {                        
                            Resource resource = new ClassPathResource("hello1.xml");
                            BeanFactory factory = new XmlBeanFactory(resource);
                            HelloWorld bean1 = (HelloWorld)factory.getBean("hello");
                            String s = bean1.sayHello(text);
                            out.println(s);                        
                    }
                    catch(Exception e) {
                            
                    }
            }
            
            public void doPost(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException
             {
              doGet(req, resp);
             }
    
    }

    컴파일 오류시 tomcat5/common/lib/servlet-api.jar 를 lib 추가한다.

  • 필터를 위한 WebContent/WEB-INF/web.xml 생성
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
    <web-app>
    	<!-- 설정 -->
    	<servlet>
    	<!-- hello1.HelloWorldServlet클래스의 서블릿이름은 HelloWorld 이다. -->
    		<servlet-name>HelloWorld</servlet-name>
    		<servlet-class>hello1.HelloWorldServlet</servlet-class>
    	</servlet>
    	
    	<!-- 맵핑 -->
    	<servlet-mapping>
    	<!-- url끝에     /servlet/HelloWorld.ok가 들어오면 서블릿이름이 HelloWorld인것을 연결시켜라 -->
    		<servlet-name>HelloWorld</servlet-name>
    		<url-pattern>/servlet/HelloWorld.ok</url-pattern> 
    	</servlet-mapping>
    </web-app>
  • 입력을 위한 index.html 생성
    <html>
    <body>
    	<form method=post
    		action="http://localhost:8080/devTest/servlet/HelloWorld.ok"><input
    		type=text name="message"> <input type=submit></form>
    </body>
    </html>

4-1-3. 실행

4-2. HelloWorld!! iBatis!!

iBatis의 장점 5가지..

적은 노력으로 SQL문을 변경할수 있다.
적은 노력으로 SQL문을 변경할수 있다.
기존 데이터베이스 프로그램 코드의 20%정도만 사용해도 80%이상의 같은 기능을 수행할 수가 있게 된다
코드를 간단(simple)하게 해준다.
코드를 간단(simple)하게 해준다.

4-2-1. SqlMap

  • src/SqlMapConfig.xml 생성
    SqlMapConfig.xml
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN" 
    "http://www.ibatis.com/dtd/sql-map-config-2.dtd">
    <sqlMapConfig>
    	<properties resource="SqlMapConfig.properties" />
    	<settings cacheModelsEnabled="true" enhancementEnabled="true"
    		lazyLoadingEnabled="true" maxRequests="32" maxSessions="10"
    		maxTransactions="5" useStatementNamespaces="false" />
    	<typeAlias alias="Hello" type="hello2.Hello" />
    	<transactionManager type="JDBC">
    		<dataSource type="DBCP">
    			<property name="JDBC.Driver" value="${driver}" />
    			<property name="JDBC.ConnectionURL" value="${url}" />
    			<property name="JDBC.Username" value="${username}" />
    			<property name="JDBC.Password" value="${password}" />
    			<property name="JDBC.DefaultAutoCommit" value="false" />			 
    			
    		</dataSource>
    	</transactionManager>
    	
    	<sqlMap resource="HelloMessage" />
    	<!-- 요런식으로 추가할 수 있다. -->
    	<!-- <sqlMap resource="Comment.xml" />  -->
    	<!-- <sqlMap resource="Message.xml" />  -->
    </sqlMapConfig>
  • settings 엘리먼트의 속성들
    acheModelsEnabled SqlMapClient 를 위한 모든 캐시모델을 가능 유무. Default: true (enabled)
    enhancementEnabled 런타임시 바이트코드 향상을 가능유무. Default: false (disabled)
    lazyLoadingEnabled 모든 늦은(lazy)로딩을 가능유무. Default: true (enabled)
    maxRequests 동시에 SQL문을 수행할 수 있는 쓰레드의 수. 셋팅값보다 많은 쓰레드는 다른 쓰레드가 수행을 완료할 때까지 블록 된다. Default: 512
    maxSessions 주어진 시간동안 활성화될 수 있는 세션의 수. Default: 128
    maxTransactions 한꺼번에 SqlMapClient.startTransaction()에 들어갈 수 있는 쓰레드의 최대갯수. 셋팅값보다 많은 쓰레드는 다른 쓰레드가 나올 때까지 블록 된다. Default: 32
    useStatementNamespaces 이 셋팅을 가능하게 하면 당신은 sqlmap이름과 statement이름으로 구성된 전체적인 이름(fully qualified name)으로 맵핑된 statement를 참조해야 한다. 예를 들면: queryForObject("sqlMapName.statementName"); Default: false (disabled)
  • transactionManager 엘리먼트의 별칭
    JDBC com.ibatis.sqlmap.engine.transaction.jdbc.JdbcTransactionConfig
    JTA com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig
    EXTERNAL com.ibatis.sqlmap.engine.transaction.external.ExternalTransactionConfig
  • dataSource 엘리먼트의 별칭
    SIMPLE com.ibatis.sqlmap.engine.datasource.SimpleDataSourceFactory
    DBCP com.ibatis.sqlmap.engine.datasource.DbcpDataSourceFactory
    JNDI com.ibatis.sqlmap.engine.datasource.JndiDataSourceFactory

4-2-2. ibatis

  • 환경
    mysql
    SQL 쿼리
    create table hello(name varchar(10), text varchar(10)); 
    
    insert into hello values("spring", "helloworld 1");
    insert into hello values("ibatis", "helloworld 2");
    insert into hello values("struts", "helloworld 3");
    
    commit;
  • hello2 패키지 생성
  • hello2.Hello.java 생성 (VO)
    Hello.java
    package hello2;
    
    public class Hello {
    	private String name;
    	private String text;
    	
    	public Hello(String name, String text) {	
    		this.name = name;
    		this.text = text;
    	}
    	
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public String getText() {
    		return text;
    	}
    	public void setText(String text) {
    		this.text = text;
    	}
    	
    	
    }
  • src/SqlMapConfig.properties 생성
    SqlMapConfig.xml의 $Driver같은 참조를 사용할 속성 정의
    SqlMapConfig.properties
    driver=org.gjt.mm.mysql.Driver
    url=jdbc:mysql://192.168.10.200:3306/swjang
    username=swjang
    password=xxxxxxxx
  • src/HelloMessage.xml 생성
    HelloMessage.xml
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd">
    <sqlMap>
    	<select id="getHelloMessage" parameterClass="string" resultMap="Hello">
      <![CDATA[
        select 
          name,
          text
        from userinfo
        where name=#name#
      ]]>
    	</select>
    </sqlMap>
  • hello2.HelloWorld.java 생성
    HelloWorld.java
    package hello2;
    
    import java.io.IOException;
    import java.io.Reader;
    import java.sql.SQLException;
    
    import com.ibatis.common.resources.Resources;
    import com.ibatis.common.util.PaginatedList;
    import com.ibatis.sqlmap.client.SqlMapClient;
    import com.ibatis.sqlmap.client.SqlMapClientBuilder;
    
    public class HelloWorld {
    
    	 
    	@SuppressWarnings("deprecation")
    	public static void main(String[] args) throws SQLException {		
    		Reader reader = null;
    		try {
    			reader = Resources.getResourceAsReader("SqlMapConfig.xml");
    			
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		
    		SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
    		
    		
    		PaginatedList list = (PaginatedList) sqlMap.queryForPaginatedList("getHelloMessage", "struts", 0);
    		
    		for (int i = 0; i < list.size(); i++) {
    			
    			System.out.println(list.getPageIndex());
    			list.nextPage();			  
    		}		
    		
    	}
    	
    }
    org.apache.commons.dbcp.BasicDataSource 클래스가 없다고 징징거릴때는?

    tomcat5/common/lib/nameing-factory-dbcp.jar 추가

그런데... 해도 에러난다?; =ㅅ=;

4-3. HelloWorld!! Spring + iBatis!!

4-3-1. SqlMapConfig.xml(ibatis용) => applicationContext.xml(spring용) 로 변경

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
	<!--
		iBATIS SQLMaps의 설정파일 위치를 지정한다. class값은 SQLMaps 1.x버전을 사용할때는
		org.springframework.orm.ibatis.SqlMapFactoryBean SQLMaps 2.x버전을 사용할때는
		org.springframework.orm.ibatis.SqlMapClientFactoryBean 를 사용한다.
	-->
	<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
		<property name="configLocation">
			<value>WEB-INF/SqlMapConfig.xml</value>
		</property>
	</bean>
	<!--
		dataSource를 사용하는것에 대한 정보를 나타낸다. 여기서 사용될수 있는 dataSource타입은 다른 문서를 참조하길
		바란다. 여기선 apache의 DBCP Connection pooling을 사용하는 것이다.
	-->
		
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
		destroy-method="close">
		<property name="driverClassName">
			<value>org.gjt.mm.mysql.Driver</value>
		</property>
		<property name="url">
			<value>jdbc:mysql://192.168.10.200:3306/swjang</value>
		</property>
		<property name="username">
			<value>swjang</value>
		</property>
		<property name="password">
			<value>xxxxxxx</value>
		</property>
		<property name="defaultAutoCommit">
			<value>false</value>
		</property>
	</bean>
	<!--
		DB연결에 관련된 설정을 DataSource형태로 지정을 했기 때문에 트랜잭션 관리를
		org.springframework.jdbc.datasource.DataSourceTransactionManager 가
		담당하도록 지정한다.
	-->
	<bean id="myTransactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource">
			<ref local="dataSource" />
		</property>
	</bean>  
  
 <!--?? -->
  <!-- 각각의 메소드 별로 트랜잭션관리 속성을 지정한다. -->
	<bean id="guestService"
		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="transactionManager">
			<ref local="myTransactionManager" />
		</property>
		<property name="target">
			<ref local="guestTarget" />
		</property>
		<property name="transactionAttributes">
			<props>
				<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
				<prop key="save*">PROPAGATION_REQUIRED</prop>
				<prop key="update*">PROPAGATION_REQUIRED</prop>
				<prop key="delete*">PROPAGATION_REQUIRED</prop>
			</props>
		</property>
	</bean>
	<!--
		소위 Spring을 사용하게 되는 비지니스 객체의 클래스를 지정하는 부분이다. 즉 여기선
		gikim.dongguk.guestboard.spring.GuestSpringImpl 클래스가 Spring의 여러가지 기능을
		담당하게 되는것이다. 그리고 관리하게 되는 DAO는 guestDAO로 지정한다.
	-->
	<bean id="guestTarget" class="gikim.dongguk.guestboard.spring.GuestSpringImpl">
		<property name="guestDAO">
			<ref local="guestDAO" />
		</property>
	</bean>
	<!--
		DAO에 관련된 셋팅이다. 실제로 iBATIS SQLMaps를 사용하게 되는 클래스를 지정하게 된다. DB정보인
		dataSource값과. iBATIS SQLMaps설정파일의 위치에 해당하는 sqlMapClient를 지정한다.
	-->
	<bean id="guestDAO" class="gikim.dongguk.guestboard.dao.IbatisGuestDAOImpl">
		<property name="dataSource">
			<ref local="dataSource" />
		</property>
		<property name="sqlMapClient">
			<ref local="sqlMapClient" />
		</property>
	</bean>
</beans>

4-3-2. code

spring은 SqlMapClient객체를 대체하는 SqlMapClientTemplate를 제공하는데 이를 생성하는 메소드는 getSqlMapClientTemplate()이다.

Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
user = (User) sqlMap.queryForObject("getUser", id);

사용자 정보를 가져오는 소스가 위와 같다고 할 때 spring의 SqlMapClientTemplate를 사용하면 아래와 같이 될 것이다..

User user = getSqlMapClientTemplate().queryForObject("getUser", id);

눈에 띄게 소스가 간편해진다. 이것밖에 장점이 없을까.? 아니다. 다음의 소스를 보자. spring이 자동적으로 트랜잭션을 처리해 주기 때문에 조금 전 입력예제로 사용되었던 소스가 아래처럼 다시 변경될 수 있다.

getSqlMapClientTemplate().insert("insertMessage", message);
return true;

spring의 트랜잭션 관리를 사용하면 위와 같이 소스가 간단해진다.

이것은 transactionAttributes 속성 하위의 설정값들에 의해 spring의 DI(dependency injection)을 사용하여 가능한 것이지만, 일단 개발자들에게는 SQLMaps로 인해 간단해진 소스가 더욱 심플해졌다는 사실 자체로 행복한 일일 것이다. 이건 개발 프레임워크를 제대로 사용할 때 개발 프레임워크가 개발자에게 주는 혜택이다

4-4. HelloWorld!! Struts + Spring + iBatis!!

5. 결론

이런 프레임워크를 사용하는 이유는...

보다 적은 노력 큰 효과
1) 유연성
2) 간결함
3) 재사용성

6. 참고자료

spring : http://cafe.naver.com/hdjv.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=299
spring의 장점 : http://epro.tistory.com/tag/spring의 장점

ibatis : http://openframework.or.kr/Wiki.jsp?page=SqlmapsOfMaso
ibatis 장점 : http://okjsp.pe.kr/seq/104465

spring + ibatis + struts로 게시판 만들기 : http://blog.naver.com/phcs1219?Redirect=Log&logNo=140044056674

문서에 대하여

Posted by 1010
51.Struts22009. 2. 23. 15:46
반응형

Apache Struts 2 Framework

  • 작성자 : 고덕한
  • 최종수정날짜 : 2007년 8월 27일
개요

Apache Struts 2 Framework 에 대한 한글 문서를 제공하여, 국내 개발자들에게 Apache Struts 2 Framework 을 익히는 데 조금이나마 쉽게 접근할 수 있도록 하고자 합니다.

이 문서에서는 Apache Struts 싸이트에 있는 문서를 기반으로 한글로 다시 작성하여 올립니다. 일부 내용은 번역이 이루어지거나 혹은 나름대로 이해하고 문서를 작성하여 올리겠습니다. 가능한한 원문에 가깝도록 내용을 구성하겠습니다.

국내 자바 개발자들이 Struts 2 Framework 를 익히고, 개발하는데 서로의 노하우를 공유할 수 있도록 게시판을 만들어 질답 및 팁을 여러사람이 볼 수 있도록 하였습니다.

version 2.0.9

Download Now
Get Started
Plugin Registry

Struts 2 Framework 란 ?

Struts 2 Framework 은 WebWork Framework 에 기반을 두고 있습니다. WebWork Framework 은 여러해동안 좋은 아키텍처로 Framework 를 정립하여, 웹 어플리케이션 개발에 많이 활용되어 왔습니다. 이에 Struts Communites 와 WebWork Communities 들이 모여서 WebWork Framework 을 Struts 2 Framework 으로 명명하여 Framework 를 발전시키고자 합의를 하였습니다.

따라서 Struts 2 Framework 는 대부분 WebWork Framework 를 따르고 있으며, 초기의 Struts 2 Framework 는 WebWork Framework 와 같다고 여겨도 됩니다.

Struts 2 Framework 는 Struts 1.x Framework 와는 전혀 다른 아키텍처로 구성되어 있습니다. 일반적으로 Framework 든 어플리케이션이든, 버전업이 되면 기존에 있는 기능에 더 많은 기능을 추가하고, 부족한 기능을 보완하여 버전업을 합니다.

하지만 Struts 2 Framework 는 처음부터 Struts 1.x Framework 에 기반하지 않고, 전혀 다른 WebWork Framework 을 이름을 바꾸어서 새로운 아키텍처로 구성된 Struts 2 Framework 을 만들었습니다. 따라서 개발자들은 Struts 1.x Framework 와 다른 Struts 2 Framework 를 다시 익혀야 됩니다.


Documentation(문서)

Struts 2 Framework 싸이트(struts.apache.org) 에 있는 문서를 한글화 합니다. 원문의 내용에 대한 의미를 잃어버리지 않도록 하기 위해서 원문을 그대로 사용하는 부분도 있고, 좀 더 나은 의미 전달을 위해서 의역해서 내용을 보완하거나 추구하는 것도 있습니다.

목차는 원문에 있는 그대로 따라서 작성하도록 하겠습니다.

관련 내용

Posted by 1010
51.Struts22009. 2. 23. 15:44
반응형
아파치 스트러츠2에 대한 튜토리얼이 아파치 사이트보다 이곳이 더 잘 되어 있군요..
스트러츠2에 대해서 소개, 태그등의 예제까지 스트러츠2를 공부하시는 분은
이 사이트를 방문하시면 한큐에 갈증을 해소할 수 있을것입니다.  아래는 스트러츠2에 대한 튜토리얼을 Copy&Paste 한 내용입니다.

Struts 2 Tutorial

RoseIndia Struts 2 Tutorial and Online free training helps you learn new elegant Struts 2 Framework with examples. Struts 2 is very elegant and flexible front controller framework based on many standard technologies like Java Filters, Java Beans, ResourceBundles, XML etc.

  1. Struts 2 Features It is very extensible as each class of the framework is based on an Interface and all the base classes are given an extra application and even you can add your own. 
  2. Struts 2 History Apache Struts is an open-source framework that is used for developing Java web application. Originally developed by the programmer and author Craig R. McClanahan this was later taken over by the Apache Software Foundation in 2002.  
  3. Struts 2 Architecture Struts and webwork has joined together to develop the Struts 2 Framework. Struts 2 Framework is very extensible and elegant for the development of enterprise web application of any size. In this section we are going to explain you the architecture of Struts 2 Framework.  
  4. Why Struts 2 The new version Struts 2.0 is a combination of the Sturts action framework and Webwork. According to the Struts 2.0.1 release announcement, some key features are:
  5. Struts 1.x Vs Struts 2.x In the following section, we are going to compare the various features between the two frameworks. Struts 2.x  is very simple in comparison to the struts 1.x ,  few of its excelling features are:  
  6. Downloading and Installing Struts 2 In this section we will download and install the Struts 2.0 on the latest version of Tomcat container. We will first download tomcat and configure it as our development server.
       
    Struts 2 Hello World Application
  7. Creating the development directory Structure In this section we will create directory structure of our Struts 2 Hello World application based on Struts 2 framework. Our Struts 2 Hello World application is your first step towards developing applications based on Struts 2 framework.
  8. Writing Jsp, Java and Configuration files In this section we will write JSP, Java and required configuration files for our Struts 2 Hello World application. Now in struts 2 struts.xml is used to configure the applications. We will also deploy and test the application.   
  9. Struts 2 xml configuration file In this section we will introduce you with the struts.xml file. This section explains you how best you can use the struts.xml file for you big projects.
     
    Struts 2 Actions
  10. Struts 2 Actions Example When a client request matches the action's name, the framework uses the mapping from struts.xml file to process the request.  
  11. Struts 2 Actions Introduction When a client request matches the action's name, the framework uses the mapping from struts.xml file to process the request. The mapping to an action is usually generated by a Struts Tag.

    Struts 2 Login Application
  12. Developing Login Application in Struts 2 In this section we are going to develop login application based on Struts 2 Framework. Our current login application does not validate the user against the database 
  13. Adding Validation to Struts 2 Login Application In this section we will write the code to validate the login application. After completing this section you will be able to write validations for your Struts 2 projects.
  14. Running and testing application In this section we will run the example on Tomcat 6.0 server and check how it works.  
  15. Client Side Validation in Struts 2 Login Application In this section we will see how to write code that will generate Java Script code for client side validation. In the last section we developed Login-validator.xml configuration file for defining the server side validation.    
  16. Validations using Struts 2 Annotations In this section we are going to validate our login application using Annotations in Action class. Our current login application does not validate the user against the database. 
  17. Login/Logout With Session In this section, we are going to develop a login/logout application with session. This application checks the user authentication. Whenever you run, it takes an user id and a password (Both the user id and password is "admin") it displays the welcome page, when both fields are correctly filled.

    Struts 2 Tags  
  18. Struts Tags In this section we will introduce you with the tags provided along with Struts 2 framework. It is necessary to understand all the tags provided along with Struts 2 framework.
     
    Struts 2 Tags Examples          
  19. Struts 2 Tags Examples (Generic Tags) Struts 2 tags tutorials and examples.
  20. Control Tags-If / Else If / Else In this section we are going to discuss the various control tags ( The Control Tags are used for flow control, such if, else and iterate.).
  21. Append Tag (Control Tags) Example In this section, we are going to describe the append tag . The append tag is a generic tag that is used to merge multiple iterators into one iterator.
  22. Generator Tag (Control Tags) Example In this section, we are going to describe the generator tag . The generator tag is a generic tag that is used to generate iterators based on different attributes passed .
  23. Generator Tag (Control Tags) Using Count Attributes In this section, we are going to describe the generator tag using the count attributes.
  24. Generator Tag (Control Tags) Using an Iterator with Id Attributes In this section, we are going to describe the generator tag using the id attributes.
  25. Iterator Tag (Control Tags) Example In this section, we are going to describe the Iterator tag. Iterator tag is used to iterate over a value. An iterable value can be either of: java.util.Collection, java.util.Iterator.
  26. Merge Tag (Control Tags) Example In this section, we are going to describe the merge tag . The merge tag is a generic tag that is used to  merge iterators. The successive call to the merged iterator causes each merge iterator to have a chance to expose its element, subsequently next call allows the next iterator to expose its element.
  27. Subset Tag (Control Tags) Example In this section, we are going to describe the subset tag . The subset tag is a generic tag that  takes an iterator and outputs a subset of it. It delegates to org.apache.struts2.util.SubsetIteratorFilter internally to perform the subset functionality.
  28. Subset Tag (Control Tags) Example Using Count In this section, we are going to describe the subset tag using the count  parameter. The count parameter indicate the number of entries to be set in the resulting subset iterator.
  29. Subset Tag (Control Tags) Example Using Start In this section, we are going to describe the subset tag using the start parameter. The start parameter is of integer type. It indicates the starting index (eg. first entry is 0) of entries in the source (needed to make available as the first entry in the resulting subset iterator).
  30. Action Tag (Data Tag) Example In this section, we are going to describe the action tag . The action tag is a generic tag that is used to call actions directly from a JSP page by specifying the action name and an optional namespace.
  31. Bean Tag (Data Tag) Example In this section, we are going to describe the Bean Tag . The Bean tag is a generic tag that is used to instantiates a class that conforms to the JavaBeans specification.
  32. Date Tag (Data Tag) Example In this section, we are going to describe the Date tag .The date tag allows to format a Date in a quick and easy way. User can specify a custom format (eg. "dd/MM/yyyy hh:mm"), can generate easy readable notations (like "in 2 hours, 14 minutes"), or can just fall back on a predefined format with key 'struts.date.format' in the properties file.
  33. Include Tag (Data Tag) Example In this section, we are going to describe the include tag . The include tag is a generic tag that is used to include a servlet's output (result of servlet or a JSP page) to the current page.
  34. Param Tag (Data Tag) Example In this section, we are going to describe the param tag. The param tag is a generic tag that is used to parameterize other tags. For example the include tag and bean tag. The parameters can be added with or without a name as a key.
  35. Set Tag (Data Tag) Example In this section, we are going to describe the Set tag . The set tag is a generic tag that is used to assign a value to a variable in a specified scope.
  36. Text Tag (Data Tag) Example In this section, we are going to describe the text tag. The text tag is a generic tag that is used to render a I18n text message.
  37. Property Tag (Data Tag) Example In this section, we are going to describe the property tag . The property tag is a generic tag that is used to get the property of a value, which will default to the top of the stack if none is specified.
  38. Struts 2 Tags (UI Tags) Examples
           
    Form Tags Examples
  39. Checkbox Tag (Form Tag) Example In this section, we are going to describe the checkbox tag . The checkbox tag is a UI tag that is used to render an HTML input element of type checkbox, populated by the specified property from the ValueStack.
  40. Checkboxlist Tag (Form Tag) Example In this section, we are going to describe the checkboxlist tag . The checkboxlist tag is a UI tag that creates a series of checkboxes from a list. Setup is like <s:select /> or <s:radio />, but creates checkbox tags.
  41. Combobox Tag (Form Tag) Example In this section, we are going to describe the combobox tag . The combo box is basically an HTML INPUT of type text and HTML SELECT grouped together to give you a combo box functionality.
  42. Datetimepicker Tag (Form Tag) Example In this section, we are going to describe the datetimepicker tag . The datetimepicker tag is a UI tag that is used to render a date/time picker in a dropdown container.
  43. Doubleselect Tag (Form Tag) Example In this section, we are going to describe the doubleselect tag . The doubleselect tag is a UI tag that renders two HTML select elements with second one changing displayed values depending on selected entry of first one.
  44. File Tag (Form Tag) Example In this section, we are going to describe the file tag . The file tag is a UI tag that renders an HTML file input element achieved through browsing.
  45. Form Tag Example In this section, we are going to describe the form tag . The form tag is a UI tag that renders HTML an input form.
  46. Label Tag (Form Tag) Example In this section, we are going to describe the label tag . The label tag is a UI tag that is used to render an HTML LABEL that allow to output label:name type of combinations that has the same format treatment as the rest of UI controls.
  47. Optiontransferselect Tag (Form Tag) Example In this section, we are going to describe the Optiontransferselect tag. The Optiontransferselect tag is a UI tag that create an option transfer select component.
  48. Optgroup Tag (Form Tag) Example In this section, we are going to describe the optgroup tag . The optgroup tag is a UI tag that creates an optgroup component which needs to resides within a select tag <s:select>.
  49. Password Tag (Form Tag) Example In this section, we are going to describe the password tag . The password tag is a UI tag that renders an HTML input tag of type password.
  50. Radio Tag (Form Tag) Example In this section, we are going to describe the radio tag . The radio tag is a UI tag that renders a radio button input field.
  51. Reset Tag (Form Tag) Example In this section, we are going to describe the reset tag . The reset tag is a UI tag that  is used together with the form tag to provide form resetting.
  52. Select Tag (Form Tag) Example In this section, we are going to describe the select tag. The select tag is a UI tag that is used to render a HTML input tag of type select.
  53. Submit Tag (Form Tag) Example In this section, we are going to describe the submit tag. The submit tag is a UI tag that is used to render a submit button. The submit tag is used together with the form tag to provide asynchronous form submissions.
  54. Textarea Tag (Form Tag) Example In this section, we are going to describe the textarea tag. The textarea tag is a UI tag that is used to render HTML textarea.
  55. Textfield Tag (Form Tag) Example In this section, we are going to describe the textfield tag. The textfield tag is a UI tag that is used to render an HTML input field of type text.
  56. Updownselect Tag (Form Tag) Example In this section, we are going to describe the updownselect tag. The updownselect tag is a UI tag that creates a select component with buttons to move up and down the elements in the select component .

    Non-Form UI Tags
  57. Actionerror and Actionmessage Tags (Non-Form UI Tags) Example In this section, we are going to describe the actionerror and actionmessage tags. The actionerror tag is a UI tag that renders action errors(in the jsp pages.) if they exists while the actionmessage tag renders action messages if they exists.
  58. Fielderror Tag (Non-Form UI Tags) Example In this section, we are going to describe the fielderror tags. The fielderror tag is a UI tag that renders field errors if they exists.                         
     
    Struts 2 Examples 
  59. Struts 2 Date
    In this section we will discuss the date processing functionalities available in the Struts 2 Framework. 
  60. Date Format Examples In this tutorials you will learn about Date Format function in Struts 2. We have provided fully tested example code to illustrate the concepts.  
  61. Struts 2 datepicker Example In this section we will show you how to develop datetimepicker in struts 2. Struts 2 uses the dojo toolkit for creating date picker.  
  62. Struts 2 Format Examples In this section you will learn how to format Date and numbers in Struts 2 Framework. Our Struts 2 Format Examples are very easy to grasp and you will learn these concepts in very small time.
  63. Struts 2 File Upload In this section you will learn how to write program in Struts 2 to upload the file on the server. In this example we will also provide you the code to save the save on the server in the upload directory.
     
    Struts 2 Resources Examples
  64. Struts 2 Resources Examples The struts 2 resources examples     
  65. Static Parameter In this section, we will develop a simple application to access the static parameter. We will use a JavaBean to set and get the static parameters. Each static parameter has a value.   
  66. Accessing Session Object In this section, we will develop a simple application to access the framework resources like the session object, session context and the last accessed session time.
  67. Access Request and Response In this section, you will learn to develop an application that accesses the request and response object in struts 2 application.

    Struts 2 Tools
  68. Struts 2 Eclipse Plugin This page contains the examples and the list of plugins that are available for Struts 2 Development using Eclipse IDE.
  69. Struts 2 IDE This page contains the list of IDE available to ease the development of Struts 2 Framework based applications. The IDE for Struts 2 will actually make the development cycle of the much easier.
  70. Struts 2 Application Developing user registration application based on Struts 2 Framework. This Struts 2 Application is a simple user registration application that will help you learn how to develop real world application using Struts 2 Framework.
  71. Struts 2 Ajax In this section explains you Ajax based development in Struts 2. Struts 2 provides built-in support for Ajax using Dojo toolkit.
Posted by 1010
01.JAVA/Java2009. 2. 23. 15:37
반응형
  • 2008/04/11 Locale class의 getLanguage() 메소드가 리턴하는 각국 언어코드
  • 2008/02/29 SimpleDateFormat 로 24시/12시 표현하기
  • 2008/02/19 java.lang.ClassNotFoundException: org.apache.taglibs.standard.tlv.JstlFmtTLV
  • 2008/02/12 SiteMesh 설치하기
  • 2008/02/11 Struts2 Framework 설치하기
  • 2008/02/11 Spring Framework 설치하기
  • 2008/01/16 자바개발환경 구성하기 - 4.IDE
  • 2008/01/16 자바개발환경 구성하기 - 3.WAS
  • 2008/01/09 자바개발환경 구성하기 - 2.Database
  • 2008/01/09 자바개발환경 구성하기 - 1.JDK 설치
  • 2008/01/09 자바개발환경 구성하기 - 목차
  • 2007/12/13 Struts 2 Tutorial - 15.스트럿츠2에서의 클라이언트측 검증
  • 2007/12/13 Struts 2 Tutorial - 14.실행 및 테스트
  • 2007/12/13 Struts 2 Tutorial - 13.로그인 어플리케이션에 Validation 추가
  • 2007/12/12 Struts 2 Tutorial - 12.Login 어플리케이션 개발
  • 2007/12/12 Struts 2 Tutorial - 11.Struts 2 Redirect Action
  • 2007/12/11 Struts 2 Tutorial - 10.Struts 2 Action 소개
  • 2007/11/29 Struts 2 Tutorial - 09.Struts 2 xml 환경설정파일
  • 2007/11/28 Struts 2 Tutorial - 08.JSP, Java, 환경설정파일 작성하기
  • 2007/11/28 Struts 2 Tutorial - 07.폴더구조
  • 2007/11/28 Struts 2 Tutorial - 06.Struts 2 다운로드 및 설치 (2)
  • 2007/11/27 Struts 2 Tutorial - 05.Struts 1 과 Struts 2 비교
  • 2007/11/27 Struts 2 Tutorial - 04.Struts 2를 사용해야만 하는 이유
  • 2007/11/27 Struts 2 Tutorial - 03.Struts 2 아키텍쳐
  • 2007/11/26 Struts 2 Tutorial - 02.Struts 2 역사
  • 2007/11/26 Struts 2 Tutorial - 01.Struts 2 특징
  • 2007/11/26 Struts 2 Tutorial - 00.목차
  • Posted by 1010
    51.Struts22009. 2. 23. 15:29
    반응형
    Posted by 1010
    51.Struts22009. 2. 23. 15:26
    반응형
    새로운 신입이라서 경력 선배분들이 하는 것을 보고 있으면 참 신기하고 재미있게 보이는게 많다..
    어깨 넘어로 보고 있자니 이런거 저런거 배우라고 하는것도 많고...배울것도 많고...
    배우고 싶은것도 많... 아니 이건 쫌 그렇고... -_-;;

    어재 처음으로  NetBeans로 struts2 Framework 이라는 것을 봤는데..(NetBeans도 처음이고..아는게 없네 ㅜㅜ)
    참... 전자동이군... 하는 생각이 ..
    몇달전에  Struts 라는 것을 처음 볼때 느낀 프레임웍이라는게 참 좋은거구나.. 하는 거였다..
    설정만 살짝살짝 해주면 일은 알아서 다 한다. (굿인데...)
    근데 요 Struts2 라는 놈은 더 자동이다 ㅡㅡ

    아직은 잘 모르겠지만 Struts1.x 와  Struts2.x 는 상당히 다르다고 하는데..
    공부할게 점점 많아지는거 같다..
    사용방법을 알아보고자 간단하게 펙토리얼을 구해 보았다



    아무튼 각설하고,

    view 단에서 발생한 Request가 최종적으로 Response되어  view 단에 출력되어지는 동작순서를 알아보자..

    1. Servlet Container(톰켓)는 Browser로 부터 Request를 받아 들인다.
        이 Request에는 해당 작업을 수행하기 위한 r_factorial.action( .do와 같은 역할)이 포함되어 있다.


    2. web.xml 에서 url을 통해 들어온 모든 request 는 Mapping에 의해 struts2 로 전달되도록
        설정되어 있다. 따라서 org.apache.struts2.dispatcher.FilterDispatcher 로 보내지게 된다.


    3. .action이 있기에  Struts2 Framework에서는 Struts2 Framework 에서 Request 를 처리하도록 한다.


    4. Sturts2 는 struts.xml 에서 요청한 r_factorial.action 과 같은 이름의 파일r_factorial이 있는지 찾는다.
        같은 이름이 존재하면 struts.xml 에서 지정한 클래스의 객체의 execute() 메소드를 실행한다.

        - 이름이 반드시 struts.xml이어야 하는것은 아니다. struts.xml에 동일한 위치에 있는 xml 파일을
           include시켜 주어도 된다(사용자별 or 기능별 action 관리를 위해 xml 파일을 나누어 관리할 수 있다)

        - xml 파일에서 이름을 찾을때 r_factorial.action과 동일한 이름 찾지만 뒤에 .action은 빼고 찾는다 ;;

    - struts.xml 파일에 example.xml 파일을 include 시켜 사용할 수 있다.


    5. r_Factorial.execute() 메소드가 실행되고, 이에 필요한 비즈니스 로직이 실행된다.
        return 하는 값이 SUCCESS 이면 정상적인 정상으로 판단하고,
        struts.xml(example.xml) 에서 지정한 Result 에 기술된 example/r_factorial.jsp 로 Forwarding 된다.

    - ActionSupport 상속을 위해 com.opensymphony.xwork2.ActionSupport 를 import 필요
    - ActionSupport 를 상속 받지 않으면 상수인 SUCCESS , 요놈이 먹히지가 않는다 -_-;;

    6. Factorial.jsp에서는 <s:property value="str" />, <s:property value="result" />태그를 인식하여
        r_Factorial.factorial() 메소드를 호출하여, HTML 을 구성한다.


    7. 마지막으로 HTML 코드를 Browser 로 response 한다.   

    일단 내가 아는건 여기까지다.. 완전 기본 뿐이지만..

    점점 더 공부해서 초중급.... 내용을 올려보련다  ^_^;;;
    Posted by 1010
    51.Struts22009. 2. 23. 15:22
    반응형
    # 강좌를 시작하며 #
    1부에서는 스트럿츠의 가장 기본인 Action mapping 을 직접 따라 해보고
    스트럿츠의흐름을 이해하도록 합시다.
    그리고 스트럿츠를 처음 시작하는 사람의 이해를 돕기 위해서 화면 캡처부분을
    많이 추가 했습니다.
    강좌의 원할한 진행을 위해 존칭은 생략 하겠습니다.


    # 스트럿츠란 #
    모델1 방식
    직접 jsp을 호출하는 방식이다. jsp에는 DB연결부터 모든 비지니스 로직과
    실제 브라우저상에 보여줄 프리젠테이션 레이어 부분이 같이있다.
    물런 Beans을 사용하면 DB부분은 따로 뺄수 있지만. 각각의 jsp 가
    호출된다면 모델1 방식이다.

    모델2(MVC) 방식
    모델1의 가장 큰 단점은 jsp 소스가 길어진다는것이다. 모든것을 jsp가 주도로
    처리 하니 당연한 일이다.그로므로서 개발 속도는 빠를지언정 나중에 그소스를
    다시 보거나 유지보수할땐 힘들어지는 경우가 많다.그래서 등장한것이 모델2
    MVC(model - Controller - view) 방식이다.모든 요청은 Controller 맞고 비지니스
    로직은 model이 담당하고 jsp는 view의 역활로 결과를 화면상에 뿌려주는 역활이다.
    모델1에서 jsp 혼자 했던 일을 각각의 역활을 나눠주는것이다. jsp는 훨씬 가벼워졌고
    비지니스로직과 프리젠테이션 레이어를 분리하므로서 비지니스로직을 재사용도 가능해졌고
    유지보수에 많은 장점을 가지게 된다.

    스트럿츠(struts) Framework
    모델2 도 Controller 가 너무 복잡해지고 재사용이 거의 불가능 해지는 단점이 있다
    그래서 그런 단점을 보완하고 모델1의 장점과 모델2의 장점을 모아서 스트럿츠를 만들었다.
    스트럿츠는 가장 널리 쓰이는 Framework중에 하나이다.


    # 기본 환경 #
    JDK 1.5
    Tomcat 5.5
    struts-1.3
    이클립스 3.2 (wtp 포함 all-in-one)


    # 환경 세팅 #
    1 기본 환경 세팅
    http://www.jspclub.co.kr/board/view.jsp?div=study&no=700&npage=1
    위 강좌를 보고 이클립스 세팅을 마친다.
    참고로 필자는 이클립스의 workspace 는 c:\dev 로 했고 프로젝트 명은 myjsp로
    했다.

    2 struts 라이브어리 다운
    http://struts.apache.org/download.cgi#struts135
    struts-1.3.5-lib.zip 을 다운 받는다.

    3 다운받은 라이브어리 WEB-INF/lib 안에 넣는다.



    # WEB-INF/web.xml 에서 struts 설정 부분 추가 #
    web.xml 부분에 확장자가 *.do 패턴으로 오는것은 모두 org.apache.struts.action.ActionServlet 을
    호출하라는 부분을 추가 하는 부분이다.
    <!--Standard  Action  Servlet  Configuration  -->    
    <servlet>    
        <servlet-name>action</servlet-name>    
        <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>    
        <init-param>    
                <param-name>config</param-name>    
                  <param-value>/WEB-INF/struts-config.xml</param-value>    
        </init-param>    
        <init-param>    
              <param-name>debug</param-name>  
                 <param-value>2</param-value>    
        </init-param>  
           <init-param>    
              <param-name>detail</param-name>    
              <param-value>2</param-value>    
        </init-param>    
        <load-on-startup>2</load-on-startup>    
    </servlet>    

    <!--  Standard  Action  Servlet  Mapping  -->    
    <servlet-mapping>    
        <servlet-name>action</servlet-name>  
           <url-pattern>*.do</url-pattern>    
    </servlet-mapping>




    # WEB-INF/struts-config.xml 파일 추가 #
    스트럿츠의 config파일이다.




    # WEB-INF/struts-config.xml 에 action-mapping 내용 추가 #
    위의 web.xml에 의해 호출된 ActionServlet은 struts-config.xml 정보를 읽어 처리 되어진다.
    action 패스가 /Index 이면 examples.IndexAction 클래스의 excute 메소드를 호출한다.
    <?xml  version="1.0"  encoding="UTF-8"?>    

    <!DOCTYPE  struts-config  PUBLIC    
    "-//Apache  Software  Foundation//DTD  Struts  Configuration  1.3//EN"
    "http://jakarta.apache.org/struts/dtds/struts-config_1_3.dtd">    
    <struts-config>    
        <action-mappings>
          <action  path="/Index"  type="examples.IndexAction">
                    <forward  name="success"  path="/index.jsp"  />
            </action>
          </action-mappings>
    </struts-config>  
      



    # examples 페키지 추가 #
    examples라는 패키지를 만든다 .



    # IndexAction class 추가 #



    # IndexAction class 비지니스 로직 부분추가 #
    struts-config.xml 정보에 의해 호출된 excute 안에서 request 에 title 이란 이름으로
    "나의 첫번째 struts 성공" 이라고 request attribute에 추가 한다.
    return mapping.findForward("success"); 이부분은 struts-config.xml 에 정의된 매핑이름이
    success 일경우 index.jsp 파일로 Forward 시켜준다
    package  examples;

    import  javax.servlet.http.HttpServletRequest;
    import  javax.servlet.http.HttpServletResponse;

    import  org.apache.struts.action.Action;
    import  org.apache.struts.action.ActionForm;
    import  org.apache.struts.action.ActionForward;
    import  org.apache.struts.action.ActionMapping;

    public  class  IndexAction  extends  Action  {

            public  ActionForward  execute(
                    ActionMapping  mapping,
                    ActionForm  form,
                    HttpServletRequest  request,
                    HttpServletResponse  response)
                    throws  Exception  {
            
             request.setAttribute("title",  "나의  첫번째  struts  성공");

                    return  mapping.findForward("success");

            }

    }



    # index.jsp 추가 #



    # index.jsp 내용 #
    examples.IndexAction 에서 넣은 request attribute 부분을 출력한다.
    <%@  page  language="java"  contentType="text/html;  charset=EUC-KR"
            pageEncoding="EUC-KR"%>
    <%=request.getAttribute("title")  %>




    # 추가된 파일들 #



    # 톰켓 서버 시작 #


    # 결과 확인 #
    "나의 첫번째 struts 성공" 이란 글씨가 보이면 성공이다.

    출처 : Tong - [별난상이]님의 STRUTS통

    Posted by 1010
    01.JAVA/Java2009. 2. 23. 14:40
    반응형
    http://java.sun.com/developer/EJTechTips/2005/tt0125.html#1






       try {           
            Connection con = makeDatabaseConnection();
            con.setAutoCommit(false);          
            //  Do whatever database transaction functionality
            //  is necessary          
            con.commit();         
        } catch (Exception ex) {
            try {
                con.rollback();
            } catch (SQLException sqx) {
                throw new EJBException("Rollback failed: " +
                    sqx.getMessage());
            }
        } finally {
            releaseDatabaseConnection();
        }
    Posted by 1010
    98..Etc/GlassFish2009. 2. 23. 14:17
    반응형
    회사에서 GlassFish 를 다운받고 서버쪽에 GlassFish 를 추가했는데 안나오는 겁니다.
    (플러그인이 재대로 설치가 안된 듯...)
    https://glassfishplugins.dev.java.net/download/index.html << 여기서 플러그인을 다운받습니다.

    일단 집에서와 비슷한 환경으로 설치를 하였습니다.... 만 WTP 에서 Server 설정을 하려 하는데
    아래와 같은 화면이 반겨주었습니다.

    Missing classpath entry ~~\appserv-rt.jar


    GlassFish 설치경로에 lib 폴더를 가보았더니 appserv-rt.jar 파일은 없고 appserv-rt.jar.pack.gz 이런 파일만 있었습니다.
    gz 파일인지 알고 압축을 풀어도 안되고... 찾아보니 pack.gz 라는 압축방식인가 그런가 봅니다.
    역시 구글링을 해본 결과... setup 을 덜 한 것 같았습니다.

    사람들이 말하는대로 lib\ant\bin\ant -f setup.xml 명령을 해주면....
    먼가 설치가 쫘르르르르 진행됩니다.


    다시 이클립스에서 서버를 설정하면.... 일단은 다음 단계로 넘어갈 수 있다는 것이지요..

    GlassFish 삽질기는 계속됩니다....

    [참고자료]
    GlassFish 플러그인 - https://glassfishplugins.dev.java.net/download/index.html
    GlassFish Plugins Forum Thread - http://forums.java.net/jive/thread.jspa?threadID=38230&tstart=0
    Posted by 1010
    98..Etc/GlassFish2009. 2. 23. 14:07
    반응형
    GlassFish Project - v2.1 FinalBuild
    (also known as v2.1 b60e Promoted Build)

    | New to GlassFish | FAQ |Resources | GlassFish Project Home | How-Tos |

    This promoted build provides necessary infrastructure support for the SailFin Application Server (Telco app server). This release also contains fixes that did not make it into GlassFish V2 Update Release. Please refer to the GlassFish V2.1 Wiki Page for details on improvements that are going into this release. Note: Multilingual support available for French, German, Spanish, Japanese, Simplified Chinese, Traditional Chinese, and Korean.

    Promoted builds are weekly builds of GlassFish which have passed a minimum level of testing which includes the quicklook tests, a sub-set of CTS tests (representative collection of 344 J2EE 1.4 tests) and a sub-set of SQE tests (22 in number). A build is not promoted unless it passes all quicklook, CTS smoke and SQE smoke tests. 

    Note: This list offers files for different platforms. Please be sure to select the proper file for your platform. Carefully review the files listed below to select the one you want, then click the link to download.  Some browsers may require you to right-click/CTRL-click to save these files to your computer.

    The majority of the GlassFish code is available under a dual license consisting of the Common Development and Distribution License ( CDDL) v1.0 and the GNU General Public License (GPL) v2.  The following page contains details about the components in GlassFish and the licenses under which they are covered.

    Instructions to unbundle and configure GlassFish

    To install and configure GlassFish you need to have JDK 5 or JDK 6 installed on your system. The configuration processing depends on Ant (1.6.5).  The bundle includes an Ant distribution that has been extended with tasks to facilitate developing Java EE 5 applications for the application server.

    1. Download one of the bundles to disk, set JAVA_HOME to the JDK you have installed on your system.
    2. Run:
         % java -Xmx256m -jar filename.jar
      This command will unbundle GlassFish and create a new directory structure rooted under a directory named 'glassfish'.
    3.  % cd glassfish
    4. If you are using a machine with an operating system that is a derivative of UNIX(tm), set the execute permission for the Ant binaries that are included with the GlassFish bundle.
      	% chmod -R +x lib/ant/bin
      	% lib/ant/bin/ant -f setup.xml 
      OR for Windows:
      	% lib\ant\bin\ant -f setup.xml 

    For GlassFish V2 UR1 with Clustering supported installation, just change step 4 from the above installation

    % lib/ant/bin/ant -f setup-cluster.xml 
    OR  for Windows:
    % lib\ant\bin\ant -f setup-cluster.xml 

    To get started with GlassFish, see the quick start guide.

    See Configuring the Cluster/Load Balancer with GlassFish V2 for how to do the load balancing after creating Clusters on GlassFish V2.

    Binary builds

    The Open Sourcing Clustering features are included in this promotion.

    Solaris SPARC Platform

    Solaris x86 Platform

    Windows Platform

    Linux Platform

    MacOS Platform

    AIX Platform


    Source bundle


    Source code for GlassFish is available in the bundle below. Some technologies are developed in other projects and only a binary version is available in the GlassFish project source tree. To find more information on where to find sources see this page.

    Build Information

    Bugs fixed in this build. 
    Posted by 1010
    98..Etc/GlassFish2009. 2. 23. 14:04
    반응형
    Glassfish는 J2EE 5를 따르는 오픈소스 애플리케이션 서버를 말한다.
    참고로 J2EE 5 는
    -JavaServer Pages(JSP) 2.1
    -JavaServer Faces(JSF) 1.2
    -Servlet 2.5
    -Enterprise JavaBeans 3.0
    -Java API for Web Services(JAX-WS) 2.0
    -Java Architecture for XML Binding(JAXB) 2.0
    -Web Services Metadata for the Java Platform 1.0
    라는 여러 표준의 버젼을 따른다.

    다운로드는 아래의 링크에서 맘에 드는 버젼으로 선택한다.
    https://glassfish.dev.java.net/public/downloadsindex.html

    Glassfish 설치하기
    Jar를 다운로드 했다면, jar파일이 있는 위치에서 다음의 명령어를 친다.
    java -Xmx256m -jar jar파일명
    그러면 동의하라는 반 강제적 화면이 나타나고,
    스크롤을 아래로 주루룩 내린 후 동의를 하면,
    파일들의 압축이 풀릴것이다.


    Glassfish를 설치하고 나서 가장 황당했던것이, bin 디렉토리에 아무것도 실행파일이 없다는 것이다.

    관련 문서도 눌러 보면 Glassfish에 대한 문서가 아니라, Sun Java System Application Server 에 대한 문서고... - -;

    Glassfish의 압축을 푼 root 디렉토리를 보면 setup.xml과 setup-cluster.xml 두개의 파일이 존재한다.
    클러스터 구성할 것이 아니라면 setup.xml을 사용하면 된다.

    Ant를 이용하여 설치하기
    그래서, 가장 먼저 ant를 설치해야 한다. (그런데 친절하게도 glassfish\lib\ant 디렉토리가 포함되어 있으며, 여기의 실행파일을 사용해도 된다.)
    ant의 bin 디렉토리를 갖고 있는 장비의 path에 등록을 하고,
    setup.xml 파일이 있는 위치에서 다음의 명령을 수행한다.
    ant -buildfile setup.xml

    아니면 귀찮으면 다음과 같이 해도 된다.

    lib\ant\bin\ant -f setup.xml

    그러면 아래와 같은 결과가 떨어지면서 필요한 파일들이 생성된다.

    아래의 내용을 펼치면 된다. ^^;

    내용 닫기

    D:\glassfish>ant -buildfile setup.xml
    Buildfile: setup.xml

    all:

    get.java.home:

    setup.init:

    check-java:

    get.java.home:

    setup.init:

    validate-java:
         [echo] Current Java Version 1.6.0_11

    get.java.home:

    setup.init:

    glassfish-jarunpack:
         [echo] Applying UnPack200 on Packed jars using JDK1.5
         [echo] D:\glassfish/lib/Pack200Task.jar

    get.java.home:

    setup.init:

    nonmac-jarunpack:

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\appserv-ext.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\appserv-ext.jar
       [delete] Deleting: D:\glassfish\lib\appserv-ext.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\toplink-essentials.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\toplink-essentials.jar
       [delete] Deleting: D:\glassfish\lib\toplink-essentials.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\appserv-rt.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\appserv-rt.jar
       [delete] Deleting: D:\glassfish\lib\appserv-rt.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\appserv-cmp.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\appserv-cmp.jar
       [delete] Deleting: D:\glassfish\lib\appserv-cmp.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\appserv-jstl.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\appserv-jstl.jar
       [delete] Deleting: D:\glassfish\lib\appserv-jstl.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\appserv-tags.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\appserv-tags.jar
       [delete] Deleting: D:\glassfish\lib\appserv-tags.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\endorsed\activation.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\endorsed\activation.jar
       [delete] Deleting: D:\glassfish\lib\endorsed\activation.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\endorsed\webservices-api.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\endorsed\webservices-api.jar
       [delete] Deleting: D:\glassfish\lib\endorsed\webservices-api.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\webservices-rt.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\webservices-rt.jar
       [delete] Deleting: D:\glassfish\lib\webservices-rt.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\webservices-tools.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\webservices-tools.jar
       [delete] Deleting: D:\glassfish\lib\webservices-tools.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\com-sun-commons-launcher.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\com-sun-commons-launcher.jar
       [delete] Deleting: D:\glassfish\lib\com-sun-commons-launcher.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\j2ee-svc.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\j2ee-svc.jar
       [delete] Deleting: D:\glassfish\lib\j2ee-svc.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\jsf-impl.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\jsf-impl.jar
       [delete] Deleting: D:\glassfish\lib\jsf-impl.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\sun-appserv-ant.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\sun-appserv-ant.jar
       [delete] Deleting: D:\glassfish\lib\sun-appserv-ant.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\javaee.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\javaee.jar
       [delete] Deleting: D:\glassfish\lib\javaee.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\appserv-admin.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\appserv-admin.jar
       [delete] Deleting: D:\glassfish\lib\appserv-admin.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\admin-cli.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\admin-cli.jar
       [delete] Deleting: D:\glassfish\lib\admin-cli.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\appserv-deployment-client.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\appserv-deployment-client.jar
       [delete] Deleting: D:\glassfish\lib\appserv-deployment-client.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\appserv-se.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\appserv-se.jar
       [delete] Deleting: D:\glassfish\lib\appserv-se.jar.pack.gz

    jarpack-tasks:

    jar-unpack:
    [unpack200] Unpacking with Unpack200
    [unpack200] Source File :D:\glassfish\lib\admin-cli-ee.jar.pack.gz
    [unpack200] Dest.  File :D:\glassfish\lib\admin-cli-ee.jar
       [delete] Deleting: D:\glassfish\lib\admin-cli-ee.jar.pack.gz

    get.java.home:

    setup.init:

    -do.copy.common:
         [copy] Copying 1 file to D:\glassfish\config

    do.copy.windows:
         [copy] Copying 1 file to D:\glassfish\config
         [copy] Copying 1 file to D:\glassfish\bin
         [copy] Copying 1 file to D:\glassfish\bin
         [copy] Copying 1 file to D:\glassfish\bin
         [copy] Copying 1 file to D:\glassfish\bin
         [copy] Copying 1 file to D:\glassfish\bin
         [copy] Copying 1 file to D:\glassfish\bin
         [copy] Copying 1 file to D:\glassfish\bin
         [copy] Copying 1 file to D:\glassfish\bin
         [copy] Copying 1 file to D:\glassfish\bin
         [copy] Copying 1 file to D:\glassfish\bin
         [copy] Copying 1 file to D:\glassfish\bin
         [copy] Copying 1 file to D:\glassfish\bin
         [copy] Copying 1 file to D:\glassfish\bin
         [copy] Copying 1 file to D:\glassfish\bin
         [copy] Copying 1 file to D:\glassfish\bin
         [copy] Copying 1 file to D:\glassfish\bin
         [copy] Copying 1 file to D:\glassfish\updatecenter\bin

    do.copy.unix:

    do.copy:

    get.java.home:

    setup.init:

    -do.tokenrep.common:

    do.token.windows:

    do.token.unix:

    do.token.jdic.windows:

    do.token.jdic.solaris-sparc:

    do.token.jdic.solaris-x86:

    do.token.jdic.linux:

    do.token.jdic.mac:

    do.token.jdic:

    do.token.enable.uc:

    do.token:

    get.java.home:

    setup.init:

    do.chmod.unix:

    do.chmod:

    create-local-registry:

    setup.reg:
         [echo] Creating the service registry file..
         [java] From Local service registry  ..

    get.java.home:

    setup.init:

    set.env.win:

    set.env.unix:

    set.env:

    create.domain:
         [exec] 포트 4848을(를) Admin에 대해 사용합니다.
         [exec] 포트 8080을(를) HTTP Instance에 대해 사용합니다.
         [exec] 포트 7676을(를) JMS에 대해 사용합니다.
         [exec] 포트 3700을(를) IIOP에 대해 사용합니다.
         [exec] 포트 8181을(를) HTTP_SSL에 대해 사용합니다.
         [exec] 기본 포트 3820을(를) IIOP_SSL에 대해 사용합니다.
         [exec] 기본 포트 3920을(를) IIOP_MUTUALAUTH에 대해 사용합니다.
         [exec] 기본 포트 8686을(를) JMX_ADMIN에 대해 사용합니다.
         [exec] 프로필을 사용하여 도메인을 만드는 중입니다: developer(구성 파일의 변
    수 AS_ADMIN_PROFILE로에 지정)
         [exec] 지정된 로켈[ko_KR]의 파일을 [D:\glassfish\lib\install\templates\loca
    les\ko_KR\index.html]에서 찾지 못했습니다. 대신 기본 (en_US) index.html을 사용합
    니다.
         [exec] 보안 저장소 사용: JKS
         [exec] 도메인 domain1이(가) 만들어졌습니다.
         [exec] 이 도메인 [domain1]의 관리자 이름 [admin]에 관련된 로그인 정보를 [C:
    \Documents and Settings\smlee\.asadminpass]에 성공적으로 저장했습니다.
         [exec] 이 파일은 계속 보호되어야 합니다. 이 파일에 저장된 정보는 asadmin 명
    령에서 이 도메인을 관리하는 데 사용됩니다.
       [delete] Deleting: D:\glassfish\passfile

    BUILD SUCCESSFUL
    Total time: 29 seconds
    D:\glassfish>



    ant 스크립트를 수행한 이후에 몇가지 설정을 마치면 서버를 기동할 수 있다.

    http://docs.sun.com/app/docs/doc/819-3193/aboaa?a=view

    링크를 보면 몇몇가지 설정할 게 있으니 참조하기 바란다.
    간단하게 정리하면(윈도우용)
    1. bin 디렉토리를 path에 추가
    2. AS_ADMIN_USER 라는 것을 환경 변수에 추가하고, 설치할때의 PC나 서버 계정을 추가한다.

    서버를 다음의 명령어로 시작할 수 있다.

    asadmin start-domain domain1


    정상적으로 수행되었다면 다음과 같은 메시지가 나타난다.

    도메인 domain1을(를) 시작합니다. 잠시 기다려 주십시오.
    로그가 D:\glassfish\domains\domain1\logs\server.log(으)로 리디렉션되었습니다.
    마스터 비밀번호를 입력하십시오>
    출력을 D:/glassfish/domains/domain1/logs/server.log(으)로 리디렉션하는 중
    도메인 domain1에서 클라이언트 요청을 받을 준비가 되었습니다. 백그라운드에서 추가
     서비스를 시작하는 중입니다.
    다음에서 해당 구성 및 로그를 사용하여 도메인 [domain1]이(가) [Sun Java System Ap
    plication Server 9.1_02 (build b04-fcs)]을(를) 실행하는 중입니다: [D:\glassfish\
    domains].
    관리 콘솔은 [http://localhost:4848]에서 사용할 수 있습니다.
    "asadmin" 명령에도 같은 포트 [4848]을(를) 사용합니다.
    사용자 웹 응용 프로그램은 다음 URL에서 사용할 수 있습니다:
    [http://localhost:8080 https://localhost:8181 ].
    다음 웹 내용을 사용할 수 있습니다:
    [/web1  /__wstx-services ].
    표준 JMX 클라이언트(예, JConsole)는 도메인 관리를 위해 JMXServiceURL:
    [service:jmx:rmi:///jndi/rmi://smlee:8686/jmxrmi]에 연결될 수 있습니다.
    도메인은 최소한 다음 포트에서 연결을 수신합니다:
    [8080 8181 4848 3700 3820 3920 8686 ].
    도메인이 Application Server 클러스터 및 다른 독립 실행형 인스턴스를 지원하지 않
    습니다.


    설치시 유의사항
    서버를 수행할때 리눅스는 상관 없겠지만,
    PC 이름이 한글일 경우 서버가 정상적으로 뜨지 않을 수 있다.
    이 경우 domain1/logs 디렉토리의 server.log 파일에 다음과 같은 메시지가 나타난다.

    com.sun.appserv.server.ServerLifecycleException
     at com.sun.enterprise.admin.server.core.JmxConnectorLifecycle.onStartup(JmxConnectorLifecycle.java:153)
     at com.sun.enterprise.server.ApplicationServer.onStartup(ApplicationServer.java:442)
     at com.sun.enterprise.server.ondemand.OnDemandServer.onStartup(OnDemandServer.java:120)
     at com.sun.enterprise.server.PEMain.run(PEMain.java:411)
     at com.sun.enterprise.server.PEMain.main(PEMain.java:338)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
     at java.lang.reflect.Method.invoke(Method.java:597)
     at com.sun.enterprise.server.PELaunch.main(PELaunch.java:412)
    Caused by: java.lang.NullPointerException
     at javax.management.remote.JMXConnectorServerFactory.newJMXConnectorServer(JMXConnectorServerFactory.java:283)
     at com.sun.enterprise.admin.jmx.remote.server.rmi.JmxConnectorServerDriver.startConnectorServer(JmxConnectorServerDriver.java:215)
     at com.sun.enterprise.admin.server.core.JmxConnectorLifecycle.onStartup(JmxConnectorLifecycle.java:134)
     ... 9 more
    Posted by 1010
    05.JSP2009. 2. 18. 17:37
    반응형

    www.servlets.com 사이트 에 접속한다. 


     

    빨간 네모 박스가 쳐져 있는 부분을 클릭한다.

     

     

    스크롤을 아래로 약간 내려 보면 DownLoad 부분이 나오는데 거기에서

    Cos 로 시작되는 파일을 다운 받는다.

    다운받은 압축 파일의 압축을 풀고

    cos-05Nov2002/lib 안에 cos.jar 아카이브 파일을

    자바 폴더와 톰켓 폴더에 각각 넣어주도록 한다.

     

    C:/Java/jdk1.6.0_06/jre/lib/ext

    C:/Java/jre1.6.0_06/lib/ext

    C:/Tomcat5.5/common/lib

     

     

    jsp 파일을 코딩시 폼양식에 enctype="multipart/form-data" 를 넣어주도록 한다.

    ex ) <form name="form" method="post" enctype="multipart/form-data">

     

    tip! enctype을 JavaScript 에서 제어하고 싶을시에는 아래와 같이 코딩해준다.

    ex) 폼이름.encoding = "multipart/form-data"; 

        form1.encoding="multipart/form-data";

     

    ※ 주의 : enctype 을 지정해 주지 않으면 파일 업로드가 되지 않으며 톰캣의 내장객체 request 객체를 사용할 수 없다.

             정확히는 enctype 을 multipart/form-data 로 설정해 주었다면 톰갯의 내장객체 request 객체를 사용할 수 없다.

     

     1) MultipartRequest 를 사용하기 위해서는 com.oreilly.servlet 패키지를 import! 해야 한다.

       ex) <%@ page import! = "com.oreilly.servlet.*" %>

     

     2) MultipartRequest 는 객체를 생성하자 마자 파일을 업로드 시킨다.

       ex) MultipartRequest multi = new MultipartRequest(request, "파일 저장 경로(String)", 파일크기(int), "인코딩");

           // 이순간 업로드가 발생된다.

     

     3) MultipartRequest 를 사용 하게 되면 톰캣의 request 객체의 getParameter 메서드를 이용하여

       값을 전달 받지 못한다. 따라서 MultipartRequest를 사용하게 되면 값을 전달 받기 위해서는 MultipartRequest 객체의

       getParameter 메서드를 이용하여 값을 전달 받아야 한다.

       ex) String name = multi.getParameter("name");

     

     4) 파일을 저장할 경로는 직접 써주기 보다는 톰캣의 내장 객체인 application 객체의 getRealPath() 메서드를 사용하자.

        String savePath = application.getRealPath("파일을 저장할 폴더");

        ex) String savePath = application.getRealPath("/product");

            MultipartRequest multi = new MultipartRequest(request, savePath);

     

     5) 파일 이름을 받아올때는 MultipartRequest 의 getFileSystemName 메서드를 사용한다.

        String fileName = multi.getFilesystemName("파라미터 name");

        ex) String fileName = multi.getFilesystemName("fileName");

     

     

     출처 : http://blog.naver.com/lbiryu/30033838465

    Posted by 1010
    05.JSP2009. 2. 18. 17:36
    반응형

    <%@ page contentType="text/html; charset=euc-kr"%>
    <
    %@page import!="java.util.*" %>

    <%
    request.setCharacterEncoding("euc-kr");

    String url = "";
        Enumeration e = request.getParameterNames();  
        while(e.hasMoreElements()){
         String name = (String)e.nextElement();
          if(request.getParameter(name)!=null){
            url += name + "=" + request.getParameter(name) + "&";
          }else{
            url += name + "=" + "" + "&";
          }
        }
    out.println(url);   
     %>

    Posted by 1010
    05.JSP2009. 2. 18. 17:35
    반응형

    출처 : http://blog.daum.net/badog/4457979

    // downloadFile.jsp

     

    <%@ page language="java" contentType="text/html; charset=euc-kr" pageEncoding="EUC-KR" %><%@ page import!="java.io.*"%><%
    request.setCharacterEncoding("euc-kr");

    String filename = new String((request.getParameter("fileName")).getBytes ("8859_1"),"EUC_KR");
    String  filePath = "C:/test";

    InputStream in= null;
    OutputStream os = null;
    File file= null;
    File viewFile = null;
    boolean skip= false;
    String client= "";

    try{
      String fname1 = "";
      String fname2 = "";
      String fname  = "";
      fname  = filename;
      fname1 = new String(fname.getBytes("8859_1"),"euc-kr");

     try{
        file = new File(filePath, fname);
        viewFile = new File(filePath, fname1);
    //   out.print("file : " + file);
        in= new FileInputStream(file);
     }catch(FileNotFoundException fe) {
         skip= true;
      }


      fname2   = new String(fname1.getBytes("euc-kr"),"8859_1");
      response.reset();
    //  client = request.getHeader("User-Agent");
    //  response.setContentType("application/x-msdownload;");
    //  response.setHeader("Content-Description", "JSP Generated Data");

     if(!skip){
        if(client.indexOf("MSIE 5.5") != -1){
          response.setHeader("Content-Type", "doesn/matter; charset=euc-kr");
          response.setHeader("Content-Disposition", "filename="+new String(fname.getBytes("euc-kr"),"8859_1"));
        }else{
         response.setHeader("Content-Type", "application/octet-stream; charset=euc-kr");
          response.setHeader("Content-Disposition", "attachment; filename="+new String(fname.getBytes("euc-kr"),"8859_1"));
        }
        response.setHeader("Content-Transfer-Encoding", "binary;");
        response.setHeader ("Content-Length", ""+file.length());
        response.setHeader("Pragma", "no-cache;");
        response.setHeader("Expires", "-1;");

        os = response.getOutputStream();
        byte b[] = new byte[10240];
        int leng = 0;
       
        while( (leng = in.read(b)) > 0 ){
          os.write(b,0,leng);
        }
     }else{
        out.println("<script>");
        out.println("alert!('파일 다운로드중 애러가 발생하였습니다.')");
        out.println("</script>");
         return;
     }
    }catch(Exception e) {
      System.out.println(e);
    }finally{
      if(os != null) try{os.close();}catch(Exception ex){System.out.println(ex);};
     if(in != null)  try{in.close();}catch(Exception ex){System.out.println(ex);};
    }%>



    <a href="downloadFile.jsp?fileName=<%=file %>">다운로드</a>



    어디서 구해온 소스인데 이거 때문에 진짜 고생했다.

    파일은 다운로드 되는데 getOutputStream 애러가 계속 나는 것이였다.

    알고보니 이놈은 스페이스나 줄바꿈 뭐 이런게 들어가면 안되는 것이다.

    <%...%><%...%> 요런식으로 다 붙여야 한다.

    그리고 다운로드 취소시에 소켓 애러가 나는데 그건 무시하자. 그건 문도 안열었는데 닫으라고 하니까 나는거다.

    Posted by 1010
    02.Oracle/DataBase2009. 2. 18. 15:57
    반응형

    MS SQL Server 2000 용 JDBC 드라이버


    직접 다운로드 받으려면 아래의 링크를 클릭해서 받으세요.


    http://www.microsoft.com/downloads/info.aspx?na=46&p=5&SrcDisplayLang=en&SrcCategoryId=&SrcFamilyId=07287B11-0502-461A-B138-2AA54BFDC03A&u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2f4%2f1%2fd%2f41d3e9c0-64d1-451e-947b-7a4cba273b2d%2fsetup.exe


    압축 해제후 setup.exe 파일을 더블클릭해서 설치하면 된다.


    시작 -> 프로그램 -> Microsoft SQL Server 2000 Driver for JDBC -> HTML Help 를

    클릭하면 사용방법을 알 수 있다.


    Quick Start 클릭 -> Connecting to a Database 클릭하면 사용방법을 볼 수 있다.

    (설명이 영어로 되어 있다. 그러나, 간단한 영어니까 읽어보면 알 수 있다.)


    --------------------------------------------------------------------------


    자바에서 JDBC 프로그래밍의 4단계가 있는데

    1. 드라이버 로딩

    2. 연결

    3. 명령

    4. 결과


    하나씩 진행해보자.


    제일 먼저 JDBC 드라이버를 JDK 설치 폴더에 복사하자.

    1. 드라이버 로딩. (JDBC 드라이버 복사 및 설정 포함)

        C:\Program Files\Microsoft SQL Server 2000 Driver for JDBC\lib 의

        mssqlserver.jar, msbase.jar, msuti.jar 의 3개의 파일을 복사해서

        JDK 설치 폴더 (예를 들어 C:\j2sdk1.4.0 에 설치했다면)

        C:\j2sdk1.4.0\jre\lib\ext 에 위에서 복사한 3개의 파일을 붙여넣는다.

        이렇게 하면 JDBC 드라이버를 JDK 에서 인식해서 사용할 수 있다.


        JDBC 프로그래밍 소스에서 MS SQL JDBC 드라이버를 로딩하려면 아래와 같이 쓰면 된다.


        Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");


    2. 연결.

       Connection conn = DriverManager.getConnection("jdbc:microsoft:sqlserver://DB서버이름 또는 localhost:1433;DataBaseName=데이타베이스명","유저명","비밀번호");


       Connection conn = DriverManager.getConnection
        ("jdbc:microsoft:sqlserver://localhost:1433;DataBaseName=pubs","sa","1234");

    3. 명령.

       Statement stmt = con.createStatement();


    4. 결과.

       ResultSet rs = stmt.executeQuery("select * from authors");


       결과를 화면에 출력하려면 반복문을 이용하여 테이블의 내용을 가져와서 출력하면 된다.


       while(rs.next()) {

          String str1 = rs.getString(1);

          String str2 = rs.getString(2);

          String str3 = rs.getString(3);


          out.println(str1 + " : " + str2 + " : " + str3 + "<br>");

       }


    msjdbc.jsp 아래 전체 소스를 참고하시오.

    <%@ page contentType="text/html;charset=euc-kr" %>
    <%@ page  import!="java.sql.*,java.util.*" %>

    <%
    // JDBC 프로그래밍 4단계
    // 1. 드라이버 로딩 -> 2. 연결 -> 3. 명령 -> 4. 결과


    // 1. 드라이버 로딩
    Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");

    out.println("드라이버 로딩 성공<br>");

    // 2. 연결.
    // Connection conn = DriverManager.getConnection("jdbc:microsoft:sqlserver://DB서버이름 또는 localhost:1433;DataBase=데이타베이스명","유저명","비밀번호");

    // 여기서는 MS SQL Server를 설치하면 같이 설치되는 예제 DB인 pubs를 사용하겠음.
    Connection conn = DriverManager.getConnection("jdbc:microsoft:sqlserver://localhost:1433;DataBaseName=pubs","sa","1234");

    out.println("연결 성공<br>");


    // 3. 명령.
    Statement stmt = conn.createStatement();

    out.println("명령 준비 성공<br>");


    // 4. 결과.
    ResultSet rs = stmt.executeQuery("select * from authors");

    out.println("결과 얻어내기 성공<br>");
    out.println("<hr>");
    out.println("<br>");

    // 결과를 화면에 출력하려면 반복문을 이용하여 테이블의 내용을 가져와서 출력하면 된다.

    while(rs.next()) {
     String str1 = rs.getString(1);  // 첫번째 필드의 값 가져오기
     String str2 = rs.getString(2);  // 두번쩨
     String str3 = rs.getString(3);  // 세번째

     out.println(str1 + " : " + str2 + " : " + str3 + "<br>"); // 출력
    }


    rs.close();

    stmt.close();

    ms-sql 2000 jdbc 드라이버 setup.exe

     

    conn.close();
    %>

     

    Posted by 1010
    02.Oracle/DataBase2009. 2. 18. 13:09
    56. Eclipse Etc.../Eclipse2009. 2. 18. 13:07
    반응형

    1. 코딩표준 : CheckStyle

    2. 코드중복발견 : PMD의 CPD

    3. 코드 커버리지 측정 : Coverlipse

    4. 의존성 분석 제공 : JDepend

    5. 복잡성 탐지 : Metrics


    =======================================================================================================

    1. 코딩표준분석 : CheckStyle

    CheckStyle 싸이트 : http://eclipse-cs.sourceforge.net/

    eclipse update 주소 : http://eclipse-cs.sourceforge.net/update



    =======================================================================================================

    2. Copy/Paste 탐지 : CPD

    eclipse update 주소 : http://pmd.sourceforge.net/eclipse




    =======================================================================================================

    3. 코드 커버리지 테스트 : Coverlipse

    Coverlipse 싸이트 : http://coverlipse.sourceforge.net

    eclipse update 주소 : http://coverlipse.sf.net/update

     

     

     

    =======================================================================================================

    4. 패키지 의존성 분석 : JDepend

    JDepent 싸이트 : http://andrei.gmxhome.de/ 여기서 eclipse plugin으로 들어가 JDepend를 찾으면 된다.

    eclipse update 주소 : http://andrei.gmxhome.de/eclipse/




    =======================================================================================================

    5. 복잡성 탐지 : Metrics

    Metrics 싸이트 : http://metrics.sourceforge.net/

    eclipse update 주소 : http://metrics.sourceforge.net/update


    Posted by 1010
    01.JAVA/Java2009. 2. 18. 12:32
    반응형

    개발자가 놓치기 쉬운 자바의 기본원리

    • 전성호(커뮤니티본부 커뮤니티개발1팀), 2006년 10월

    초록(abstract)

    개발자가 놓치기 쉬운 자바의 기본 원리에 대하여 기본적이긴 하지만 개발하면서 느끼고 경험한 내용을 정리하였다.

    목차

    1 객체지향의 구멍 static
    1.1 Java는 객체지향 언어이다?
    1.2 전역변수
    2 Java는 Pointer언어이다? (Java에는 Pointer밖에 없다?)
    2.1 Java는 primitive형을 제외하곤 모두 Pointer이다
    2.2 null은 객체인가?
    2.3 String에 대하여
    2.4 객체지향의 캡슐화 파괴 주의
    2.5 배열에 대하여
    2.5.1 배열은 object 인가?
    2.5.2 배열의 length는 왜 field(member variable)인가?
    2.5.3 final과 배열에 대하여...
    2.5.4 "Java에서의 다차원 배열은 존재하지 않는다."
    2.6 인수(parameter/argument)전달의 개념
    2.6.1 "Java에서 parameter(argument) 전달은 무조건 'call by value' 이다"
    2.6.2 "C와 같은 언어는 static linking이지만, Java는 dynamic linking이다."
    2.7 GC 에 대하여 잠깐!
    2.7.1 "Garbage Collection은 만능이 아니다."
    2.8 Java Pointer 결론
    2.8.1 "결국 Java에는 pointer가 있는 것인가, 없는 것인가?"
    3 상속과 interface의 문제점
    3.1 상속
    3.1.1 상속에 있어서의 생성자(constructor)
    3.1.2 "down cast는 본질적으로 매우 위험하다"
    3.1.3 "추상클래스에 final이 있으면 compile error이다"
    3.2 interface
    3.2.1 "interface는 interface일뿐 다중 상속의 대용품이 아니다."
    3.3 상속 제대로 사용하기
    4 package와 access 제어에 관한 이해
    4.1 package
    4.1.1 "package는 '계층구조' 인가?"
    4.1.2 "compiler 가 인식하는 class검색 순서(소스코드내 클래스가 발견될 경우 그 클래스의 위치를 찾는 순서)"
    4.2 access 제어
    4.2.1 "interfacde member의 access 제어"
    4.2.2 그렇다면 interface를 다른 package에 대하여 숨기고 싶으면 어떻게 하는가?
    5 기타 Java 기능
    5.1 Thread
    5.1.1 "Multi Thread에서는 흐름은 복수이지만 data는 공유될 수 있다."
    5.1.2 "Thread는 객체와 직교하는 개념이다."
    5.1.3 "Synchronized 의 이해"
    5.1.4 "Thread 사용법의 정석은?"
    5.2 Exception
    5.2.1 "finally 절은 반드시 어떠한 경우에도 실행되는가?"
    5.2.2 "예외의 종류 3가지 (Error, RuntimeException, 그밖의 Exception)"
    5.2.2.1 Error
    5.2.2.2 RuntimeException
    5.2.2.3 그밖의 Exception
    5.2.3 "OutOfMemoryError는 어떻게 처리해야 하는가?"
    5.3 Object Serialize
    5.3.1 "Serialize를 위해서는 marker interface인 java.io.Serializable interface를 implements해야한다."
    5.3.2 "super class는 Serializable이 아닌데 sub class만 Serializable인 경우의 문제점"
    5.3.3 "transient field의 복원(?)관련"
    5.3.4 "Stack Overflow에 주의하라!"
    5.4 "nested class / inner class / 중첩클래스"
    5.4.1 "중첩클래스의 개념"
    5.4.2 "내부클래스는 부모의 참조를 몰래 보유하고 있다."
    5.4.3 "local inner class에 대하여"
    5.4.4 "anonymous class(무명클래스)에 대하여"
    6 이래도 Java가 간단한가?
    6.1 method overload 에서의 혼란?
    6.1.1 "overload란 이름이 가고 인수가 다른 method에 compiler가 다른 이름을 붙이는 기능"
    6.1.2 "그렇다면 overload에서 실제로 혼동되는 부분은 무엇인가?"
    6.1.3 (참고) 또다른 혼동, overload한 method를 override 하면?
    6.2 상속/override/은폐 에서의 복잡함
    6.2.1 "Java class의 member 4 종류"
    6.2.2 "override시 method 이름에 대한 함정"
    6.2.3 "또다른 나의(?) 실수 - 말도 안되는 오타"
    6.2.4 "static member를 instance를 경유하여 참조해서는 안 된다."
    6.2.5 "super keyword는 부모의 this"
    6.3 상속에 관한 또 다른 문제
    6.4 그밖의 함정
    6.4.1 "생성자에 void 를 붙인다면?"
    6.4.2 "if / switch 의 함정"
    7 Java 기능 적용 몇가지
    7.1 대규모 개발에서 interface 분리하기
    7.1.1 "interface 분리의 필요성"
    7.2 Java에서의 열거형
    7.3 Debug write
    8 Java 5.0 Tiger 에 대하여
    8.1 Working with java.util.Arrays
    8.2 Using java.util.Queue interface
    8.3 java.lang.StringBuilder 사용하기
    8.4 Using Type-Safe Lists
    8.5 Writing Generic Types
    8.6 새로운 static final enum
    8.7 Using java.util.EnumMap
    8.8 Using java.util.EnumSet
    8.9 Convert Primitives to Wrapper Types
    8.10 Method Overload resolution in AutoBoxing
    8.11 가변적인 argument 개수 ...
    8.12 The Three Standard Annotation
    8.13 Creating Custom Annotation Types
    9 The for/in Statement
    9.1 for/in 의 자주 사용되는 형태
    10 Static Import
    10.1 static member/method import
    11 References

    1 객체지향의 구멍 static #

    1.1 Java는 객체지향 언어이다? #

    "Java는 완전한 객체지향 언어이다" 라는 주장을 자주 접하게 된다. 만일 이것이 사실이라면 Java를 사용하는 한 "기존의 절차지향 프로그래밍을 전혀 할수 없을것 같지만 그렇지 않다. 빠져나갈 구멍이 있는 것이다. static을 이용하면 비 객체지향 언어처럼 코딩할 수 있다.

    static method는 instance가 아닌 클래스에 속하는 method로, class method라고 부른다. 반대로 static이 아닌 method는 instance method라고 부른다.

    static method는 this가 없다. instance method에는 숨겨진 파라미터로 this가 건네진다. (아래 "객체지향에 흔희 있는 오해" 참고) 하지만 static method는 절차지향의 함수와 동일하므로 숨겨진 파라미터 this는 없다. 그래서 static method에서는 전달한 this가 없으므로 instance method를 호출하거나 instance field를 참조할 수 없는 것이다.

    (참고) 객체지향에 흔히 있는 오해

    • 오해1. "객체지향에서는 객체끼리 서로 메세지를 주고 받으며 동작한다." 라는 말을 듣고 다음과 같이 생각할 수 있다. "객체지향에서는 객체가 각각 독립하여 움직인다는 것인가, 그러면 각 객체에 독립된 thread가 할당되어 있단 말인가?" 그렇지 않다. "메세지를 보낸다"라는 것은 단순히 각 객체의 함수 호출에 불과하다.

    • 오해2. "객체지향에서는 method가 class에 부속되어 있다"는 말을 듣고 다음과 같이 생각할 수 있다. "그러면 instance별로 method의 실행코드가 복제되고 있는 것이 아닌가?" 물론 이것도 오해다. method의 실행코드는 종래의 함수와 동일한 어딘가 다른곳(JVM의 class area)에 존재하며 그 첫번째 파라미터로 객체의 포인터 this가 건네질 뿐이다.

    • 오해3. "그렇다면 각 instance가 method의 실행코드를 통째로 갖고 있지 않는 것은 확실하지만, method의 실행 코드의 포인터는 각 instance별로 보관하고 있는것이 아닌가?" 이것은 약가 애매한 오해이긴 하다. JVM 스펙에서는 class영역에 실행코드를 갖고 있으며, method 호출시 별도의 stack frame이 생성되어 실행되고 실행 완료시 복귀 주소를 전달한다.

    1.2 전역변수 #

    static에서 public field는 전역변수(global variable, 글로벌 변수)이다. 여기서 "글로벌 변수는 왜 안 되는가"에 대해 잠깐 생각해 본다. 우리는 흔히 "글로벌 변수는 될수있는한 사용하지 않는 것이 좋다"라고 한다. 그 이유는 글로벌 변수는 어디서든 참조할 수 있고 값을 변경할 수 있기 때문이다.

    또한 파라미터나 리턴값으로 교환해야 할 정보를 글로별 변수를 경유(사용)하여 건네주면 함수의 역할이 불분명 해지고 흐름도 애매해 진다. 마지막 이유로는 "글로벌 변수는 하나밖에 없다"는 것이다. 이는 어디서 이값을 변경했는지 알 수 없게 하는 지름길이고 실무에서도 간혹 발생하긴 하지만, 이 하나밖에 없는 변수가 버전업으로 두개가 필요하게 되었을때 확장도 대형 프로젝트에서는 힘들어진다.

    따라서 static에서 public은 final을 붙여 상수로 사용해야지 그 외의 용도는 자제하는 것이 좋을 것이다.

    • (참고) final 초기화에서의 주의점. 예를 들어 다음과 같은 코드를 보았을때 우려되는 점은 무엇인가?

    public final static Color WHITE = new Color(255, 255, 255);
    

    위의 코드는 java.awt.Color에서 발췌한 것인데, final 변수는 한번 초기화 되면 변경이 불가능한데 object로 초기화 할 경우 WHITE라는 필드가 변경될 수 없는 것이지 그것이 가리키는 객체는 아니라는 점이다.

    과거 신규 서비스 개발시 final 변수 필드에 설정파일을 읽어 cache하는 singleton class의 특정 member 를 이용하여 초기화 할 경우 이 멤버값이 변경되면 final 변수의 값이 변경되었는데 프로그램에서는 이상한 짓을 하는 원인을 찾기가 상당히 어려웠던 경험을 하고 난 후 부터 이런 코드는 냄새나는 코드로 여겨지게 되었다.

    static은 글로벌변수와 동일하므로 남발해서는 안된다. static을 사용할 경우 다음 두가지는 최소한 기억한다.

    1. static field는 final의 경우와 달리 정말 "하나여도 되는지" 여부를 잘 생각해야 한다.
    2. static method는 주저하지 말고 쓰되 다음 두가지의 경우 매우 활용적이다.
      1. 다른 많은 클래스에서 사용하는 Utility Method 군을 만드는 경우. (주로 Utility Class의 method)
      2. 클래스 안에서만 사용하는 "하청 메소드(private method)". 이유를 예를 들어 설명하면, 아래와 같은 조금은 과장된 클래스가 있다고 하자.

                    public class T ..
                        private int a;
                        private int b;
                        private int c;
                        
                        private int calc(){
                            c = a + b;
                            return c * c;
                        }
       
                        ....other method or getter/setter...
    

    위의 클래스 T의 경우 내부에서 calc라는 instance 함수를 사용하게 되면 c 의 값이 매번 변하게 된다. 이는 무심코 하는 실수로 클래스내에서 private method는 모든 멤버 instance 변수에 접근 가능하게 되면서 발생한다. c의 값이 변하지 않기를 바랄수 있다. 이때 안전한 방법은 다음과 같이 calc 하청 메소드를 static method로 수정하면 안전하다.

                private static int calc(int a, int b){
                   int c = a + b;
                   return c * c;
                }
    

    여기서 a와 b는 멤버 변수를 접근할수 없어 전달해야한다.(static에는 this가 없어 instance field를 참조할 수 없다는 것은 이미 위에서 설명했다.) 또한 c도 같은 이유로 사용할 수 없어 로컬 변수로 선언하고 사용하고 있다. 이럴 경우 메소드가 약간 커질수 있지만 instance member 변수를 안전하게 사용할 수 있다는 장점이 있다. 이것은 static을 다시한번 생각하게 하는 좋은 예가 되었을 것이다.

    2 Java는 Pointer언어이다? (Java에는 Pointer밖에 없다?) #

    2.1 Java는 primitive형을 제외하곤 모두 Pointer이다 #

    "Java에는 포인터가 없다" 라고 Java의 장점 이라고 생각하는 것은 입문자도 외우고 있다. 하지만 이 부분은 의외로 Java를 혼란스럽게 하는 주범이라고 생각한다. Java에 포인터가 없기는 커녕 primitive(int, short, char, long...등 JVM의 Heap에 object로 생성되지 않는것들)를 제외하면 "포인터 밖에 없는 언어이다"라는 명제가 성립되게 된다. 사실 여기서 포인터라고 함은 C 의 그것과는 조금 다른 reference(참조)이긴 하지만...

    "즉, 자바의 클래스형의 변수는 모두 포인터이다."

    2.2 null은 객체인가? #

    Java에서 공참조(힙에 실제로 참조되는 object가 없는 참조)의 경우는 당연히 객체가 붙어 있지 않다. 그러나, Java API 레퍼런스의 NullPointerException 항에는 다음과 같이 기술되어 있다.

    "object가 필요한 경우 application이 null을 사용하려고 하면 throw된다. 가령 다음과 같은 경우이다."
    • null object의 instance method 호출
    • null object의 field(member variables)에 대한 액세스 또는 그 값의 변경
    • null의 길이를 배열처럼 취득할 경우
    • null의 slot을 배열처럼 액세스 또는 수정
    • null을 Throwable처럼 throw 할 경우

    위에서 null object라는 말이 등장하는데 이는 공참조에 객체가 붙어 있지 않은 것이 아니라 null을 가리키는 객체라고 볼수 있다. 즉, 공참조라는 것은 JVM에서 봤을때 아무것도 참조하지 않는것이 아니라 null이라고 하는 object를 참조하고 있는것이다. 그러나 JSL 4.3.1에서는 다음과 같이 나와있다.

    "참조값(reference)은 이러한 객체의 포인터나 어떤 객체도 참조하지 않는 특수한 null참조가 된다"

    즉, 공참조는 어떤 객체도 참조하지 않는다고 단정하고 있다. 하지만 '==' 연산에 있어 두개의 객체가 모두 null이거나 동일한 객체 또는 배열 참조의 경우 true라고 되어있는것으로 봐서 서로 다른 두 객체가 동일한 null을 참조하고 있으므로 true가 된것이 아닌가 하는 생각을 할 수 있다.

    즉, null이 Object의 instance 형태는 아니지만 개념적으로 봤을때 null도 object라고 봐야 하지 않을까?

    2.3 String에 대하여 #

    String Object에 대한 생각.

                String str = "111222";
                String a = "111";
                String b = "222";
                String c = "111";
                String d = b;
                String t = str.substring(0,3);  //111
    

    위의 소스를 보고 다음이 참인지 생각해 보자. (==연산자는 포인터의 비교이지 값의 비교가 아님)

    1. str == (a + b) ==> 이것은 두개의 참조와 하나의 참조를 비교했으므로 당연히 false이다.
    2. a == b ==> 이것은 당연히 false
    3. d == b ==> 이것은 동일한 reference이므로 true
    4. a == t ==> a 와 t 는 둘다 값이 "111"이다. 하지만 이것은 서로 다른 참조를 가져 false이다. 그렇다면 다음 5번도 false일까?
    5. a == c ==> 이것은 true이다. 아.. 4번과 혼란스럽다. 이것이 참인 이유는? ==> 이것의 해답은 JSR 3.10.5에 다음과 같이 나와 있기 때문이다.

    "동일한 내용의 문자열 리터럴에 관해서는 인스턴스를 하나밖에 생성하지 않는다."

    즉, 위의 a와 c 는 '=' 를 이용하여 문자열 리터럴을 생성하게 되는데 a 에서 이미 만들어 놓았으므로 c에서는 그것을 참조한다.

    2.4 객체지향의 캡슐화 파괴 주의 #

    "object pointer를 반환하는 getter method는 객체지향의 캡슐화가 파괴될 가능성이 있다." 이는 object형의 field(member variable)의 getter에서 이 object를 그냥 반환하면 이 object를 받은쪽이나 참조하고 있는 다른쪽에서 이 object의 내용을 변경하게 되므로 사실 캡슐화(은닉)는 이루어 지지 않았다고 봐야한다.

    "이럴 경우 object를 clone(복제) 하여 반환하지 않아도 되는지를 반드시 생각해 본다."

    object의 복사에는 shallow copy와 deep copy가 있다.

            //(참고)Member에는 두개의 field(Identity Class 형의 ID와 Family Class 형의 family)가 있다. 
            
            /** shallow copy */
            Member shallowCopy(){
                Member newer = new Member();
                newer.id = this.id;
                newer.family = this.family;
                
                return newer;
            }     
            
            /** deep copy */
            Member deepCopy(){
                Member newer = new Member();
                newer.id = new Idetity(this.id.getId(), this.id.getName());
                newer.family = new Family(this.family.getFamilyName(), this.family.getFamilyInfo());
                
                return newer;
            }
            
    

    위 소스에서 보듯이 shallowCopy 는 object를 복사하여 반환한것 처럼 보이지만, 사실은 Member object만 새로 생성되었을뿐 Member의 field는 newer와 this 둘다 서로같은 힙의 id와 family를 참조한다. 하지만 두번째 method인 deepCopy의 경우 Member의 field를 새로 생성하여 복사하므로 서로 다른 id와 family이다.

    "Java에서는 clone이라는 method가 준비되어 사용되는데 이는 기본이 shallow copy임을 명심해야 한다. deep copy를 사용하기 위해서는 clone method를 overload하거나 따로 만들어 직접 기술해야 한다." (참고) object를 immutable(변하지 않는, 불변의 객체)로 만드는 요령
    1. 모든 field(member variable)를 생성자(constructor)를 이용하여 초기화 한다.
    2. 모든 field는 private으로 선언하고, getter method는 만들되 setter는 기술하지 않는다.

    즉, 값을 변경하기 위해서는 object를 다시 만들어야만 하는 불편은 있지만 안전하게 사용하려 할때 유용하다.

    2.5 배열에 대하여 #

    2.5.1 배열은 object 인가? #

    JVM에서 배열은 object로 취급되어 object와 같이 aload, astore와 같이 bytecode로 기술되어 진다. int[] iarr = new int10; 에서 보는것과 같이 new로 Heap 영역에 object를 생성하므로 object임을 알 수 있다.

    2.5.2 배열의 length는 왜 field(member variable)인가? #

    String의 길이를 구할때는 length()와 같이 method를 이용하는데 배열은 object임에도 불구하고 legth와 같이 필드로 되어있다. '이래도 Java가 완전한 객체지향 언어인가' 라는 의심이 들게 한다. 그렇다면 length가 public이므로 array.length = 100; 과 같이 하면 배열 크기가 변경되나?

    이것은 컴파일 오류가 난다. length는 final이라 값을 변경 할 수 없다는 것이다. 그렇다면 final field로 한 이유는 무엇이냐는 Java News Group에 찾아보면 대부분이 "효율을 위해서"라고 되어 있다. JIT compiler를 사용하지 않는한은 method보다는 field가 빠른건 당연한 것이다.

    그런데 정말 알수 없는것은 byte code에서는 arraylength라는 전용명령으로 컴파일 된다. 즉, length는 Java의 문법이 어찌되었든 JVM레벨에서는 field가 아닌것이 분명하다. 그렇다면 효율을 위해서 field로 했다는 것은 도데체 무슨 소리인가?

    전문가들의 대답에는 이것은 Java의 수수께끼 중 하나라고 대답하는 사람이 많다고 한다.^^;

    2.5.3 final과 배열에 대하여... #

    우리가 흔희 앞에서도 나온바 있지만 final은 값을 변경할 수 없는 것이라고만 생각하지 object로 되어 있을 경우 그 object는 변경 가능하다는 것을 잊곤한다. 배열도 object이므로 마찬가지다.

    final int[] iarr = new int[5]; 일경우 iarr = null; 은 에러가 나지만 iarr[3] = 5; 는 에러가 나지 않는다. 즉, final이 지정되어 있는것은 iarr이지 iarr이 가리키는 곳 배열의 요소가 아닌 것이다.

    2.5.4 "Java에서의 다차원 배열은 존재하지 않는다." #

    가령 2차원 배열 처럼 보이는 int[][] iarr 또는 int[] iarr[] 은 일차원 배열 두개이지 2차원 행열 구조가 아닌것이다. 즉, 두개의 배열은 각각이 배열로 되어 있는 것이지 테이블(행열)형태가 아니다.

    2.6 인수(parameter/argument)전달의 개념 #

    2.6.1 "Java에서 parameter(argument) 전달은 무조건 'call by value' 이다" #

    primitive type의 경우 호출한 쪽의 변수값은 호출 받은 method내에서 값이 변경되어도 변경되지 않는다. reference type의 경우도 reference되는 object에 대해서는 함께 변경되지만 reference pointer는 call by value이다. object를 가리키는 pointer는 call by value로 변경되지만 Heap의 실제 object내용은 변경되지 않는다.

    2.6.2 "C와 같은 언어는 static linking이지만, Java는 dynamic linking이다." #

    따라서 Java는 Class 파일이 처음에 한꺼번에 memory에 읽혀지는 것이 아니라 런타임시에 그것이 필요해 졌을때 읽혀지고 링킹된다. static field의 영역도 Class가 읽혀지는 시점에 비로서 확보된다. 이렇게 되면 최초 가동시간이 단축되고 끝까지 사용하지 않는 Class의 경우 신경쓸 필요가 없어지게 된다.

    따라서 static field는 프로그램이 시작되어 해당 Class가 필요해 졌을때 JVM이 알아서 load/link 해 준다. 즉, static field는 프로그램이 실행되기 시작할 때부터 끝날때까지 계속해서 존재하는 것이라고 보면 된다. (참고) 링킹(linking)의 의미

    link된다는 것은 Class가 memory에 loading될 때 특정 메모리 번지에 loading되는데 이 메모리 번지는 loading될때 마다 다른 번지수에 loading된다. 이때의 메모리 주소값(Java에서는 실제 메모리 값이 아닐 수 있다)을 현재 실행중인 프로그램에서 알 수 있도록 하여 해당 Class에 대한 참조가 가능하도록 연결하는 과정이다.

    정적(static) link라는 것은 이러한 메모리에 대한 주소 정보를 컴파일 시에 compiler가 미리 결정하는 것이고, 동적(dynamic) link라는 것은 프로그램 수행 중 결정되는 것을 의미한다. 정적인 link의 경우 직접적으로 메모리의 번지값이 할당 되는 것이 아니라 offset값(기준위치로 부터의 index값)으로 연결시킨다.

    2.7 GC 에 대하여 잠깐! #

    2.7.1 "Garbage Collection은 만능이 아니다." #

    Java에는 free가 없다. GC가 알아서 해준다. 하지만 GC 수행중에는 프로그램이 멈추는 것과 동일한 증상이 나타나기 때문에 GC가 자주 발생하지 않도록 프로그램 해야 한다. 서비스 되고 있는 시스템에서도 가끔 시스템이 응답이 늦어지는 시점이 있는데, 이는 GC가 수행되고 있는 중이 대부분이다.

    그렇다면 GC가 자주 발생하지 않도록 해야 하는데 가장좋은 방법은 무엇일까? 그것은 바로 불필요한 객체를 생성하지 않는 것이 아닐까?

    개인적으로 Java에 free가 없는것이 너무나 든든하게 느껴진다. 이유는 두개의 변수가 Heap내의 하나의 object를 reference하고 있을 경우 실수로 하나의 변수만 free해 버리면 나머지 하나는 dangling pointer라하여 reference pointer가 모르는 사이데 사라져 버려 곤경에 처하는 것을 예방해 주기 때문이다.

    참고로 Object class에는 finalizer라는 method가 있어 GC 수행시점에 호출되는 method가 있지만 이것은 GC가 언제 수행될지 알 수 없으므로 과신하지 말아야 할 것이다.

    2.8 Java Pointer 결론 #

    2.8.1 "결국 Java에는 pointer가 있는 것인가, 없는 것인가?" #

    Java는 Heap내의 Object를 참조(reference)하고 있고, 참조는 결국 개념이 포인터와 같은 것이므로, "Java에는 pointer가 없다"는 것은 어불성설이다.
    // 이부분에 대해 Object를 이해하시면 족히 이런 문제는 사라질것으로 봅니다.
    // 클래스에 대한 인스턴스(object)들은 reference로 밖에 가질(참조될)수 없기 때문입니다.
    // 컴파일러 입장이 아닌 언어 자체의 사상을 가지고 쉽게 이해시키는 것이 좋을것 같습니다.

    JSR 4.3.1을 보면 다음과 같은 말이 나온다.

    "참조값(reference)은 객체의 pointer이거나, 또는 어떠한 객체도 참조하지 않는 특수한 null 참조가 된다"

    또한 java.sun.com의 Java programmer's FAQ에 "Java는 pointer가 없다고 하는데, linked list는 어떻게 만들어야 하나?"라는 질문에 다음과 같이 답변이 나와있다.

    (답변) Java에 관한 많은 오해중에서 이것이 가장 심각한 것이다. 포인터가 없기는 커녕 Java에 있어 객체지향 프로그래밍은 오로지 pointer에 의해 행해진다. 다시 말새 객체는 항상 포인터를 경유해서만 access되며 결코 직접적으로 access되지 않는다. pointer는 reference(참조)라고 불리며 당신을 위해 자동으로 참조된다.

    "Java에는 pointer가 없고 주장하는 모든 서적과 글들은 Java의 reference사양에 모순된다고 봐야 할 것이다."

    3 상속과 interface의 문제점 #

    3.1 상속 #

    3.1.1 상속에 있어서의 생성자(constructor) #

    "child의 default 생성자가 있으면 그 생성자에는 parent의 생성자(super()) 호출이 compile시 자동 삽입된다." 따라서 super() 이전에 다른 코드가 있으면 object가 생성되기 이전이므로 오류를 발생하게 된다.

    3.1.2 "down cast는 본질적으로 매우 위험하다" #

    down cast - child의 type으로 parent를 casting - 는 parent 형태의 type이 정말 child type인지 compile시에는 알 수 없다. 실행시에 type check가 이루어 지므로 runtime시에 ClassCastException이 발생할 가능성이 커진다.

    "프로그래밍시 오류는 가능한한 compile시에 처리하는것이 좋다."

    3.1.3 "추상클래스에 final이 있으면 compile error이다" #

    abstract method가 있는 클래스는 추상 클래스이고 추상클래스는 상속되지 않으면 아무런 의미가 없기 때문이다.

    3.2 interface #

    3.2.1 "interface는 interface일뿐 다중 상속의 대용품이 아니다." #

    interface를 method signature - 추상클래스와 같이 구현부는 없이 선언부만 있는 method - 의 용도로 생각하는것이 Java에서는 옳다. 즉, interface는 final field와 abstract method가 있는 클래스와 동일하긴 하지만 상속의 의미와는 그 용도가 다르다. 공통된 type을 정의하는것으로 보는것이 맞는 의미일 것이다.

    또한 interface는 클래스를 재이용하기 위해 상속을 사용하여 캡슐화의 파괴를 수반하는 것을 방지하는 기능이있다. 상속을 사용하면 모두 구현후 마치 소스 코드가 여기저기 천 조각을 주워 모아 만든 '누더기'같이 보이는 것에 한숨을 쉰 경험이 있을 것이다. 이 부분을 interface로 구현하면 보다 깔끔한 코드가 나오게 된다. 물론 public과 protected를 적절히 잘 사용해도 되긴 하지만 말이다.

    하지만 상속은 메소드 오버라이드한 경우 클래스를 마음대로 개조해 버린 셈이 되므로 어디선가 묘한 모순이 발생하게 될 가능성도 높아질뿐 아니라 추상클래스의 경우 실제 구현부가 어디에 위치하는지도 에매하게 느껴질 수 있어 불안한 코드가 되고 만다.

    3.3 상속 제대로 사용하기 #

    "그렇다면 제대로 된 상속은 어떻게 판단할 수 있을까?"

    상속은 'is a'관계가 성립해야 올바르다. 즉 '서브클래스(자식) is a 슈퍼클래스(부모)'가 성립해야 한다. 예를 들면 Red is a Color는 올바른 명제이지만 Engine is a Car는 'has a'관계이므로 상속이라고 볼 수 없다. "따라서 'has a'관계는 상속이 아니므로 composition과 delegation을 이용하면 된다."

    composition은 '객체를 field가 갖게 하는 방법'을 의하므로 'has a'관계가 정확히 성립한다. "상속 대신 composition과 delegation(조작이나 처리를 다른 객체에 위임)을 사용하면 다음과 같은 이점이 있다."

    1. 상속에서는 슈퍼클래스가 허용하고 있는 조작을 서브클래스에서 모두 허용해야 하지만, composition과 delegation에서는 조작을 제한할 수 있다.
    2. 클래스는 결코 변경할 수 없지만, composition하고 있는 객체는 자유롭게 변경할 수 있다. 예를 들면 학생 클래스가 영원이 학생이 아니라 나중에 취직을 하여 직장인 클래스가 될수 있다.
    상속을 composition과 delegation으로 변경하는 요령은? 여기서 Shape를 상속한 Polyline과 Circle을 변경한다면 다음과 같다.
    1. Shape(부모)의 공통된 내용을 구현한 구현 클래스(ShapeImpl)를 만든다.
    2. Polyline과 Circle 클래스에서 ShapeImpl을 composition하고 부모와 공통되지 않는 method를 각각 위임 받는다.
    3. ShapeImpl 클래스의 method를 추출한 ShapeIF interface를 작성하고 Polyline과 Circle에서는 implements 한다.

    4 package와 access 제어에 관한 이해 #

    4.1 package #

    4.1.1 "package는 '계층구조' 인가?" #

    처음 Java를 접하면서 package에 대해 이해할때 마치 파일시스템과 같은 계층구조라고 이해하게 되어 ' import /test/*.class '는 왜 안되는지 의아해 했던 기억이 있다. 그리고 부모 directory에 있는 클래스에서 왜 자식 directory에 있는 Class를 import없이 사용할 수 없는지도 이상했다.

    즉, package에서 동일 부모라도 서로 다른 package는 완전히 별개의 package였던 것이다. 이 부분에 관해서는 JLS 7.1 에서 다음과 같이 기술되어 있다고 한다.

    "package가 계층적인 이름 구조로 되어 있는 것은 관련된 package를 일정 규약에 따라 체계화하기 위해서이고, package 안에서 선언되어 있는 top-level형과 동일한 이름을 가진 서브 package를 갖는 것이 금지되어 있는 점을 제외하면 특별한 의미는 없다."

    즉, Java에서는 package이름을 계층적으로 명명할 수 있을뿐 package구조 자체에는 어떤 계층적인 의미 부여도 할 수 없는 것이다. 다시 말해서 Java에서는 package이릉을 계층적으로 명명할 수 있을 뿐 구조자체는 평평한 것이다. 실제로 바이트 코드의 내용을 보면 깨어진 내용중에 java/lang/String과 같이 완전한 한정이름을 class이름으로 사용됨을 알 수 있다.

    4.1.2 "compiler 가 인식하는 class검색 순서(소스코드내 클래스가 발견될 경우 그 클래스의 위치를 찾는 순서)" #

    1. 그 class자신
    2. 단일형식으로 임포트된 class
    3. 동일한 패키지에 존재하는 다른 class
    4. 온디멘드 형식(..* 형태) 임포트 선언된 class

    4.2 access 제어 #

    public은 다른 package에서 참조 가능하고, 무지정할 경우 동일한 package내에서만 참조 가능하다.

    4.2.1 "interfacde member의 access 제어" #

    interface의 member field/method는 모두 public이다. interface member에 protected나 private을 지정할 수는 없다. 또한 public을 지정할 필요도 없다. 지정해도 상관없지만 JLS 9.4에서는 다음과 같이 명시되어 있다.

    "interface의 method에 대하여 public 수식자를 지정하는 것이 허용되고 있지만, style로서는 전혀 권장할 수 없다."

    즉, interface member는 모두 public이라 되어 있는 것이다. 또한 James Gosling도 집필에 참가한 '프로그래밍 언어 Java 3판'에서는 다음과 같이 기술되어 있다고 한다.

    "public이 아닌 member를 interface에게 갖게 하는 것은 아무런 의미가 없다. interface의 member에 대한 access제어에 interface 자신의 access 제한을 적용하는 것이므로 이것은 아무런 의미가 없다."

    4.2.2 그렇다면 interface를 다른 package에 대하여 숨기고 싶으면 어떻게 하는가? #

    그것은 interface 자체 선언에 public이 아닌 것을 적용하면 되는 것이다. member별로 제어할 수 없어 불편한 면도 있지만, 나름대로 그럴 듯한 규칙이다. 하지만 이것은 정말 이상한 논리가 아닐수 없다. public이 아닌 interface에 public method가 무슨 의미가 있는지 알 수 없기 때문이다. 이 interface를 구현한 클래스에서도 method는 모두 public이 되어야 하는데, 이것도 아무래도 이상하다.

    5 기타 Java 기능 #

    5.1 Thread #

    5.1.1 "Multi Thread에서는 흐름은 복수이지만 data는 공유될 수 있다." #

    Multi processing에서는 흐름은 복수이지만 data는 독립되어 있다. 하지만 Multi Thread에서는 Heap과 static영역에 관한 한 2개 이상의 Thread 사이에 공유가 이루어 진다. 따라서 2개 이상의 Thread에서는 동일한 static field를 참조할 수 있고, 동일한 객체에 접근할 수도 있다. 그러나 stack만은 Thread별로 독립되어 있다. stack은 method에 들어가는 시점에 확보되고 빠져 나오는 시점에 확보되고 빠져 나오는 시점에 Free 되므로 2개 이상의 Thread에서 공유할 수는 없는 것이다.

    5.1.2 "Thread는 객체와 직교하는 개념이다." #

    Multi Thread는 어디까지나 Thread라는 처리 흐름이 여러 개 존재할 수 있다는 의미이다. 요약하면 다음 3가지 이다.
    1. Multi Thread에서는 Thread라는 처리 흐름이 2개 이상 존재할 수 있다.
    2. 어떤 Thread에서 움직이기 시작한 method가 다른 method를 호출 했을때 호출된 측의 method는 호출한 측의 method와 동일한 Thread에서 동작한다.
    3. Thread의 경계와 객체의 경계는 전혀 관계가 없다. 즉, Thread와 객체는 직교하고 있다.

    5.1.3 "Synchronized 의 이해" #

    Multi Thread 기반의 programming시에 synchronized를 놓쳐 자주는 일어나지 않으나 뭔가 잘못되어 가는것을 경험한 적이 있다. 즉, 이것이 원인이 되어 버그가 발생한 경우 그 버그는 재현성이 지극히 낮아지기 때문에 꽤 고생을 하게 된다. 이런 사태가 발생하게 되면 버그의 원인을 찾기가 어렵게 되고 해당 application은 언제 발생할지도 모르는 오류가 있는 상태 그대로 운영되기 때문에 심각성이 내포되어 있다고 할 수 있다.

    이러한 사태를 방지하기 위해서는 critical section을 2개 이상의 Thread가 동시에 실행되지 않도록 '배타 제어'를 해야한다. 그 키워드가 바로 synchronized이다.

    synchronized에는 synchronized(obj){} 형태와 method에 synchronized 를 붙이는 두가지 방법이 있는데, 이 둘은 범위만 같다면 같은 의미이다. 예를 들어 설명하면, 아래의 소스에서 method1()과 method2()는 동일하다.

            synchronized void method1(){
                ...
            }
            
            void method2(){
                synchronized(this){
                    ...
                }
            }
    

    이렇게 동일한 의미를 두가지로 만든것은 method단위로 synchronized를 걸 일이 그만큼 많다는 것을 의미한다. 많이들 오해하고 있는 부분이 위의 소스에서 알수 있듯이 method에 synchronized를 사용한다는 것은 '그 객체에 해한 조작은 동시에 하나의 Thread라는 것이지 method 호출이 하나의 Thread가 아닌것이다'

    그렇다면, Thread A가 obj의 Lock을 설정하고 있는 상태에서 다시 한번 Thread A 자신이 obj의 Lock을 설정하면 어떻게 될까? 이 경우 Thread A는 이미 이 obj에 대하여 Lock을 보유하고 있으므로 기다리지는 않아도 된다. 위의 소스에서 method1에서 method2를 호출한다면?

    method1에서 이미 obj의 Lock을 보유 했으므로 method2의 synchronized(this) 부분에서는 Lock을 기다리지 않아도 된다.

    즉, Lock의 기준이 특정Thread에 있어서 Lock의 기준이 method가 아닌 object인 것이다. 이 규칙 덕분에 synchronized method도 재귀호출이 가능해지고, synchronized method가 동일한 instance의 synchronized method를 호출할 수 있는 것이다.

    주의할 점은 static method에 synchronized가 있다면 static은 this참조가 없다고 위에서 설명하였으므로, 이 클래스의 Class 객체를 Lock하게 된다. 기준이 xx.Class가 되는 것이다.

    5.1.4 "Thread 사용법의 정석은?" #

    Thread 사용법에는 다음 두가지의 정석이 있다.
    1. Runnable을 implements하고 Thread의 참조를 보유(composition) 하는 방법. 이경우는 단지 Runnable만 implement함으로서 해결되는 경우가 대부분이긴 하지만, 그 class 내에서 해당 class의 Thread를 조작하게 된다면 composition한 Thread 객체에 delegation하면 된기 때문이다.
    2. Thread class를 상속하는 방법. JDK의 소스를 보면 Thread class에는 Runnable을 implements 하고 있다. 그리고 run method는 native method이다. 따라서 Thread를 상속한 모든 클래스는 사실 Runnable을 implements하고 있는 것이다. run method는 abstract가 아니므로 구현되어 있고 우리는 이를 오버라이드하여 사용하고 있다. 이 방식을 사용하면 Thread의 method를 안팍으로 자유롭게 호출할 수 이지만, 이미 다른 class를 상속하고 있다면 이 방식을 사용할 수는 없다.
    JDK API Reference의 Runnable에 과한 설명중에 다음과 같은 내용이 있다.

    "Thread class의 method중 run method만을 오버라이드하여 사용하는 경우는 Runnable interface만 implements하여 사용하면 된다. 왜냐하면, class의 기본적인 동작을 수정 또는 확장하지 않는한 그 class를 sub class화 하는 것은 바람직하지 않기 때문이다."

    그렇다면 위에서 언제나 1)번 방식을 사용하면 되는 것 아닌가 라는 의문이 생기게 된다. 왜 귀찮게 2)의 방법을 고민하는 것인가, 극단적이긴 하지만 만일에 사태에 이 클래스가 다른 클래스를 상속받게 되는 경우도 있을수 있는데.

    하지만 이것은 아닐것이다. 만약 이렇다면 Thread class가 Runnable을 implements할 필요가 없었을 것이기 때문이다. 또한 Thread는 생성자의 인수로 Runnable의 reference를 취득한 후 계속해서 그것을 보유한다는 것도 이상하다. Thread에 있어 Runnable이 필요한 것은 start() 때 뿐이므로 start()의 인수로 Runnable을 건네줘도 좋을 것이다.

    그럼에도 불구하고 굳이 Thread에서 계속적으로 Runnable을 보유하고 있는 것은 Runnable객체와 Thread를 강하게 결합시키려는 의도 때문이다. 이것은 의도적으로 위의 2)의 방법을 권장하는 듯한 느낌을 받게 하는듯 하다.

    그렇다면 API Reference의 말은 단지 상속을 피하라는 의미만 있는 것인가? 마지막으로 한가지 추정이 되는 부분은 Thread에는 suspend()나 stop()등과 같은 method가 현재 모두 deprecate되었다. 또한 sleep()이나 yield()는 모두 static method이므로 굳이 Thread 객체를 보유할 필요가 없다.

    그렇다면 위의 1)의 방법에서 Thread객체를 composition할 필요가 없어진다.

    "그렇다면 Thread를 아무도 보유하지 않고 Runnable만 implements한 방식이 최선인가?"

    무엇이 정답인지 도무지 알길이 없다. ^^;

    5.2 Exception #

    5.2.1 "finally 절은 반드시 어떠한 경우에도 실행되는가?" #

    try ~ catch 문의 finally 절은 'loop라면 break, method라면 return 절'을 만나도 뒤에 있는 finally절은 수행된다. 하지만 다음의 경우는 그렇지 않다.

            try{
                ...
                System.exit(1);
            }catch(...){
            }finally{
                ... //이 부분은 실행되지 않는다.
            }
    

    5.2.2 "예외의 종류 3가지 (Error, RuntimeException, 그밖의 Exception)" #

    5.2.2.1 Error #
    이에 관해선 JLS 11.2.1에 다음과 같이 기술되어 있다. "체크되지 않는 예외 클래스(Error와 그 Sub class)는 프로그램안의 다양한 위치에서 발생할 가능성이 있으며, 회복이 불가능하기 때문에 컴파일시 체크되지 않는 것이다. 이러한 예외를 프로그램에서 선언한다고 해도 난잡하고 무의미한 것이 될 뿐이다."

    Java의 클래스 librury에서 Error의 sub class를 살펴봐도 AWTError, LinkageError, ThreadDeath, VirtualMachineError 등 'catch해도 소용 없을 것' 들 뿐이다. (OutOfMemoryError는 VirtualMachineError 아래에 위치한다.)
    5.2.2.2 RuntimeException #
    위의 Error 이외의 Exception들은 application에서 catch할 가능성이 있는 예외들이다.(버그가 없으면 발생하지 않는 예외들) 그리고 RuntimeException은 '어디서든 발생할 가능성이 있는 예외'이다. RuntimeException의 sub class로는 NullPointerException, ArrayIndexOutOfBoundException, ClassCastException 등을 들 수 있다. '이러한 예외는 버그가 없는 한 발생하지 않으므로 일일이 throws 를 작성하지 않아도 된다.'

    프로그램에 버그가 없는 한 발생할 수 없는 예외가 발생한 경우 C 언어와 같이 영역 파괴가 일어나기 쉬운 언어라면 프로그램 전체를 종료시키는 것이 정답이겠지만, Java와 같이 영역파괴가 일어나지 않도록 실행시 체크(JVM Classloader의 formal verification process)를 하고 동적으로 프로그램을 load하는 언어에서는 국소적인 NullPointerException 때문에 프로그램 전체를 중지시켜서는 안 될 것이다.

    따라서, RuntimeException은 catch하지 않는 것이 바람직하다고 볼 수 있다. 버그가 있는 프로그램은 신속히 종료시키는 것이 대부분의 경우 최선의 방책이라 생각하기 때문이다.
    5.2.2.3 그밖의 Exception #
    위의 RuntimeException이외의 Exception의 sub class는 사용자의 잘못된 조작 등으로 인해 프로그램에 버그가 없어도 발생할 가능성이 있고 그에 대하여 프로그램이 확실히 대응해야 하는 경우에 사용된다. 예를 들면 FileNotFoundException등이다.

    그런데 개발하다 보면 이상하고 의아한 것이 하나 있다. 숫자 부분에 문자를 넣었을때 발생하는 NumberFormatException이다. 이것은 이상하게도 RuntimeException의 sub class이다. 이것은 RuntimeException이 아니었으면 하는데 NumberFormat체크는 Runtime시에만 가능한 모양이다.

    5.2.3 "OutOfMemoryError는 어떻게 처리해야 하는가?" #

    예전에 Swing에서 Tree구조를 이용하는 프로젝트를 한적이 있다. 이때 Tree에 branch와 node가 무수히 생기자 JVM은 OutOfMemoryError를 내뱉었다. 이에 급한 마음에 OutOfMemoryError를 catch하여 사용자에게 재시작을 요청하는 Dialog를 띄우도록 수정하였다면 이 Dialog가 과연 떳을까? 현재 메모리가 부족한 판에 Dialog를 띄울 메모리가 남아있질 않았던 것이다. 다행히 Dialog가 떴어도 작업은 계속되지 못했을 것이다. NullPointerException가 나기 때문이다.

    원인은 나중에 찾았는데, Tree구조에서 부모부터 자식들을 붙이는 순으로 Tree를 구성하는데 자식들을 줄줄이 붙여나가다가 메모리 부족현상이 발생하였고 NullPointerException은 자식이 없으니 클릭하는 순간 null을 반환하여 발생하였던 것이다.

    OutOfMemoryError의 가장 좋은 해결책은 불필요한 객체를 만들지 않는 것이었다. 그리고 Tree생성시에도 자식부터 만들고 부모를 만드는 순서로 프로그램을 수정하여 프로젝트를 정상적으로 마칠수 있었다.

    마지막에 드는 심정은 프로그램이 OutOfMemoryError를 일으키는 원인이 과연 이렇게 구성되어 발생했는지 어떻게 알수 있을까 하는 의문이다.

    5.3 Object Serialize #

    Java에서는 ObjectOutputStream의 writeObject() method에 데이타 구조 저장소의 참조만 건네주기만 하면 그 안에 있는 모든 객체를 1차원 stream으로 출력해 준다. (파일이나 ByteArrayOutputStream을 이용한 메모리로) 단, static field는 Serialize되지 않는데 이는 Serialize의 대상이 instance 객체뿐이기 때문이다.

    5.3.1 "Serialize를 위해서는 marker interface인 java.io.Serializable interface를 implements해야한다." #

    여기서 marker interface는 java.lang.Cloneable과 같이 method와 field의 정의는 없지만 객체 Type을 위한 interface이다. 예전에 Serialize를 이용하여 데이타를 유지하는 프로젝트를 한 적이 있는데 그때 생각했던것이 '모든 class들이 기본적으로 Serializable을 implements하고 있으면 편할텐데..'라는 생각이었다. 하지만 이것은 상당히 위험한 발상이었다.

    Serializable이 기본으로 implements되어 잇으면 엉뚱한 객체까지 Serialize되고 그것을 알아채지도 못하는 사태가 일어날 가능성이 높다. Serializable이 optional인 이유는 이러한 이유 때문이리라..

    5.3.2 "super class는 Serializable이 아닌데 sub class만 Serializable인 경우의 문제점" #

    Serialize을 이용하여 프로젝트를 할때 한번쯤 실수할 수 있는 부분이 상속된 class의 Serialize이다. 컴파일 에러도 없고 Deserialize도 잘 되었다. 하지만 키가 되는 값이 null과 0이었다. 영문을 몰라 다른곳을 헤매여도 보다가 결국 찾은 원인은 부모의 field는 Serialize되지 않는다는 것을 알게 되었다. transient와 마찬가지로 형식별 default 값으로 채워졌었다. 이는 컴파일과 실행시 아무런 오류없이 실행되어 나를 힘들게 하였기에 Java가 원망스러웠던 기분좋은 추억이다. ^^;

    5.3.3 "transient field의 복원(?)관련" #

    Serialize를 이용한 프로젝트를 할때는 writeObject와 readObject를 이용하여 기본적으로 제공하는 Serialize를 customizing할수있다.

    Serializable에 대한 API reference에도 다음과 같이 나와있다.

    "Serialize와 Deserialize에 대한 특별한 handling을 위해서는 다음 두개의 특별한 메소드를 구현하면 된다."

    private void writeObject(java.io.ObjectOutputStream out) throws IOException;
    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
    

    이 두 method가 private으로 되어 있는 것을 보고 처음에는 의아해 했었던 기억이 있다. 이를 protected나 public으로 하면 제대로 동작하지 않는다. 이는 override가 이니기 때문이다. 사실은 속에서 reflectiond을 이용하여 강제적으로 호출되고 있는것이다. reflection에서는 private method까지 찾을 수 있기 때문이다.

    또한 private으로 한 가장 큰 이유는 Serialize를 객체자신이 직접 해야 안전하다는 의미도 있지 않을까 하는 생각도 든다. 다시 본론으로 들어가서 transient를 복원하는 것에 얘기를 하자면, 사실 transient는 Serialize대상에서 제외되는 것인데 복원을 할 수 있다는 말이 안된다. 하지만 프로젝트를 진행하다 보면 logic상 가능한 경우가 많이 있다.

    즉, 모든 field를 Serialize하지 않고 필요한 것만 하고 특정 field는 Serialize한 field들을 이용하여 복원하는 방법이다. 또한 Serialize당시의 객체 상태와 Deserialize시의 객체상태가 서로 다를 수 있는 field도 그것에 해당된다. cafeid만으로 나머지 field는 DB에서 읽어오게 한다면 나머지 field는 transient로 처리하고 Deserialize시 readObject()에서 복원하는 것이다.

    5.3.4 "Stack Overflow에 주의하라!" #

    Serialize를 하다보면 참조로 연결된 객체를 recursive하게 거슬러 올라가며 이것이 너무 깊어지면 Stack Overflow가 발생한다. 가령 linked list같은 경우이다. 이것을 Serialize하면 그 요소수만큼 recursive 호출이 발생한다. 과거(JDK1.3.0시절) 프로젝트 당시 JVM이 5111에서 Stack Overflow가 발생했던 기억이 있다.

    물론 실행시 java option에 -Xss 를 이용하여 statck 크키를 조절할 수 있지만 이것은 개발자가 아닌 실행하는 사람들에게 부담이었다. JDK의 LinkedList class의 소스를 보면 writeObject()와 readObject()를 다음과 같이 변경하고 있다.

            private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException {
                s.defaultWrtieObject(); //이 코드는 무조건 들어가게 되는데 이곳 소스의 System.arraycopy()에서 overflow발생한다.
                
                s.writeInt(size);   //이부분이 실제 추가되어 Stack Overflow를 예방한다.
                
                for(Entry e = ...)
                    s.writeObject(e.element);
                }
                ...
            }
            
            //readObject()도 이와 같은 개념으로 변경되어 있다.
    

    5.4 "nested class / inner class / 중첩클래스" #

    5.4.1 "중첩클래스의 개념" #

    개인적으로 중첩클래스를 어떠한 경우는 사용하지 않으려 한다. 사용하기가 만만치 않고 코드 읽기가 힘들어 지기때문이다. 하지만 '어떤 클래스 내에서 은폐할 목적으로 사용하는 클래스가 있다면 이것을 사용해야 한다' 실제로 Java의 AWT 클래스 Event Handler를 비롯하여 많은 클래스에서 중첩클래스를 사용하고 있다. 또한 내부 class는 그것을 둘러싸는 class의 instance(enclosing object라고 하는)의 field를 참조 할수 있는것도 장점이다. 하지만 이는 내부클래스가 아닐경우 부부 클래스를 new해서 사용하는것과 별반 다를께 없지 않은가.

    5.4.2 "내부클래스는 부모의 참조를 몰래 보유하고 있다." #

    내부 클래스의 instance는 부모의 instance에 대한 참조를 몰래 보유하고 있기 대문에 위에서 얘기한 부모의 field를 참조할 수 있는 것이다. 그러므로 static method에서는 내부클래스를 생성할 수 없다. 다음 예를 보면 바로 알수 있다.

            class Test{
                class InnerClass {
                    int i;
                    ...
                }
                
                public static void main(String[] args){
                    InnerClass icls = new InnerClass();
                    ...
                }
            }
    

    이 소스를 compile하면 다음의 오류가 발생한다. "non-static variable this cannot be referenced from a static context..." main method는 static이므로 this를 참조할수 없다는 것이다. 이는 InnerClass가 new 되면서 외부 클래스 Test의 this를 보유해야 하는데 여기서 static을 만나니 오류를 표출시킨것이다. 물론 일반 instance method에서는 오류가 나지 않는다.

    5.4.3 "local inner class에 대하여" #

    local inner class라 함은 method내에서 선언된 inner class이다.

            public class OuterClass {
                public int get(){
                    int i = 9;
                    int id = 99;
                    int id2 = 99;
                    final int id3 = 100000;
                    
                    class LocalInnerClass {
                        int id = 100;
                        
                        LocalInnerClass(){
                            System.out.println("LocalInnerClass");   
                        }
                        
                        int getId(){
                            return id3 + id;
                        }
                    }   
                    
                    LocalInnerClass lic = new LocalInnerClass();
                    return id + lic.getId();
                }   
                
                public static void main(String[] args){
                    OuterClass outer = new OuterClass();
                    System.out.println("id = " + outer.get());  
                    //결과 값은 "100000(id3) + 100(LocalInnerClass.id) + 99(OuterClass.get())" 인 100199가 나온다.
                }
                
            }
    

    위 소스의 LocalInnerClass는 get() 이라는 method에서만 보이는 class이다. 그리고 특이할 만한 부분이 OuterClass의 get() method에서 final로 선언된 id3이 LocalInnerClass에서 참조 가능해 진다. id2를 참조하면 compile error가 나지만 final로 선언된 것은 오류가 나지 않는다.

    이는 local variable은 method에서 나오는 순간 사라지는데, local inner class는 local variable보다 수명이 조금더 길기 때문에 final만 허용한 것이다.

    5.4.4 "anonymous class(무명클래스)에 대하여" #

    무명 클래스는 말그대로 이름이 없는 클래스이다.

            class AnonymousTest {
                private interface Printable {
                    void print();
                }
                
                static void doPrint(Printable p){
                    p.print();
                }
                
                public static void main(String[] args){
                    doPrint( new Printable(){
                                public void print(){
                                    System.out.println("this is new Printable print()");
                                }
                             });
                }
            }
    

    위 소스의 "doPrint( new Printable(){" 부분이 무명클래스 이다. compile을 수행하면 AnonymousTest$Printable.class, AnonymousTest$1.class, AnonymousTest.class 세개의 클래스가 생긴다. 여기서 AnonymousTest$Printable.class는 Printable interface이고 AnonymousTest$1.class이 무명클래스이다.

    이 소스를 보면 처음에 드는 의심이 Printable interface를 new 했다는 것이다. 여기서 굳이super class(이 소스에서는 interface)를 저정해야 하는 이유는 아무것도 상속하지 않는 무명 클래스의 instance를 만들어 봐야 의미가 없기 때문에 이렇게 한듯하다.

    "무명클래스는 어떤 class나 interface를 상속/구현 해야만 그 instance를 사용할 수 있는 것이다" 이처럼 무명 클래스를 사용하면 어떤 절차(수행)를 다른 method의 인수로 건네줄 수 있게 된다. 하지만 간단한 로직만 구현처리해야 한다.

    "무명클래스는 조금만 복잡해져도 급격히 소스의 가독성이 떨어지게 되므로 남용하지 않는 것이 바람직하다"

    6 이래도 Java가 간단한가? #

    6.1 method overload 에서의 혼란? #

    6.1.1 "overload란 이름이 가고 인수가 다른 method에 compiler가 다른 이름을 붙이는 기능" #

    overload를 구현하면 bytecode로 변환시 다른 이름으로 method가 변환되어 별개의 method로 처리된다. 이를 JVM에서 method descripter라 하여 Oolong asembler로 변화시 다른 형태의 method가 된다. 예를 들어 "void get(double d, long l)" 은 "get(DJ)V"로 변경된다. 여기서 D는 double, J는 long, V는 void를 의미한다.

    그런데 여기서 "get(DJ)" 부분만 method 이름이므로 return type이 다른 동일 method는 overload 할 수 없다. 따라서 overload는 정적(compile시 결정)이라는 명제가 성립니다. 그래서 동적으로 사용되면 compile시 오류를 표출한다. 아래의 소스를 보자. 여기에는 IFS라는 interface와 이를 implements한 Impl1, Impl2 라는 class가 있다.

            //IFS.java
            interface IFS {
                public String getName();
            }
            
            //Impl1.java
            class Impl1 implements IFS {
                public String getName(){
                    return "Impl1";
                }
            }
         
            //Impl2.java
            class Impl2 implements IFS {
                public String getName(){
                    return "Impl2";
                }
            }   
            
            //main이 있는 OverloadTest.java
            public class OverloadTest {
        
                static void pr(int i){
                    System.out.println("pr_int : " + i);   
                }
                
                static void pr(String s){
                    System.out.println("pr_string : " + s);   
                }
                
                static void pr(IFS ifs){
                    System.out.println("pr_string : " + ifs.getName());
                }
                
                static void pr_run(Impl1 i1){
                    System.out.println("pr_run : " + i1.getName());
                }
                
                static void pr_run(Impl2 i2){
                    System.out.println("pr_run : " + i2.getName());
                }
                
                public static void main(String[] args){
                    OverloadTest test = new OverloadTest();
                    test.pr(10);
                    test.pr("Jeid");   
                    
                    IFS ifs1 = new Impl1();
                    test.pr(ifs1);
                    
                    IFS ifs2 = new Impl2();
                    test.pr(ifs2);
                    
                    //pr_run(ifs1);
                    //pr_run(ifs2);
                }
            }
    

    위의 소스를 수행하면 정상적으로 compile이 될것인가?

    당연히 잘 된다. pr()은 overload를 잘 구현했다. 하지만 소스 하단의 두 주석문을 풀면 어떻게 될까? 이는 compile오류를 낸다.

            OverloadTest.java:36: cannot resolve symbol
            symbol  : method pr_run (IFS)
            location: class OverloadTest
                    pr_run(ifs1);
                    ^
            OverloadTest.java:37: cannot resolve symbol
            symbol  : method pr_run (IFS)
            location: class OverloadTest
                    pr_run(ifs2);
                    ^
            2 errors
    

    실제 위 둘의 pr_run method는 bytecode로 변환시 "pr_run(Lpackage_name.IFS)V"로 동일하게 생성된다. 따라서 compile시에 오류를 표출한다. 이 소스를 보면 알 수 있듯이 "method overload는 정적(compile시)으로 미리 결정되며, 동적(실행시판단)으로 사용할수 없다."

    6.1.2 "그렇다면 overload에서 실제로 혼동되는 부분은 무엇인가?" #

    다음 소스를 보고 실제로 수행되는 method를 찾아보라.

            class OverloadTest2 {
                static int base(double a, double b){ ... }  //method A
                
                static int count(int a, int b){ ... }  //method B
                static int count(double a, double b){ ... }  //method C
                
                static int sum(int a, double b){ ... }  //method D
                static int sum(double a, int b){ ... }  //method E
            }
    

    • base(3,4) 를 호출했을때 수행되는 method는? => 당연히 method A (3과 4는 정수라도 double이 되므로 정상적으로 수행됨)

    • count(3,4) 를 호출했을때 수행되는 method는? => B와 C중 갈등이 생긴다. 이럴경우 JVM은 가장 한정적(more specific)한 method를 찾는다. 여기서 3과 4는 정수형에 가까우므로 method B 가 호출된다.

    • count(3, 4.0) 을 호출했을때 수행되는 method는? => 이것은 4.0 이 double이므로 method C 가 더 한정적이므로 method C 가 호출된다.
    • sum(3,4.0) 을 호출했을때 수행되는 method는? => 이것은 당연히 type이 일치하는 method D.
    • sum(3,4) 를 호출했을때 수행되는 method는?? => 이런 코드가 소스내에 있으면 다음과 같은 compile 오류를 표출한다.

                 OverloadTest.java:48: reference to sum is ambiguous, both method sum(int,double)
                   in OverloadTest and method sum(double,int) in OverloadTest match
                        System.out.println("sum(3,4) = " + sum(3,4));
                                                           ^
                 1 error
    

    method D와 method E가 애매하다는 compile 오류이다. 이것은 둘중 어느것이 더 한정적인지 찾을 수 없으므로 bytecode 를 생성 할 수 없다는 것이다.

    "이렇듯 compiler에게 불필요한 오해(혼동)를 초래하는 overload는 사용하지 않는 것이 좋다. 개인적으로 overload를 가능한 사용하지 않으려 하고 필요하다면 인수의 개수가 다른 overload를 사용하는 편이다."

    6.1.3 (참고) 또다른 혼동, overload한 method를 override 하면? #

    overload란 compiler가 bytecode변환시 다른 이름을 붙이는 기능이라는 것을 위에서 설명했다. 따라서 super class에서 overload한 method를 상속하여 override하면 완전 별개의 method를 override한것처럼 JVM은 판단한다. 즉, overload와 override는 직교(전혀상관없는)하는 개념이다.

    6.2 상속/override/은폐 에서의 복잡함 #

    6.2.1 "Java class의 member 4 종류" #

    1. instance field
    2. instance method
    3. static field
    4. static method
    여기서 상속을 하였을 경우 runtime시 객체의 형식에 따라 선택되는 것은? 2번 instance method 뿐이다. 즉, 동명의 member를 sub class에서 선언했을 때 instance method만 override 되고 나머지는 완전 별개의 member가 된다. 따라서 위의 1,3,4는 sub class에서 동일하게 선언했을 경우 별개의 것으로 인식되며 compile시에 무엇을 access 할지 결정된다.

    즉, instance method는 override되지만 instance field/static field는 은폐된다. override는 실행시 객체의 형식에 따라 처리 할당되지만, 은폐의 경우는 compile시에 결정되고 만다.

    6.2.2 "override시 method 이름에 대한 함정" #

    과거에 코딩을 하던중 정말이지 어처구니 없는 경우를 당했다. override 하는 method이름을 잘못써서 황당한(?) 고생을 한적이 있다. super class의 writable()이라는 method를 writeable()이라고 override(?)하였는데 프로그램 수행 중에 writable()이 항상 false가 나오는 것이 아닌가? 그래서 소스를 추적추적 하다 몇시간을 허비했었던 기억이 있다.

    java를 접한지 얼마되지 않았고 요즘같이 eclipse같은 에디터도 없이 메모장에서 코딩하던 시절이라 더욱 고생했던것 같다. 한참 후에야 우연히 스펠링이 잘못된걸 알고 얼마나 황당했던지... 지금 생각하면 이것도 좋은 추억이리라.

    무조건 override 잘 되었을거라 생각 했던 나의 불찰도 있었지만 compile때나 runtime시 아무런 반응을 보이지 않던 Java도 원망스러웠다. 2003년도에 C#으로 프로젝트를 했는데 C#은 상속의 override에 대하여 "override void writalbe().."과 같이 정의시 override를 명시해야 된다는 것을 보고 상당히 마음에 들어 했던 기억이 있다. 가독성도 뛰어날 뿐더러 나의 몇시간동안의 헤메임도 없을 것이기 때문다. Java도 이렇게 확실한 명세였으면 정말 좋겠다.

    6.2.3 "또다른 나의(?) 실수 - 말도 안되는 오타" #

    위의 method이름을 잘못써서 고생하기 이전에 아주 비슷한 고생을 한적이 있다.

    '난 정말 바보인가'라는 생각을 들게 했던 문제였다. 초보 시절에는 왜이리도 오타가 많이 나던지... 요즘은 대충 키보드 두드려도 오타가 잘 안나는데 그 시절에 오타 때문에 느린 CPU에서 컴파일을 몇번을 했는지... 기억을 되살리면 소스는 다음과 같다.

            public class Member {
                private int memberNo;
                
                public int getMemberNo(){
                    return this.memberNo;
                }
                
                public void setMemberNo(int menberNo){
                    this.memberNo = memberNo;
                }
                
                ......
            }
    


    위 소스의 Member에는 다른 여러가지 member field가 있는데 DB의 member table에 memberid 컬럼이 memberno로 변경되면서 Member class의 memberId를 memberNo로 변경하게 되었다. 위와 같이 수정하여 배포해놓고 테스트를 하는데 시스템이 완전히 뒤죽박죽으로 돌아버리는 것이 아닌가. 이 경우도 method 이름처럼 몇시간을 헤매었다.

    이번에 argument의 오타로 인한 어처구니 없는 실수였다. setMemberNo(int menberNo)에서 문제가 발생되었던 것이다. 인수의 memberNo를 menberNo로 잘못친것이다. 그래서 memberNo에는 해당 member의 memberno가 아닌 0이 모두 들어갔어던 것이다. 시스템은 memberno를 기준으로 도는 부분이 너무나 많았기에 오류나는 부분도 많았으며 DB에서는 제대로 된 memberno을 읽어 왔으며, compile과 runtime시 아무런 반응도 없었기에, 초보자를 그렇게도 고생시켰나 보다.

    이것도 member field면 무조건 this를 붙이도록 하던지 Java가 인수는 'm_'와 prefix를 붙이도록 Coding Style을 정의- SUN사이트의 Java Coding 규약에는 "Variable names should not start width underscore_ or dollar sign $ characters, even though both are allowed." 와 같이 명시되어 있다 - 했더라면 발생하지 않았을 문제이다.

    또한 C언어나 C#에서 처럼 compile 경고레벨을 높여놓으면 "menberNo는 어디서도 사용하지 않습니다."와 같은 메세지를 보여 줬더라면 고생을 덜 하지 않았을까?

    6.2.4 "static member를 instance를 경유하여 참조해서는 안 된다." #

    예를 들어 ClassA 에 public static int AA 라는 static field가 있을 경우 ClassA.AA 로 접근해야 하는데, 다음과 같이 사용하는 실수를 범한다.(물론 오류는 없지만)

            ClassA a = new ClassA(); 
            int i = a.AA;       //instance를 경유하여 접근
            int j = ClassA.AA;  //올바르게 접근
    

    그럼 왜 굳이 ClassA.AA와 같이 instance가 아닌 class이름을 붙여야 할까?

    static member(static field/static method)는 compile시에 이미 어느것을 호출할 지 결정하기 때문에 위의 a.AA와 같은 것은 static이 아닌것 같은 오해와 혼란만 가져오기 때문이다. 심지어 개인적으로는 동일 class 내 - 위 소스에서 ClassA의 member method - 에서 ClassA.AA라고 사용하는 편이다.

    이는 local variable과 혼동될 염려도 없을뿐더러 AA라는 변수가 static이라는 것도 확실히 알 수 있기 때문이다. 물론 private static 의 경우는 ClassA.BB 와 같이 하지 않고 BB 라고 해도 무방하겠지만 말이다.

    6.2.5 "super keyword는 부모의 this" #

    Java 개발자 대부분은 'super' 에 대하여 그렇게 민감하지 않을 것이다. 그거 super() 나 super.method1() 과 같이 사용되지 그 이상에 대해선 깊이 생각하지 않게 된다. super를 한마디로 정리하면 다음과 같다.

    "super keyword는 instance method등에서 this를 사용할 수 있는 곳에서만 쓸 수 있다. this의 자리에 super라고 쓰면 현재 class의 member가 참조되는 대신 부모 class의 member가 참조되는 것이다."

    6.3 상속에 관한 또 다른 문제 #


    6.4 그밖의 함정 #

    6.4.1 "생성자에 void 를 붙인다면?" #

    생성자에 void를 붙인다면 그 class가 new 될때 그 생성자(?)가 실행될까?? 아래의 'Constuctor'라는 문자열은 출력될까?

            public class ConstructorTest{
                void ConstructorTest(){
                    System.out.println("Constuctor");
                }
                .....
            }
    

    출력되지 않는다. 물론 compile시 아무런 경고도 없었다. 즉, void가 붙은 ConstructorTest()는 생성자가 아니라 instance method일 뿐이었고 new시에는 default constructor가 실행 되었던 것이다.

    6.4.2 "if / switch 의 함정" #

    Java 개발자라면 대부분이 초보시절에 if 조건절에 '==' 대신 '='을 써본 기억이 있을것이다. 예를 들어 "if( isListenLecture == Student.STUDENT )" 를 "if( isListenLecture = Student.STUDENT )" 로 잘못 쓴 경우이다. 여기서 Student.STUDENT는 boolean type이다. 여기서 isListenLecture는 항상 Student.STUDENT 값을 갖게 되는 버그가 생긴다. 이는 compile시에 아무런 경고도 없다. 이렇게 한번 당하고 나면 앞으로는 '=='를 정확히 쓰게 되거나 아니면 다음과 같이 쓴다.

    "if( isListenLecture )" 또는 "if( !isListenLecture )" 라고 말이다. 이것이 더욱 간결하고 의미도 분명해 지기 때문이다. 또한 다음 소스와 같은 오류도 범하는 경우가 있다. 이는 잘못된 indentation으로 빚어지는 초보의 함정이다.

    이글을 읽는 분께 한가지 당부드리고 싶은것은 여기서 초보라고 다 그런건 아니라는 것이다.

            ....
            if( a < 5 )
                b = 3;
                c = 10;   //이부분은 나중에 추가된 라인이다.
                
                
            if( isStudent )
                if( isFemale )
                    sayHello("Hi~~");
            else
                sayHello("Hello Professor~");
    

    위의 소스중 c = 10; 이 if( a < 5 )의 참일때 수행된다고 오해할 수도 있고, sayHello("Hello Professor~"); 부분이 if( isStudent )의 else 부분이라고 오해 할 수도 있다. 이것은 전적으로 indentation(들여쓰기)의 불찰로 개발자가 잘못 읽을 수 있는 부분이다. Java Coding Style에서는 if문 다음에 한줄의 코드가 있더라도 {} 를 사용하길 권고한다. 그러면 첫번째 if문과 같은 오류를 방지할 수 있고 두번째 if문에서도 보다 가독성이 생길 것이다.

    이와 유사한 것으로 switch문의 case 절에서 break를 쓰지 않아 항상 동일하게 처리되는 버그도 경험해 보았을 것이다.

    7 Java 기능 적용 몇가지 #

    7.1 대규모 개발에서 interface 분리하기 #

    7.1.1 "interface 분리의 필요성" #

    Java와 같은 객체지향언어에서는 공개해야 할 method만을 public으로 하고, 공개할 필요가 없는 것은 private으로 하여 class의 상세한 내용을 은폐할 수 있게 되어 있다. 그런데 private 부분이 은폐되어 있는것 처럼 보이는가?

    소스를 보면 훤히 들여다 보이는데?

    대규모 개발은 하부 class부터 bottom-up으로 진행하는 것이 이상적인 형태일 것이다. 그런 형태로 개발하면 임의의 시점에서 테스트를 할 수도 있다. 그러나 현실적으로 단기간에 많은 수의 개발자가 붙어서 단시간에 개발을 진행하는 경우가 많다. 또한 서로 호응하는 관계에 있는 class들은 어느쪽이 하부인지 정의하기가 난감할때가 많다. 이런경우 우리는 흔히 package단위로 나누어 개발한다. 하지만 이럴경우 어느정도 코딩이 종료될때까지 테스트하기가 상당히 힘들어 진다. Java에서는 private member와 method 구현까지 하나의 파일에 코딩하는데 개발 중간에 공개하여 다른 개발자가 이용해야 하는 class를 배포할 수 없으므로 동시 개발이 까칠해 진다.

    이 상황에서 다른 package(개발자)에 공개해야 하는 class 부분을 interface로 공개하면 많은 부분 유연하게 된다. 이 interface를 다른 개발자는 개발을 하고 테스트가 필요하다면 TestImpl class를 만들어 하면된다. RMI나 CORBA에서도 Stub은 이런식으로 IDL을 정의한다.

    7.2 Java에서의 열거형 #

    Java에서는 열거형-C의 구조체, 공용체-이 없다. 열거형이 왜 필요하냐고 반문하는 개발자도 있을 것이다.

    하지만 열거형이 없어 곤란을 경험한 개발자도 꽤 있으리라 본다. 최근언어(특히 객체지향 언어) - Java, Eiffel, Oberon등 - 에는 열거형은 포함되어 있지 않다. C#에는 있긴 하지만.

    이런 이유로 Java AWT의 Label class는 다음과 같이 구현되어 있다.(텍스트의 정렬값관련)

            public static final int LEFT = 0;
            public static final int CENTER = 1;
            public static final int RIGHT = 2;
            ...
            
            label.setAlignment(Label.CENTER);
            ...
    

    하지만 위의 소스에는 문제가 있다. setAlignment() method의 인자가 int인 것이다. 만약 위에 정의한 0, 1, 2가 아닌 다른 int 값이 들어가도 compile/runtime시 알수가 없다. 그래서 주석을 달게 되는데, 주석이라 함은 정말이지 최후의 수단이라고 봐야 한다.

    실제로 우리가 개발해 놓은 소스에도 이런부분이 있으리라 예상된다. 이 문제를 어떻게 하면 해결할 수 있을까? Java에서 열거형을 한번 만들어 보자.

            //LabelAlignment.java
            public class LabelAlignment {
                private LabelAlignment() {} //이는 생성자를 private으로 하여 다른데서는 만들지 못하도록 하기위함이다.
                
                public static final LabelAlignment LEFT = new LabelAlignment():
                public static final LabelAlignment CENTER = new LabelAlignment():
                public static final LabelAlignment RIGHT = new LabelAlignment():
            }
            
            //변형된 Label.java 의 일부..
            public synchronized void setAlignment(LabelAlignment alignment){
                if( alignment == LabelAlignment.LEFT ){
                    ...//왼쪽으로 맞추기..
                }else if( ...
                    ...
                }
            }
            ...
    

    위에서 작성한 소스는 잘 작동한다. 서로 다른 3개의 instance이므로 reference가 달라 '==' 연산도 가능하고, 훌륭하다.

    하지만 한가지 문제가 있다. LabelAlignment가 Serializable한 class에서 serialize되었다 deserialize 된다면?

    LabelAlignment alignment 는 새로운 instance가 되고 serialize전의 reference와 다른 참조 위치를 갖게 되어 '==' 연산은 버그를 발생시킨다. 그럼 이것만 해결하면 되겠는데, 어떻게 refactoring하면 될 것인가? '==' 연산 대신 equals로 변형하면 되겠는데.

            //LabelAlignment.java
            public class LabelAlignment {
                private int flag;
                private LabelAlignment(int flag){
                    this.flag = flag;
                } 
                
                public static final LabelAlignment LEFT = new LabelAlignment(0):
                public static final LabelAlignment CENTER = new LabelAlignment(1):
                public static final LabelAlignment RIGHT = new LabelAlignment(2):
                
                public boolean equals(Object obj){
                    return ((LabelAlignment)obj).flag == this.flag;
                }
            }
            
            //변형된 Label.java 의 일부..
            public synchronized void setAlignment(LabelAlignment alignment){
                if( LabelAlignment.LEFT.equals(alignment) ){
                    ...//왼쪽으로 맞추기..
                }else if( ...
                    ...
                }
            }
            ...
    

    하하, Serialize까지 잘 작동한다. ^^;

    여기서 Debug를 고려한다면 0, 1, 2 대신 문자열로 "LEFT", "CENTER", "RIGHT"로 한다면 더욱 명확하지 않을까?

    (주의) 위에서처럼 LabelAlignment.LEFT 라고 쓰기 싫어서 상수 interface를 만들어 그걸 implements 하여 그냥 LEFT 라고 쓰는 것을 뿌듯해 하며 쓰는 개발자들이 있다. 물론 Swing의 소스들을 보다보면 SwingConstants라는 interface에 LEFT를 비롯하여 온갖 잡다한 상수를 집어넣어놓고 여기 저기서 implements해서 사용하고 있다. 이런 코딩 스타일은 '내 스타일이야~' 가 아니라 냄새나는 코드이다.

    LEFT라는 것이 구현한 class에 이미 있을 수 있을 수 있을뿐아니라 구현한 모든 클래스에서 LEFT를 보유하여 SwingConstants.LEFT뿐 아니라 Impl.LEFT로도 사용되게 되어 온갖 혼란을 초래하게 된다. 입력량을 줄이기 위해 interface를 implements 해서는 안되지 않을까?

    7.3 Debug write #

    C에서는 다음과 같이 pre-process로 정의하면 DEBUG라는 식별자를 #define하지 않으면 컴파일후 해당 소스의 부분이 삭제된다.

            #ifdef DEBUG
                fprintf(stderr, "error...%d\n", error);
            #endif /* DEBUG */
    

    그럼 Java에서는?

    Java에서는 Pre-process가 없지만 다음과 같이 작성했을때 Debug.isDebug 가 final로 선언되어 있으면 compile후 아래 3줄 모두 삭제 된다.(단 Debug.isDebug 가 false 로 초기화 되었다면 제거된다.)

            if( Debug.isDebug ){
                System.out.println("error..." + error);
            }
    

    Java는 compile시 byte code 생성시 final은 정적으로 판단하여 미리 정의하기 때문에 위의 3줄은 삭제될 수 있다. if문과 함께 없어지게 되므로 처리 속도에 피해를 주지 않는다. 단, 주의해야 할 점은 Debug.isDebug 값이 변경되면 이 것을 사용하고 있는 측도 모두 함께 다시 compile해야 한다. bytecode를 다시 만들어야 하기 때문이다.

    그런데, 이 소스를 Debug.write()와 같이 static 으로 하여 이 method내에서 판단하게 하면 편리할텐데. 그리고 class별로 ON/OFF 처리를 할 수 있으면 좋을텐데, 어찌 하면 가능할 것인가?

    그럼 먼저 호출한 쪽의 class이름을 찾아보자. 접근은 Exception의 printStackTrace()로 부터 시작되었다. 하지만 이 소스에는 Exception 객체를 new한 시점에 결정되어 있다. 그래서 부모인 Throwable의 생성자를 확인해 보니 fillInStackTrace() 로 되어있는데 이 method는 native method였다.

    API Reference를 보면 Thread class에서는 dumpStackTrace()라는 method가 있었다. 소스를 보니, 그것도 생성시점이었다. 아무래도 예외방면에서 찾는건 무리인듯 했다.

    그래서 class의 호출계층을 나타내는 java.lang.SecurityManager의 getClassContext() method로 접근하였다. sample 소스는 다음과 같다.

            // 1. GetCallerSecurityManager.java
            public final class GetCallerSecurityManager extends SecurityManager {
                public Class[] getStackTrace(){
                    return this.getClassContext();   
                }
            }
            
            // 2. GetCallerClass.java
            public final class GetCallerClass {
                private static GetCallerSecurityManager mgr;
                
                static{
                    mgr = new GetCallerSecurityManager();
                    System.setSecurityManager(mgr);
                }
                
                public static void writeCaller(String str){
                    Class[] stk = mgr.getStackTrace();
                    int size = stk.length;
                    for(int i = 0; i < size; i++){
                        System.out.println("stk[" + i + "] = " + stk[i]);   
                    }   
                    
                    String className = stk[2].getName();
                    
                    System.out.println("className is " + className + " : " + str);
                }
            }
            
            // 3. GetCallerClassMain1 : 호출하는 클래스 예제 1
            public class GetCallerClassMain1 {
                public static void main(String[] args){
                    GetCallerClass.writeCaller(", real is 1.");
                }
            }
            
            // 4. GetCallerClassMain1 : 호출하는 클래스 예제 2
            public class GetCallerClassMain2 {
                public static void main(String[] args){
                    GetCallerClass.writeCaller(", real is 2.");
                }
            }
    

    위의 3번 주석과 4번 주석 부분을 수행하면 다음과 같은 결과가 나온다.

        className is GetCallerClassMain1 : , real is 1.
        className is GetCallerClassMain2 : , real is 2.
    

    정확히 호출한 클래스를 표현하고 있다. 이것을 비교해서 클래스별 ON/OFF를 구현하면 된다.

    8 Java 5.0 Tiger 에 대하여 #

    Tiger에서는 새로운 개념의 적용이 많은 부분 시도 되었다. 이중 가장 기본이 되는 몇가지를 살펴보자.

    8.1 Working with java.util.Arrays #

    Tiger에서는 무엇보다도 Collection class들에 대해 많은 부분 정비하였다. 예를 들면 for/in 구문 지원과 Generic Type member와 Arrays Utility class 등이다. 그럼 Collection에 대한 static method들을 담고 있는 Arrays 에 대해 다음 example로 한눈에 살펴보자.

    package com.jeid.tiger;
    
    import java.util.Arrays;
    import java.util.Comparator;
    import java.util.List;
    
    public class ArraysTester {
    
    	private int[] arr;
    
    	private String[] strs;
    
    	public ArraysTester(int size) {
    		arr = new int[size];
    		strs = new String[size];
    		for (int i = 0; i < size; i++) {
    			if (i < 10) {
    				arr[i] = 100 + i;
    			} else if (i < 20) {
    				arr[i] = 1000 - i;
    			} else {
    				arr[i] = i;
    			}
    			strs[i] = "str" + arr[i];
    		}
    	}
    
    	public int[] getArr() {
    		return this.arr;
    	}
    
    	public String[] getStrs() {
    		return this.strs;
    	}
    
    	public static void main(String[] args) {
    		int size = 50;
    		ArraysTester tester = new ArraysTester(size);
    
    		int[] testerArr = tester.getArr();
    		int[] cloneArr = tester.getArr().clone();
    		String[] testerStrs = tester.getStrs();
    		String[] cloneStrs = tester.getStrs().clone();
    
    		// clone test
    		if (Arrays.equals(cloneArr, testerArr)) {
    			System.out.println("clonse int array is same.");
    		} else {
    			System.out.println("clonse int array is NOT same.");
    		}
    
    		if (Arrays.equals(cloneStrs, testerStrs)) {
    			System.out.println("clonse String array is same.");
    		} else {
    			System.out.println("clonse String array is NOT same.");
    		}
    
    		// 2부터 10까지 값 셋팅
    		Arrays.fill(cloneArr, 2, 10, new Double(Math.PI).intValue());
    
    		testerArr[10] = 98;
    		testerStrs[10] = "corea";
    		testerStrs[11] = null;
    
    		List<String> listTest = Arrays.asList(testerStrs);
    		System.out.println("listTest[10] = " + listTest.get(10));
    
    		System.out.println("------- unsorted arr -------");
    		System.out.println("Arrays.toString(int[]) = " + Arrays.toString(testerArr));
    		System.out.println("Arrays.toString(String[]) = " + Arrays.toString(testerStrs));
    
    		Arrays.sort(testerArr);
    		// Arrays.sort(testerStrs); //NullPointerException in sort method..(null이 없더라도 길이에 대한 크기 체크는 못함)
    		Arrays.sort(testerStrs, new Comparator<String>() {
    			public int compare(String s1, String s2) {
    				if (s1 == null && s2 == null) {
    					return 0;
    				} else if (s1 == null && s2 != null) {
    					return -1;
    				} else if (s1 != null && s2 == null) {
    					return 1;
    				} else if (s1.length() < s2.length()) {
    					return -1;
    				} else if (s1.length() > s2.length()) {
    					return 1;
    				} else if (s1.length() == s2.length()) {
    					return 0;
    				} else {
    					return s1.compareTo(s2);
    				}
    			}
    		});
    
    		System.out.println("------- sorted arr -------");
    		System.out.println("Arrays.toString(int[]) = " + Arrays.toString(testerArr));
    		System.out.println("Arrays.toString(String[]) = " + Arrays.toString(testerStrs));
    		
    		System.out.println("------------------------------------------------");
    
    		String[][] mstrs1 = { { "A", "B" }, { "C", "D" } };
    		String[][] mstrs2 = { { "a", "b" }, { "c", "d" } };
    		String[][] mstrs3 = { { "A", "B" }, { "C", "D" } };
    
    		System.out.println("Arrays.deepToString(mstrs1) = " + Arrays.deepToString(mstrs1));
    		System.out.println("Arrays.deepToString(mstrs2) = " + Arrays.deepToString(mstrs2));
    		System.out.println("Arrays.deepToString(mstrs3) = " + Arrays.deepToString(mstrs3));
    		
    		if( Arrays.deepEquals(mstrs1, mstrs2)) {
    			System.out.println("mstrs1 is same the mstrs2.");
    		}else {
    			System.out.println("mstrs1 is NOT same the mstrs2.");
    		}
    		
    		if( Arrays.deepEquals(mstrs1, mstrs3)) {
    			System.out.println("mstrs1 is same the mstrs3.");
    		}else {
    			System.out.println("mstrs1 is NOT same the mstrs3.");
    		}
    		
    		System.out.println("mstrs1's hashCode = " + Arrays.deepHashCode(mstrs1));
    		System.out.println("mstrs2's hashCode = " + Arrays.deepHashCode(mstrs2));
    		System.out.println("mstrs3's hashCode = " + Arrays.deepHashCode(mstrs3));
    	}
    
    }
    

    8.2 Using java.util.Queue interface #

    Queue를 이용하여 First In First OutOrdering한 Queue를 구현 가능하다.

    package com.jeid.tiger;
    
    import java.util.LinkedList;
    import java.util.PriorityQueue;
    import java.util.Queue;
    
    public class QueueTester {
    	public static void main(String[] args) {
    		System.out.println("---------- testFIFO ----------");
    		testFIFO();
    		System.out.println("---------- testOrdering ----------");
    		testOrdering();
    	}
    
    	private static void testFIFO() {
    		Queue<String> q = new LinkedList<String>();
    		q.add("First");
    		q.add("Second");
    		q.add("Third");
    
    		String str;
    		while ((str = q.poll()) != null) {
    			System.out.println(str);
    		}
    	}
    
    	private static void testOrdering() {
    		int size = 10;
    		Queue<Integer> qi = new PriorityQueue<Integer>(size);
    		Queue<String> qs = new PriorityQueue<String>(size);
    		for (int i = 0; i < size; i++) {
    			qi.offer(10 - i);
    			qs.offer("str" + (10 - i));
    		}
    		
    		for (int i = 0; i < size; i++) {
    			System.out.println("qi[" + i + "] = " + qi.poll() + ", qs[" + i + "] = " + qs.poll());
    		}
    	}
    }
    

    8.3 java.lang.StringBuilder 사용하기 #

    StringBuffer가 synchronize하지 않은 method들로 구성된 듯한 StringBuilder를 사용하므로 성능 향상을 도모할수 있다. 사용법은 StringBuffer와 동일하다.

    package com.jeid.tiger;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    
    public class StringBuilderTester {
    	public static void main(String[] args) {
    		List<String> list = new ArrayList<String>();
    		list.add("str1");
    		list.add("str2");
    		list.add("str3");
    
    		String ret = appendItems(list);
    		System.out.println("ret = " + ret);
    	}
    
    	private static String appendItems(List<String> list) {
    		StringBuilder sb = new StringBuilder();
    		for (Iterator<String> iter = list.iterator(); iter.hasNext();) {
    			sb.append(iter.next()).append(" ");
    		}
    		return sb.toString();
    	}
    }
    

    8.4 Using Type-Safe Lists #

    Collection에 type을 명시하여 type-safe 하게 처리 가능. 아래에서 type을 명시하지 않을 경우 compile error가 남을 보여준다. tip으로 Number를 이용하여 byte, short, int, long, double, float 동시 사용하는 부분 참조.

    package com.jeid.tiger;
    
    import java.util.Iterator;
    import java.util.LinkedList;
    import java.util.List;
    
    public class ListTester {
    	public static void main(String[] args) {
    		List<String> list = new LinkedList<String>();
    		list.add("str1");
    		list.add("str2");
    		list.add(new Integer(123));  // <-- String이 아니므로 compile error!!
    		
    		//Iterator에 String type을 명시하므로 정삭작동됨.
    		for (Iterator<String> iter = list.iterator(); iter.hasNext();) {
    			String str = iter.next();
    			System.out.println("srt = " + str);
    		}
    		
    		//Iterator에 String type을 명시하지 않았으므로 아래 A 부분에서 compile 오류 발생!!
    		for (Iterator iter = list.iterator(); iter.hasNext();) {
    			String str = iter.next(); //A
    			System.out.println("srt = " + str);
    		}
    		
    		//byte, short, int, long, double, float 동시 사용
    		List<Number> lstNum = new LinkedList<Number>();
    		lstNum.add(1);
    		lstNum.add(1.2);
    		for (Iterator<Number> iter = lstNum.iterator(); iter.hasNext();) {
    			Number num = iter.next();
    			System.out.println("num = " + num);
    		}
    	}
    }
    

    8.5 Writing Generic Types #

    class 나 interface keyword에 type을 명시하여 동일 타입 명시 가능. 주의 할 점은 any type은 static 일 수 없다.(동적으로 type이 정해지므로)

    class AnyTypeList<T> {
    //class AnyTypeList<T extends Number> {  // <-- 이는 Number를 상속한 type은 허용하겠다는 의미.
    	private List<T> list;
    	//private static List<T> list;  // <-- 이는 정적이므로 compile error 발생!!! 
    	public AnyTypeList(){
    		list = new LinkedList<T>();
    	}
    	
    	public boolean isEmpty(){
    		return list == null || list.size() == 0;
    	}
    	
    	public void add(T t){
    		list.add(t);
    	}
    	
    	public T grap(){
    		if (!isEmpty() ) {
    			return list.get(0);
    		} else {
    			return null;
    		}
    	}
    }
    

    8.6 새로운 static final enum #

    예제를 통해 알아보자.

    package com.jeid.tiger;
    
    import com.jeid.BaseObject;
    import com.jeid.MyLevel;
    
    public class EnumTester extends BaseObject {
    	private static long start = System.currentTimeMillis();
    	
    	public static void main(String[] args) {
    		try {
    			test();
    			enum1();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		printEllapseTime();
    	}
    	
    	private static void test() throws Exception {
    		byte[] b = new byte[0];
    		System.out.println(b.length);
    	}
    
    	private static void enum1() {
    		//enum TestEnum { A, B };  //enum cannot be local!!!
    		
    		for(MyVO.TestEnum te: MyVO.TestEnum.values()){
    			System.out.println("Allow TestEnum value : " + te);
    		}
    		System.out.println("---------------------------------------");
    		
    		MyVO vo = new MyVO();
    		vo.setName("enum1");
    		vo.setLevel(MyLevel.A);
    		System.out.println(vo);
    		System.out.println("isA = " + vo.isA() + ", isGradeA = " + vo.isLevelA()+ ", isValueOfA = " + vo.isValueOfA());
    		System.out.println("getLevelInKorean = " + vo.getLevelInKorean());
    	}
    
    	private static void printEllapseTime() {
    		System.out.println("==> ellapseTime is " + (System.currentTimeMillis() - start) + " ms.");
    	}
    }
    
    
    package com.jeid.tiger;
    
    import com.jeid.BaseObject;
    import com.jeid.MyLevel;
    
    public class MyVO extends BaseObject {
    	enum TestEnum {
    		A, B
    	}; // this is same public static final
    
    	private int id;
    
    	private String name;
    
    	private MyLevel grade;
    
    	// private List<T> list;
    
    	public MyLevel getLevel() {
    		return grade;
    	}
    
    	public void setLevel(MyLevel grade) {
    		this.grade = grade;
    	}
    
    	public boolean isA() {
    		return "A".equals(this.grade);
    	}
    
    	public boolean isValueOfA() {
    		return MyLevel.valueOf("A").equals(grade);
    	}
    
    	public boolean isLevelA() {
    		return MyLevel.A.equals(this.grade);
    	}
    
    	//A,B,C..대신 0,1,2... 도 동일함.
    	public String getLevelInKorean() {
    		switch(this.grade){
    		case A:
    			return "수";
    		case B:
    			return "우";
    		case C:
    			return "미";
    		case D:
    			return "양";
    		case E:
    			return "가";
    		default:
    			return "없음";
    		}
    	}
    
    	public int getId() {
    		return id;
    	}
    
    	public void setId(int id) {
    		this.id = id;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    }
    
    

    8.7 Using java.util.EnumMap #

    java.util.Map과 동일하나 key가 enum type이어 한다. 예제로 살펴보자.

    package com.jeid.tiger;
    
    import java.util.EnumMap;
    
    public class EnumMapTester {
    
    	private enum MyEnum {
    		A, B, C
    	}; // this is same the static final..
    
    	public static void main(String[] args) {
    		MyEnum[] enums = MyEnum.values();
    		System.out.println("MyEnum is " + enums[0] + ", " + enums[1] + ", " + enums[2]);
    
    		EnumMap<MyEnum, String> em = new EnumMap<MyEnum, String>(MyEnum.class);
    		em.put(MyEnum.A, "수");
    		em.put(MyEnum.B, "우");
    		em.put(MyEnum.C, "미");
    		em.put(MyEnum.B, "가"); //key 중복은 HashMap과 동일하게 overwrite임.
    
    		for (MyEnum myEnum : MyEnum.values()) {
    			System.out.println(myEnum + " => " + em.get(myEnum));
    		}
    	}
    }
    

    8.8 Using java.util.EnumSet #

    java.util.Set과 동일하나 value가 enum type이어 한다. 예제로 살펴보자.

    package com.jeid.tiger;
    
    import java.util.EnumSet;
    
    public class EnumSetTester {
    
    	private enum MyEnum {
    		A, B, C, a, b, c
    	}; // this is same the static final..
    
    	public static void main(String[] args) {
    		MyEnum[] enums = MyEnum.values();
    		System.out.println("MyEnum is " + enums[0] + ", " + enums[1] + ", " + enums[2]);
    
    		EnumSet<MyEnum> es1 = EnumSet.of(MyEnum.A, MyEnum.B, MyEnum.C);
    		EnumSet<MyEnum> es2 = EnumSet.of(MyEnum.a, MyEnum.b, MyEnum.c);
    		EnumSet<MyEnum> es3 = EnumSet.range(MyEnum.a, MyEnum.c);
    		if (es2.equals(es3)) {
    			System.out.println("e2 is same e3.");
    		}
    
    		for (MyEnum myEnum : MyEnum.values()) {
    			System.out.println(myEnum + " contains => " + es1.contains(myEnum));
    		}
    	}
    }
    

    8.9 Convert Primitives to Wrapper Types #

    int, short, char, long, double등 primitive와 이들의 Object Wrapper 인 Integer, Shrt, Char등 간의 converting에 있어 자동으로 처리해주는 boxing과 unboxing이 지원 됨에 따라 type에 대한 유연한 처리가 가능해졌다. 예제로 살펴보자.

    package com.jeid.tiger;
    
    public class AutoBoxingTester {
    
    	public static void main(String[] args) {
    		int i = 0;
    		Integer ii = i; // boxing. JDK 1.4에서는 incompatible type error가 발생 했었으나 Tiger에서는 괜찮다.
    		int j = ii; // unboxing
    
    		for (ii = 0; ii < 5; ii++) { // Integer인데도 ++ 연산자 지원.
    		}
    
    		i = 129;
    		ii = 129;
    		if (ii == i) {
    			System.out.println("i is same ii.");
    		}
    
    		// -128 ~ 127 사이의 수는 unboxing이 되어 == 연산이 허용되지만,
    		// 그 범위 외의 경우 Integer로 boxing된 상태므로 equals를 이용해야함.
    		// 이는 버그가 발생했을 경우 찾기 쉽지 않은 단점도 내포하고 있다.!!
    		checkIntegerSame(127, 127); // same
    		checkIntegerSame(128, 128); // Not same
    		checkIntegerEquals(128, 128); // equals
    		checkIntegerSame(-128, -128); // same
    		checkIntegerSame(-129, -129); // Not same
    		checkIntegerEquals(-129, -129); // equals
    		
    		System.out.println("--------------------------------------------");
    		Boolean arriving = false;
    		Boolean late = true;
    		String ret = arriving ? (late ? "도착했지만 늦었네요." : "제시간에 잘 도착했군요.") : 
    								(late ? "도착도 못하고 늦었군요." : "도착은 못했지만 늦진 않았군요.");
    		System.out.println(ret);
    		
    		StringBuilder sb = new StringBuilder();
    		sb.append("appended String");
    		String str = "just String";
    		boolean mutable = true;
    		CharSequence chSeq = mutable ? sb : str;
    		System.out.println(chSeq);
    	}
    
    	private static void checkIntegerSame(Integer ii, Integer jj) {
    		if (ii == jj) {
    			System.out.println("ii = " + ii + ", jj = " + jj + " ==> jj is same ii.");
    		} else {
    			System.out.println("ii = " + ii + ", jj = " + jj + " ==> jj is NOT same ii!!");
    		}
    	}
    
    	private static void checkIntegerEquals(Integer ii, Integer jj) {
    		if (ii.equals(jj)) {
    			System.out.println("ii = " + ii + ", jj = " + jj + " ==> jj is equals ii.");
    		} else {
    			System.out.println("ii = " + ii + ", jj = " + jj + " ==> jj is NOT equals ii!!");
    		}
    	}
    
    }
    

    8.10 Method Overload resolution in AutoBoxing #

    int가 127을 초과할 경우 boxing이 이루어 질듯 하지만, method overload에 있어서는 boxing이 이루어 지지 않아 JDK1.4와 동일한 결과를 얻는다. 예제로 살펴보자.

    package com.jeid.tiger;
    
    public class OverloadTester {
    	public static void main(String[] args) {
    		double d = 10;
    		Integer ii = new Integer(10);
    		doSomething(10);
    		doSomething(1000);
    		doSomething(ii);
    		doSomething(d);
    	}
    
    	private static void doSomething(Integer ii) {
    		System.out.println("This is doSomething(Integer)");
    	}
    
    	private static void doSomething(double d) {
    		System.out.println("This is doSomething(double)");
    	}
    }
    

    8.11 가변적인 argument 개수 ... #

    인수가 가변적일 경우 인수의 개수가 없는것 부터 다수개까지 모두 지원. 예제로 살펴보자.

    package com.jeid.tiger;
    
    public class VarArgsTester {
    	public static void main(String[] args) {
    		setNumbers(1, 2);
    		setNumbers(1, 2, 3, 4);
    		setNumbers(1);
    		// setNumbers(); //해당 되는 method가 없어 compile error!!
    		System.out.println("==============================================");
    		setNumbers2(1, 2, 3, 4);
    		setNumbers2(1);
    		setNumbers2();
    	}
    
    	// this is same setNumbers(int first, int[] others)
    	private static void setNumbers(int first, int... others) {
    		System.out.println("-----------setNumbers()----------- : " + first);
    		for (int i : others) {
    			System.out.println("i = " + i);
    		}
    	}
    
    	// this is same setNumbers(int[] others)
    	private static void setNumbers2(int... others) {
    		System.out.println("-----------setNumbers2()----------- : "
    				+ (others != null && others.length > 0 ? others[0] : "null"));
    		for (int i : others) {
    			System.out.println("i = " + i);
    		}
    	}
    }
    

    8.12 The Three Standard Annotation #

    @Override - sign the override from superclass.

        //정상적인 사용
        @Override
        public int hashCode(){
            return toString().hashCode();
        }
        
        //스펠링이 틀려 compile error!!
        @Override
        public int hasCode(){   //misspelled => method does not override a method from its superclass error!!
            return toString().hashCode();
        }
    

    @Deprecated deprecated 주석과 동일하나 부모의 method가 deprecated되면 자식의 method를 사용해도 deprecated로 나온다.

    package com.jeid.tiger;
    
    public class AnnotationDeprecateTester {
    	public static void main(String[] args){
    		DeprecatedClass dep = new DeprecatedTester();
    		dep.doSomething(10);    //deprecated
    	}
    }
    
    class DeprecatedClass {
    	@Deprecated
    	public void doSomething(int ii){    //deprecated
    		System.out.println("This is DeprecatedClass's doSomething(int)");
    	}
    	
    	public void doSomethingElse(int ii){
    		System.out.println("This is DeprecatedClass's doSomethingElse(int)");
    	}
    }
    
    class DeprecatedTester extends DeprecatedClass {
    	@Override
    	public void doSomething(int ii){
    		System.out.println("This is DeprecatedTester's doSomething(int)");
    	}
    }
    

    @SuppressWarnings SuppressWarnings에 인자는 String[] type으로 여러개를 배열형태로 쓸수 있다.

    package com.jeid.tiger;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class AnnotationSuppressWarningsTester {
    	@SuppressWarnings({"unchecked", "fallthrough"} )
    	private static void test1(){
    		List list = new ArrayList();
    		list.add("aaaaaa");
    	}
    	
    	@SuppressWarnings("unchecked")
    	private static void test2(){
    		List list = new ArrayList();
    		list.add("aaaaaa");
    	}
    	
    	//warning이 없는 소스.
    	private static void test3(){
    		List<String> list = new ArrayList<String>();
    		list.add("aaaaaa");
    	}
    }
    

    8.13 Creating Custom Annotation Types #

    나만의 annotation을 정의할 수 있는데 키워드는 @interface이 각 method정의가 member라고 보면 된다. 간단한 예를 보면 다음과 같다.

    package com.jeid.tiger;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Documented
    @Target( { ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotation {
    	String columnName();
    	String methodName() default "";
    }
    
    //사용하는 쪽..
    public class AnnotationTester {
    
    	@MyAnnotation(columnName = "test", methodName = "setTest")
    	private String test;
    
    	@MyAnnotation(columnName = "grpid")
    	public String grpid;
    
        ....
    }
    
    //위의 test 멤버의 경우 다음과 같이 접근 가능하다.
    Field testField = cls.getDeclaredField("test");
    if (testField.isAnnotationPresent(MyAnnotation.class)) {
        Annotatioin anno = testField.getAnnotation(MyAnnotation.class);
        System.out.println(anno.columnName() + ", method = " + anno.methodName());
    }
    

    9 The for/in Statement #

    9.1 for/in 의 자주 사용되는 형태 #

    for/in은 무엇보다 다양한 유형의 예제를 보는것이 제일 빠를것이다. 형태별 사용 예제를 살펴보면 다음과 같다.

    //1. 가장 단순한 형태인 배열(array)
    String[] strs = { "aaa", "bbb", "ccc" };
    for (String str : strs) {
        System.out.println(str);
    }
    
    //2. List by using Iterator
    List<Number> lstNum = new LinkedList<Number>();
    lstNum.add(1);
    lstNum.add(1.2);
    for (Iterator<Number> iter = lstNum.iterator(); iter.hasNext();) {
    	Number num = iter.next();
    	System.out.println("num = " + num);
    }
    
    //3. List를 바로 사용
    List<String> lst = new LinkedList<String>();
    lst.add("aaaaa");
    lst.add("bbbbb");
    lst.add("ccccc");
    lst.add("ddddd");
    for (String str : lst) {
    	System.out.println("str = " + str);
    }
    
    // 4. List of List
    List[] lists = { lst, lst };
    for (List<String> l : lists) {
    	for (String str : l) {
    		System.out.println("str = " + str);
    	}
    }
    
    

    10 Static Import #

    10.1 static member/method import #

    Tiger에서는 다른 클래스의 member와 method를 import 할수 있다. 단, static 일 경우만 가능하다.

    //예를 들어 System.out.println() 이라는 것을 사용하기 위해서는 다음의 import 문이 필요하다.
    
    import java.lang.System;   //물론 java.lang 이기에 import 문이 필요없지만 예를 들자면 그렇다는 것이다.&^^
    //허나, Tiger에서는 다음과 같이 사용할수 있다.
    import static java.lang.System.out;
    ...
    out.println(...);
    
    // method를 import 한다면..
    import static java.lang.System.out.println;
    ...
    println(...);
    
    

    Posted by 1010
    06.Ajax2009. 2. 18. 12:02
    반응형
    "AJAX Programming” 온라인 강좌(10주 과정)
      썬마이크로시스템즈 자바 에반젤리스트 신 상 철 진행

    썬마이크로시스템즈에서 자바 에반젤리스트로 활동 중이시며, 한국에도 방한하여 JCO Conference 등에서 열정적인 강의를 선보이셨던 신상철씨가 오는 8월 4일부터 10주간 AJAX 무료 온라인 강좌를 진행합니다.
    국내 개발자 여러분들의 많은 참여 바랍니다.
    (본 강좌는 전세계 개발자 대상이므로 영어로 진행됩니다.)


    2006년 8월 4일에 “AJAX Programming” 무료 온라인 코스(10주 과정)가 시작됩니다. AJAX를 처음 배우시는 분이나, 실력을 더 쌓고 싶으신 분 모두 수강하실 수 있습니다. 10주의 코스 동안 AJAX의 기본 컨셉부터 Dojo 툴킷, jMAki, Google Web Toolkit, AJAX-fied JavaServer Faces (JSF) components와 같은 다양한 AJAX 프레임웍과 툴킷의 사용법까지 모두 배우게 됩니다.

    이 코스는 온라인상에서 진행된다는 것과 무료라는 것을 제외하면 실제 대학 수업처럼 진행됩니다. 프레젠테이션 자료를 공부한 뒤에는 매주 과제가 나가며, 모르는 것을 서로 질문/답변할 수 있도록 수강생 메일링 리스트가 제공됩니다. 수업에 필요한 모든 강의자료(슬라이드, 강의노트, 플래쉬 데모 파일, 실습 자료, 과제물 등 포함)는 웹사이트에서 제공됩니다. 아래 주소로 내용이 없는 이메일을 하나 보내시면 바로 자동으로 등록하실 수 있습니다.
    ajaxworkshop-subscribe@yahoogroups.com
    본 강의의 신청 기한은 없으며, 강좌가 끝나기 전까지 등록하시면 됩니다. 단, 과제를 모두 제출하셔야 수강한 것으로 인정됩니다.
    FAQ는 아래 링크에서 확인하시기 바라며, 그 외 문의는 SKDN@Sun.COM(한글 문의 가능)으로 보내주시기 바랍니다.

    Posted by 1010
    54.iBATIS, MyBatis/iBatis2009. 2. 18. 11:59
    반응형
    허접 구닥다리 wono의 Linux에서 JSP 시작하기 3.

    (IBatis 사용하기)


    원본 글 사이트는 아래와 같습니다.


    http://blog.naver.com/wono77/140030004047

     

    * 글쓴 History:

    최초 글쓴시각- 2006년 10월 20일.

    수정- 2006년 10월 27일.

    이번엔 DB를 접근할 차례입니다.


    (제 강좌는 Linux 콘솔에서 직접 java 명령어로 컴파일합니다.

    DB는 mysql 사용.

    일단은 윈도우와 요즘 인기있는 자바툴인 이클립스를 쓰지 않습니다.

    초보가 구조적으로 디렉토리 구조등을 이해하기 위해서 리눅스 콘솔이 더 좋다고 생각하기 때문입니다.

    3번 강좌를 보시기전에 1,2번 강좌를 선행하시기 바랍니다.^^)


    먼저 IBatis를 프레임웍 기반이 아닌,

    처음부터 초보가... mysql db를 생쿼리로 날리는 것 밖에 모르는 ..

    log4j, struts, spring을 모르는 정말 초보가 IBatis로 SqlMap을 어떻게 접근해나가야할까..

    저는 그런 고민을 하였으며,

    iBatis를 시작하는 많은 사람들이 고민하였을 문제일것입니다.


    그러나, 인터넷에는 그런 한글 문서를 찾기가 힘들더군요.

    구전으로 전해지는것일까요? (아마, 그런것 같습니다.)

    아니면, 좋은 출판된 책이라도 있는 것일까요? (이건 아직 아닌것 같습니다^^)


    IBatis를 어떻게 어디서 다운받아서 어디에 설치하고, 설정은 어떻게 하라는

    초보적인 문서가 없었습니다.


    그래서 직접 설치하면서 하나하나 정리해 보았습니다.


    여기서 일단 집고 넘어가보지요.


    IBatis 가 무엇입니까?


    DB를 xml 형식으로 좀더 효율적으로 사용하자는 것입니다.

    java 파일에서 db를 사용할때, xml에 따로 빼서 사용하자는 건데...


    hibernate란 것도 있습니다.

    이 IBatis란 것을 spring+Ibatis, struts+Ibatis로 쓰기도 하고, log4j+Ibatis로도 쓰기도 합니다.


    http://ibatis.apache.org/javadownloads.html

    일단 위 사이트에서 iBatis를 다운로드 받으세요.


    바이너리 판이라서 설치하실 필요가 없습니다.

    윈도우에 일단 받아서 압축을 풀어보시면,

    저 파일중 필요한 폴더는 lib 단 1개입니다.


    lib안에 3개의 jar파일이 있는데요, 실제 필요한 것은 2개입니다.


    ibatis2-common-2.1.6.589.jar

    ibatis2-sqlmap-2.1.6.589.jar

    사용하는 jar 파일들은 일단 톰캣에서 공통적으로 사용하는 common에 밀어 넣도록 하겠습니다.


    /apache-tomcat/common/lib

    위 폴더 아래에 2파일을 밀어 넣는다.


    그리고 사용하기 위한 설정에 대한 설명이 "이동국"님이 작성하신 메뉴얼이 역시 위 링크에 있습니다.

    허락은 감히 받지 않았지만, 그 pdf 메뉴얼을 여기 올립니다.

    문서가 2개인데 하나는 용량이 5메가라 안올라가네요..


    lib에 파일을 밀어 넣었는데, 윈도우, 리눅스 모두 이 lib 디렉토리의 classpath를 잡아주어야합니다.


    저는 리눅스 bash 쉘을 쓰므로, .bash_profile 을 아래와 같이 설정합니다.

    저는 자바를 /home/wono/jsp/jdk 에 설치했으며,

    톰캣은 /home/wono/jsp/local/apache-tomcat 에 설치했습니다.


    # .bash_profile

    # Get the aliases and functions
    if [ -f ~/.bashrc ]; then
        . ~/.bashrc
    fi

    # User specific environment and startup programs

    SVN_EDITOR=/usr/bin/vim
    export SVN_EDITOR

    IRTEAM=/home/wono

    PATH=$PATH:$HOME/bin:/usr/local/bin:

    export PATH
    unset USERNAME

    #자바 설정

    JAVA_HOME=/home/wono/jsp/jdk
    CATALINA_HOME=/home/wono/jsp/local/apache-tomcat
    PATH=$JAVA_HOME/bin:$CATALINA_HOME/bin:$PATH
    export JAVA_HOME CATALINA_HOME
    #export CLASSPATH="$CATALINA_HOME/common/lib/servlet-api.jar:$JAVA_HOME/mysql-connector-java-5.0.2-beta-bin.jar:."
    export CLASSPATH="$CATALINA_HOME/common/lib/servlet-api.jar:$JAVA_HOME/mysql-connector-java-5.0.2-beta-bin.jar:$CATALINA_HOME/common/lib/jsp-api.jar"
    export CLASSPATH="$CLASSPATH:$CATALINA_HOME/common/lib:$CATALINA_HOME/common/lib/*.jar:$CATALINA_HOME/common/lib/ibatis2-common-2.1.6.589.jar:$CATALINA_HOME/common/lib/ibatis2-sqlmap-2.1.6.589.jar:."
    #export CLASSPATH="$CLASSPATH:$CATALINA_HOME/common/lib/jsp-api.jar"
    #--------------------------------------------------------------
    # myapp
    # myapp의 lib추가
    #export CLASSPATH="$CATALINA_HOME/webapps/myapp/WEB-INF/lib:$CATALINA_HOME/webapps/myapp/WEB-INF/lib/*.jar"
    export CLASSPATH="$CLASSPATH:$CATALINA_HOME/webapps/myapp/WEB-INF/classes:$CATALINA_HOME/webapps/myapp/WEB-INF/classes/*.xml:$CATALINA_HOME/webapps/myapp/WEB-INF/classes/*.properties"

    export PATH


    source .bashrc를 해주거나, 재접을 하시고, 1번 강좌에서 설명한

    myapp라는 폴더에서 작업을 하겠습니다.


    제가 iBatis로 해볼 작업은 다음과 같습니다.


    Mysql의 DB명 testDB

    Table 이름과 속성은 아래와 같습니다.

    tb_Person{

    int pid,

    varchar pname

    }
     

    안에 값을 간단히 넣어 두세요.^^

    insert into tb_Person values(2222,'wono');

    insert into tb_Person values(1111,'kanoe');


    이제 가장 간단한 select 쿼리를 날리는 예제를 iBatis로 작성하겠습니다.


    select pid,pname from tb_Person where pid=2222;


    이걸 만들겁니다.

    사실 php로 코딩하자면 꿀입니다. 아주 간단합니다.

    또는 기존의 java로 코딩해도 별거 아닙니다.


    그냥 아래처럼 코딩하면 됩니다. 이것이 model1 방식입니다.


    db 이름을 testDB이며 로그인 아이디는 loginId, 패스워드는 1111, 로그인포트 3306인 경우.


    import java.sql.*;

          class Driver {
            public static void main(String argv[]) {
                try {
                    Class.forName("org.gjt.mm.mysql.Driver");
                    System.out.println("jdbc 드라이버 로딩 성공");
                } catch (ClassNotFoundException e) {
                    System.out.println(e.getMessage());
                }
                try {
                    String url = "jdbc:mysql://localhost:3306/testDB";
                    Connection con = DriverManager.getConnection(url,"loginId","1111");
                    System.out.println("mysql 접속 성공");
                    Statement stmt = con.createStatement();
                    ResultSet rs = stmt.executeQuery("select pid from tb_Person where pid=2222");
                    System.out.println("Got result:");
                    while(rs.next()) {
                        String no= rs.getString(1);
                        System.out.println(" no = " + no);
                    }
                    stmt.close();
                    con.close();
                } catch(java.lang.Exception ex) {
                    ex.printStackTrace();
                }
            }
          }


    이러면 끝입니다. 간단합니다.(우선 pid빼기일때..)

    머리아프게 iBatis 쓸필요 없습니다.

    하지만, 이렇게 살수는 없지 않겠습니까?^^;

    파일수도 늘어나고, xml도 써야하고;; 머리아프겠지만, 조금더 함께 고생해봅시다~

    쿼리문을 다 xml하나에 모아보자는데....


    그래서 아래와 같은 총 6개의 파일들이 필요합니다.

    이제 하나하나 살펴 보겠습니다.


    3개의 java 파일과,

    apache-tomcat/webapps/myapp/WEB-INF/classes 안에 넣을 다음 3개의 설정파일이 필요합니다..


    3개의 자바 파일은 myapp 안에 그냥 두면 됩니다.


    1. MyAppSqlMapConfig.java (ibatis와의 connectionPool 생성 및 db문xml 파싱)

    2. Person.java  (id 값을 가져오기 위한 person 클래스입니다.)

    3. DBTest.java  ( 이안에 main이 있습니다.)


    3개의 설정 파일은 apache-tomcat/webapps/myapp/WEB-INF/classes 에 둡니다.


    1. Person.xml  (table을 가지고 놀 db 쿼리문을 여기에 xml로 작성하셔야합니다.)

    2. SqlMapConfig.properties  (db 연결용 connect 파일, id, pass가 들어있음)

    3. SqlMapConfig.xml (ibatis의 핵심 설정 파일. Person.xml등 정의)

    설정 파일의 소스를 먼저 본후, 소스를 하나하나 보겠습니다.


    1. Person.xml


    <?xml version="1.0"?>
    <!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd">
    <sqlMap namespace="Person">
    <select id="getPerson" resultClass="Person">
        SELECT pid as id,pname as name

        FROM tb_Person
        WHERE
        pid = #value#
    </select>
    </sqlMap>


    쿼리문을 하나 만들때 마다 <select id..>를 선언합니다.

    getPerson이라고 이름지었는데, 실제 DBTest.java 소스에서 이 getPerson 이름을 사용해서,

    이곳을 호출합니다.

    pid as id에서 이 id를 알리어스라고 하는데, 이렇게 as id로 알리아스를 해주어야,

    자바 프로그램에서 사용이 가능합니다.

    이 id라는 것은 Person.java 라는 프로그램에서 실제로 선언한 프로그램 변수명이어야 합니다.


    2. SqlMapConfig.properties


    driver=org.gjt.mm.mysql.Driver
    url=jdbc:mysql://localhost:3306/testDB
    username=loginId
    password=1111


    이건 그냥 connect 설정입니다.


    3. SqlMapConfig.xml


    <?xml version="1.0" ?>
    <!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN" "http://www.ibatis.com/dtd/sql-map-config-2.dtd">
    <sqlMapConfig>
    <!--<properties resource="examples/domain/SqlMapConfig.properties" />-->
    <properties resource="WEB-INF/classes/SqlMapConfig.properties" />
    <!--<properties resource="SqlMapConfig.properties" />-->
    <!--These settings control SqlMap configuration details, primarily to do with transaction management. They are all optional (see the Developer Guide for more). -->
    <settings
        cacheModelsEnabled="true"
        enhancementEnabled="true"
        lazyLoadingEnabled="true"
        maxRequests="32"
        maxSessions="10"
        maxTransactions="5"
        useStatementNamespaces="false"
    />
    <!--Type aliases allow you to use a shorter name for long fully qualified class names. -->
    <!--<typeAlias alias="order" type="testdomain.Order" />-->
    <!--Configure a datasource to use with this SQL Map using SimpleDataSource.
    Notice the use of the properties from the above resource -->
    <transactionManager type="JDBC" >
      <dataSource type="SIMPLE">
       <property name="JDBC.Driver" value="${driver}" />
       <property name="JDBC.ConnectionURL" value="${url}" />
       <property name="JDBC.Username" value="${username}" />
       <property name="JDBC.Password" value="${password}" />
      </dataSource>
    </transactionManager>
    <!--Identify all SQL Map XML files to be loaded by this SQL map. Notice the paths
    are relative to the classpath. For now, we only have one… -->
    <sqlMap resource="WEB-INF/classes/Person.xml" />
    <!--<sqlMap resource="Person.xml" />-->
    </sqlMapConfig>

    별다른 설명은 필요 없을듯합니다.

    제 경우 classpath에 위치 지정을 해줬는데됴, WEB-INF/classes 와 같이 위치 지정을 직접 안하면, 안되더군요.



    이제 자바 소스 들어갑니다.~


    1. MyAppSqlMapConfig.java (ibatis와의 connectionPool 생성 및 db문xml 파싱)


    import java.io.*;
    import com.ibatis.common.resources.*;
    import com.ibatis.sqlmap.client.*;

    public class MyAppSqlMapConfig {
            private static final SqlMapClient sqlMap;
            static {
                try {
                        String resource = "SqlMapConfig.xml";
                        Reader reader = Resources.getResourceAsReader(resource);
                        sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
                } catch (Exception e) {
                        e.printStackTrace();
                        throw new RuntimeException("Error initializing class. Cause:" + e);
                }
            }

            public static SqlMapClient getSqlMapInstance() {
                return sqlMap;
            }

    }


    2. Person.java  (id 값을 가져오기 위한 person 클래스입니다.)


    import java.util.*;

    public class Person {

        private int id;

        private String name;

        // setter
        public void setId (int id) { this.id = id; }

        // getter
        public int getId () { return id; }

        public void setName (String name) { this.name = name; }

        public String getName () { return name; }

    }


    3. DBTest.java  ( 이안에 main이 있습니다.)


    import java.sql.SQLException;
    import java.util.*;

    import com.ibatis.sqlmap.client.*;

    public class DBTest {

        /**
         * @param args
         * @throws SQLException
         */
        public static void main(String argv[]) throws SQLException {
            // TODO Auto-generated method stub
            // select
            /*
            */
            selectTest();
        }

        public static void selectTest () throws SQLException
        {
            //sqlMap 초기화(MyAppSqlConfig.java)
            SqlMapClient sqlMap = MyAppSqlMapConfig.getSqlMapInstance();


            Integer personId = 2222;
            //Person.xml 안의 ID가 getPerson인 DB 선언에서 값이 psersonId(2222)인것을 select>해옴
            Person person = (Person) sqlMap.queryForObject("getPerson",personId);

            System.out.println("- Id : " + person.getId());

            System.out.println("- name : " + person.getName());

            System.out.println("\nSelect Done");
        }

    }


    짝짝짝...

    그대로 한번 꼭 해보시길 바랍니다.


    결과는


    - Id: 2222

    - name: wono


    라고 나오겠지요? ^^


    저도 처음에 남이 하는걸 볼때는 쉬워 보였는데, 직접 해볼려니 어렵더군요.


    아, 컴파일은 각각 해주시면 됩니다.(아직 모든 파일들을 한방에 쏵~ 컴파일 해주는 ant 설정은 해주지 않았습니다. 뒷 강좌에서 리눅스 ant에 대해 다루겠습니다.^^)


    1. javac MyAppSqlMapConfig.java

    2. javac Person.java 

    3. javac DBTest.java 


    그리고, java DBTest 라고 해주시면...

    값을 확인해 보실수 있습니다.^^



    이 강좌를 iBatis를 처음 접하는 저와 같은 모든 이땅의 java, jsp 초보프로그래머에게 바칩니다.

    조금이라도 도움이 되셨다면, 덧글이라도 살짝 남겨주세요. 감사합니다.


    iBatis 사이트(http://ibatis.apache.org/javadownloads.html)의 이동국님께서 올려주신 메뉴얼을 많이 참고하였음을 밝히며, 조금밖에 안바꼈지만, 본 강좌의 저작권은 wono77에게 있습니다.

    퍼가실때는 스크랩을 해주세요. 감사합니다. ^^ (__)


    이제 이 iBatis의 기능으로 insert, delete, update 를 추가해서 게시판을 만들거나, struts, spring, log4j 같은 프레임웍을 조금씩 얹어가볼 생각입니다.

    강좌는 계속 수정,보완되며... 진행 될 예정입니다.^^

    Posted by 1010
    반응형

    openCRX Demo

    Welcome to the openCRX demo server. You can test drive a openCRX with any recent browser by clicking any of the provided links below (please note that we develop/test with IE 6.0 SP1, IE 7.0, Opera 9.10+, Mozilla 1.7.3, Firefox 1.5+, 2+, 3+, Google Chrome v1.0+, and Safari 3.0+ - older browsers might find it challenging to render openCRX pages so that you will most likely end up with severly garbled output):

    Demo Server provided by CRIXP Corp.
    crx/core openCRX/Core is a demo of the full-blown openCRX system.

    Continue to crx/core demo
     
    crx/store openCRX/Store is a store-like custom front-end that connects to openCRX/Core
    (i.e. all the data is managed by openCRX/Core). The store is a nice demonstration of how
    you can hide the complexities of an ERP/CRM system behind a user-friendly facade.

    Continue to crx/store demo
     
    Posted by 1010
    98..Etc/velocity2009. 2. 11. 18:33
    반응형

    소개


    Velocity는 Java기반의 템플릿 엔진이고, 개발자가 쉽게 생성하고, 그 형식의 문서를 만들 수 있고, 사용자의 데이터를 보여줄 수 있도록 지원하는 간단하고 강력한 개발 도구입니다. 이 가이드에서는 Velocity를 사용한 개발의 기본 개요에 대해서 설명해 갑니다. 그리고, Velocity의 사용법을 위해 2개의 주요한 사용법에 초점을 맞힙니다. :


  • Servlet 베이스 WWW 개발
  • 일반적인 애플리케이션에서의 사용

    Velocity를 사용해 당신의 Servelt에서 클래스에 기반한 VelocityServlet 클래스를 사용해 매우 쉽게 Servlet을 개발하는 것과

    역할에서는 유틸리티 클래스를 사용해 애플리케이션 개발을 하는 것에 관하여, 여러분은 이들 사이에 본질적인 차이는 없다는 것을 알게될 것입니다.


    시작에 앞서

     

    이 정보는 Velocity 사이트와 문서의 어느 다른 곳에서 찾아내질지도 모릅니다만, 그것은 완전하게 여기에 포함되고 있습니다. Velocity를 여러분의 컴퓨터에서 실행하는 것은, 매우 간단합니다. 모든 디렉토리에서의 참조는 Velocity 배포 트리의 루트 상대 패스됨에 주의해 주십시오.


        1. Velocity 배포를 입수해 주십시오. release와, nightly snapshot와, 직접 CVS code repository 등을 이용하는 것이 가능합니다. 좋게 동작한다고는 생각합니다만, 하지만, 최신의 기능을 위해, nightly snapshot이 아마 최선의 방법이겠지요. 상세 정보는, 여기를 참조해 주십시오.

        2. Java 구축 툴인 Jakarta Ant 을 아직 인스톨 하지 않고 있는 경우에는, 우선 그것을 인스톨 해 주십시오. Velocity를 구축하는데 필요하고, Velocity를 사용하는것에도 필요합니다.

        3. 배포는 build 디렉토리로 이동합니다.

        4. ant <build target> 타입은 <build target> 이하의 내용 중 하나입니다. :

    • jar bin 디렉토리에 완전한 Velocity jar를 생성합니다. 이 jar는, 'velocity-X. jar'라고 합니다. 여기에서의 「X」는, 현재의 버전 번호입니다. 이 jar는 Velocity에 대해 필수 종속을 필요로하지 않습니다. 여러분이 이 대상(target)을 사용한다면, 여러분은 반드시Jakarta Commons의 Collections 컴포넌트 jar을 얻어야 하고, 당신의 CLASSPATH (or WEB-INF/lib)를 포함시켜야 합니다. 여러분이 그 내장된 logging이나 템플릿 변환을 사용하는 것을 원한다면, 여러분의 CLASSPATH나 webapp의 WEB-INF/lib에 그 적절한 jar를 포함해야 합니다. 편의상, 여러분은 ORO나 Logkit, Commons Collections에 포함된 jar로 생성하기 위한 대상(target)으로 jar-dep로 사용할 수 있습니다.
    • jar-dep Jakarta Avalon Logkit 패키지로부터 logging을 위해 필수 지원을 포함하고, Jakarta Commons으로 세부적인 환경을 지원하고, Jakarta ORO 패키지를 사용해서 웹매크로(WebMacro) 템플릿 변환을 필수지원하여, bin 디렉토리에 완전한 Velocity jar를 생성됩니다.
    • jar-core bin 디렉토리에 'velocity-core-X.jar'라는 이름의 작은 사이즈의 Velocity jar를 생성합니다. 이 jar에는 Velocity 기능의 코어가 포함되고 있습니다만, Anakia, Texen 같은 유틸리티와, VelocityServer를 지원하는 기본 클래스는 예지는 포함되고 있지 않습니다. 그것은 정규 jar 와 같은 외부의 종속성 요구사항을 가지고 있습니다.
    • jar-util 'velocity-util X.jar'라는 유틸리티 Velocity jar를 bin 디렉토리에 생성합니다. 이 jar는, 유틸리티 코드, 특히 Anakia, Texen과 WebMacro 템플릿 변환 유틸리티를 포함합니다. 그것은 정규 jar 와 같은 외부의 종속성 요구사항을 가지고 있습니다.
    • jar-servlet 'velocity-servlet-X.jar'라는 유틸리티 Velocity jar를 bin 디렉토리에 생성합니다. 이 jar는, servlet 프로그래머를 위한 유틸리티 코드를 포함합니다. 그것은 정규 jar 와 같은 외부의 종속성 요구사항을 가지고 있습니다.
    • jar-j2ee J2EE 지원을 필요로 하는 모든 컴포넌트를 포함하는 'jar' 대상처럼, 완전한 jar를 생성합니다. 현재, 이것은 org.apache.velocity.runtime.resource.loader.DataSourceResourceLoader만을 포함합니다. 일반적으로, 그것은 'velocity-j2ee-X.jar'라하고, bin 디렉토리에 있습니다. 주의: 만약 이 생성 대상을 사용하고 싶을 경우, 반드시 build/lib 디렉토리에 j2ee. jar를 복사(또는 링크)을 해 두어야 합니다. 우리는, 배포의 일부로써 그것을 제공하고 있지 않습니다. 좋은 소스는 http://java. sun. com/에 있습니다. 그것은 정규 jar 와 같은 외부의 종속성 요구사항을 가지고 있습니다.
    • jar-J2EE-dep J2EE 지원하고, Jakarta Avalon Logkit으로 logging지원을 포함하고, 과 Jakarta ORO패키지로 부터 regexp 지원하는 완전한 jar를 생성합니다. 상기의 jar-deps 타겟을 참조해 주십시오.
    • examples 은 예제 디렉토리에 있는 예제 프로그램으로 예제 코드를 생성합니다. 이것은 또, forumdemo 예제 프로젝트 생성의 생성 대상이 될 것 입니다.
    • forumdemo examples/forumdemo 디렉토리에 예제 웹에플리케이션을 생성합니다.
    • docs 은, Velocity의 Anakia XML 변환 툴을 사용해 이들 문서를 docs 디렉토리에 생성합니다. stylesheets를 대신에 Velocity 템플릿를 사용하는 것이 가능합니다.-시도해 보세요! 주: 이 대상은, jakarta-site2 프로젝트가 jakarta-velocity 배포 디렉토리와 같은 디렉토리로에 위치하도록 해야 합니다. 이 대상의 상세한 정보는 build.xml 파일을 보세요.
    • jar-src 모든 Velocity 소스코드를 하나의 jar에 정리되고, bin 디레크토리에 위치합니다.
    • javadocs docs/api 디렉토리에 Javadoc클래스 문서로 생성됩니다.
    • test (after jar) will test Velocity against it's testbed suite of test routines - test (jar 후에)는 테스트 루틴(일련의 작업)의  testbed 세트를 대비하여 Velocity를 테스트를 할 것입니다.
    • help 이용 할 수 있는 생성 대상의 일람을 표시합니다.

        5. 반드시 필요하지는 않지만 , 생성을 테스트하는것은 좋은 생각입니다. 위에서 보여진 test 타겟을 사용해 주십시오.

        6. 그렇습니다.! Velocity는 사용될 준비가 되었습니다. 클래스 패스 또는 다른 적절한 장소에 jar를 둡니다(만약 servlet에서 사용하는 것이라면 webapp의 lib 디렉토리 등)

        7. 예를 실행해 보고 싶을 경우는, (처음의 경우에는 특히 권장합니다 ), ant examples를 통해 예제의 build를 사용하세요.


    부록

     

    Velocity는 collections과 같은 Java 2 API의 요소(elements)를 사용하고, Java 2 Standard Edition SDK (Software Development Kit)에 의해 생성됩니다. Velocity의 실행은 Java 2 Standard Edition RTE (Run Time Environment)(또는 물론 SDK를 사용할 수 있다.)가 사용되어진다.

    Velocity는 또한 일반적인 기능성을 위해 몇몇의 패키지들에 의존합니다. 그들은 편의상 build/lib 디렉토리에 포함됩니다. 그러나 기본생성대상(:default build target) (위를 참조하세요.)에 그들은 포함되지 않습니다. 만약 기본생성대상(:default build target)을 사용하길 원한다면, 반드시 classpath에 의존(dependencies)을 추가해야 합니다.

    • Jakarta Commons Collections - 필수.
    • Jakarta Avalon Logkit - 옵션, 매우 공통적입니다. 만약 Velocity에서 기본 파일기반 logging을 사용한다면 필요합니다.
    • Jakarta ORO - 옵션. the org.apache.velocity.convert.WebMacro template변경 유틸리티를 사용할 때 필요합니다.

    리소스


    대부분의 리소스와 예제를 프로그래머에게 이용할 수 있게하고, 우리는 당신이 우리의 예제를 보고, 문서와 소스코드를 보는 것을 권합니다. 이하는 훌륭한 소스의 일부입니다  :


  • 유저와 개발자 커뮤니티 : mail-lists에 참가하여 주십시오.
  • Mail-list 보관소 : http://www.mail-archive.com라면 충분합니다. 검색박스에 'velocity' 낱말에 넣고 -user, -dev 보관소 둘다 보아 주십시오
  • 소스 코드 : src/java/... : Velocity 프로젝트의 모든 소스 코드가 있습니다
  • 애플리케이션 예제 1 : examples/app_example1 : 응용 프로그램에서 Velocity를 어떻게 사용하는가 보인 간단한 예제
  • 애플리케이션 예제 2 :examples/app_example2 : Velocity 응용 유틸리티 클래스를 사용한 응용 프로그램에서 Velocity를 사용을 보여주는  간단한 예제
  • servlet 예제 : examples/servlet_example1 : servlet에서 Velocity를 사용하는 방법을 보인 간단한 예제
  • logger 예제 : examples/logger_example : 모든 로그 메시지를 수신하기 위해 Velocity를 등록하고, 고객 logging 클래스를 생성하는 방법을 보여주는 간단한 예
  • XML 예제 : examples/xmlapp_example : Velocity 템플릿을 사용하여 XML 문서 데이타에의 접근과 JDOM의 사용법이 간단한 예제. 문서 트리를 떠돌아 다니는 순환 Velocimacro의 데모를 포함합니다.
  • event 예제 : examples/event_example : Velocity 1.1의 API로 이벤트 운용을 사용한 예제
  • Anakia 에플리케이션 : examples/anakia : XML 데이타의 스타일시트 렌더링(stylesheet renderings)을 생성하기 위해 Velocity를 사용한 애플리케이션 예제
  • Forumdemo web app : examples/forumdemo : servlet 기반의 포럼 애플리케이션의 움직임 본보기 
  • 문서 : docs : Velocity 프로젝트를 위해 html로 생성된 모든 문서
  • API 문서 : docs/api : Velocity 프로젝트를 위해 생성된 Javadoc 문서
  • 템플릿 : test/templates : testbed 디렉토리에 템플릿의 큰 집합(collection), VTL(Velocity Template Language)의 사용법이 훌륭한 소스가 있습니다.
  • context example : examples/context_example : two examples showing how the Velocity context can be extended. For advanced users.
  • context 예제 : examples/context_example : Velocity context을 확장할 수 있는 방법을 보여주는 2개의 예제가 있습니다. 고급자용.

     

    위의 모든 디렉토리의 참조는, 배포 루트 디렉토리의 상대 패스입니다.


    Velocity 사용 방법


        'The Fundamental Pattern'

     

        응용프로그램과 servlet 에서 Velocity를 사용하는 경우 (또는 정확하게는 기타의 경우도 ), 이하의 것을 실행해야 합니다.

    1. Velocity의 초기화. 이것은, Velocity를 위한 쌍방의 패턴을 사용할 때에 적용하고, Singleton과 마찬가로 '실행시 인스턴스 분리' (상세하게 붙어서는 하기 참조 ) 한 번만 실행합니다.
    2. Context 오브젝트의 생성 (상세는 나중에..)
    3. Context에 당신의 데이타 오브젝트의 추가
    4. 템플릿의 선택
    5. 출력을 생성하기 위해(때문에) 당신의 데이타와 템플릿의 머지('Merge')

        코드에서, org.apache.velocity.app.Velocity 클래스를 통해 Singleton 패턴을 사용하려면, 이렇게 합니다.


    import java.io.StringWriter; 
    import org.apache.velocity.VelocityContext;
    import org.apache.velocity.Template;
    import org.apache.velocity.app.Velocity;
    import org.apache.velocity.exception.ResourceNotFoundException;
    import org.apache.velocity.exception.ParseErrorException;
    import org.apache.velocity.exception.MethodInvocationException;
    Velocity.init(); 
    VelocityContext context = new VelocityContext(); 
    context.put( "name", new String("Velocity") ); 
    Template template = null; 
    try { template = Velocity.getTemplate("mytemplate.vm"); 
    } catch( ResourceNotFoundException rnfe ) {
     // couldn't find the template
    } catch( ParseErrorException pee ) {
     // syntax error : problem parsing the template
    } catch( MethodInvocationException mie ) {
     // something invoked in the template // threw an exception
    } catch( Exception e ) {}
    StringWriter sw = new StringWriter(); 
    template.merge( context, sw );

        이것이 기본적인 패턴입니다. 대단히 단순하지 않나요? 이것은, 일반적으로 당신이 템플릿을 렌더링하는데 Velocity를 사용할 때에 실행하는 것입니다. 당신은 아마도 당연히 이런 코드를 쓰고 있지 않을 것입니다.-우리는 servlet과 응용프로그램의 둘다를 위해서, 보다 간단하게 만들기 위해 도움되는 2∼3의 툴을 준비하고 있습니다. 이 가이드의 후반부에, 우리는 두개의 servlet에서 일반적인 애플리케이션 처럼 Velocity를 사용하는 것에 대해서 설명할 것입니다. 그리고, 우리는 쉽게 만들기 위해 제공하는 툴을 검토합니다. 어느쪽의 경우도 상기의 순서가 그 화면 뒤에서, 움직이고 있는 것은 사실입니다.


    To Singleton Or Not To Singleton


        Velocity 1. 2 버젼이나 이후 버젼부터, 개발자는 현재 Velocity 엔진을 사용하기 위해, Singleton 모델과 Separte Instance 모델의  2개의 옵션이 있습니다.  어느쪽의 방법도 같은 Velocity 코드의 코어를 사용하고, Velocity에 의해 간단하게 당신의 Java 에플리케이션에 통합되는 것이 가능합니다.


        Singleton Model

     

        이것은 legacy  패턴, JVM(또는 Web 에플리케이션, depending)에서 하나의 Velocity 엔진의 instance가 모두 공유됩니다. 이것은 리소스의 공유와 지역적 설정을 위해 매우 편리한 방법입니다. 예컨대, 이것은 servlet 2. 2이후 버젼과 호환되는 독자적인 Velocity의 instance를 가질 수 있는 각각의 Web 에플리케이션이고,  템플릿, 로그, 기타 처럼 리소스 공유를 Web 에플리케이션의 servlet이 지원하는, web 에플리케이션에서 사용하기 위한 매우 적절한 모델입니다.

    싱글 톤은, org.apache.velocity.app.Velocity 클래스에서 접근하는 것이 가능하고, 이하처럼 사용합니다.


    import org.apache.velocity.app.Velocity; 
    import org.apache.velocity.Template; ...
    /* * Configure the engine - as an example, we are using 
     * ourselves as the logger - see logging examples
     */
    Velocity.setProperty( Velocity.RUNTIME_LOG_LOGSYSTEM, this); 
    /* * now initialize the engine */ 
    Velocity.init();
    ... 
    Template t = Velocity.getTemplate("foo.vm");

        Singleton 모델은, org.apache.velocity.servlet.VelocityServlet 베이스 클래스에서 사용되고, 유틸리티 클래스는, servlet을 간단하게 작성하기 위해 배포되는 것에 주의해 주십시오. 이 클래스를 확장하는 것은 Velocity를 사용하는 servlets를 쓰는 것이 가장 공통적이고편리한 방법입니다만, 다른 목적을 위해 이 클래스를 사용하지 않는 것은 당신의 자유입니다.


        Separate Instance

     

        새로운 1. 2버젼부터, Separate instance는 같은 JVM(또는 Web 에플리케이션 )에서 Velocity의 인스턴스를 대부분 생성, 설정,사용하는것을 지원합니다.


    이것은 같은 에플리케이션에서 템플릿 디렉토리와, 로그, 기타 등의 설정을 분할하고 싶을 때에 도움이 됩니다. Separate instance를 사용하기 위해서는, org.apache.velocity.app.VelocityEngine 클래스를 사용합니다. 상기의 Singleton의 예제와 비슷한 예제가 있습니다.

    import org.apache.velocity.app.VelocityEngine; 
    import org.apache.velocity.Template;
    ... 
    /* * create a new instance of the engine */ 
    VelocityEngine ve = new VelocityEngine(); 
    /* * configure the engine. In this case, we are using 
     * ourselves as a logger (see logging examples..)
     */
    ve.setProperty( VelocityEngine.RUNTIME_LOG_LOGSYSTEM, this); 
    /* * initialize the engine */ 
    ve.init(); 
    ... 
    Template t = ve.getTemplate("foo.vm");

    보이는것 처럼, 이것은 매우 심플하고 간단한 것입니다. 단순한 문법의 변경에서의 제외하고, Velocity를 사용하면 Singleton과 Separate instance의 요구때문에 당신의 에플리케이션과 템플릿의 고 레벨의 구조를 변경할 필요는 없습니다.


    프로그래머로써, 당신이 사용해야 하는 클래스는 싱글 톤 모델을 사용하는 경우에는 org.apache.velocity.app.Velocity 클래스를, non-Singleton 모델 ('Separate instance')은 org.apache.velocity.app.VelocityEngine을 Velocity 내부에 영향을 미친다.


    에플리케이션에서 org.apache.velocity.runtime 패키지의 internal Runtime, RuntimeConstants, RuntimeSingleton or RuntimeInstance 클래스를 결정해 사용하지 말아 주십시오. 이것들은 내부 사용만을 상정하고 있고, 오래지 않아 변경될 것입니다. 위에서 언급했듯이 당신이 사용할 클래스는 org.apache.velocity.app 패키지, 그리고 VelocityVelocityEngine 클래스입니다.

     만약 어느것이든지 그들 클래스로가 잘못되었거나 필요하다면, 변경을 제안하는 것에 주저하지 말아 주십시오-이들 클래스는 에플리케이션 개발자를 대상으로 합니다.


    The Context

     

        The Basics


        'context'의 개념은, Velocity에 있어서 주요하고, 시스템의 일부의 사이에서 데이타 중심의 콘테이너를 이동시키는 공통의 테크닉입니다. context의 사고방식은 Java layer(혹은, 당신 프로그래머)와 template layer(또는 설계자(designer))사이에서 데이타의 'carrier'라 합니다. 프로그래머로써의 당신은, 다양한 타입(당신의 에플리케이션이 요구하는 것은 무엇이든지)의 오브젝트를 모으게 되고, context에서 그것들을 두게 됩니다. 설계자(designer), 이들 objects와 그들의 methods에, 그리고, properties는 references라는 template elements를 통해 접근 가능하게 되게 됩니다. 일반적으로, 당신은 에플리케이션의 자료를 결정하기 위해 설계자(designer)와 일하게 됩니다. 어떤 의미에서, 이것은 템플릿에서 접근하는 설계자(designer)를 위한 데이터 설정을 생성하는 'API'가 될 것입니다.

    따라서, 개발 프로세스의 양상으로의 그것은 약간의 시간과 신중한 분석을 바치는 가치가 있습니다.

  • Posted by 1010
    56. Eclipse Etc.../Eclipse2009. 2. 11. 16:41
    반응형

    이클립스 설치후 깔아야할 플러그인들 ..

    ( 현재 Eclipse 3.2.x 기준 )

    1. 기본적으로 WTP 플러그인을 설치한다.
        (Update 실행하면 됨 ㅋㅋ)

    2. AnyEdit 말이 필요 없다. 필수!
    - Ctrl + Shift + R 누르면 해당 링크로 바로 이동 ㅡ_ㅡ; 소스레벨의 F3키와는 다른 편리함 이밖에도 다른 기능들이 조낸 많음
    - 사이트 :  http://andrei.gmxhome.de/anyedit/index.html
    - 업데이트 : http://andrei.gmxhome.de/eclipse/

    3. properEdit
    - 각종 property 파일 수정할때 native2ascii 할 필요가 없게 해주는 유용함. ㅋ 일본어, 한글, utf-8 다 지원한다.

    4. Extended VS Presentation
    - 이클립스 스타일을 변경해줌과 동시에 인터페이스가 바뀐다 ㅡㅡ; 지금 랭킹 1위야 ㅡㅡ; 그밖에 여러가지
    - 사이트: http://andrei.gmxhome.de/skins/index.html
    - 업데이트 : http://andrei.gmxhome.de/eclipse/

    5. QuickREx - regular expressions
    - 웹개발을 하다보면 말이지 레귤러 익스프레션을 사용할 일이 생긴다고 ㅡㅡ; 요거 그거야 ㅋ
    - 사이트 : http://www.bastian-bergerhoff.com/eclipse/features/web/QuickREx/toc.html 
    - 업데이트 : http://www.bastian-bergerhoff.com/eclipse/features

    6. Log4E
    -  말안해도 알겠쥐?
    - 사이트 : http://log4e.jayefem.de
    - 업데이트 : http://log4e.jayefem.de/update

    7. Oxygen XML Editor and XSLT Editor/Debugger
    - XML 써바야지 ㅡㅡ;
    - 사이트 : http://www.oxygenxml.com
    - 업데이트 : http://www.oxygenxml.com/InstData/Eclipse

    8. JadClipse
    -  이건 역컴파일러라는거지 ㅎㅎ 넘 괜찮은넘 ㅡㅡ;
    - 사이트 : http://jadclipse.sourceforge.net
    - 업데이트 :

    9. PMD For Eclipse
    -
    - 사이트 : http://pmd.sourceforge.net
    - 업데이트 : http://pmd.sourceforge.net/eclipse/

    10. Code Analysis Plugin - CAP
    -  요건 페키지, 파일 들이 어떤 구조로 되어 있는지 한눈에 알 수 있게 해준다. 스크린샷 참고
    - 사이트 : http://cap.xore.de
    - 업데이트 : http://cap.xore.de/update/

    11. Checkstyle Plug-in
    - 알려진 소스에 대한 스타일 체크
    - 사이트 : http://eclipse-cs.sourceforge.net/
    - 업데이트 : http://eclipse-cs.sourceforge.net/update

    12. QuantumDB Eclipse Plugin
    - SQL
    - 사이트 : http://quantum.sourceforge.net/
    - 업데이트 :
    파일다운로드




    13. Maven Integration for Eclipse
    - 마빈 플러그인 이클립스에서 마빈을 사용하여 빌드를 할 수 있게 해준다 .. ㅋㅋ 필수조 ㅎㅎ
    - 사이트 : http://m2eclipse.codehaus.org/
    - 업데이트 : http://m2eclipse.codehaus.org/update/

    14. Lib Copy
    - 마빈 플러그인 이클립스에서 마빈을 사용하여 빌드를 할 경우 WTP와 통합이 되도록 해준다 ㅋㅋ 자세한 사항은 아래 사이트 참조 ( 이건 WTP를 사용 하지 않을꺼라면(대신 sysdo tomcat plugin 사용) 안해도 된다)
    - 사이트 : http://adam.kruszewski.name/projects/libcopy
    - 업데이트 : http://adam.kruszewski.name/eclipse

    15. Sysdeo Eclipse Tomcat Launcher plugin
    -  톰켓 플러그인
    - 사이트 : http://www.sysdeo.com/eclipse/tomcatplugin
    - 업데이트 :  톰켓 6.0 까지 지원 아직 배타이지만 정식 나오겠지 (압축풀어 설치)
    파일 다운 로드





    16. SubVersion 버전 관리 툴
    - 버전 관리 막강한 client 툴 이거 없으면 못해 CVS도 있지만 서브 버전의 막강한 기능을 구현
    - 사이트 : http://www.polarion.org/p_subversive_features.php
    - 업데이트 : http://www.polarion.org/download/p_subversive/update-site/


    ■ 이클립스 플러그인 관련 사이트

    http://www.eclipse-plugins.info 간단한 플러그인 정보와 인기도(?) 확인 가능
    http://www.sourceforge.net 각종 이클립스 플러그인 프로젝트들이 등록되어있음
    http://www.eclipseplugincentral.com 플러그인 쇼핑몰, 포럼


    ■ DB 플러그인

    1) Quantum DB (http://sourceforge.net/projects/quantum/)

    왼쪽 북마크에 접속하고자 하는 DB 추가하고 환경잡기(ID, 비번, 접속드라이버 등)
    원하는 북마크를 오른쪽버튼 클릭해서 DB에 connect한 후 오른쪽 쿼리 에디터에서 쿼리.

    [참고]
    - 오라클 JDBC드라이버 : C:oracleora81jdbclibclases12.zip 찾아서 추가 (oracle.jdbc.driver.OracleDriver)
    - connection URL : jdbc:oracle:thin:@000.00.00.000:1521:ORACLE8

    2) dbedit (http://sourceforge.net/projects/dbedit/)

    3) jfacedbc #상용# (http://sourceforge.net/projects/jfacedbc/)

    소스포지에 있는 버전은 2.X 버전이고 3.0부터는 상용으로 http://www.jfacedbc.com/ 에서 다운/구매 가능 (기능은 확실히 좋을 듯...)



    ■ XML 플러그인

    1) XMLBuddy http://www.xmlbuddy.com/
    XMLBuddy pro는 #상용#입니다.

    2) oxygen #상용#
    url update : http://www.oxygenxml.com/InstData/Eclipse/site.xml

    3) MyEclipse Enterprise Workbench #상용# (http://www.myeclipseide.com)
    MyEclipse 설치하면 깔리는 XML 에디터.

    4) 그 외 JXMLEditor, MetaCoder , Sunbow , X-Men, XML Schema Quality Checker



    ■ J2EE 개발 플랫폼

    1) Lomboz (http://forge.objectweb.org/projects/lomboz)
    롬보즈를 쓰기 위해서는 EMF(http://www.eclipse.org/emf)도 깔려있어야 함

    2) MyEclipse Enterprise Workbench #상용# (http://www.myeclipseide.com)



    ■ JSP 에디터 플러그인

    1) SolarEclipse (http://sourceforge.net/projects/solareclipse/)
    jsp 하이라이팅 기능만 있음

    2) Lomboz jsp editor (http://forge.objectweb.org/projects/lomboz)
    롬보즈 설치하면 깔리는 jsp 에디터. 코드 어시스턴스 기능 있음.

    3) MyEclipse Enterprise Workbench #상용# (http://www.myeclipseide.com)
    MyEclipse 설치하면 깔리는 jsp 에디터. 롬보즈가 저장 시 에러 체크를 하는 반면, 실시간으로 에러 체크를 한다고 함.



    ■ 각종 플러그인

    1) Yoxos ( http://www.yoxos.com/ )

    유용한 플러그인들을 묶어 프로그램 인스톨하는 형식으로 배포.
    종류별로 잘 분류되어 있고 설치시 필요한 플러그인만 선택하여 설치 가능.

    2) subversion (svn) 플러그인
    url update : http://subclipse.tigris.org/update

    3) SWT/Swing 디자이너 #상용# http://www.swt-designer.com/




    ■ 플러그인 설치

    1) 설치유형 1 : 복사
    받은 플러그인 파일을 C:eclipseplugins 에 복사하고 재시작

    2) 설치유형 2 : url update
    Help > Software Updates > Find and Install 메뉴 선택
    "search for new features to install" 선택후 next 버튼
    new remote site 버튼을 클릭하여 플러그인명과 url update 주소를 입력하면 다운 받을 수 있다.

    3) 플러그인 설치 문제 해결

    복사해서 플러그인을 설치 할 때 가끔 반영이 안되는 문제가 있다.
    똑같이 설치를 해도 잘 되는 컴이 있는가 하면 그렇지 않은 것도 있으니... -_-a
    처음 실행 이전에 플러그인을 모두 복사해야 정상작동할 듯 싶다. 일단 실행 이후에 플러그인을 추가 설치하면 간혹 말썽이다.

    첫째, Help > Software Updates > Manage Configuration 에서 설치되지않은 것들이 있으면 enable 시켜준다.
    이렇게 해서 해결 된다면 제일 편하게 해결된 것.

    둘째, eclipse 폴더 아래 configuration 폴더를 지우고 재시작.

    셋째, 이래도 안 깔리면.... 이클립스를 아예 새로 풀고 플러그인들 먼저 다 복사해 둔 후 최초실행 시킨다.


    출처 : http://www.cyworld.com/kangs007

    Posted by 1010