본문 바로가기

Dev.../웹서비스

[펌] Velocity Template Engine 시작하기

[첨 언] : 이 문서는 JavaWorld의 문서를 번역한 것입니다. 따라서 라이센스는 
아마도 JavaWorld와 원저작자가 가지고 있지 않을까 싶습니다. 편의상 경어는 
생략합니다. [번 역] : 최 호필(hops) 
E-mail : hops@bcline.com Homepage : http://hops.x-y.net 
[번역일] : 2003년 4월 30일 
[원 문] : http://www.javaworld.com/javaworld/jw-12-2001/jw-1228-velocity_p.html  
Start up Velocity Template Engine 
[참 고] : 모든 예제는 J2SE v1.4.1_01, Velocity v1.3에서 테스트되었습니다. 
 

Velocity Template Engine 시작하기

자바 기반의 웹 컨텐트 생성도구, Open Source Velocity

Summary
Velocity Template Engine은 여러분들이 어플리케이션이나 서블릿 내에서 데이터를 표현하게 만들어 준다. 주로 서블릿 기반의 웹사이트들과 같은 다이나믹한 개발에 사용되는데 Velocity의 템플릿과 자바 코드간의 깔끔한 분리는 모델 2 스타일 Model-View-Controller(MVC) 웹 개발에 대하여 이상적으로 만들어 줄 수 있다. 일반적인 템플릿 엔진들처럼 Velocity는 코드생성, XML 생성과 변환, 그리고 텍스트 스트림 프로세싱과 같은 많은 다른 목적들에도 적합하다. 이 아티클은 Velocity Template Language(VTL)을 소개하고 Velocity엔진에서 어떻게 사용하는지 예제를 제공한다. 또한 자바 서블릿 환경에서 어떻게 웹 컨텐트를 생성하는지도 포함한다.(3,000 글자정도; 2001년 12월 28일)
Geir Magnusson Jr. 작성


Velocity는 국제적으로 자발적 참여 커뮤니티에 의해 개발된 오픈소스 템플릿 도구이고, Apache Software Foundation의 Jakarta Project에 의해 주관된다. 무료로 이용가능한 소스코드를 다운받을 수 있는 웹사이트인 Jakarta Velocity Project에 속해 있는 사용자들이 질문에 대한 대답들을 해 줄 준비가 되어 있고 일반적인 템플릿 문제들에 대한 솔루션들을 제공해 줄 준비가 되어있다. Velocity는 WebMacro 프로젝트로부터 영감을 받았다.

이 아티클에서 Velocity Template Engine과 템플릿 랭귀지인 Velocity Template Language(VTL)에 대한 간략한 입문서를 제공한다. 또한 몇가지 예제를 통해서 어떤식으로 Velocity를 사용하는지 데모를 보여줄 것이다.

당연히 Hello World
아무런 설명도 필요없는 프로그래밍 관련 주제는 Hello World 예제외에는 없을 것이다. Velocity에서 사용하는 어떠한 어플리케이션이라도 두 부분을 필요로 한다. 첫번째는 템플릿으로써, 이 예제는 아래에 있다. 이 파일명은 helloworld.vm이 된다.


  Hello $name!  Welcome to Velocity!

두번째는 HelloWorld.java로 명명된 위의 템플릿에 대응되는 자바 프로그램이다.


import java.io.StringWriter;

import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;


public class HelloWorld
{
    public static void main( String[] args )
        throws Exception
    {
        /*  먼저 엔진을 얻고 초기화를 한다.  */

        VelocityEngine ve = new VelocityEngine();
        ve.init();

        /*  다음으로 템플릿을 얻어낸다.  */

        Template t = ve.getTemplate( "helloworld.vm" );

        /*  컨텍스트를 생성하고 데이터를 추가한다. */

        VelocityContext context = new VelocityContext();

        context.put("name", "World");

        /* 이제 StringWriter 안으로 템플릿을 표현한다. */

        StringWriter writer = new StringWriter();

        t.merge( context, writer );

        /* World를 보여준다. */

        System.out.println( writer.toString() );    
    }
}

이 프로그램을 컴파일하고 실행을 하면 아래의 결과를 볼 수 있다.
[역자 주]: Velocity 1.3의 경우 컴파일과 Run을 하기 위해서는 클래스패스에 velocity-dep-1.3.jar가 잡혀 있어야 한다.


  Hello World!  Welcome to Velocity!

이것은 사소한 예제이긴 하지만, Velocity templating은 어떤 것이라는 사상을 제공해 준다는 결정적인 부분을 포함하고 있다.

왜 이것을 사용해야 하는가?
일반적인 템플릿 도구들이 사용하기 쉽도록 디자인된 것과 같이 Velocity는 데이터를 formatting하고 표현할 수 있게 요구되는 어떠한 자바 어플리케이션 영역에서도 유용하게 사용된다. 여러분들은 다음과 같은 이유때문에 Velocity를 사용해야만 한다.

  • 다양한 어플리케이션 영역들에 적용된다.
  • 템플릿 디자이너에게 단순하고 명확한 신택스(syntax)를 제공한다.
  • 개발자에게 간단한 프로그래밍 모델을 제공한다.
  • 템플릿과 코드가 분리되기 때문에 서로 독립적으로 개발하고 유지보수 할 수 있다.
  • Velocity 엔진은 어떠한 자바 어플리케이션 환경, 특히 서블릿과 쉽게 통합된다.
  • Velocity는 템플릿이 컨텍스트 내에 있는 데이터 객체의 어떠한 public 메소드들에게 엑세스하는 것을 가능하게 만들어준다.

마지막 포인트는 매우 중요하다 -- 이것은 여러분들이 이미 존재하는 여러분들의 클래스를 재사용할 수 있다는 것을 의미한다. 따라서 여러분들의 템플릿에서 사용하길 원하는 객체들은 특정 방식, 예를 들어 자바빈즈나 아니면 특별한 I/O를 구현(implement) 한다던지, JSP(JavaServer Pages taglibs와 같은 lifecycle 방식으로 재구성되어질 필요가 없다. 단 하나의 필요사항은 메소드들이 public으로 선언되어야 한다는 것뿐이다. 우리가 자세하게 template language를 다룰때 이것에 대해서 좀 더 알아볼 수 있을 것이다.

Velocity의 장점 중의 한가지는 어플리케이션 내에서 기능적인 책임의 분리는 강력하게 강제화시키고 있다는 것이다. 이것은 템플릿이 어플리케이션 코드가 본질적으로 사용가능하게 만드는 객체들에 대해서 엑세스하는 것을 제한함으로써 수행된다. 이것은 Model-View-Controller(MVC) 개발에서 디자이너들이 배타적으로 데이터 표현(the view)에 촛점을 맞출 수 있도록 해 주고, 어플리케이션 프로그래머들은 어플리케이션 컨트롤(the controller)과 비즈니스 로직과 데이터 관리(the model)에만 촛점을 맞출 수 있도록 해 준다. MVC는 정교한 어플리케이션들의 개발과 지속적인 유지보수 두가지 모두를 단순화시키는 것이 잘 적용된 개발 패턴이다.

어느 곳에서 이것을 사용하는가?
Velocity는 아래와 같은 곳에서 성공적으로 사용될 수 있다.

  • 서블릿 기반의 웹 어플리케이션
  • 자바와 SQL 코드 생성(Generation)
  • XML processing과 transformation
  • RTF 파일 생성과 같은 Text processing

Velocity는 대다수 일반적으로 자바 서블릿 기반의 웹 어플리케이션 개발에 있어 JSP와 다른 렌더링 기술들과 결합 또는 대체하는 렌더링 엔진으로써 사용된다. 템플릿 syntax가 유지보수하기 쉽다는 것을 제외하고라도, Velocity의 template language는 조작하기 쉽고, 데이터를 생성하지 않고 데이터를 표현할 수 있기 때문에 웹 개발에서 사용된다. 이것은 템플릿 내에서 programming하는 것을 지양하게 만든다. 이것은 아주 좋은 것이다. 자바 코드의 비즈니스와 어플리케이션 로직이 포함되어야 할 곳에서만 존재하게 된다. J2EE(Java 2 Platform, Enterprise Edition) platform이 JSP보다 다른 output 기술들에 적합되어 있기 때문에, Velocity는 J2EE 웹 개발에 적합하다. 비록 JSP가 J2EE 스펙에 포함되어 있기는 하지만, J2EE는 JSP의 사용을 필요로 하지는 않는다.

어떻게 동작하는가?
어떠한 어플리케이션에서 하는 것처럼 Velocity 기반 어플리케이션을 생성하는데 똑같은 일반적인 프로세스를 사용한다. 이제는 위에 있는 Hello World 어플리케이션보다 좀 더 흥미있는 예제를 생각해 보자. 여러분들은 애완동물 가게를 운영하고 판매 홍보를 하기 위해 대량의 email을 생성해서 발송하길 원한다고 가정해 보자. 먼저 여러분들은 email을 다자인해야 한다. 그리고나서 그 디자인을 기반으로 해서 템플릿과 코드를 개발해야만 한다.

디자인시 고려할 문제들
디자인을 위해 3가지 항목을 고려해야 할 필요가 있다.

  • email 안에 포함되어야할 데이터는 어떤 것인가?
  • 데이터 항목은 어떤 형식을 가져야만 하는가?(예를 들어 list, Map 또는 String)
  • 무엇이 그러한 데이터 항목들을 호출하는가?

예를 들어, 각기 다르게 홍보된 가격을 가진 3가지의 애완동물을 판매하기로 결정했다고 가정해 보자. 여러분들은 각 애완동물 이름과 그 가격을 매칭시켜놓은 map을 사용하기로 결정하고 그런 다음에 list 안에 3개의 map을 모두 저장하기로 결정한다. 이 list를 petList로 호출하고, map 안의 애완동물 명을 name, 가격을 price란 이름으로 호출한다. 이제 여러분들은 관련된 데이터, 형식, 이름을 식별했기에 코드를 작성하고 템플릿을 디자인할 수 있다.

코드 작성과 템플릿 디자인
일단 여러분들이 데이터 명세에 동의한다면, Velocity는 여러분들이 코드를 작성하고 템플릿을 디자인하는 것을 병렬적으로 할 수 있도록 만들어준다. 디자이너는 템플릿 안의 nondata presentation content(image들, text 등과 같은)와 데이터를 통합시킨다. 이러한 경우 우리는 간단하게 email body를 아래처럼 작성한다.


  $petList.size() Pets on Sale!

  We are proud to offer these fine pets
  at these amazing prices.  This month only,
  choose from:

  #foreach( $pet in $petList )
    $pet.name for only $pet.price
  #end

   Call Today!

프로그래머로써 여러분들은:

  • 데이터 소스들 -- JDBC(Java Database Connectivity)를 통한 데이터베이스, 파일, 또는 그냥 계산된 어떤 값 -- 로부터 모든 데이터를 가져온다.
  • 약속된 이름들을 이용하여 컨텍스트 안으로 그 데이터를 넣는다.
  • 결과값을 만들기 위해 컨텍스를 가지고 템플릿을 렌더링한다.

여러분들은 내가 VelocityContext 클래스를 context으로 언급했던 Hello World 예제로부터 다시 생각해 볼 수 있을 것이다. java.util.Map로 형상화되었기에 컨텍스트는 템플릿이 엑세스하는 어플리케이션이나 서블릿에 의해 제공되는 데이터를 담고 있는 객체이다.

이 예제에서 우리는 우리의 데이터 소스들(여기서는 직접 코드에다가 넣었지만)로부터 모든 데이터를 얻고, 구성하고 컨텍스트에 추가한다.


   /* create our list of maps  */

   ArrayList list = new ArrayList();
   Map map = new HashMap();

   map.put("name", "horse");
   map.put("price", "$100.00");
   list.add( map );

   map = new HashMap();
   map.put("name", "dog");
   map.put("price", "$59.99");
   list.add( map );

   map = new HashMap();
   map.put("name", "bear");
   map.put("price", "$3.99");
   list.add( map );

   /*  add that list to a VelocityContext  */

   VelocityContext context = new VelocityContext();

   context.put("petList", list);

이제 컨텍스트 안에 구성되어서 위치된 데이터와 준비된 템플릿을 가지고 우리는 컨텍스트에 대해서 템플릿을 렌더링할 수 있다. 여기에 그 코드가 있다.


import java.io.StringWriter;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;

public class PetStoreEmail
{
    public static void main( String[] args )
        throws Exception
    {
        /*  first, get and initialize an engine  */

        VelocityEngine ve = new VelocityEngine();
        ve.init();

        /*  organize our data  */

        ArrayList list = new ArrayList();
        Map map = new HashMap();

        map.put("name", "horse");
        map.put("price", "$100.00");
        list.add( map );

        map = new HashMap();
        map.put("name", "dog");
        map.put("price", "$59.99");
        list.add( map );

        map = new HashMap();
        map.put("name", "bear");
        map.put("price", "$3.99");
        list.add( map );

        /*  add that list to a VelocityContext  */

        VelocityContext context = new VelocityContext();
        context.put("petList", list);

        /*  get the Template  */

        Template t = ve.getTemplate( "petstoreemail.vm" );
        //[역자 주] 한글을 사용한다면 Template t = ve.getTemplate("petstoreemail.vm","KSC5601");을 사용한다.

        /*  now render the template into a Writer  */

        StringWriter writer = new StringWriter();

        t.merge( context, writer );

        /* use the output in your email body */

      sendEmail( writer.toString() );
    }
}

이 완성된 프로그램은 여러분들의 email body를 생성한다. Velocity는 Writer 안으로 template들을 표현하기 때문에, 여러분들은 손쉽게 결과물을 관리(manage)할 수 있다. 이 경우, 표현된 결과물은 StringWriter를 통해 String으로 보냈으나, 파일이나 browser, 또는 데이터베이스의 BLOB(binary large object)으로 손쉽게 보낼 수 있다. 이것이 바로 왜 Velocity가 자바 어플리케이션들과 그럽게 쉽게 통합될 수 있는가에 대한 이유들 중 하나이다.

프로그램의 output (여러분들의 email body)는 아래와 같이 된다.


  3 Pets on Sale!

  We are proud to offer these fine pets
  at these amazing prices.  This month only,
  choose from:

    horse for only $100.00
    dog for only $59.99
    bear for only $3.99

   Call Today!

Velocity Template Language
나는 두개의 다른 예제들을 통해 Velocity 템블릿들을 보여주었지만, 두 개의 케이스 모두 특별한 마크업이 무엇이었는지에 대해서는 아무런 설명을 하지 않았다(비록 여러분들이 아마도 추측했었겠지만).

Velocity Tempalte Language(VTL)은 두 파트를 제공하는 아주 간단한 문법이다. 컨텍스트 내에서 엑세스가 되는 객체들에 대한 형식인 references와 control과 action에 사용되는 문장들의 집합인 directives이다. "표준 비즈니스 카드에 충분히 맞추어져 있는 형태 집합을 가진 언어 정의"(Jim Jagielski의 "Getting Up to Speed with Velocity"를 참고하라)로 설명되었듯이 VTL은 커뮤니티에 의해 계획적으로 간결하고 작게 유지되어져 왔다.

References
템플릿 안의 References는 데이터를 엑세스한다. 이것들은 템플릿의 non-VTL 컨텐트와 자유롭게 섞인다. 형식적으로 정의된 것은, reference는 '$'문자로 시작하고 그리고 컨텍스트 내의 어떤 것을 참조하는 템플릿 내의 어떤 것이다. 만일 대응되는 데이터 객체가 컨텍스트 내에 존재하지 않는다면, 템플릿은 일반 텍스트로 reference를 취급하고 그것을 그대로 output stream에 보내서 표현한다.

여기에 non-VTL 컨텐트와 함께 섞여 있는 간단한 reference를 포함하고 있는 짧은 템플릿이 있다.


    Hello $name!  Welcome to Velocity!

여기에서 reference는 $name가 된다. Hello World 예제에서처럼, Velocity는 템플릿 안에 있는 $namename 키로써 컨텍스트에 존재하는 것의 toString() 리턴 값으로 대체한다.


    Hello World!  Welcome to Velocity!

Velocity 레퍼런스는 어떠한 객체의 public 메소드를 엑세스하는 것을 허용하게 만들어 주고, 템플릿의 syntax는 Java code 내에서 사용했던 것과 동일하게 되어 있다. 여기에 몇가지 예제들이 있다.


   There are $myBean.getSize() elements.

   $myObject.anotherMethod( 1, "more data ")

  
   $foo.getBar().barMethod("hello", $moredata )

  
   $foo.myMethod( $bar.callThis() )

여러분들은 아마 애완동물(Pet Store) email 예제로부터 다시 생각해 낼 수도 있을 것이다. 그 예제에서 우리는 java.util.Map에다가 이름(name)과 가격(price) 정보를 저장했었고, nameprice의 두 토큰을 사용해서 데이터를 접근했었다.


   $pet.name for only $pet.price

이러한 것은 Velocity가 JavaBean과 같이 introspection 메커니즘을 사용했기 때문에 동작하게 된다. 그렇게 됨으로써 property notation을 사용한 레퍼런스들로 메소드를 엑세스할 수 있도록 만들어 주게된다. 애완동물 예제 템플릿에서, Velocity의 introspection 기능은 nameprice의 키를 가지고 Mappublic get(String) 메소드를 찾고 호출(invoke)하게 만들어 준다. 우리는 템플릿 내에서 get(String) 메소드를 직접 호출하는 다른 방식을 사용해서 똑같은 데이터를 엑세스할 수도 있다.


   $pet.get('name') for only $pet.get('price')

이 방법은 똑같은 결과를 산출해 낸다. 그리고 실질적으로 무엇이 발생되었는지를 좀 더 확실하게 보여준다. 그렇지만 프로퍼티 노테이션을 사용하는 나머지 다른 한 방법이 좀 더 읽기 쉽고, 여러분의 템플릿과 데이터 클래스의 세부적인 구현과의 의존성을 줄일 수 있는 방법이다. 예를 들면, 여러분들은 public 메소드들인 getName()getPrice()를 가진 클래스로 List 안의 Map을 대체한다 하더라도 원래 예제 템플릿에서 쓰였던 아래 부분들은 계속해서 잘 동작하게 된다.


  $pet.name for only $pet.price

이것이 바로 Velocity가 여러분의 어플리케이션의 모델-컨트롤러 부분으로부터 view에 대한 커플링을 줄일 수 있도록 해 주는 한가지 방법이다. Velocity의 레퍼런스를 이용한 데이터 엑세스 지원은 강력하면서도 유연한 기능이다. 여러분들의 템플릿 레퍼런스는 퍼블릭하게 엑세스할 수 있는 메소드들에 대응하기 위해서 또는 Velocity의 프로퍼티 형식을 통해서 엑세스하는 것이 가능하게 하기 위해서 필요하다.

지시자(Directives)
지시자(Driective)는 VTL의 나머지 중요한 부분이다. 레퍼런스들처럼 그것들도 템플릿 내에서 다른 non-VTL 컨텐트와 자유롭게 혼용될 수 있다. VTL 내의 지시자(directive)는 다음과 같다.


    #set()
    #if()
    #else
    #elseif()
    #end
    #foreach()
    #include()
    #parse()
    #macro()

#set() 지시자는 템플릿 내에서 레퍼런스 값을 셋팅하게 해 준다. 이것은 컨텍스트 내에 기존에 존재하는 객체를 대체할 수 있거나 새로운 객체로 생성할 수 있다. 프리젠테이션 로직에 있어 디자이너에게 아주 유용한 점은 #set()는 정수에 대한 일반적인 수학적 연산(+,-,/*,%)을 허용할 뿐만 아니라 참/거짓도 평가할 수 있다는 것이다.


    #set( $startrow = 0)
    #set( $count = $current + 1 )
    #set( $isReady = ( $isOn && $isOpen) )

지시자의 #if() #else #elseif() #end 셋트는 많은 프로그래밍과 스크립트 언어에서와 마찬가지로 일반적인 if/then/else 기능을 제공해준다. #if()와 #elseif()는 Boolean 값으로 처리할 수 있는 논리적 연산자인 &&, ||, !, ==, >, >=, <, <=를 사용할 수 있는 표현식을 가지게 된다.


    #if( $value > 5 )
      bigger
    #elseif( $value < 5 )
      smaller
    #else
      just right
    #end

#foreach() 반복 지시자는 두개의 아규먼트를 갖는다. 각각의 값이 할당되는 변수에 대한 레퍼런스와 반복을 수행하게 될 컬렉션 값이 있다. 거기에 약간의 "문법적으로 설탕" 역할을 하는 in 단어가 포함된다.


    #foreach( $item in $itemList )
      My $item.
    #end

#foreach()가 지원하는 컬렉션의 타입으로는 다음과 같은 것들이 있다.

  • Object[]
  • java.util.Collection
  • java.util.Map (iterates over the mapped values)
  • java.util.Iterator
  • java.util.Enumeration

#include()#parse() 지시자는 둘 다 아규먼트로써 템플릿이나 스태틱 리소스를 가지고 템플릿이나 리소스를 적절한 장소에 포함해서 output stream으로 렌더링한다는 점에서 비슷하다. 차이점은 #include()는 어떠한 처리과정 없이 특정 리소스의 내용을 포함(include)하고 #parse()는 특정 리소스를 템플릿처럼 취급하여 현재 컨텍스트에 대하여 모든 지시자들과 레퍼런스들을 처리하게 된다.

여러분들은 이 두개의 지시자를 동적으로 결과물을 생성하는데 사용할 수 있다. 예를 들면, 웹 어플리케이션에서 여러분은 서로 다른 네이게이션 레이아웃이나 컬러/디자인 스키마를 가진 최상위 템플릿들과 같은 여러분의 페이지를 위한 골격을 세울 수 있다. 그런 다음에 동적/정적 컨텐트 엘리먼트들이 사용자와 어플리케이션 상태에 근거하여 런타임시에 #parse()나 (그리고) #include()된다.


    <table>
      <tr><td> #parse( $header ) </td></tr>
      <tr><td> #parse( $body ) </td></tr>
      <tr><td> #parse( $footer ) </td></tr>
    </table>

#macro() 지시자는 디자이너로 하여금 지시자 같이 호출될 수 있는 Velocimacro라고 불리는 파라미터화된 VTL code를 생성할 수 있도록 해 준다. 서브루틴과 비슷한 이러한 형태는 여러분들이 재사용할 수 있는 더 쉬운 사용, 가독성, 유지보수성을 위한 명시적 파라미터들을 가지고 있는 VTL 조각들을 생성할 수 있도록 해 준다. Velocimacro는 훌륭하면서도 강력한 툴이고, 아래에 나오는 예제는 최상의 예제이다.

Velocimacro 예제
여러분들이 디자이너가 <select> 양식을 만들기 위해 사용해야 하는 VTL을 캡슐화시키길 원한다고 가정을 해 보자. 여러분들은 regular VTL code 안에 Velocimacro를 정의할 수 있다.


  #macro( select $name $displayname $choicelist )
    <SELECT name=$name>
    <option value="">$displayname</option>
    #foreach( $choice in $choicelist )
      <option value=$choice>$choice</option>
    #end
    </select>
  #end

이렇게 되면, 여러분들이 HTML <select> 형식이 필요로 하는 어느때라도 여러분들은 단순히 지시자처럼 Velocimarco를 호출하기만 하면 된다.


  Please choose:  #select( "size" "--SIZE--" $sizelist )

렌더링 될 때, Velocity는 아규먼트들을 넘김으로써 Velocimacro를 자동적으로 확장한다.

Velocimacro는 recursion 능력, private local context를 지원, 그리고 심지어 private, template-specific namespace들로 분할 되어지는 능력과 같은 많은 흥미로운 형태를 가지고 있다. 더 많은 정보를 원한다면, Velocity 웹 사이트에 있는 사용자와 개발자 문서를 참조하길 바란다.

VTL 잡동사니
몇가지 다른 VTL 형태를 언급해야만 할 거 같다. VTL은 여러분들이 템플릿 내에서 integer, string 문자열, Boolean 값, 객체의 배열, 연속적인 integer의 배열들을 생성할 수 있도록 허용한다.


  #set( $myint = 5 )
  #set( $mystring = 'Hello There')
  #set( $mybool = true )
  #set( $objarr = [ "a", $myint, $mystring, false ] )
  #set( $intrangearr = [1..10] )

VTL은 또한 참조값(지시자와 Velocimacro들을 포함해서)들을 삽입할 수 있는 쌍따옴표(")를 사용해서 string 문자열을 가지게 만들수도 있다.


  #set( $foo = 'bar')
  #set( $interp = "The value is '$foo'")

$interp의 결과 값은 문자열 The value is 'bar'가 된다.

Velocity 웹 사이트에 완성된 VTL 문서를 찾을 수 있다.

똑같은 데이타, 다른 양식(템플릿)
이제 여러분들은 레퍼런스와 지시자들을 알았으니 우리의 애완동물가게 email 예제를 계속해 보자.

여러분들의 email 메시지를 HTML로 전환한다고 가정해 보자. Velocity를 이용하면 여러분들은 템플릿을 변경함으로써 손쉽게 전환하는 것을 할 수 있다. 여러분들의 코드는 변하지 않고 고스란히 남아있게 할 수 있다. 여기에 똑같은 데이터로부터 HTML을 생성해 내는 다른 템플릿이 있다.


  <HTML>
    <HEAD>
      <TITLE>Pet Store Sale!</TITLE>
    </HEAD>


    <BODY>
      <CENTER>
      <B>$petList.size() Pets on Sale!</B>

      <BR/>
      We are proud to offer these fine pets
      at these amazing prices.  
      <BR/>
      This month only, choose from:
      #set( $count = 1 )  
      <TABLE>
        #foreach( $pet in $petList )
          <TR>
            <TD>$count)</TD>
            <TD>$pet.name</TD>
            <TD>$pet.price</TD>
          </TR>
          #set( $count = $count + 1 )
        #end
      </TABLE>
      <BR/>

      <I>Call Today!</I>
      </CENTER>

    </BODY>
  </HTML>

이 템플릿을 사용하면, 여러분의 email body는 이제 아래처럼 보이게 된다.


  <HTML>
    <HEAD>
      <TITLE>Pet Store Sale!</TITLE>
    </HEAD>


    <BODY>
      <CENTER>
      <B>3 Pets on Sale!</B>

      <BR/>
      We are proud to offer these fine pets
      at these amazing prices.  
      <BR/>
      This month only, choose from:
      <TABLE>
          <TR>
            <TD>1)</TD>
            <TD>horse</TD>
            <TD>$100</TD>
          </TR>
          <TR>
            <TD>2)</TD>
            <TD>dog</TD>
            <TD>$59.99</TD>
          </TR>
          <TR>
            <TD>3)</TD>
            <TD>bear</TD>
            <TD>$3.99</TD>
          </TR>
      </TABLE>
      <BR/>

      <I>Call Today!</I>
      </CENTER>

    </BODY>
  </HTML>

이 예제는 어떻게 Velocity가 여러분들로 하여금 데이터와 코드로부터 프리젠테이션을 분리할 수 있도록 만들어 주는지를 잘 보여 주고 있다. 우리는 다른 템플릿을 가지고 똑같은 데이터와 코드를 사용했다.

XML template
마지막 애완동물 가게 예제로써 XML 문서를 생성해 내는 똑같은 프로그램을 이용하자. 다시 한번 우리는 템플릿을 변경한다.


<?xml version="1.0"?>

<salelist>
#foreach( $pet in $petList )
  <pet>
    <name>$pet.name</name>
    <price>$pet.price</price>
  </pet>
#end
</salelist>


똑같은 프로그램과 이 템플릿을 이용하여 아래의 결과를 얻을 수 있다.


<?xml version="1.0"?>

<salelist>
  <pet>
    <name>horse</name>
    <price>$100.00</price>
  </pet>
  <pet>
    <name>dog</name>
    <price>$59.99</price>
  </pet>
  <pet>
    <name>bear</name>
    <price>$3.99</price>
  </pet>
</salelist>

Velocity와 Servlet를 이용한 프로그래밍
마지막으로 서블릿과 함께 Velocity를 사용해 보자. Velocity 배포본은 org.apache.velocity.servlet.VelocityServlet라는 서블릿 기반 클래스를 포함하고 있다. 이 org.apache.velocity.servlet.VelocityServlet 클래스는 모든 Velocity와 Servlet API를 조절(handle)할 수 있게 함을로써 여러분들이 여러분들의 어플리케이션에만 신경을 쓸 수 있게 만들어준다. (대부분 아주 간단하다). 최소한 여러분들은 컨텍스트 안에 데이터를 집어 넣고, 템플릿을 리턴받는 메소드만은 구현해야만 한다. 아래의 클래스는 request를 핸들링하고 Velocity를 사용하여 템플릿을 렌더링한다(실제 에러핸들링 없이).


import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;

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

import org.apache.velocity.Template;
import org.apache.velocity.context.Context;
import org.apache.velocity.servlet.VelocityServlet;

import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.exception.ParseErrorException;


public class Sample extends VelocityServlet
{
    public Template handleRequest( HttpServletRequest request,
         HttpServletResponse response, Context context )
    {        
        /* organize our data  */

        ArrayList list = new ArrayList();
        Map map = new HashMap();

        map.put("name", "horse");
        map.put("price", "$100.00");
        list.add( map );

        map = new HashMap();
        map.put("name", "dog");
        map.put("price", "$59.99");
        list.add( map );

        map = new HashMap();
        map.put("name", "bear");
        map.put("price", "$3.99");
        list.add( map );

        /* add that list to the context  */

        context.put("petList", list);

        /* get the template */

        Template template = null;
      
        try
        {
            template =  getTemplate("petstoreemail.vm");
        }
        catch( Exception e )

        {
            System.out.println("Error " + e);
        }

        return template;
    }}

환경설정과 디플로이가 적절하게 되면, 이것은 HTML을 생성하는 애완동물 가게 예제와 같이 똑같은 결과를 생성해 내고 서블릿 엔진이 클라이언트 브라우져로 전달하게 될 것이다.

템플릿, deployment information과 추가적인 설정 소스 코드를 포함하여 완벽한 작업 예제를 원한다면 Velocity Project에 의해 제공되는 배포본 안의 서블릿 예제를 보길 바란다.

이제는 여러분들의 차례이다.
Velocity는 아래와 같은 특징을 가지고 있다.

  • 디자이너와 프로그래머 둘다 사용하기 쉽다.
  • 코드로부터 프리젠테이션 형식을 분리해 준다.
  • 기존에 존재하는 클래스를 사용할 수 있게 만들어준다.
  • 어떠한 자바 어플리케이션과 같이 작업할 수 있다.
  • 무료이고 business-friendly open source license인 Apache

    Velocity를 사용하는 것에 관하여 흥미로운 점들 중 한가지는 템플릿 모델의 간결함이 "올바른 방법"으로 수행할 수 있도록 만들어 줄 수 있다는 것이다.

    여러분들은 이 주장을 확인할 수 있다. 이제 여러분들은 Velocity를 가지고 시작하는 방법을 알았고, 진입장벽이 꽤나 낮다는것을 확신할 수 있었을 것이다. 예제들은 작성하기 쉽고 서블릿이나 standalone 프로그램 둘다 적용가능 했다. 여러분들은 Jakarta Velocity Project 웹 사이트로부터 배포본을 다운받음으로써 Velocity와 여러분 자신이 친숙해질 수 있다. 이것은 기본적인 형태나 많은 향상된 형태들을 다룰 수 있는 standalone 어플리케이션과 서블릿 예제들을 가지고 있다. 문서는 잘 정리되어 있고 supportive 커뮤니티는 여러분들을 충분히 도와 줄 수 있다. 메일링 리스트에 등록해서 자유를 느끼기 바란다. 여러분들은 지금 당장은 Velocity에 대한 효용성을 가지지 못할 수도 있다. 그러나 매일 반복되는 프로그래밍 작업에서 이것이 얼마나 자주 문제들을 해결해 줄 수 있는지 놀라게 될 것이다.


    저자에 대해
    Geir Magnusson Jr.는 software개발, 시스템 아키텍쳐, 실시간 데이터 전송에 전문적인 독립 컨설턴트이다. 그는 Velocity Project에 대한 공헌자로 노력하고 있으며, Jakarta Project의 관리 커뮤니티에서 봉사하고 있다. 그 역시 Aapache Software Foundation의 멤버이다.