2007년 2월 28일 수요일

FCKeditor 2.4 설정 입문

FCKeditor 2.4 설정에 대하여 정리를 좀 해봤습니다.



FCKeditor 은 파워풀한 위지윅 에디터로서 파일 업로드 기능까지 내장되여 있다.
FCKeditor 설치법 및 java 웹 어플리케이션하고의 연동사항은 예전에 올린 글속에 포함이 되여있으므로 생략하겠다.



1. 불필요한 폴더 및 파일들을 삭제하여 용량을 확보한다.

삭제해야 할 파일 및 폴더 리스트

_samples
_testcases
_documentation.html
_upgrade.html
_whatsnew.html
fckeditor.asp
fckeditor.pl
fckeditor.afp
fckeditor.cfc
fckeditor.cfm
fckeditor.lasso
fckeditor.php
fckeditor.py
fckeditor_php4.php
fckeditor_php5.php
license.txt
htaccess.txt

2. fckconfig.js설정파일에 대한 수정

// 자동으로 클라이언트측 언어 설정을 탐지하여 FCKeditor 언어모드를 설정해준다.
FCKConfig.AutoDetectLanguage = true ;

// 기본 언어모드를 설정해준다. en이면 영문모드이다.
FCKConfig.DefaultLanguage  = 'en' ;

// 스킨 설정
FCKConfig.SkinPath = FCKConfig.BasePath + 'skins/default/' ;

// 툴바가 로딩될때 펼침상태로 보여질 여부를 설정
FCKConfig.ToolbarStartExpanded = true ;

// 새로운 폰트를 첨가할수 있다.
FCKConfig.FontNames  = 'Arial;Comic Sans MS;Courier New;Tahoma;Times New Roman;Verdana' ;

편집기에 입력되는 기본 글자 크기는 설정파일이 아닌 CSS파일에서 설정해주어야 한다.
FCKeditor\editor\css\fck_editorarea.css를 열어서 아래와 같이 바꿔주면 된다.
body, td
{
 font-family: Arial, Verdana, Sans-Serif;
 font-size: 14px;
}

3. 툴바 요소들에 대한 설정

에디터가 로딩될때 만약 특정된 툴바셋을 지정하지 않으면 기본적으로 세팅된 툴바가 로딩된다.
FCKConfig.ToolbarSets["Default"] 이 배열에 나열된 하나하나의 개체들은 매 하나의 툴과 1:1 매칭이 되여진다. 사용자는 자신의 입맛에 맞게 툴바에 나열될 툴들을 커스터마이징 할수 있다.

4. 문자 스타일에 대한 설정

자주쓰는 문자열에 대한 스타일은 미리 정의하여 쓸수 있다. 이런 정의는 XML파일에 설정할수 있다. FCKeditor루트에 보면 fckstyles.xml 파일이 존재하는데 이것이 바로 스타일 설정파일이다.

fckstyles.xml 파일 보기...



5. 템플릿에 대한 설정

템플릿에 대한 정의는 fcktemplates.xml에서 할수 있다. fcktemplates.xml파일 경로는 fckconfig.js 에서 설정해줄수 있다.
FCKConfig.TemplatesXmlPath = '/mytemplates.xml' ;

more..

Struts 2.0.6 General Availability Release

Struts 2.0.6 GA버젼이 새롭게 릴리즈 됐네요.



간단한 개요

Apache Struts 2는 엔터프라이즈 자바 어플리케이션을 구축함에 있어서 추가확장이 가능한 훌륭한 프레임웍이다. 이 프레임웍은 전반적인 자바 어플리케이션 개발 라이프싸이클(빌드, 디프로이, 메인테인) 에 마추어서 만들어 져 있다.

Apache Struts 2는 WebWork 2로 많이 알려져 있었으며 독립적으로 여러해 동안 별개의 프로젝트로 개발이 되여져 왔었다. 결국 WebWork + Struts = Struts 2 버젼대로 출시하게 되였다.

플랫폼 요구사항

  • Servlet API 2.4
  • JSP API 2.0
  • Java 5

    Apache Struts 2 아키텍쳐



    1. 웹브라우저가 리소스(/mypage.action, /reports/myreport.pdf, 기타) 요청을 한다.
    2. Filter Dispatcher은 요청을 받어들이고 적당한 액션을 결정한다.
    3. Interceptor들은 자동적으로 요청에 workflow, vlidation, file upload등과 같은 여러가지 공용적으로 사용이 되여질 기능들을 추가한다.
    4. Action 메소드가 실행이 되여진다. (보통 데이타베이스에서 데이타를 저장하거나 얻는 과정이다.)
    5. 결과가 렌더링되여 웹브라우저에 출력이 되여진다. 출력포맷은 다양한데 HTML, images, PDF 등을 모두 지원한다.

    다운로드

  • 돌아오는 학기내 읽어야할 책자들...

    S/W분야



    소프트웨어 블로그 베스트 29선

    more..





    패턴을 활용한 리팩터링

    more..



    H/W 분야



    유비쿼터스 컴퓨팅의 핵심 RFID Handbook (Second Edition)

    more..



     

    연변과학기술대학 -- YUST (Yanbian University Science & Technology)

     


    2007년 2월 27일 화요일

    Spring과 Timer 사이의 연동으로 인한 스케쥴링

    스케쥴링을 하기 위하여서는 아래 몇가지 개념부터 먼저 잡고 넘어가야한다.
    job : 이것은 독립적인 작업단위로서 job은 지정된 단위간격을 주기로 실행이 되여진다.
    trigger : job의 실행을 하기위한 조건을 명시한다. 이런 조건은 단순히 고정된 시간으로 구성이 되여질수 도 있고 아니면 복잡한 데이타로 구성이 되여질수도 있다.
    scheduler : trigger의 집합으로써 직책은 전체 스케쥴링 시스템을 관리하는것이다.

    Spring은 여러가지 보조적 클래스를 이용하여 Timer와 연동하여 사용되여진다.
    ScheduledTimerTask와 TimerTask가 그 가장 대표적인 보조클래스이다.
    또한 TimerFactoryBean을 통하여 Spring은 자동적으로 지정된 trigger한테 새로운 공유된 Timer 인스턴스를 생성해주고 Timer는 이런 Trigger 를 이용하여 해당 job을 실행해준다.

    ApplicationContextTimer.xml

    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"

    "http://www.springframework.org/dtd/spring-beans.dtd">

    <beans>

      <!-- 주입시킬 클래스를 선언적 방식으로 명시하였다. -->

      <bean id="generatorJob"

            class="com.xxx.nnserp.spring.SmsTransferLegacy">

      </bean>

     

      <!-- MethodInvokingTimerTaskFactoryBean 사용하여

                  generatorJob 동적 프록시를 생성하였으며 TimerTask 특성을 가지게 하였다. -->

      <bean id="generatorJobProxy"

            class="org.springframework.scheduling.timer.
                   MethodInvokingTimerTaskFactoryBean"
    >

          <property name="targetObject">

              <ref local="generatorJob"/>

          </property>

          <property name="targetMethod">

              <value>send</value>

          </property>

          <property name="arguments">

              <value>xxx</value>

          </property>

      </bean>

     

      <!-- 실제 타이머태스크가 작동할 시간단위를 설정해준다. -->

      <bean id="repeatingTrigger"

        class="org.springframework.scheduling.timer.ScheduledTimerTask">

        <!-- 시동후 20초후 작업을 실행한다. -->

        <property name="delay">

          <value>20000</value>

        </property>

        <!-- 5초마다 작업을 실행한다. -->

        <property name="period">

          <value>5000</value>

        </property>

        <!-- 위에서 선언한 generatorJobProxy timerTask 주입시킨다. -->

        <property name="timerTask">

          <ref local="generatorJobProxy" />

        </property>

      </bean>

     

      <!-- 스케쥴러속성에 타임태스크와 반복설정관련 트리거를 추가해준다. -->

      <bean id="scheduler"

        class="org.springframework.scheduling.timer.TimerFactoryBean">

        <property name="scheduledTimerTasks">

          <list>

            <ref local="repeatingTrigger" />

          </list>

        </property>

      </bean>

    </beans>

     
    ApplicationContextTimer.xml 는 Spring의 ApplicationContext에 대한 설정파일로서 이 예제에서는 실제 타이머 어떻게 작동할것인지에 대한 룰들을 정의하고 또한 어느 클래스에 대하여 스케쥴링을 할것인지를 설정해준다.

    SmsTransferLegacy.java

    public class SmsTransferLegacy {

           public void send(String args)

           {

                 System.out.println(LibDatetime.getTimeString() + " 시각에 " + args +

                                                                                                              " SMS 발송!");

           }

     

    }


    SmsTransferLegacy.java 클래스는 사실상 주기적으로 실행이 되여져야 할 클래스로서 이 예제에서는 단순히 실행이 되여질때마다 타임스템프를 출력시키는것으로 구현했다.

    성공적인 프로젝트를 위한 팀장 덕목 10가지

    1 본인 스스로 이해하라

    자기 자신도 이해할 수 없는 프로젝트를 진행하게 되면, 계속 스스로 논리적 모순에 빠져 일의 진행에 고통을 느끼게 된다. 프로젝트를 진행하기에 앞서 가장 먼저

    ' 왜 이 프로젝트를 해야 하는가? '
    ' 이 프로젝트로 얻게 될 효과는 무엇인가? '
    ' 어떻게 진행할 것인가? '

    에 대해 먼저 생각을 정리해야 한다. 이 생각이 정리되어야 함께 일할 팀원을 이해시키고, 진행 상 어려움에 봉착했을 때 뚜렷한 목표의식을 가지고 헤쳐나갈 수 있다. 프로젝트의 제 1 클라이언트는 바로 자기 자신이다.


    2 팀장은 프로젝트에 대해 팀원을 이해시켜라

    팀원들도 해당 프로젝트를 이해하지 못하는데 누가 프로젝트를 정상적으로 이끌겠는가? 결국 실무를 행하는 사람들은 팀원들인데 말이다. 그러므로 반드시 팀장은 프로젝트에 대해 팀원들을 먼저 설득시켜야 한다. 이를 위해서는 '회사가 이러이러 하니 무조건 해야돼' 식은 아주 곤란하다. 이는 오히려 프로젝트에 대한 이해보다는 반발심을 불러일으킬 소지가 있다. 강요가 아닌 논리적인 설명으로 프로젝트에 대해 이해시켜야 한다.

    3 프로젝트 목표를 공유하라

    프로젝트는 무엇을 추구하고 있는가? 이를 통해 얻으려고 하는 것은 무엇인가? 이는 매우 중요한 문제이다. 우선 팀장 스스로 프로젝트의 목표에 대해 분명히 생각이 서 있어야 하며, 이를 팀원들에게 공유시켜야 한다. 목표는 반복적으로, 다양한 방법으로 설파시켜 팀원 모두가 적어도 목표만큼은 자다가도 외우도록 해야 한다. 또한 프로젝트가 추구하는 목표에 대해 서로의 생각을 맞추기 위해 토론해 보는 것도 좋다. 이런 과정들이 프로젝트를 더 탄실하게 만들어 줄 것이다.  


    4 개인의 목표를 설정하라

    프로젝트를 진행하는 행위가 단지 회사에만 좋다면, 개인의 입장에서는 괴로울 수 밖에 없다.
    팀원 각각이 이 프로젝트를 통해 얻을 목표를 설정하도록 하라. 이는 팀원들이 더 적극적으로 프로젝트에 참여하도록 만든다.


    5 윈-윈에 대해 생각하라

    프로젝트의 성공은 중요하다. 하지만, 그 성공이 1회적 성공으로 그치지 않고 다른 프로젝트의 성공들로까지 연결된다면 이는 최고의 팀이라고 할 수 있을 것이다. 그러기 위해서는 프로젝트의 성공과 팀원들의 성공이 함께 할 수 있는 방법에 대해 끊임없이 고민하고 실행해야 한다. 프로젝트의 성공이 팀원들의 성공이 아니냐라고 생각하는 사람도 있겠지만 그렇지 않다고 생각한다. 프로젝트는 성공했지만, 팀원들은 그 프로젝트로 인해 의욕을 상실하고 오히려 그 업계를 떠나려고까지 생각하는 사람을 많이 봤다. 이런 프로젝트가 팀원들에게 성공적이었다고 할 수 있을까? 적어도 팀원에게 성공이라는 것은, 스스로 성공한 경험을 심어주는 것과 그로 인한 자신감을 얻는 것, 앞으로 더 큰 가능성들을 제시해 주는 것이 아닐까라고 생각한다.


    6 서로의 입장에서 생각하고 대화하라

    같은 팀원들 간이라도 상대방이 이해할 수 있는 방법으로 대화하라. 그것은 서로에 대한 이해를 높임은 물론 원활한 커뮤니케이션을 발생시켜, 프로젝트를 좀 더 성공적으로 이끌 수 있을 것이다.


    7 팀원들도 사람이라는 것을 기억하라

    어떤 시스템과 방법론을 도입하더라도 결국 프로젝트를 진행하는 것은 사람이다. 개개인에 대한 이해가 있어야 그들이 가진 최대의 능력을 뽑아낼 수 있고, 그들이 프로젝트를 통해 성장할 수 있도록 할 수 있다. 이것을 이해하지 못하면, 팀원들이라는 존재는 오직 프로젝트를 위한 자원일 뿐이게 된다. 그 뒤의 상황은 불보듯 뻔하다.


    8 원칙을 지키되 유연성을 발휘하라

    프로젝트 관리에서 원칙을 지키는 것이 중요하다는 것은 매우 중요하다. 하지만, 원칙도 그 급이 있다. 프로젝트를 관리하기 위해 필요한 원칙들을 그 중요도에 따라 구분하고 거기에 따른 유연성을 발휘할 필요가 있다. 가장 중요한 원칙이라면, 이로 인해 프로젝트가 무너질 위험까지 있다고 판단된다면 그 원칙은 어떤 일이 있어도 지켜야 한다. 하지만, 그렇지 않은 항목들에 대해서는 유연성을 발휘하자.
    또한, 서로가 지켜야할 원칙은 프로젝트가 본격적으로 들어가기에 앞서 반드시 문서를 통해 공유하고 이에 대해 의견을 나눠볼 필요가 있다. 이를 통해 서로 지켜야할 원칙을 확인하고, 원칙에 있을 수 있는 오류를 시정할 기회를 가질 수 있다.


    9 지시사항과 논의 사항을 구분하라

    팀원을 배려한다고 해서 모든 것을 팀원과 논의하라는 것은 아니다. 오히려 모든 것을 논의하게 되면 쓸데없는 회의들이 생길 것이고, 업무의 흐름이 끊기는 일이 자주 발생할 것이며, 업무의 효율을 떨어뜨릴 것이다. 이런 일이 발생하지 않도록, 팀장은 지시사항과 논의 사항을 분명히 구분해야 한다. 어떻게 일을 정의하느냐에 따라 모든 것이 논의의 대상이 될 수 있는 것은 분명하지만, 그래도 이를 구분해내야 한다.  업무시간 내 효율성을 중시하는 팀장이 있다고 할 경우, 그 팀장에게 있어 '업무 시간 중 메신저를 사용하지 마라'는 지시사항이지 논의사항은 아니다.


    10 신뢰를 주라

    말과 행동의 균형을 이뤄 신뢰를 보여주라. 말로는 당신들을 신뢰한다고 하고는, 행동은 전혀 상반된 행동을 한다면 신뢰하지 않을 것이다. 또, 행동으로만 신뢰를 주는 것은 팀원들이 모를 수도 있다. 원래 저런가라고 생각할 수 있다. 신뢰라는 것도 가끔은 말로 표현되는 것이 중요하다. 말이 좀 더 직접적이기 때문이다. 하지만, 이런 말은 앞에서도 말했듯이 반드시 행동이 동반되지 못한다면 말만 하는 사람으로 비쳐지게 된다. 그리고 초기에는 신뢰를 하지 못하더라고, 신뢰하기 위한 행동을 보이면 그것이 오히려 진정한 신뢰로 변하기도 한다. 신뢰는 팀의 결속을 더 단단히 시켜준다는 사실을 잊어버리지 말자.

    출처 : http://flyfish.tistory.com/165

    2007년 2월 26일 월요일

    Java Annotation 해석

    Language Contents(언어 관련 주제들)

    Annotations(덧붙이는 말)
    --------------------------------------------------------------------------------

    많은 API들은 상당한 양의 반복 사용되는 코드를 요구합니다. 예를들어, JAX-RPC 웹 서비스를 작성하기 위해서, 당신은 interface와 구현부분을 쌍으로 제공해야만 합니다. 이러한 반복 사용되는 코드는 만약 그 프로그램이 어떤 메서드들이 원격으로 접근이 되는지 [덧붙이는 말]과 함께 "꾸며졌다면" 도구에 의해서 자동으로 생성되어질 수 있습니다.

    다른 API들은 프로그램과 동시에 유지해져야 하는 "부가적인 파일들"을 요구합니다. 예를 들어, JavaBeans는 BeanInfo 클래스를 bean과 동시에 유지해져야 하고, Enterprise JavaBeans(EJB)는 배포 설명자를 요구하죠. [덧붙이는 말]은 만약에 이런 부가적인 파일들 안에 있는 정보들이 프로그램 자체 내에 내장하고 있는 [덧붙이는 말]과 같이 유지된다면 더욱 편리하고 더 에러를 적게 내게 됩니다.

    Java platform은 항상 다양한 괴상한 [덧붙이는 말] 기술들을 가져왔습니다. 예를 들어서, transient 표시자는 그 field는 serialization 하위 시스템에 의해서 무시되어져야만 하는 field를 나타내는데 쓰이는 이상한 [덧붙이는 말]이고, @deprecated javadoc 태그는 method가 더이상 사용되지 않아야 한다는 것을 나타내는 이상한 [덧붙이는 말]입니다. 5.0을 배포판에 따라, platform은 일반적인 목적의 [덧붙이는 말](또한 metadata로 알려진) 기능을 가지게 되었고, 이것은 당신이 정의하고 사용할 수 있는 개개인의 [덧붙인는 형태]를 허용해줍니다. 그 기능은 [덧붙이는 형태에 대한 정의], [덧붙여지는 정의]에 대한 문법과 [덧붙여지는 말들을 읽기 위한 API], [덧붙이는 말을 표시하기 위한 클래스 파일], 그리고 [덧붙여지는 말을 처리하는 도구]를 포함합니다.

    [덧붙이는 말]은 직접적으로 프로그램의 의미에 영향을 주지 않으나, 도구들과 라이브러리들에의해 여겨지는 바가 다르도록 영향을 끼칩니다. 이 말은 실행 중인 프로그램의 의미가 번갈아서 영향을 받을 수 있다는 뜻입니다. [덧붙이는 말]은 소스 파일, 클래스 파일, 또는 실행시간에 Reflection(실행 시간의 클래스 명이나 메서드 명 같은 것을 얻어오는 자바의 수단)으로 부터 읽어들여질 수 있습니다.

    [덧붙이는 말은] javadoc 태그들을 보조합니다. 일반적으로, 만약 표시가 영향을 미치도록 의도되었거나 문서화를 하도록 의도되었다면, 그것은 아마도 javadoc 태그가 되어져야만 합니다; 아니면, 그것은 하나의 [덧붙이는 말]이 되어야 합니다.

    전형적인 응용 프로그램 개발자들은 절대로 [덧붙이는 말 형태]를 정의하지 않아야 할 것이지만, 그렇게 하는 건 그다지 어렵지 않습니다. [덧붙이는 말 형태]는 일반적인 interface 정의와 유사합니다. 하나의 at-표시(@) 를 interface 예약어 앞에 적으면 됩니다. 각각의 method 선언은 하나의 [덧붙이는 말 형태]의 element를 정의 합니다. Method 선언은 아무런 파라메터도 가져서는 안되고 throws 구문을 가져도 안됩니다. 반환 형태는 기본 형태인 String, Class, enums, [덧붙이는 말], 그리고 앞에 나열한 형태들의 배열로 강제 됩니다. Method들은 기본 값을 가질 수 있습니다. 여기에 [덧붙이는 말 형태] 선언에 대한 하나의 예가 있습니다.

    /**
     * 확장을 위한 요청(RFE)을 설명합니다. 이것은 [덧붙이는 말]이 붙어진
     * API element가 존재하도록 합니다.

     */

    public @interface RequestForEnhancement {
        int    id();
        String synopsis();
        String engineer() default "[unassigned]";
        String date();    default "[unimplemented]";
    }

    한번 [덧붙이는 말 형태]가 정의 되면, 당신은 [덧붙이는 말 선언]을 사용할 수 있습니다. 하나의 [덧붙이는 말]은 특별한 종류의 표시자 이고, 다른 표시자들 이 사용될 수 있는(public, static, 또는 final) 아무 위치에서나 사용되어질 수 있습니다. [덧붙이는 말]들은 하나의 at 표시(@) 다음에 [덧붙이는 말 형태]와 element-value 쌍의 리스트들을 중괄호로 묶여진 것을 포함하고 있습니다. value들은 확실히 컴파일 시점의 상수가 될 것입니다. 여기에 위에서 선언한 [덧붙이는 말 선언]에 대응하는, [덧붙이는 말]을 가진 하나의 method 선언이 있습니다:

    @RequestForEnhancement(
        id       = 2868724,
        synopsis = "Enable time-travel",
        engineer = "Mr. Peabody",
        date     = "4/1/3007"
    )

    public static void travelThroughTime(Date destination) { ... }
    element가 없는 하나의 [덧붙이는 말 형태]는 하나의 구두점 [덧붙이는 말 형태]로 표시됩니다, 예를 들어:

    /**
     * [덧붙여진 API 요소]의 명시는 변화를 예고하고, 변경되기 쉽다는 것을

     * 나타냅니다.
     */

    public @interface Preliminary { }

    내용들을 구두점 [덧붙이는 말]로 생략하는 게 허용됩니다, 아래처럼 말이죠:

    @Preliminary public class TimeTravel { ... }

    [덧붙이는 말]에 단일 element만 있는 경우, element는 반드시 value로 이름지어져야 합니다, 아래처럼 말이죠:

    /**
     * [덧붙여진 API element]와 관련있는 저작권 알림.
     */
    public @interface Copyright {
        String value();
    }

    그것은 element 명과 등호 표시(=)를 하나의 단일-element [덧붙이는 말]을 생략할 수 있도록 허용합니다. 이 [덧붙이는 말]의 element 명이 value일 경우엔 말이죠, 아래와 같이 말이죠:

    @Copyright("2006 CONI 임은천")
    public class OscillationOverthruster { ... }

    그것 모두를 묶기 위해서, 우리는 하나의 단순한 [덧붙이는 말]에 기반을 test framework를 작성하겠습니다. 첫째로, 우리는 하나의 method가 test method라는 것을 나타내고, test 하는 도구를 통해서 실행되어져야 한다는 것을 암시하기 위해서 하나의 표시자 [덧붙이는 말 형태]가 필요합니다:

    import java.lang.annotation.*;

    /**
     * [덧붙이는 말]이 붙은 method는 test method를 암시합니다.
     * 이 [덧붙이는 말]은 parameter가 없는 static method 여야 합니다.
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface Test { }

    [덧붙이는 말 형태] 선언은 스스로를 [덧붙이도록] 한다는 것에 주의 하세요. 그런 [덧붙이는 말]을 meta-annotations(부연 : 덧붙이는 말을 설명하는 덧붙이는 말)이라고 불립니다. 첫번째는(@Retention(RetentionPolicy.RUNTIME)) 이 형태의 [덧붙이는 말]로 선언된 것은 VM에 의해서 유지되므로 실행-시간에 reflection을 통해서 읽어질 수 있다는 것을 암시합니다. 두번째 것은 (@Target(ElementType.METHOD))  이 [덧붙이는 말] 형태가 오직 method 선언을 [덧붙이는 말]을 적용하는데만 쓰일 수 있다는 것을 암시합니다.

    여기에 프로그램의 몇몇 method가 위의 interface로 [덧붙이는 말]이 적용된 예제 프로그램이 있습니다:

    public class Foo {
        @Test public static void m1() { }
        public static void m2() { }
        @Test public static void m3() {
            throw new RuntimeException("Boom");
        }
        public static void m4() { }
        @Test public static void m5() { }
        public static void m6() { }
        @Test public static void m7() {
            throw new RuntimeException("Crash");
        }
        public static void m8() { }
    }

    여기 부터는 test 하는 도구의 코드 입니다:

    import java.lang.reflect.*;

    public class RunTests {
       public static void main(String[] args) throws Exception {
          int passed = 0, failed = 0;
          for (Method m : Class.forName(args[0]).getMethods()) {
             if (m.isAnnotationPresent(Test.class)) {
                try {
                   m.invoke(null);
                   passed++;
                } catch (Throwable ex) {
                   System.out.printf("Test %s failed: %s %n", m, ex.getCause());
                   failed++;
                }
             }
          }
          System.out.printf("Passed: %d, Failed %d%n", passed, failed);
       }
    }

    도구는 class 명을 command line의 매개 변수처럼 쓰고 명시된 class의 모든 method를 하나씩 지나가면서 Test [덧붙이는 말](위에 정의된)이 적용된 각각의 method를 실행해 보려고 시도합니다. 하나의 method가 하나의 Test [덧붙이는 말]을 가지고 있는지 Reflection을 통해 조사하는 문장은 연두색으로 색칠되어 있습니다. 만약 하나의 test method 실행이 exception을 throws 한다면, test는 실패한 것으로 여겨질 것이고, 실패 보고서가 출력됩니다. 끝으로, test 중에 성공하고 실패한 갯수를 보여주는 요약 내용이 출력됩니다. 여기에 당신이 test 하는 도구를 Foo 프로그램(위의 프로그램)을 실행했을 때 어떻게 보이는지 있습니다:
    $ java RunTests Foo
    Test public static void Foo.m3() failed: java.lang.RuntimeException: Boom
    Test public static void Foo.m7() failed: java.lang.RuntimeException: Crash
    Passed: 2, Failed 2

    이 test하는 도구가 확실히 하찮은 것일지라도, 그것은 [덧붙이는 말]의 power를 보여주고 그것의 제한성을 능가하기 위해서 쉽게 확장될 수 있다는 것을 보여줍니다.
    --------------------------------------------------------------------------------
    Copyright © 2004 Sun Microsystems, Inc. All Rights Reserved.
    Please send us comments and suggestions

    저작권  © 2004 Sun Microsystmes, Inc. 모든 권리가 있습니다.
    저희에게 조언과 제안을 부탁드립니다.
    Java Software

    -------------------------------- 원문http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html

    Stripes로 하는 자바 웹 개발

    Stripes는 오픈소스로서 웹 개발은 개발자에게 단순하며 생산성 있어야 한다는 원칙에 입각하여 설계된 액션 기반(action-based)의 자바 웹 프레임워크이다. 전통적인 자바 웹 개발이 결합도를 낮추는 것(decoupling)을 통한 융통성에 집중한 나머지 다수의 설정 파일(multiple configuration files), 부수적인 객체(additional object), 그리고 기타 단편화된 자원들(fragmented resources)이 만들어지는 결과를 낳았는데 이러한 문제들로 수많은 개발자들이 더 높은 학습곡선과 낮아진 생산성을 겪게 되었다. 그 결과 일부 자바 개발자들은 Ruby on RailsDjango와 같은 비자바 프레임워크(non-Java Framework)로 옮겨가게 되었다. Stripes와 같은 자바 웹 프레임워크는 개발공정의 능률을 높여주는 대안 프레임워크의 성공으로부터 이제 막 배우기 시작하고 있다. 이 기사는 Stripes이 루비 온 레일즈(Ruby on Rails)에서 가능한 것과 같은 단순성을 제공해 주면서, 자체적으로 어떻게 스트러츠(Struts)와 같은 다른 액션 기반의 자바 웹 프레임워크와 구별되는지에 대해 보여줄 것이다.

    [그림 1]은 Stripes로 작성된 애플리케이션에서 전형적으로 나타나는 이벤트와 컴포넌트의 일반적인 흐름을 보여준다.


    [그림 1] 전형적인 Stripes의 흐름

    여러분도 볼 수 있듯이 이것은 여러분이 MVC 프레임워크에서 볼 수 있는 것과 거의 유사하다. Stripes와 다른 액션 기반의 프레임워크간의 한 가지 주된 차이점은 Stripes는 외부 설정 파일이 없다는 것이다. 앞으로 다루겠지만 Stripes는 어노테이션(annotation)과 ‘설정보다는 관례(convention over configuration)’ 이용하여 좀 더 개발에 집중할 수 있게 해주고 번잡스러움은 피하게 해준다.

    첫 번째 Stripe Action 만들기

    곧바로 무엇이 어떻게 돌아가는지 이해하기 위해 “Hello World” 예제를 만들어 보면서 Stripes 프레임워크에 뛰어들어 보도록 하자. HelloWorldAction 클래스는 사용자에게 성명을 물어 본 다음 그것을 별도의 뷰(view)에 출력할 것이다. 먼저 컨트롤러 자바 클래스를 작성한다.

    public class HelloWorldAction implements ActionBean {   

      @ValidateNestedProperties({
        @Validate(field = "firstName", required = true,
                  on = {"hello"}),
        @Validate(field = "age", required = true, minvalue = 13,
                  on = {"hello"})
      })
      private Person person;
      private ActionBeanContext context;
       
      @DefaultHandler
      public Resolution index() {
        return new ForwardResolution("Hello.jsp");
      }
           
      public Resolution hello() {
        return new ForwardResolution("SayHello.jsp");
      }

      public void setPerson(String person) {this.person = person;}
      public String getPerson() { return person;}
      public void setContext(ActionBeanContext c) {this.context = c; }
      public ActionBeanContext getContext() {return context; }
    }

    컨트롤러 클래스는 ActionBean이라 불리는 Stripes에 특정한 인터페이스를 구현하는 POJO(Plain Old Java Object)와 닮았다. 모든 Stripes 액션은 StripesDispatcher 서블릿이 ActionBeanContext 객체를 현재 서비스되고 있는 액션에 주입하도록 이 인터페이스를 구현할 필요가 있다. ActionBeanContext 객체는 여러분이 요청(request), 응답(response), 서블릿 컨텍스트(servlet context)와 같은 API 객체에 접근할 수 있도록 해준다. Stripes 애플리케이션에서는 이러한 저수준 API 객체에 접근할 필요가 거의 없다. 또한 ActionBeanContext 클래스는 여러분이 현재 서비스 되고 있는 액션에 관한 상태 정보를 얻을 수 있도록 해줄 뿐만 아니라 현재 서비스되고 있는 액션으로부터의 통보 메시지(informational message)와 오류 메시지를 추가할 수 있도록 해준다. ActionBeanContext 필드와 접근자(accessor)는 모든 Stripes 액션들이 이 구현 클래스를 필요로 할 것이므로 기반 클래스에 저장될 수도 있다.

    컨트롤러 클래스의 나머지 부분들은 다른 자바 개발자들에게 친숙할 것이다. Person이라는 객체는 뷰에서 한 사람의 성과 이름을 읽고 기록하는데 사용될 접근자를 포함한다. 이 객체는 단순히 중첩된 객체에 불과하나 Stripes는 자바 컬렉션(Java Collection), 제네릭 지원(generics support), 그리고 색인화된 프로퍼티(indexed propertis)를 통해 좀 더 복잡한 데이터 바인딩도 할 수 있도록 해준다. Stripes가 복잡한 데이터 바인딩을 처리할 수 있으므로 여러분의 도메인 객체를 그것을 필요로 하는 다른 계층에서도 재사용 할 수 있다. 예를 들어 Stripes를 통해 도메인 객체 내에 들어있는 정보들을 수집하여 Hibernate와 같은 다른 POJO 프레임워크나 EJB 3를 이용하여 퍼시스턴스 차원의 변경을 손쉽게 할 수 있다.

    hello 메소드 호출시 사용자가 성명을 입력하도록 하는 간단한 Stripes 유효성 검증 어노테이션(validation annotation)이 person 필드에 추가되어 있다. 만일 사용자가 필수 입력란에 내용을 입력하지 않으면 원래 페이지로 되돌아온 다음 이 유효성 검증과 관련된 오류 메시지가 보여질 것이다. 이 유효성 검증은 어노테이션 속성(on = {“hello”})에 지정되어 있는 것과 같이 hello 이벤트가 요청되었을 경우에만 검사될 것이다. 또한 Stripes는 유효성 검증의 유형과 필드명에 근거한 sensible default를 사용하여 오류 메시지를 만들어낼 것이다. 예를 들어 만약 한 Person 객체의 필수 입력필드인 firstName이 폼이 전송될 때 주어지지 않을 경우 사용자는 다음과 같은 오류 메시지를 보게 될 것이다:

    Person First Name is a required field.
    (Person First Name은 필수 입력필드입니다.)
    
    이 메시지는 Person.firstName에 대한 객체 그래프 컴포넌트(object graph component)를 이용하여 생성되는데 이것은 메시지를 좀 더 사람이 읽기 쉬운 형태로 만들어 준다. 이러한 유효성 검증 오류 메시지는 좀 더 커스터마이즈가 필요할 경우 오버라이드할 수 있다. 또한 Person 객체의 프로퍼티인 age라 불리는 Integer 타입의 필드도 있다. Stripes는 먼저 Integer 필드인 person.age에 대한 요청 파라미터 값의 타입 변환을 수행한 다음 그 값을 Person 객체내의 값에 바인딩할 것이다. 그 값이 Person 객체의 age 필드에 바인딩되고 나면 Stripes는 그 Integer 값이 13보다 작은지에 대한 유효성 검사를 수행할 것이다. 만약 사용자가 정수 대신 문자열을 입력할 경우 사용자는 다음과 같은 메시지를 보게 될 것이다:
    The value (Mark) entered in field Person Age must be a valid number.
    (Person Age 필드에 입력된 값(표시)은 유효한 숫자여야 합니다.)
    
    만약 사용자가 정수지만 13보다 작은 값을 입력할 경우 다음 메시지를 보게 될 것이다:
    The minimum allowed value for Age is 13.
    (Age에 허용된 최소값은 13입니다.)
    
    다시 한번 말하지만 우리는 이러한 오류 메시지에 대한 어떠한 외부 설정(external configuration)을 제공할 필요가 없었다. 이러한 유효성 검사를 제공하는 어노테이션이 여러분의 필드에 인라인되어 개발자가 유효성 검사를 위치시키는 것과, 유효성 검사가 수행될 것을 알게되는 것, 그리고 유효성 검사에 대한 유지보수성 변경(maintenance change)을 용이하게 한다.

    이 Stripes 액션에는 호출가능한 두 개의 메소드(이벤트라 불리는)도 포함되어 있는데, 이벤트는 ActionBean 클래스에서 다음과 같은 서명을 가진 메소드로서 나타난다:
    public Resolution eventName
    
    index 메소드에 @DefaultHandler가 표시되어 있음을 주목하라. 이 액션에는 여러 개의 이벤트가 있으므로 그것들 중 하나는 기본 이벤트로 지정되어 있을 필요가 있다. 만약 이러한 액션을 요청하는 URL에 이벤트가 기입되어 있지 않으면 Stripes는 @DefaultHandler 어노테이션이 지정된 이벤트를 찾아 그것을 실행시킬 것이다.



    이제 Hello World 예제에 뷰 로직을 추가해 보자. 기본적으로 Stripes는 JSP를 표준 뷰 기술로 지원하기는 하나 FreeMarker와 같은 다른 뷰 기술을 사용할 수도 있다. 여기에는 Stripes 태그 라이브러리를 제외하고는 사실 새로이 배워야 할 것이 없다. Hello.jsp라 불리는 첫 번째 뷰는 사용자가 이름을 입력하고 전송할 수 있도록 해줄 것이다.

    <%@ taglib prefix="stripes"
              uri="http://stripes.sourceforge.net/stripes.tld" %>
    <html>
      <head>
        <title>Stripes Hello World</title>
      </head>
      <body>
        <stripes:errors/>
        <stripes:form
            beanclass="com.
                       myco.
                       web.
                       stripes.
                       action.
                       example.
                       HelloWorldAction">
        Say hello to: <br>
        First name: <stripes:text name="person.firstName"/>
        <br>
        Age:<stripes:text name="person.age"/><br>
        <stripes:submit name="hello" value="Say Hello"/>
        </stripes:form>
      </body>
    </html>

    이 JSP는 읽고 유지보수 하기에도 간단하다. 폼과 입력 필드에 사용된 Stripes 태그들은 HTML에 그것과 대응되는 태그들과 매우 유사하다. Stripes:form 태그는 beanclass라 불리는 속성을 포함하고 있는데 이것은 앞서 정의하였던 컨트롤러 클래스의 전체 경로를 포함한 이름이다. 우리는 beanclass 속성 대신 stripes:form 태그의 액션 속성을 사용할 수도 있었다. 그러나 beanclass 속성은 여러분이 Stripes 액션에 대한 리팩터링을 수행할 필요가 있을 경우 리팩터링을 더 쉽게 만들어 준다. 아래에는 액션 속성을 사용할 경우 stripes:form 태그를 어떻게 지정해야 하는지 나타나 있다:
    <stripes:form action="/example/HelloWorld.action">

    stripes:input 태그들 중 하나는 입력 필드의 값을 컨트롤러 내의 Person 객체의 firstName
    필드에 저장하는데 사용될 person.firstName의 name 속성을 지정한다.
    마지막으로 stripes:submit 태그는 Stripes HelloWorldAction 클래스가 hello 이벤트를
    사용하도록 지시하는데 사용될 name 속성을 지정한다.

    이제 이름과 성의 값을 HelloWorldAction에 전송하도록 설정할 것이다.
    우리가 해야할 일은 오직 별도의 뷰에 그것을 출력하도록 하는 것이다.






    <%@ taglib prefix="stripes"
           uri="http://stripes.sourceforge.net/stripes.tld" %>
    <html>
      <body>
        <stripes:errors/>
        <h2>Hello ${actionBean.person.firstName} your age is
                  ${actionBean.person.age} </h2>
        <p/>
        <stripes:link beanclass="com.myco.web.stripes.action.
                                       example.HelloWorldAction">
          Say Hello Again
        </stripes:link>
      </body>
    </html>

    이 JSP는 action에 직접 연결된 레퍼런스에 접근하여 사람의 이름과 성 필드의 내용을 출력할 것이다.
    이러한 목적으로 Stripes는 자동적으로 actionBean 요청 속성(request attribute)을 포함하는데
    그것은 JSTL로 접근가능하다. 마지막으로 stripes:link 태그를 사용하여 HelloWorldAction
    클래스로 되돌아가는 링크를 하나 만들어서 다른 이름을 입력하여 출력하게 할 수 있도록 하였다.
    뿐만 아니라 이러한 방식으로 stripes:link가 명시적으로 index 이벤트를 참조하도록
    만들 수도 있다:
    <stripes:link beanclass="com.myco.web.stripes.action.
    example.HelloWorldAction"
    event="index">Say Hello Again</stripes:link>

    index 메소드에 @DefaultHandler 어노테이션을 지정하였으므로 Stripes는 이벤트 속성 없이도
    어떤 메소드를 실행할지 알게 된다.



    설정보다는 관례(Convention Over Configuration)


    이제 자바 컴포넌트들을 작성하였으므로 URL에 액션이 맵핑되도록 설정하고 두 개의 뷰에 그것들을
    연결시킬 것이다. 잠깐만 기다려라, 이건 Stripes이므로 아무런 외부 설정파일이 필요하지 않다.

    너무 좋아서 믿지 않을 수도 있겠지만 이것은 Stripes에서 가장 생산성 있는 기능 중의 하나이다.
    Stripes는 설정보다는 관례을 이용하여 액션을 URL에 맵핑시킨다. 또한 기호화된
    이름(symbolic names)을 실제 뷰에 맵핑시키기 위하여 외부 설정 파일을 사용할 필요도 없다.
    이는 개발자들이 뷰의 실제적인 경로에 이르는 SUCCESS와 같은 기호화된 이름 사이사이를 찾아
    다니는 방법을 결정하기 위하여 설정 파일들 사이를 여기저기 헤집고 다닐 필요가 없다는 것을
    의미한다. 즉, 자바와 뷰 컴포넌트를 외부적으로 묶을(external wiring) 필요가 없다.
    이는 더 나은 유지보수성과 더 높은 생산성으로 우리를 이끌어 준다.

    Stripes는 어떻게 각각의 액션을 외부적으로 혹은 다른 어노테이션이 없이 Java 액션 클래스에
    대한 묵시적인 URL 맵핑을 제공할까? 이것은 web.xml 파일 안에 들어있는 Stripes 설정과 URL
    맵핑을 생성하기 위한 sensible defaults를 이용하는 방법을 가지고 설명할 수 있다.
    먼저 StripesFilter라 불리는 Servlet 필터에 대해 논의해볼 필요가 있다.
    아래에 web.xml 파일안에 들어있는 StripesFilter의 기본 설정이 나타나 있다:



    <filter>
      <display-name>Stripes Filter</display-name>
      <filter-name>StripesFilter</filter-name>
      <filter-class>
        net.sourceforge.stripes.controller.StripesFilter
      </filter-class>
        <init-param>
        <param-name>ActionResolver.UrlFilters</param-name>
        <param-value>/WEB-INF/classes</param-value>
      </init-param>
    </filter>

    Servlet 컨테이가 구동될 때 StripesFilter는 init-param 요소의 초기화를 수행한다.
    가장 중요한 init-param 요소 중 하나는 ActionResolver. UrlFilters 파라미터이다.
    이것은 Stripes에게 Stripes와 관계된 클래스를 어디에서 찾아보아야 하는지 알려준다.
    이 경우 Stripes는 모든 ActionBean 인터페이스를 구현하는 클래스들을 기본적으로
    /WEB-INF/classes 경로에서 찾아보게 될 것이다. 각각의 위치한 ActionBean 클래스는 그러한
    클래스에 대한 기본 바인딩 URL과 함께 Map에 추가될 것이다. Stripes가 Hello World 예제
    클래스에 어떠한 일을 하는지 예제를 살펴보기로 하자.

    HelloWorldAction 클래스가 /WEB-INF/classes 경로 안에 들어있고 ActionBean 인터페이스를
    구현하므로 그것은 Stripes 서블릿으로 인식될 것이다. 예제에서 사용된 HelloWorldAction
    클래스의 전체 경로를 포함한 이름(fully qualified name)은
    com.myco.web.stripes.action.example.HelloWorldAction이다.
    전체 경로를 포함한 이름은 이제 다음의 규칙에 따라 URL 바인딩으로 변환된다.
    1. 전체 경로를 포함한 클래스 이름에서 www, web, stripes, action과 일치하는 문자열이 나타나는 부분을 뽑아낸다. 예제에서는 패키지명에서 4개 중 3개가 일치한다. 따라서 “example.HelloWorldAction”만 남게 된다.
    2. 클래스명의 끝에서부터 "Action"과 " Bean"이 존재할 경우 제거한다. 우리가 작성했던 클래스가 Action으로 끝나기 때문에 “example.HelloWorld”가 된다.
    3. 이제 마침표(.)를 슬래시(/)로 치환하면 “example/HelloWorld”가 된다.
    4. 마지막으로 URL 바인딩을 완성시키는 바인딩 접미사(기본값으로 .action)를 마지막에 추가한다. 최종 결과는 “example/HelloWorld.action”가 된다.
    이제 Stripes가 ActionBean 클래스를 찾았고 그것에 대한 URL 바인딩을 생성하였으므로 그것들은 URL 바인딩이 키이고 ActionBean을 구현하는 클래스를 값으로 가지는 java.util.Map>에 캐싱될 것이다. 아래에 우리가 작성했던 예제가 Map에 어떻게 저장될 것인지 나타나 있다:

    URL 바인딩 ActionBean 클래스
    /example/HelloWorld.action com.myco.web.stripes.action.example.HelloWorldAction

    논의해볼 필요가 있는 두 번째 사항은 Stripes가 URL 바인딩을 거꾸로 여러분이 구동시키고자 하는 ActionBean 클래스로 변환시키는 방법에 관한 것이다. 이것은 아래와 같이 web.xml 파일안에 설정되어 있는 Stripes 디스패처 서블릿(Stripes dispatcher Servlet)의 책임이다.

    <servlet>
         <servlet-name>StripesDispatcher</servlet-name>
         <servlet-class>
            net.sourceforge.stripes.controller.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
      <servlet-name>StripesDispatcher</servlet-name>
      <url-pattern>*.action</url-pattern>
    </servlet-mapping>

    StripesDispatcher의 책임 중 하나는 URL을 Stripes ActionBean 클래스로 해석(resolve)하는 것이다. 사용자가 http://host/uri/example/HelloWorld.action URL을 요청할 경우 Stripes 디스패처 서블릿은 URL 바인딩 맵 안을 살펴보고 com.myco.web.stripes.action.example.HelloWorldAction 클래스를 찾아서 그것의 인스턴스를 인스턴스화시킬 것이다. 마지막으로 index 메소드가 기본 핸들러로 어노테이션을 통해 정의되어 있고 URL상에 이벤트가 지정되어 있지 않으므로 index 메소드가 호출될 것이다.

    그럼 HelloWorldAction의 hello 메소드를 직접 실행시키고자 하면 어떻게 될까? URL은 아래와 같이 요청 파라미터로 이벤트명을 포함할 필요가 있을 것이다:
    http://host/uri/example/HelloWorld.action?hello=&firstName=Mark&age=13
    

    hello 요청 파라미터에 대해서는 아무런 값도 지정하지 않았음을 유의하라. 이 경우 StripesDispatcher는 hello 요청 파라미터명과 public Resolution hello()라는 메소드 서명을 가진 HelloWorldAction 클래스 안의 메소드명이 서로 일치하는 것으로 인식할 것이다. 메소드명은 초기화시 성능을 위해 별도의 Map에 캐싱될 것이다.

    우리는 지금까지 Stripes의 기본사항들과 간단한 액션을 작성하는 방법, 그리고 몇가지 프레임워크의 작동 방식에 대해 알아보았다. 우리는 web.xml에 몇 가지 초기화 설정을 함으로써 프레젠테이션 컴포넌트에 묶기 위한 별도의 XML 설정파일을 갖는 것을 피할 수 있다. 이는 몇 가지 연유로 중요한 의미를 지닌다. 먼저 어떠한 수정을 해야 할 경우 여러분은 URL을 보고 즉시 우리가 어떤 클래스를 찾아봐야 할지를 알게 된다. 다음으로 설정 파일이 커지고 그것을 관리할 수 없을 지경에 다다랐을 경우에 우리를 보조해줄 별도의 툴도 필요하지 않게 된다. 이러한 설정 파일을 제거함으로써 더 이상 프레임워크에 수많은 메타 데이터를 주입시키지 않아도 된다. 결론적으로 우리는 컴포넌트가 각기 다른 것들과 관계되는 방법을 서술하는 별도의 파일을 계속적으로 유지할 필요가 없어진다.

    Ajax

    그럼 좀 더 고급스러운 기능은 어떠한가? Stripes가 Ajax를 처리하는 방법을 살펴보도록 하자. 우리는 위의 Hello World 예제에 이미 존재하는 내용을 갱신하는 Ajax 호출을 포함되도록 수정할 것이다. 이 예제는 Stripes 액션에 Ajax 호출을 제공하기 위하여 Prototype을 어떻게 이용하는지 보여줄 것이다. 이 예제의 소스는 리소스에서 참조할 수 있다. 먼저 Hello.jsp가 Prototype 자바스크립트 라이브러리를 포함하도록 수정하자. 또한 Ajax 호출을 위한 자바스크립트 함수를 추가하고 onclick 이벤트를 가진 새로운 버튼을 참조하도록 전송 버튼을 변경할 것이다:

    <%@ taglib prefix="stripes"
                uri="http://stripes.sourceforge.net/stripes.tld" %>
    <html>
      <head>
        <title>Stripes Hello World</title>
        <script
            src="${pageContext.request.contextPath}/js/prototype.js"
            type="text/javascript"></script>

        <script type="text/javascript">
           function sayHelloAjax() {
              var myAjax = new Ajax.Updater('hello',
              "<stripes:url
                   beanclass="com.
                              myco.
                              web.
                              stripes.
                              action.
                              example.
                              HelloWorldAction"
                   event="sayHelloAjax"/>",
              {
                  method: 'get',
                  parameters: Form.serialize('helloForm')
              });
            }
        </script>
      </head>
      <body>
        <stripes:errors/>
        <stripes:form
            beanclass="com.
                       myco.
                       web.
                       stripes.
                       action.
                       example.
                       HelloWorldAction"
            id="helloForm">
            Say hello to: <br>
            First name: <stripes:text
                              name="person.firstName"/><br>

            Age:<stripes:text name="person.age"/><br>

            <stripes:button
                    name="helloAjax"
                    value="Say Hello"
                    onclick="sayHelloAjax()"/>

            <div id="hello"></div>

        </stripes:form>
      </body>
    </html>

    stripes:button은 onclick 이벤트를 가지는데 이것은 HelloWorldAction 클래스의 sayHelloAjax를 호출하여 그 결과를 hello라 불리는 div 태그안에 리턴할 것이다. 아래에는 HelloWorldAction 클래스 안에 추가해야 할 필요가 있는 새로운 메소드가 나타나 있다:

    public Resolution sayHelloAjax(){
      return new ForwardResolution("SayHelloAjax.jsp"); 
    }

    이름과 성에 대한 바인딩이 Stripes에 의해 처리되기 때문에 이 메소드가 하는 일은 그리 많지는 않다. 따라서 이 메소드의 책임은 오로지 SayHelloAjax.jsp라 불리는 파셜 페이지(partial page)로 포워딩 하는 것 뿐이다. 아래는 SayHelloAjax.jsp의 내용이다:

    <h2>Hello ${actionBean.person.firstName} your age is ${actionBean.person.age}!</h2>
    

    Spring 통합


    Stripes는 Spring과 통합할 수 있는 기능을 내장하고 있다. 여러분은 Spring의 빈(bean)이나 서비스를 여러분의 Action에 자동으로 주입시킬 수 있다. Stripes 방식에서는 이렇게 하는 것은 Spring 컨텍스트 설정을 제외하고는 외부 설정을 필요로 하지 않는다. Spring 설정에 다음과 같이 정의된 빈이 있다고 가정하자:

    <bean id="personService" parent="abstractTxDefinition">
      <property name="target">
        <bean class="com.myco.service.impl.PersonServiceImpl"/>
      </property>
    </bean>


    person 서비스를 Stripes 액션에 주입시키기 위해서는 Spring 빈의 이름과 일치하는 프로퍼티와 설정자 메소드(setter)를 추가해 준다. Stripes는 적절한 Spring 빈을 액션 클래스에 주입시키기 위하여 @SpringBean 어노테이션을 제공해 준다. 아래에 무엇이 Stripes 액션에 포함되어야 하는지 나타나 있다:

    private PersonService personService;

    @SpringBean
    public void setBlogService(BlogService blogService) {
      this.blogService = blogService;
    }

    이 기사는 Stripes의 고급 기능에 대해 모두 다루지는 못한다. 그러나 Stripes documentation은 매우 포괄적이므로 필요하면 Stripes documentation을 참조하라. 뿐만 아니라 Stripes은 Tiles과 유사한, 외부 설정을 필요로 하지 않는 레이아웃 관리자를 포함하고 있다. 추가적으로 라이프사이클 이벤트(life-cycle events), 파일 업로드, 그리고 그 이상의 것들에 걸쳐 사용될 수 있는 인터셉터(interceptor)도 사용할 수 있다.

    결론

    Stripes는 강력하지만 심플한 자바 웹 프레임워크이다. Stripes는 어노테이션과 제네릭과 같은 Java 5의 기능을 이용하는데 이는 자바 개발자가 외부 설정파일을 유지하는 것을 회피할 수 있게 해주며 생산성을 증가시킨다. Stripes는 어려운 웹 개발 작업을 쉽게 만들어 주며 단순한 작업들을 훨씬 더 쉽게 만들어 준다.

    리소스

    Mark Eagle는 조지아주의 애틀랜타에 위치한 MATRIX Resource, Inc의 수석 소프트웨어 엔지니어이다.

    제공 : 한빛 네트워크
    저자 : Mark Eagle
    역자 : 이정목
    원문 : http://www.onjava.com/pub/a/onjava/2007/01/24/java-web-development-with-stripes.html