98..Etc/velocity2010. 2. 19. 18:19
반응형
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 EmailDemo
{
    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", "Cow");
        map.put("price", "$100.00");
        list.add( map );
 
        map = new HashMap();
        map.put("name", "Eagle");
        map.put("price", "$59.99");
        list.add( map );

        map = new HashMap();
        map.put("name", "Shark");
        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( "./src/email_xml.vm" );

        /*
         *  now render the template into a Writer, here
         *  a StringWriter
         */

        StringWriter writer = new StringWriter();

        t.merge( context, writer );

        /*
         *  use the output in the body of your emails
         */

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


-------------------------------------------------------------------------------------
<?xml version="1.0"?>

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

Posted by 1010
98..Etc/velocity2010. 2. 19. 18:18
반응형
/*
 * Copyright 2000,2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.io.Writer;

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

import org.jdom.Document;
import org.jdom.input.SAXBuilder;


/**
 * Example to show basic XML handling in a template.
 *
 * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
 * @version $Id: XMLTest.java,v 1.2.12.1 2004/03/04 00:18:30 geirm Exp $
 */
public class XMLTest
{
    public XMLTest( String templateFile)
    {    
        Writer writer = null;

        try
        {
            /*
             *  and now call init
             */

            Velocity.init();

                       
            /*
             * build a Document from our xml
             */

            SAXBuilder builder;
            Document root = null;

            try
            {
                builder = new SAXBuilder(  "org.apache.xerces.parsers.SAXParser" );
                root = builder.build("./src/test.xml");
            }
            catch( Exception ee)
            {
                System.out.println("Exception building Document : " + ee);
                return;
            }

            /*
             * now, make a Context object and populate it.
             */

            VelocityContext context = new VelocityContext();
            context.put("root", root);

            /*
             *  make a writer, and merge the template 'against' the context
             */
 
            Template template = Velocity.getTemplate(templateFile);

            writer = new BufferedWriter(new OutputStreamWriter(System.out));
            template.merge( context , writer);  
        }
        catch( Exception e )
        {
           System.out.println("Exception : " + e);
        }
        finally
        {
            if ( writer != null)
            {
                try
                {
                    writer.flush();
                    writer.close();
                }
                catch( Exception ee )
                {
                    System.out.println("Exception : " + ee );
                }
            }
        }
    }

    public static void main(String[] args)
    {
        XMLTest t;

        t = new XMLTest("./src/xml.vm");
    }
}


-------------------------------------------------------------------------------------
//File: test.xml
<?xml version="1.0" encoding="UTF-8"?>
<document>
  <properties>
    <author>
  <email>velocity-user@jakarta.apache.org</email>
  <name>
     <last>
    <full>Team</full>
    <firstinitial>T</firstinitial>
     </last>
     <first>
    Velocity
     </first>
  </name>
    </author>
    <title>
        The Jakarta Project
    </title>
  </properties>

  <body>
  I am the body
  </body>
</document>
-------------------------------------------------------------------------------------
//File: xml.vm
#macro ( recursive $e $indent )    
    #if( $e.getChildren().size() > 0 )
        $indent <$e.getName()>
        #foreach ($child in $e.getChildren() ) 
            #recursive( $child "$indent  " )
        #end
        $indent </$e.getName()>
    #else
        $indent <$e.getName()>
        $indent    $e.getTextTrim()
        $indent </$e.getName()>
    #end
#end

#set($i = " ")

First, we print out the document tree with a 
recursive Velocimacro :

#recursive( $root.getRootElement() $i )


Next, we access pieces of data directly :

email : $root.getRootElement().getChild("properties").getChild("author").getChild("email").getText()
last name :  $root.getRootElement().getChild("properties").getChild("author").getChild("name").getChild("last").getChild("full").getText()

           
       
Posted by 1010
98..Etc/velocity2010. 2. 19. 18:17
반응형

/*
 * Copyright 2000-2001,2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


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

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

import java.io.*;
import java.util.ArrayList;

/**
 * This class is a simple demonstration of how the Velocity Template Engine
 * can be used in a standalone application.
 *
 * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
 * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
 * @version $Id: Example.java,v 1.4.8.1 2004/03/04 00:18:29 geirm Exp $
 */

public class Example
{
    public Example(String templateFile)
    {
        try
        {
            /*
             * setup
             */

            Velocity.init("./src/velocity.properties");
           
            /*
             *  Make a context object and populate with the data.  This
             *  is where the Velocity engine gets the data to resolve the
             *  references (ex. $list) in the template
             */

            VelocityContext context = new VelocityContext();
            context.put("list", getNames());
           
            /*
             *  get the Template object.  This is the parsed version of your
             *  template input file.  Note that getTemplate() can throw
             *   ResourceNotFoundException : if it doesn't find the template
             *   ParseErrorException : if there is something wrong with the VTL
             *   Exception : if something else goes wrong (this is generally
             *        indicative of as serious problem...)
             */

            Template template =  null;

            try
            {
                template = Velocity.getTemplate(templateFile);
            }
            catch( ResourceNotFoundException rnfe )
            {
                System.out.println("Example : error : cannot find template " + templateFile );
            }
            catch( ParseErrorException pee )
            {
                System.out.println("Example : Syntax error in template " + templateFile + ":" + pee );
            }

            /*
             *  Now have the template engine process your template using the
             *  data placed into the context.  Think of it as a  'merge'
             *  of the template and the data to produce the output stream.
             */

            BufferedWriter writer = writer = new BufferedWriter(
                new OutputStreamWriter(System.out));

            if ( template != null)
                template.merge(context, writer);

            /*
             *  flush and cleanup
             */

            writer.flush();
            writer.close();
        }
        catch( Exception e )
        {
            System.out.println(e);
        }
    }

    public ArrayList getNames()
    {
        ArrayList list = new ArrayList();

        list.add("ArrayList element 1");
        list.add("ArrayList element 2");
        list.add("ArrayList element 3");
        list.add("ArrayList element 4");

        return list;
    }

    public static void main(String[] args)
    {
        Example t = new Example("./src/example.vm");
    }
}
-------------------------------------------------------------------------------------
## This is an example velocity template

#set( $this = "Velocity")

$this is great!

#foreach( $name in $list )
    $name is great!
#end

#set( $condition = true)

#if ($condition)
    The condition is true!
#else
    The condition is false!
#end    


-------------------------------------------------------------------------------------
#
# This is a simple example of a velocity properties file.
#
# Any property that is not listed here will have it's default
# value used.  The default values are located in :
#  *  src/java/org/apache/velocity/runtime/default/velocity.defaults
#  *  http://jakarta.apache.org/velocity/developer-guide.html
#
# as an example, we are changing the name of the velocity log
#
runtime.log = velocity_example.log
Posted by 1010
98..Etc/velocity2010. 2. 19. 18:15
반응형
import java.io.StringWriter;
import java.io.Writer;
import java.util.Properties;

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

public class HelloWorldProperties {

  public static void main(String[] args) throws Exception {
    Properties props = new Properties();
    props.put("input.encoding", "utf-8");

    Velocity.init(props);

    Template template = Velocity.getTemplate("./src/HelloWorld.vm");

    VelocityContext context = new VelocityContext();

    Writer writer = new StringWriter();
    template.merge(context, writer);

    System.out.println(writer.toString());
  }
}      
-------------------------------------------------------------------------------------
Hello World!
Posted by 1010
98..Etc/velocity2010. 2. 19. 18:14
반응형
import java.io.StringWriter;
import java.io.Writer;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.event.EventCartridge;
import org.apache.velocity.app.event.MethodExceptionEventHandler;
import org.apache.velocity.app.event.NullSetEventHandler;
import org.apache.velocity.app.event.ReferenceInsertionEventHandler;
import org.apache.velocity.context.Context;

public class EventHandler implements ReferenceInsertionEventHandler,
    NullSetEventHandler, MethodExceptionEventHandler {

  public EventHandler(Context ctx) {
    EventCartridge ec = new EventCartridge();
    ec.addEventHandler(this);
    ec.attachToContext(ctx);
  }

  public Object referenceInsert(String reference, Object data) {
    System.out.println("referenceInsert: " + reference + " data: " + data);

    return data;
  }

  public boolean shouldLogOnNullSet(String lhs, String rhs) {
    System.out.println("shouldLogOnNullSet");
    System.out.println("lhs:" + lhs + " rhs:" + rhs);

      return true;
  }

  public Object methodException(Class cls, String method, Exception e)
      throws Exception {
    return "An " + e.getClass().getName() + " was thrown by the " + method
        + " method of the " + cls.getName() + " class [" + e.getMessage() + "]";
  }

  public static void main(String[] args) throws Exception {
    Velocity.init();

    Template t = Velocity.getTemplate("./src/eventHandler.vm");

    Context ctx = new VelocityContext();
    ctx.put("person", "Joe");
    ctx.put("exception", new ExceptionGenerator());

    EventHandler hdl = new EventHandler(ctx);

    Writer writer = new StringWriter();
    t.merge(ctx, writer);

    System.out.println(writer);
  }

}


import java.util.Random;

public class ExceptionGenerator {

  public String generate() throws Exception {
    Random rnd = new Random();

    int x = rnd.nextInt(5);

    if (x == 2) {
      throw new Exception("Unlucky!");
    } else {
      return "No Exception";
    }
  }
}
-------------------------------------------------------------------------------------
#set($myNull1 = $validNull)
#set($myNull2 = $invalidNull)

This is $person

$exception.generate()
$exception.generate()
$exception.generate()
$exception.generate()
           
Posted by 1010
98..Etc/velocity2010. 2. 19. 18:13
반응형
import java.io.StringWriter;
import java.io.Writer;
import java.util.Date;

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

public class VMDemo {

  public static void main(String[] args) throws Exception {
    Velocity.init();
    Template t = Velocity.getTemplate("./src/VMDemo.vm");

    VelocityContext ctx = new VelocityContext();

    ctx.put("aDate",new Date());
    Writer writer = new StringWriter();
    t.merge(ctx, writer);

    System.out.println(writer);
  }
}
-------------------------------------------------------------------------------------
Hello $aaDate.getDate()
           
Posted by 1010
98..Etc/velocity2010. 2. 19. 18:11
반응형
import java.io.StringWriter;
import java.io.Writer;

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

public class ResourceLoaders {

  private static final String FILE_RESOURCE_LOADER_TEMPLATE = "./src/ResourceLoader1.vm";

  private static final String JAR_RESOURCE_LOADER_TEMPLATE = "./src/ResourceLoader2.vm";

  private static final String CLASSPATH_RESOURCE_LOADER_TEMPLATE = "./src/ResourceLoader3.vm";

  public static void main(String[] args) throws Exception {
    processTemplate(FILE_RESOURCE_LOADER_TEMPLATE);
    processTemplate(FILE_RESOURCE_LOADER_TEMPLATE);
    processTemplate(JAR_RESOURCE_LOADER_TEMPLATE);
    processTemplate(JAR_RESOURCE_LOADER_TEMPLATE);
    processTemplate(CLASSPATH_RESOURCE_LOADER_TEMPLATE);
    processTemplate(CLASSPATH_RESOURCE_LOADER_TEMPLATE);
  }

  private static void processTemplate(String templateName) throws Exception {
    Velocity.init();
    Template template = Velocity.getTemplate(templateName);
    VelocityContext context = new VelocityContext();
    Writer writer = new StringWriter();
    template.merge(context, writer);
    System.out.println(writer.toString());
  }
}
-------------------------------------------------------------------------------------
//File: ResourceLoader1.vm
ResourceLoader1 Template!

//File: ResourceLoader2.vm
ResourceLoader2 Template Modified!


//File: ResourceLoader3.vm
ResourceLoader3 Template 3

           
Posted by 1010
98..Etc/velocity2010. 2. 19. 18:10
반응형

import java.io.StringWriter;
import java.io.Writer;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.tools.generic.MathTool;

public class MathToolExample {
  public static void main(String[] args) throws Exception {
    Velocity.init();

    Template t = Velocity.getTemplate("./src/mathTool.vm");

    VelocityContext ctx = new VelocityContext();
    ctx.put("math", new MathTool());
    ctx.put("aNumber", new Double(5.5));

    Writer writer = new StringWriter();
    t.merge(ctx, writer);

    System.out.println(writer);
  }
}
-------------------------------------------------------------------------------------
$math.random is a random number
Posted by 1010
98..Etc/velocity2010. 2. 19. 18:09
반응형
-------------------------------------------------------------------------------------

import java.io.StringWriter;
import java.io.Writer;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.tools.generic.IteratorTool;

public class IteratorToolExample {

  public static void main(String[] args) throws Exception {
    Velocity.init();

    Template t = Velocity.getTemplate("./src/iteratorTool.vm");

    VelocityContext ctx = new VelocityContext();
    ctx.put("var", new IteratorTool());

    Writer writer = new StringWriter();
    t.merge(ctx, writer);

    System.out.println(writer);
  }
}
-------------------------------------------------------------------------------------
#set($list = ["A", "B", "C", "D", "E"])

#foreach($item in $list)
    $item
#end
Posted by 1010
98..Etc/velocity2010. 2. 19. 18:08
반응형

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

import java.io.StringWriter;
import java.io.Writer;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.tools.generic.RenderTool;

public class VMDemo {

  public static void main(String[] args) throws Exception {
    Velocity.init();
    Template t = Velocity.getTemplate("./src/VMDemo.vm");

    VelocityContext ctx = new VelocityContext();

    Writer writer = new StringWriter();
    t.merge(ctx, writer);

    System.out.println(writer);
  }
}
-------------------------------------------------------------------------------------
<html>
    <head>
        <title>Gimli's Widgetarium</title>
    </head>
    <body>
        <table>
            #set ($rowCount = 1)            
            #set ($products = ["one", "two", "three"])
            #foreach($product in $products)
                #if ($rowCount % 2 == 0)
                    #set ($bgcolor = "#FFFFFF")
                #else
                    #set ($bgcolor = "#CCCCCC")                
                #end
                <tr>
                    <td bgcolor="$bgcolor">$product</td>
                    <td bgcolor="$bgcolor">$product</td>
                </tr>                        
                #set ($rowCount = $rowCount + 1)
            #end
        </table>
    </body>
</html>

           

Posted by 1010
98..Etc/velocity2010. 2. 19. 18:07
반응형
import java.io.StringWriter;
import java.io.Writer;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.tools.generic.RenderTool;

public class VMDemo {

  public static void main(String[] args) throws Exception {
    Velocity.init();
    Template t = Velocity.getTemplate("./src/VMDemo.vm");

    VelocityContext ctx = new VelocityContext();

    Writer writer = new StringWriter();
    t.merge(ctx, writer);

    System.out.println(writer);
  }
}
-------------------------------------------------------------------------------------
#set ($companyName = "Name")
<html>
  <head>
    <title>$companyName Homepage</title>
  </head>
  <body>
    <h1>Welcome!!</h1>
    #if ($userType == "VIP")
      <h2>You are a VIP!</h2>
    #else
      <h2>You are not a VIP!</h2>
    #end
  </body>
</html>
Posted by 1010
98..Etc/velocity2010. 2. 19. 18:07
반응형
import java.io.StringWriter;
import java.io.Writer;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.tools.generic.IteratorTool;

public class IteratorToolExample {

  public static void main(String[] args) throws Exception {
    Velocity.init();

    Template t = Velocity.getTemplate("./src/iteratorTool.vm");

    VelocityContext ctx = new VelocityContext();
    ctx.put("var", new IteratorTool());

    Writer writer = new StringWriter();
    t.merge(ctx, writer);

    System.out.println(writer);
  }
}
-------------------------------------------------------------------------------------
#set($list = ["A", "B", "C", "D", "E"])

#foreach($item in $list)
    #if($velocityCount <= 3)
        $item
    #end
#end
           
Posted by 1010
98..Etc/velocity2010. 2. 19. 18:05
반응형
-------------------------------------------------------------------------------------
Today's date is:       $date
Today's date is also:  $date.long           #* using property shortcut *#
Today's date is also:  $date.get('long')    #* using full syntax *#
The date and time is:  $date.default $date.short

Another date is:       $aDate
Another date is also:  $date.format('medium', $aDate)

-------------------------------------------------------------------------------------
import java.io.StringWriter;
import java.io.Writer;
import java.util.Calendar;
import java.util.TimeZone;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.tools.generic.DateTool;

public class DateToolExample {

  public static void main(String[] args) throws Exception {
    Velocity.init();

    Template t = Velocity.getTemplate("./src/dateTool.vm");

    VelocityContext ctx = new VelocityContext();
    ctx.put("date", new DateTool());

    Calendar aDate = Calendar.getInstance(TimeZone.getTimeZone("PST"));
    aDate.set(200, 11, 25);

    ctx.put("aDate", aDate);

    Writer writer = new StringWriter();
    t.merge(ctx, writer);

    System.out.println(writer);
  }
}
Posted by 1010
98..Etc/velocity2010. 2. 19. 18:03
반응형
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 EmailDemo
{
    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", "Cow");
        map.put("price", "$100.00");
        list.add( map );
 
        map = new HashMap();
        map.put("name", "Eagle");
        map.put("price", "$59.99");
        list.add( map );

        map = new HashMap();
        map.put("name", "Shark");
        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( "./src/email_html.vm" );

        /*
         *  now render the template into a Writer, here
         *  a StringWriter
         */

        StringWriter writer = new StringWriter();

        t.merge( context, writer );

        /*
         *  use the output in the body of your emails
         */

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

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

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


    <BODY>
      <CENTER>
      <B>$petList.size() Pets on Sale!</B>
     
      <BR/>
      This is an email generated by velocity
      <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>
     
     <I>Call Today!</I>
     Bests <br>
     www.java2s.com
      </CENTER>
 
    </BODY>
  </HTML>


Posted by 1010
98..Etc/velocity2010. 2. 19. 18:01
반응형
-------------------------------------------------------------------------------------

import java.io.StringWriter;
import java.io.Writer;

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

public class ContextChaining {

  public static void main(String[] args) throws Exception {
    Velocity.init();

    Template template = Velocity.getTemplate("./src/ContextChaining.vm");

    VelocityContext context1 = new VelocityContext();
    VelocityContext context2 = new VelocityContext(context1);

    context1.put("firstName", "Joe");
    context2.put("lastName", "Wang");

    Writer writer = new StringWriter();
    template.merge(context2, writer);

    System.out.println(writer.toString());
  }
}
-------------------------------------------------------------------------------------
This is my first name $firstName
This is my last name $lastName

Full Name is $firstName $lastName

Posted by 1010
98..Etc/velocity2009. 4. 3. 13:00
반응형

$res.setHeader("Pragma", "no-cache");
$res.setHeader("Cache-Control", "no-cache");
$res.setHeader("Expire", "0");


response 객체에다가 이렇게 설정

Posted by 1010
98..Etc/velocity2009. 3. 23. 15:10
반응형

Velocity의 Developer's Guide를 따라하면서 정리해본것 입니다.


Download(다운로드)

우선 Velocity 배포본을 다운로드 받는다.

그리고 Ant 를 다운받는다.


Dependencies(의존성)

개발을 위해서는 Java 2 Standard Edition SDK (Software Development Kit)이 필요하고,

Velocity를 실행시키기 위해서는 Java 2 Standard Edition RTE (Run Time Environment)이 필요하다.(물론 RTE 대신에 SDK를 사용하는것도 가능하다.)


Velocity는 다음 세가지의 패키지에 의존성을 가지고 있다.

Jakarta Commons Collections - 반드시 필요함.

Jakarta Avalon Logkit - 선택적이지만 Velocity에서 파일기반의 logging을 위해서는 필요하다.

Jakarta ORO - 선택적이지만 org.apache.velocity.convert.WebMacro 템플릿 변환 툴을 사용하기 위해서는 필요하다.

이 패키지들은 build/lib 폴더안에 넣거나 classpath에 추가하면 된다.


How Velocity Works(Velocity는 어떻게 움직이는가)

Velocity를 사용하여 어플리케이션이나 서블릿을 개발할 때는 보통 다음과 같은 과정을 거친다.


1. Velocity의 초기화

2. Context 객체의 생성

3. Context에 사용자의 데이터 객체(data objects)를 추가한다.

4. 템플릿을 선택한다.

5. 산출물(output)을 만들기 위해 템플릿과 사용자의 데이터를 병합(Merge)한다.


code로 이 과정을 표현하면 다음과 같다.

이 파일은 org.apache.velocity.app.Velocity.java 인데, 실제 자신이 어플리케이션을 개발할 때에도 이러한 패턴으로 작성하면 된다.

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(); // 1.Velocity의 초기화  
VelocityContext context = new VelocityContext(); 
// 2.Context의 생성
context.put( "name", new String("Velocity") ); 
// 3. Context에 사용자의 데이터 객체(data objects)를 추가한다.


Template template = null;
try { 
template = Velocity.getTemplate("mytemplate.vm");
// 4. 템플릿을 선택한다.
} 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 ); 
// 5. 산출물(output)을 만들기 위해 템플릿과 사용자의 데이터를 병합(Merge)한다.
figure 1. velocity의 작동 과정의 예
 

The Context(컨텍스트)

Velocity에서 Context 라는것은 가장 핵심의 요소면서, 시스템의 부분들사이에서 데이터를

손쉽게 이동시킬 수 있는 일종의 컨테이너(Container)다.

즉, 이말은 Context가 실제 Java Layer와 Template Layer간의 데이터를 주고 받을 때, 그 운반체의 역할을 한다는 말과 같다.

Context는 Java의 Map과 같은 형태를 취한다. key-value의 쌍으로 구성되기 때문에,

Java에서 일반적으로 사용되는 Map을 다룰때와 같이 다루면 된다.


Velocity Template Language(밸로시티 템플릿 언어)

VTL은 Template에서 사용되는 Velocity 고유의 언어를 의미한다.

실제 Template파일을 열어서 코드를 보면 따로 설명을 하지 않아도 충분히 이해할 수 있을만큼 간단한 형태를 보여준다.

example중에서 app_example1의 example.vm을 열어보면 다음과 같은 코드를 볼 수 있다.


## This is an example velocity template

#set( $this = "Velocity")

$this is great! but it's so hard.

#foreach( $name in $list )
    $name is great!
#end

#set( $condition = true)

#if ($condition)
    The condition is true!
#else
    The condition is false!
#end   


figure 2. template의 예

 

 

References(참조형)

variables(변수) - Velocity에서 변수는 다음과 같이 $를 먼저 쓰고 그 뒤에 식별자를 적어주는 방식으로 사용한다.

$foo


property(특성) - 프로퍼티도 다음과 같이 $다음에 식별자를 쓰고, 마침표(.)후에 다시 식별자의 형태로 사용한다.

$foo.name


method(메소드) - 메소드도 역시 $다음에 식별자를 쓰고, 마침표(.)후에 호출할 메소드의 이름을 적는다.

$foo.getName()


Directives(지시형)

#set - reference의 값을 설정한다.

#if/elseif/else - 조건문 제어

#foreach - 반복문 제어

#include - velocity로 파싱(parsing) 되지 않은 파일의 출력

#parse - velocity로 파싱(parsing) 된 파일 출력

#stop - template 엔진의 정지

#macro - 반복적으로 사용할 vm 정의


Comment(주석)

## - 한줄짜리 주석

#* ... *# - 여러줄짜리 주석


The Examples(예제)
Velocity 배포본의 디렉토리 구조는 다음과 같다.

figure 3. velocity 배포본의 디렉토리 구조


일단 실제 Velocity의 소스를 볼 수는 없고 Velocity가 무엇인지 맛부터 보는것이 좋을것이다.

그래서 필요한것이 바로 examples를 이용하는 것이라고 볼 수 있겠다.

우선 앞서 다운받은 Ant가 설치가 되어있어야 한다. Ant의 설치는 별다른게 아니라

압축을 풀고, 자신이 원하는 위치에 이 Ant디렉토리를 위치시킨 다음에

classpath에 ANT_HOME의 이름으로 Ant디렉토리를 등록시켜주면 된다.

(물론 path에 %ANT_HOME%\bin도 추가해줘야한다.)


콘솔창을 이용하여, build 디렉토리로 이동해서

ant examples 명령어를 주면 무언가 작업이 일어난다.

(win98은 실행창에서 command를, nt,2000,xp는 cmd를 입력하면 콘솔창이 뜬다.)

이 명령어가 하는 일은 examples 폴더에 있는 모든 파일을 컴파일 해주는 역할을 한다.

우선 가장 손쉬운 예제부터 보도록 하자.

앞서 얘기가 나온 app_example1부터 살펴보자.



figure 4. 예제 app_example1의 디렉토리 구조


이 예제를 실행시켜보면 다음과 같은 화면이 출력된다.

 
figure 5. 예제 app_example1의 실행 결과
 
-- 이후 작성중 --
네이버

최초작성일 : 2005-02-22

최종수정일 : 2005-02-23

 

이번에는 웹어플리케이션 예제를 한번 분석해보려고 합니다.

다음번에는 이 예제를 조금 더 발전시켜보는 방향으로 해보죠

 

일단 velocity에서 제공해주는 예제중에서 forumdemo라는 예제를 분석해보도록 하겠습니다.

기능은 간단한 forum의 기능을 제공해주는 작은 어플리케이션입니다.

물론 DB는 사용하지 않습니다.

이 어플리케이션은 다음과 같은 폴더 구조를 가지고 있습니다.

 

 

우리가 중요하게 봐야할 곳은 template폴더의 vm들과 WEB-INF/web.xml, WEB-INF/conf/velocity.properties 그리고 소스파일들이지요.

 

template은 명칭 그대로 템플릿을 모아둔 폴더 입니다.

list.vm은 message들의 목록을 출력할 때 쓰이는 템플릿이고,

reply.vm은 해당 message에 reply할 때 사용되는 템플릿이며,

view.vm은 해당 message와 그 하위의 reply들을 화면에 출력할 때 사용되는 템플릿입니다.

 

일단 예제를 한번 돌려보면서 해보는게 좋겠지요?

이전에 ant examples를 했다면 아마도 forumdemo도 모두 컴파일이 되어 있을겁니다.

(안하셨다면 이전 게시물을 참고하시기 바랍니다.)

이 forumdemo폴더 자체를 tomcat이설치된폴더/webapp 밑으로 복사를 합니다.

(물론 ant를 이용하여 자동으로 deploy해도 되겠지만 지금은 일단 복사하는 방법을 선택합니다.)

 

tomcat을 기동하고, 브라우저창에 http://localhost:8080/forumdemo 를 입력하시면 다음과 같은 화면이 나옵니다. 아무거나 클릭을 해볼까요?

 

당황스럽게도 404에러, 즉 페이지를 찾을 수 없다는 에러가 나는데, 이것은 web.xml에서 servlet을 mapping시켜주지 않아서 생기는 현상입니다.

 

 

WEB-INF/web.xml 파일에 다음을 추가시켜 줍니다.

<servlet-mapping>
        <servlet-name>forum</servlet-name>
        <url-pattern>/servlet/forum</url-pattern>
</servlet-mapping>

 

자 tomcat을 재시작 시킨후에 다시 한번 아무 메뉴나 클릭해봅시다.

 

 

이번에는 500에러가 나타납니다. 왜그럴까요? 에러로그를 잘 살펴보시면 template을 가져오지 못했기 때문에 에러를  발생시킨것을 알 수 있습니다.

이것도 역시 WEB-INF/web.xml파일이 잘못되어 있어서 발생하는 현상입니다.

<init-param>
        <param-name>properties</param-name>
        <param-value>/WEB-INF/conf/velocity.properties</param-value>
</init-param>

를 다음과 같이 바꿔줍니다.

 

<init-param>
        <param-name>org.apache.velocity.properties</param-name>
        <param-value>/WEB-INF/conf/velocity.properties</param-value>
</init-param>

 

다시 tomcat을 재시작한 후에 클릭해보면 제대로 나오는것을 확인 할 수 있습니다.

일단 예제가 돌아가기 시작하고 있으니 이제 실제적으로 이 어플리케이션을 분석해보도록 하겠습니다.

 

이 어플리케이션은 모든 서블릿요청은 org.apache.velocity.demo.ControllerServlet 이 담당합니다.

get방식으로 parameter를 받아서 그에 해당하는 action을 org.apache.velocity.demo.action 하위의 클래스들로 실행시켜주는 것이지요.

 

ControllServlet.java

(import는 생략했습니다.)

 

public class ControllerServlet extends VelocityServlet

{
    private static String ERR_MSG_TAG = "forumdemo_current_error_msg";

   
    /**
     *  template path에 대한 정보를 가져오기 위한 메소드 입니다.
     */

    protected Properties loadConfiguration(ServletConfig config )
        throws IOException, FileNotFoundException
    {
        String propsFile = config.getInitParameter(INIT_PROPS_KEY);
       
        /*
         *  webapp root에 대한 절대경로를 통해서 template파일의 위치를 찾습니다.

         *  tomcat과 같은 servlet 2.2 이상의 지원하는 container에서 가능하다고 하네요.
         */

        if ( propsFile != null )
        {
            String realPath = getServletContext().getRealPath(propsFile);
       
            if ( realPath != null )
            {
                propsFile = realPath;
            }
        }
       

       // 설정파일을 load합니다. 500에러가 발생했던 이유가 여기에 있는거지요.

       // 내부적으로는 org.apache.velocity.properties로 정의되어 있었는데,

       // web.xml에서는 properties로 정의되어 있었기때문에 찾지못해서 에러가 발생했던 것이죠.
       Properties p = new Properties();
       p.load( new FileInputStream(propsFile) );
     

       /**
        *  template의 경로와 log의 경로를 설정합니다.

        */

       // 설정파일에 정의되어있는 resource loader(차후에 다시 얘기나옵니다.)의 경로(path)를 찾아서 실제 경로로 바꾸어 다시 정의합니다. [file.resource.loader.path = /template]

       String path = p.getProperty("file.resource.loader.path");

       if (path != null)
       {
           path = getServletContext().getRealPath( path );
           p.setProperty( "file.resource.loader.path", path );
       }
       

       // 역시 설정파일에 정의되어있는 runtime.log의 경로를 실제 경로로 바꾸어 다시 설정합니다. [runtime.log = /forumdemo_velocity.log]
       path = p.getProperty("runtime.log");

       if (path != null)
       {
           path = getServletContext().getRealPath( path );
           p.setProperty("runtime.log", path );
       }

       return p;
    }


    /**
     * 서블릿을 제어하기 위해서 VelocityServlet의 handleRequest메소드를 확장하여 사용합니다.

     * @param VelocityServlet에서 생성된 Context

     * @return template
     */

    public Template handleRequest( Context ctx )
    {
        HttpServletRequest req = (HttpServletRequest)ctx.get(VelocityServlet.REQUEST);
        HttpServletResponse resp = (HttpServletResponse)ctx.get(VelocityServlet.RESPONSE);
        Template template = null;
        String templateName = null;
       
        HttpSession sess = req.getSession();
        sess.setAttribute(ERR_MSG_TAG, "all ok" );

        try
        {
            // processRequest를 통해서 파라미터의 command(list, reply 등등)에 해당하는

            // template의 이름을 받아옵니다.
            templateName = processRequest( req, resp, ctx );
            // template이름을 이용하여 template을 가져옵니다.
            template  = getTemplate( templateName );
        }
        catch( ResourceNotFoundException rnfe )
        {
            String err = "ForumDemo -> ControllerServlet.handleRequest() : Cannot find template " + templateName ;
            sess.setAttribute( ERR_MSG_TAG, err );
            System.out.println(err );
        }
        catch( ParseErrorException pee )
        {
            String err = "ForumDemo -> ControllerServlet.handleRequest() : Syntax error in template " + templateName + ":" + pee ;
            sess.setAttribute( ERR_MSG_TAG, err );
            System.out.println(err );
        }
        catch( Exception e )
        {
            String err = "Error handling the request: " + e ;
            sess.setAttribute( ERR_MSG_TAG, err );
            System.out.println(err );
        }

        return template;
    }
   
    /**
     * command패턴을 이용하여 request에서 넘어온 command에
 해당하는 template의 이름을 반환합니다.

     * 각 command는 org.apache.velocity.demo.action의 하위의 클래스들에 구현되어 있습니다.

     * exec메소드에 각 command가 담당한 부분에 대한 처리가 들어있습니다.

     * 메세지들을 context에 담는다던지하는 것들 말이지요...
     * @param the request
     * @param the response
     * @param the context
     * @return 사용할 템플릿의 이름
     */
    private String processRequest( HttpServletRequest req, HttpServletResponse resp, Context context )
     throws Exception
    {
        Command c = null;
        String template = null;
        String name = req.getParameter("action");
       
        if ( name == null || name.length() == 0 )
        {
            throw new Exception("Unrecognized action request!");
        }
               
        if ( name.equalsIgnoreCase("list") )
        {
            c = new ListCommand( req, resp);
            template = c.exec( context );
        }
        else if ( name.equalsIgnoreCase("post") )
        {
            c = new PostCommand( req, resp );
            template = c.exec( context );
        }
        else if (  name.equalsIgnoreCase("reply") )
        {
            c = new ReplyCommand( req, resp );
            template = c.exec( context );
        }
        else if (  name.equalsIgnoreCase("postreply") )
        {
            c = new PostReplyCommand( req, resp );
            template = c.exec( context );
        }
        else if ( name.equalsIgnoreCase("view") )
        {
            c = new ViewCommand( req, resp );
            template = c.exec( context );
        }
        return template;
    }


    /**
     *  에러가 발생했을때 브라우저 상에 출력하기 위한 메소드입니다.

     *  VelocityServlet의 error메소드를 override하여 사용합니다.

     */
    protected  void error( HttpServletRequest request, HttpServletResponse response, Exception cause )
        throws ServletException, IOException
    {
        HttpSession sess = request.getSession();
        String err = (String) sess.getAttribute( ERR_MSG_TAG );

        StringBuffer html = new StringBuffer();
        html.append("<html>");
        html.append("<body bgcolor=\"#ffffff\">");
        html.append("<h2>ForumDemo : Error processing the request</h2>");
        html.append("<br><br>There was a problem in the request." );
        html.append("<br><br>The relevant error is :<br>");
        html.append( err );
        html.append("<br><br><br>");
        html.append("The error occurred at :<br><br>");

        StringWriter sw = new StringWriter();
        cause.printStackTrace( new PrintWriter( sw ) );

        html.append( sw.toString()  );
        html.append("</body>");
        html.append("</html>");
        response.getOutputStream().print( html.toString() );
    }
}

 

네이버

최초작성일 : 2005-02-23

최종수정일 : 2005-02-25


이번엔 command 클래스들과 om패키지를 조금 살펴볼까 합니다.

이전에 말했듯이 command의 구현체들은 org.apache.velocity.demo.action 패키지안에 있습니다.



command.java의 경우에는 하위 command들을 위한 abstract class(추상클래스)입니다.

우선 ListCommand를 살펴보겠습니다. 생각보단 짧죠?


public class ListCommand extends Command
{
    /** template의 이름을 정의해 둡니다. */
    public static final String LIST = "list.vm";

    // 나중엔 이 변수에 담길 template의 이름을 DB에서 가져오거나 parameter로 받으면 되겠죠?
   

    // 생성자겠지요?
    public ListCommand( HttpServletRequest req, HttpServletResponse resp )
    {
        super( req, resp );
    }
   
    /**
     * 메세지들을 가져와서 context에 담습니다. 이때 메세지들은 Vector의 형태로 묶여 있게 됩니다.
     */
    public String exec( Context ctx )
    {
        Object[] list = ForumDatabase.listAll(); // 메세지를 가져오는 부분입니다.
       
        if ( list == null || list.length == 0 )
        {
            ctx.put("hasMessages", Boolean.FALSE );   
        }
        else
        {
            ctx.put("hasMessages", Boolean.TRUE );
            ctx.put("listall", list ); // 메세지가 존재하면 해당 메세지 list를 context에 담습니다(put)
        }
       
        return LIST; // 그리고 해당하는 템플릿의 이름을 반환해 줍니다.
    }
}


간단하지 않습니까?

사실상 이녀석이 하는 일은 context에 db클래스에서 뽑아낸 정보들을 담는역할밖에 없으니까요.

이 역할자체는 나머지 command 클래스들에서도 공통적으로 나타납니다.

(당연한거겠지요-_-;;)

PostCommand.java를 한번 살펴보겠습니다.

다른곳이라곤 exec메소드 뿐입니다.(이 역시 당연한거겠죠?)


public String exec( Context ctx )
    {

        // 변수에 넘겨받은 값들을 정의합니다.
        String name = request.getParameter("name");
        String subject = request.getParameter("subject");
        String email = request.getParameter("email");
        String content = request.getParameter("content");
       

        // 메세지 객체를 만들고 앞에서 설정한 변수를 이 객체에 담습니다.
        Message message = new Message();
        message.setName( name );
        message.setSubject( subject );
        message.setEmail( email );
        message.setContents( content );
       

        // Database 클래스에 메세지객체를 저장합니다.
        ForumDatabase.postMessage( message );
       

        // 메세지를 저장한 후에 보여줄 화면을 List로 정의하고 있기 때문에

        // list를 생성하여 context에 담습니다.

        Object[] list = ForumDatabase.listAll();
       
        ctx.put("listall", list );
        ctx.put("hasMessages", Boolean.TRUE );
        // 그리고 ListCommand의 List 즉 list.vm을 반환해줌으로써 보여줄 화면을 list.vm으로 설정하게 됩니다.
        return ListCommand.LIST;
    }


ListCommand에서는 말씀드렸던것처럼 db클래스에서 데이터를 가져오는 역할을 했습니다.

PostCommand의 경우에는 메세지를 작성할 때 사용하는 클래스인데, 기본적으로

parameter로 받은 정보들을 message객체에 set하고 그것을 db클래스에 저장하는 역할을 하고 있습니다.


나머지 클래스들도 같은 방법으로 동작하고 있기 때문에 추가적인 설명은 하지 않겠습니다.

Command클래스의 이름으로 대충 파악하실수 있을꺼라 생각합니다.


org.apache.velocity.demo.om 패키지에 있는 두 클래스가 실제적으로 persistence layer를 맡고 있습니다.

Message 클래스는 설명이 필요 없는 Bean 클래스입니다.(실제 소스를 보시면 아시겠지만 set/get만을 하고 있는 클래스입니다)

한가지 특이할만한 점이라고 하면, 한 메세지에 달리는 덧글들은 해당하는 메세지가 가지고 있다는 것입니다.

이는 소스에서 살펴보실수 있듯이 Reply을 Vector형태로 가지고 있기 때문에 가능하게 되는 것입니다.

바로 이 부분이죠. private Vector replies = null;


ForumDatabase는 HashTable에 사용자가 작성한 메세지를 key/value 방식으로 담고 있습니다.

따라서 클래스가 하는 작업은 HashTable에 메세지를 넣고, 빼고, 리스트 정도가 있습니다.


ForumDatabase.java

public class ForumDatabase
{
    private static Hashtable messages = new Hashtable(); // 메세지를 저장할 HashTable
    private static int nextId = 0; // key값입니다. 0부터 시작합니다.
    private static ForumDatabase me = null;
   
    /** 생성자 */
    private ForumDatabase()
    {}
   
    /**
     * 신규 메세지 작성

     */
    public static synchronized void postMessage( Message message )
    {
        Integer nextNumber = new Integer( nextId++ ); // 기존의 key 값에 +1을 해줍니다.

        message.setId( nextNumber ); //  메세지의 key값으로 설정합니다.
        messages.put( nextNumber,  message ); // HashTable에 key와 message를 담습니다.
    }
   
    /**
     * 저장되어 있는 모든 메세지들의 리스트를 반환합니다.

     */
    public static Object[] listAll()
    {
        return messages.values().toArray();
    }
   
    /**
     * 특정한 한 메세지를 가져옵니다.

     */
    public static synchronized Message getMessage( String index )
    {

        // HashTable에서 넘겨받은 key으로 해당하는 메세지를 찾아서 반환합니다.
        return (Message)messages.get( new Integer( index ) );
    }
   
    /**
     * 메세지에 덧글을 추가합니다.
     */
    public static synchronized void postReply( Message reply, String parent )
    {
        Message thread = getMessage( parent );
        thread.addReply( reply );
    }

Posted by 1010
98..Etc/velocity2009. 2. 27. 15:52
반응형

The Apache Velocity project introduces an alternative syntax to the familiar JSP expressions and scriptlets. Resin's extension allows the use of Velocity-style syntax in JSP files. The Velocity-style syntax is transformed into JSTL standard tags.

  1. Enabling velocity-style syntax
  2. expressions
  3. scriptlets
  4. if statements
  5. foreach statements

The syntax is based on expressions like ${foo} and scriptlets with #\{...}#. Because the alternative syntax avoids the brackets which fill JSP pages, it can make pages more readable and therefore more maintainable.

Because Resin's Velocity-style syntax is transformed to the JSTL tag library, all JSTL expressions are allowed.

JSP style
<%
int count;
%>

<h3>A sample <%= count %></h3>

<% if ("foo".equals(request.getParameter("a"))) { %>
  <h3>Foo!</h3>
<% } else { %>
  <h3>Bar!</h3>
<% } %>

The same JSP file could be written in Velocity-style as follows. The jsp:directive is required because JSP pages use strict JSP syntax by default.

Velocity style
<jsp:directive.page velocity='true'/>
#{
int count;
}#

<h3>A sample ${count}</h3>

#if ("foo" == params.a)
  <h3>Foo!</h3>
#else
  <h3>Bar!</h3>
#end

The choice between the two is a matter of preferences. An advantage of the velocity style is that expressions and scriptlets avoid using brackets. In large pages, sorting out the HTML or XML from the JSP syntax can become confusing.

Enabling velocity-style syntax

Velocity-style syntax can either be enabled on a per-JSP page with velocity='true' or in the web-app with the <jsp> tag:

Enabling velocity for a page
<jsp:directive.page velocity='true'/>
  ...

Enabling velocity for a web-app
<web-app>
  <jsp velocity='true'/>
  ...
</web-app>

expressions

Expressions are enclosed between "${" and "}", for example '${count}' and '${count + 15}'.

The '${...}' syntax is equivalent to '<c:out value="..."/>'.

#{

${expression}

scriptlets

Scriptlets use the '#{ ... }#' syntax. This is entirely equivalent to '<% ... %>'. (Note, Velocity does not have this syntax because it creates its own language instead of escaping to Java.)

#{
 statements
}#

#{
String key = request.getParameter("key");
if (key.equals("")) {
  response.sendError(500, "Bad key");
  return;
}
}#
...

if statements

The velocity-style syntax directly supports if statements. The syntax is

#if (expr1)
  ...
#elseif (expr1)
  ...
#else
  ...
#end

The expressions can be any JSTL expression. The if statement is transformed into:

<c:choose>
<c:when test="${expr1}">
  ...
</c:when>
<c:when test="${expr2}">
  ...
</c:when>
<c:otherwise>
  ...
</c:otherwise>
</c:choose>

foreach statements

The velocity-style syntax directly supports iteration with a foreach statements.

#foreach (var in expr)
  ...
#end

This style of foreach is transformed into the following:

<c:forEach items="${expr}" var="var">
  ...
</c:forEach>

An example use might be the following:

foreach in Java
<jsp:page.directive velocity='true' import='java.lang.*'/>
#{
  ArrayList list = new ArrayList();
  list.add("foo");
  list.add("foobar");
  pageContext.setAttribute("list", list);
}#
#foreach (value in list)
  <li>${value}
#end

The velocity-style syntax also supports integer iteration.

An example might be the following:

foreach in Java
<jsp:page.directive velocity='true'/>
#foreach (value in [3..9])
  <li>$value
#end

Posted by 1010
98..Etc/velocity2009. 2. 27. 15:15
반응형

웹에서 처럼 Java application 에서 velocity 를 사용한다.

그러면 화면(로그) 구성 로직을 vm 에 옮기고 변화가 많지않은 부분을 java 로 코딩하여

컴파일을 해 놓으면 어떤 로직에 수정이 가해졌을 때 재 컴파일 없이 properties 처럼

Vm 파일만 수정하면 된다. 활용여하에 따라서 효과적이고 유지보수와 개발의 편리성을

제공할수 있을 것 같다.

 

필요한 jar : commons-collections-3.2.jar, commons-lang-2.3.jar, velocity-1.5.jar,

velocity-dep-1.4.jar, velocity-tools-1.3.jar, velocity-tools-generic-1.4.jar,

velocity-tools-view-1.1.jar

 

jdk : 1.4

 

java 소스 상에서 사용하기 위해선 다음과 같은 절차를 따른다.

1: Velocity.init() 메서드를 사용하여 엔진을 초기화 한다.

2: VelocityContext 객체를 생성하는데 이곳에 넘길값을 셋팅한다.

3: methodproperties 를 다루는데 사용하는 Template 객체를 생성한다.

이 객체에 velocity 파일위치를 파라미터로 넘겨주면 리턴값으로 Template 객체를넘겨준다.

그리고 이 Template 객체에 VelocityContext 를 넘겨주면된다.

 

Velocity.init();

Template template=Velocity.getTemplate("./src/velocity/conditionals/if.vm");

VelocityContext context = new VelocityContext();


Writer writer =
new StringWriter();

template.merge(context, writer);

 

System.out.println(writer);

 

소스를 컴파일 하게 되면 console vm 에 대한 로그는 나타나지 않는다.

Velocity.log  파일을 자동으로 만들어 컴파일에 대한 내용을 출력한다.


Posted by 1010
98..Etc/velocity2009. 2. 27. 15:11
반응형

1. 주석 사용
## 로 시작하면 한 줄 코멘트
#* 로 시작하고 *#로 끝나면, 여러 줄 코멘트
#** 로 시작하고 *#로 끝나면, 블록 코멘트.

2. 레퍼런스
$(variable) : 컨텍스트에서 제공되는 변수에 대한 레퍼런스
$(variable.property) : 속성에 대한 레퍼런스
$(cariable.method(arg)) : 메소드에 대한 레퍼런스

예)
$date.format("yyyy-MM-dd", $createTime)

3. 디렉티브
#set : 레퍼런스의 값 설정
#if/#elseif/#else : 조건문 제어
#foreach : 객체 리스트에 댛란 반복 제어
#include : 벨로시티로 파싱되지 않은 로컬 파일 출력
#parse : 벨로시티로 파싱된 로컬 템플릿 출력
#stop : 템플릿 엔진의 동작 정지
#macro : 반복적으로 사용될 VM(velocimacro)

예)
*. set
#set ($val = 1234567)

*. if/elseif/else
#if( $foo == $bar ) -> 등치 연산자
#if( $foo == 42 )
#if( $foo == "bar" )
#if( !$foo ) -> Boolean NOT

*. foreach
$allPages가 List나 Array인 경우
#foreach( $page in $allPages)
   $page
#end

$allPages가 Map이나 Hashtable일 경우

#foreach( $key in $allPages.keySet())
   $key -> $allPages.get($key)
#end

*. include
Velocity에 의해 파싱되지 않는 로컬 파일(들)을 렌더링
#include ("a.html")

*. parse
Velocity에 의해 파싱되는 로컬 템플릿을 렌더링
#parse ("me.vm")

*. macro
편리한 함수를 만들어서 사용 가능함
#**
 * General purpose date formatter. Need to be careful of whitespace.
 * @param dateFormat Date format to be used (see java.text.SimpleDateFormat).
 * @param date Date object to be formatted (see java.util.Date).
 *#
#macro(formatDate $dateFormat $date )
  $utils.formatDate($date, $dateFormat)
#end

4. toolbox.xml(Velocity Tool)을 활용한 사용자 정의 오브젝트의 사용
toolbox.xml에 사용자 정의 클래스를 적용하여 vtl에서 사용할 수 있다. getXX(), setXX(), isXX() 형태로 정의되었을 경우 가능

예)
*. Date Tool
org.apache.velocity.tools.generic.DateTool class를 추가함
$date.format("yyyy-MM-dd HH:mm:ss", $myDate)   -> 2008-06-03 19:11:09

*. Number Tool
org.apache.velocity.tools.generic.NumberTool class를 추가함
$number.format("currency", $val)   -> ₩1,234,567
$number.format("integer", $val)    -> 1,234,567

*. Escape Tool
org.apache.velocity.tools.generic.EscapeTool를 추가함
$javascript                  -> I'm Mimul
$esc.javascript($javascript) -> I\'m Mimul

Posted by 1010
98..Etc/velocity2009. 2. 27. 15:10
반응형

Velocity UI for Eclipse

This project leverages the Eclipse platform (v2.x) by adding support for the template/scripting engine Velocity. It provides the following plugins:
org.apache.velocity
Velocity binaries (currently v1.3.1-final) packaged as an Eclipse plugin
org.vaulttec.velocity.ui
Velocity-aware text editor (associated to files with extensions '*.vsl' or '*.vm') with outline view

Editor Features

  • Syntax-highlight for Velocity Template Language (VTL)
  • Outline view with hierarchy of VTL directives and Velocimacro references
  • Content assist for VTL directives (Screenshot) and references (Screenshot) -> auto-activation after the character '#' or '$' or manually via keyboard shortcut Ctrl+Space
  • Automatic template validation while typing (the first syntax error is show in task list and the according line is marked in annotation column) -> Screenshot
  • Annotation hover with definition of references (Screenshot) and template syntax errors (Screenshot)
  • Go to definition of variable or Velocimacro reference under current cursor position (via context menu or keyboard shortcut F3)
  • Comment and uncomment blocks (via Ctrl+/ and Ctrl+\)
  • Preference pages for definition of Velocity counter name and user-defined Velocity directives (Screenshot)
  • Preference pages for color settings of the editor's syntax highlighting (Screenshot)
  • Preference pages for Velocimacro library (Screenshot)

Installation

Via Eclipse Update Manager

Online updates are available on http://veloedit.sourceforge.net/updates/. Define a site bookmark in Eclipse's Update Manager view (Screenshot), navigate to the update site via this bookmark (Screenshot) and install the Velocity UI feature. This update site can also be downloaded from SourceForge and used locally.

Manually

Download the archives org.apache.velocity_x.x.x.zip and org.vaulttec.velocity.ui_x.x.x.zip from here and unzip them in your Eclipse plugin directory "<eclipse install path>/plugins/".
SourceForge Logo
Posted by 1010
98..Etc/velocity2009. 2. 27. 14:40
반응형
VTL (Velocity Template Language)에 대해서는 여지껏 접해본바 없는 상황인지라 문법 익히기에도 급급하다.
대충 문법 정의 문서를 살펴보니 그리 어려운 언어는 아니라는 결론을 얻었다.

HTML 사용 하는거야 그냥 똑같이 쓰면 되고, 그 안에 스크립트를 끼워 넣는 것인데...
좀 더 쓰다 보면 익숙해지겠지... :-)

자.. 이제 익숙해지는 단계 이전까지는 뭔가 도움이 될만한 것들을 찾아봐야 하는데, 역시나 이클립스를 무시할 수가 없다. Velocity 코드 작성을 위한 Plug-In이 분명 존재할 것이란걸 믿고 찾아봤더니...
세상에나... 정말로 있다!!

Eclipse 사이트의 Plug-In Central 화면 캡춰



이제 설치를 해보자.

Velocity WebEditor - Eclipse Plugin : 아래 다운로드 클릭
상단에 링크된 파일을 다운받아서 압축을 해제하면 plugin 디렉토리가 생성되고 그 안에 실제로 설치에 필요한 디렉토리 및 파일들이 존재한다.


com.hudson.velocityweb_1.0.8 디렉토리를 Eclipse 설치 디렉토리 아래 plugins 디렉토리 하위에 복사.

Eclipse가 실행 중이었다면 재실행 해야 반영된다.


VM 파일을 수정하는 화면이다. 가장 도움이 되는 기능이 Syntex Coloring 과 Code Assist 기능이 지원된다는 것.
이제 눈을 부릅뜨고 코딩하는 일만 남았다.

조금이라도 빨리 퇴근하길 바라는 마음에서... ㅠ_ㅠ
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
    98..Etc/velocity2009. 1. 23. 15:06
    반응형

    <%
    int count;
    %>

    <h3>A sample <%= count %></h3>

    <% if ("foo".equals(request.getParameter("a"))) { %>
      <h3>Foo!</h3>
    <% } else { %>
      <h3>Bar!</h3>
    <% } %>

    접기

    velocity의 경우 :

    접기

    <jsp:directive.page velocity='true'/>
    #{
    int count;
    }#

    <h3>A sample ${count}</h3>

    #if ("foo" == params.a)
      <h3>Foo!</h3>
    #else
      <h3>Bar!</h3>
    #end

    Posted by 1010
    98..Etc/velocity2009. 1. 23. 15:05
    반응형

    Spring과 함께 사용

    전형적인 디렉토리 구조

    그림:VelocityDirectoryStructure.png

    • velocity와 velocity tool을 사용하기 위해 필요한 jar 파일을 lib에 넣어야 한다.
      • velocity-dep-*.jar : velocity 그리고 관련된 클래스 파일
      • velocity-tools-*.jar : velocity tool
      • commons-digester
      • commons-collections
      • commons-beanutils
    • /WEB-INF/velocity 를 velocity template 루트로 잡는다.
    • /WEB-INF/velocity/VM_global_library.vm 가 디폴트 매크로 파일이 된다.
    • /WEB-INF/toolbox.xml 은 velocity tool의 설정이다.
    • 각 설정파일의 위치를 변경하려면 *-servlet.xml에서 한다.

    *-servlet.xml

    • -servlet.xml 에 velocity 관련 설정을 넣어 사용할 수 있다.

    SpringMVC를 참고할 것.

    velocity properties

    velocity 관련 설정은 별도의 velocity.properties를 만들어 할 수도 있지만, *-servlet.xml에서 직접 할 수도 있다. 'velocityConfig' 부분의 'velocityProperties' 부분에 property를 추가하면 된다. velocity property의 전체 항목은 velocity jar 파일의 /org/apache/velocity/runtime/default/velocity.properties 에서 확인할 수 있다.

    VM_global_library.vm

    예를들어 다음과 같이 만들 수 있다.

    #macro (xhtml)
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE html 
       PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    #end
    

    VTL (Velocity Template Language) 문법

    간단한 예제

    <html>
    <body>
    #set ($foo = "Velocity")
    Hello $foo World!
    </body>
    <html>
    

    코멘트

    ## 로 시작하면 한 줄 코멘트

    ## 한 줄 코멘트 single-line comment
    

    #* 로 시작하고 *#로 끝나면, 여러 줄 코멘트

    #*
     여러 줄 코멘트. 
     여기에 표시되는 내용은 
     Velocity Template Engine이 무시해버린다.
    *#
    

    #** 로 시작하고 *#로 끝나면, 블록 코멘트. 사실 여러 줄 코멘트와 다를 것은 별로 없다. 저자나 버전 등을 넣는데 주로 사용한다.

    #**
     This is a VTL comment block and
     may be used to store such information
     as the document author and versioning
     information:
     @author
     @version 5
    *#
    

    변수 Variable

    변수는 $로 시작하며, [a-zA-Z0-9-_] 문자가 변수에 사용될 수 있다.

    #set로 변수에 값을 세팅할 수 있다.

    #set ($foo = "bar")
    

    원래는 ${foo} 형태가 정식적인(formal) 표현이다. 텍스트 중간에 변수가 들어갈 때 잘못 파싱되는 것을 방지하기 위해, 반드시 이 형태를 사용해야 할 경우가 있다.

    Jack is a $vicemaniac.
    Jack is a ${vice}maniac.
    

    프라퍼티 Property

    변수 안의 프라퍼티에 접근할 수 있다.

    $customer.address
    $purchase.total
    

    Java Beans 표준의 property 규칙이 그대로 사용된다. (getX(), setX() 등)

    메소드 Method

    변수로부터 메소드를 곧바로 실행할 수도 있다.

    $customer.getAddress()
    $date.format("yyyy-MM-dd", $createTime)
    

    조용한 레퍼런스 Quiet Reference

    만약 $foo 라고 썼는데 foo 라는 이름의 객체가 존재하지 않는다면, $foo 라는 글자가 결과에 그대로 표현된다. 객체가 존재하지 않을 때 아무것도 표현되지 않게 하려면, $ 다음에 !를 붙인다.

    <input type="text" name="email" value="$email"/>
    <input type="text" name="email" value="$!email"/>
    

    물론 정식적인 표현도 가능하다.

    <input type="text" name="email" value="$!{email}"/>
    

    escaping

    '$' 를 표현하려면 \$ 로 한다. '\$' 는 '\\$' 로 표시한다.

    혹은 다음과 같이 할 수 있다.

    #set ($dollar = "$")
    $dollar
    

    지시자 Directive

    지시자는 #로 시작한다. ${..}와 같은 이유로, #{..} 표현도 가능하다.

    #if($a==1)true enough#elseno way!#end
    #if($a==1)true enough#{else}no way!#end
    

    #set

    변수에 값을 지정하기 위해 사용한다.

    #set ($primate = "monkey") ## literal
    #set ($monkey = $bill) ## variable reference
    #set ($monkey.Friend = "monica") ## string literal
    #set ($monkey.Blame = $whitehouse.Leak) ## property reference
    #set ($monkey.Plan = $spindoctor.weave($web)) ## method reference
    #set ($monkey.Number = 123) ## number literal
    #set ($monkey.Say = ["Not", $my, "fault"]) ## ArrayList
    #set ($monkey.Map = {"banana" : "good", "roast beef" : "bad"}) ## Map
    
    #set ($value = $foo + 1)
    #set ($value = $bar - 1)
    #set ($value = $foo * $bar)
    #set ($value = $foo / $bar)
    

    같은 변수에 다른 값을 넣으면, 마지막 넣은 값이 저장된다.

    값을 unset 하는 기능은 없다.

    Literal

    set 할때 문자열은 큰따옴표(") 로 감싸진다. 이 안에 변수가 있으면, 그것도 해석(parse)된다.

    #set( $directoryRoot = "www" )
    #set( $templateName = "index.vm" )
    #set( $template = "$directoryRoot/$templateName" )
    $template
    

    결과값은

    www/index.vm
    

    하지만 작은따옴표(')로 감싸면 해석되지 않는다.

    #set( $foo = "bar" )
    $foo
    #set( $blargh = '$foo' )
    $blargh
    

    결과는

    bar
    $foo
    

    조건문 if-else

    #if ($foo < 10)
       Go North
    #elseif ($foo == 10)
       Go East
    #elseif ($bar == 6)
       Go South
    #else
       Go West
    #end
    

    == 연산은 primitive, string, object를 비교하는데, object의 경우 toString()의 값이 비교된다.

    AND 연산 : &&

    #if ($foo && $bar)
       This AND that
    #end
    

    OR 연산 : ||

    #if ($foo || $bar)
       This OR That
    #end
    

    NOT 연산 : !

    #if (!$foo)
      NOT that
    #end
    

    $!foo 와 !$foo 를 혼동하지 말 것!

    반복문 Loops

    $allProducts가 List나 Array인 경우에는 이렇게 한다.

    #foreach( $product in $allProducts )
       $product
    #end
    

    $allProducts가 Map이나 Hashtable이라면, 이렇게 할 수 있다.

    #foreach( $key in $allProducts.keySet() )
       Key: $key -> Value: $allProducts.get($key)
    #end
    

    현재 루프 카운트는 $velocityCount로 알아올 수 있다.

    #foreach( $customer in $customerList )
       $velocityCount : $customer.Name
    #end
    

    $velocityCount 이름과 0부터 시작하는지 1부터 시작하는지 등은 설정 가능하다.

    include

    #include ("one.txt")
    #include ("one.gif","two.txt","three.htm")
    #include ("greetings.txt", $seasonalstock)
    

    파일의 내용을 그대로 include한다. 여러 파일을 한꺼번에 include할 수 있다. 파일 이름에 변수가 들어갈 수 있다.

    parse

    #parse ("me.vm")
    

    파일을 파싱해서 그 결과를 include한다. 한번에 하나의 파일만 가능하다.

    Count down.
    #set ($count = 8)
    #parse ("parsefoo.vm")
    All done with dofoo.vm!
    
    #set ($count = $count - 1)
    #if ($count > 0)
       #parse ("parsefoo.vm")
    #else
       All done with parsefoo.vm!
    #end
    

    재귀적으로 사용 가능한데, 깊이가 정해져있다. 깊이는 설정 가능하고, 디폴트로 10이다.

    stop

    #stop
    

    파싱을 멈춘다.

    매크로

    일종의 함수 같은 것이다.

    다음과 같이 정의하고,

    #macro (d)
       <tr><td></td></tr>
    #end
    

    다음과 같이 사용한다.

    #d()
    

    파라미터를 매크로 이름 뒤에 변수로 받을 수 있다.

    #macro (callme $a)
       $a $a $a
    #end
    

    이렇게 사용한다.

    #callme ($foo.bar())
    

    Velocity Tool

    Cookie Tool

    $cookie.foo.value
    $cookie.add("cookieName", "cookieValue")
    

    Import Tool

    $import.read("http://www.rolizen.com/import/url")
    

    Parameter Tool

    $params.foo
    $params.getString("foo")
    $params.getNumber("foo")
    $params.getInt("foo")
    

    Alternator Tool

    예를들어, 루프를 돌면서 table의 tr을 찍는데, 홀수줄은 흰색으로, 짝수줄은 회색으로 찍고 싶은 경우,

    #set ($color = $alternator.auto(["fff", "eee"))
    #foreach ($item in $listItems)
    <tr style="background-color:#$color">...</tr>
    #end
    

    Date Tool

    $date                                          -> 2007. 2. 5 오후 3:14:43 
    $date.get("yyyy-MM-dd HH:mm:ss")               -> 2007-02-05 15:14:43
    $date.format("yyyy-MM-dd HH:mm:ss", $myDate)   -> 2007-02-03 16:31:34
    

    Number Tool

    #set ($val = 1234567)
    $number.format("currency", $val)   -> ₩1,234,567
    $number.format("integer", $val)    -> 1,234,567
    $number.format("0,000", $val)      -> 1,234,567
    $number.format("0,0000", $val)     -> 123,4567
    $number.format("0", $val)          -> 1234567
    

    Escape Tool

    $html                        -> "bread" & "butter"
    $esc.html($html)             -> "bread" & "butter"
    
    $xml                         -> "bread" & "butter"
    $esc.xml($xml)               -> "bread" & "butter"
    
    $javascript                  -> He didn't say, "Stop!"
    $esc.javascript($javascript) -> He didn\'t say, \"Stop!\"
    
    $esc.dollar                  -> $
    $esc.d                       -> $
    
    $esc.hash                    -> #
    $esc.h                       -> #
    
    $esc.backslash               -> \
    $esc.b                       -> \
    
    $esc.quote                   -> "
    $esc.q                       -> "
    
    $esc.singleQuote             -> '
    $esc.s                       -> '
    
    $esc.exclamation             -> !
    $esc.e                       -> !
    

    Iterator Tool

    List Tool

    List나 Array에서 엘리먼트를 get / set 할 수 있다.

    $primes                    -> new int[] {2, 3, 5, 7}
    $list.size($primes)        -> 4
    $list.get($primes, 2)      -> 5
    $list.set($primes, 2, 1)   -> (primes[2] becomes 1)
    $list.get($primes, 2)      -> 1
    $list.isEmpty($primes)     -> false
    $list.contains($primes, 7) -> true
    

    Math Tool

    Sorter Tool

    Velocity Tool 만드는 법

    일반적인 Tool

    그냥 일반적인 class를 만들면 된다. public한 field와 method를 사용할 수 있다.

    context 를 갖는 Tool

    public class MemberUtil {
       private HttpServletRequest request;
       private HttpSession session;
       private MemInfoData meminfo;
    
       public void init(Object obj) {
          ChainedContext cc = (ChainedContext)obj;
          this.request = cc.getRequest();
          this.session = request.getSession(true);
          meminfo = (MemInfoData)session.getAttribute(MemInfoData.MEMINFO_SESSION_KEY);
          if (!validMemInfo(meminfo))
             meminfo = null;
       }
    
       private boolean validMemInfo(MemInfoData mid) {
          return (mid != null) && (mid.getMemNo() > 0) && (mid.getOpenid() != null);
       }
    
       public HttpServletRequest getRequest() {
          return request;
       }
    
       public HttpSession getSession() {
          return session;
       }
    
       public MemInfoData getMeminfo() {
          return meminfo;
       }
    
       public boolean isLogin() {
          return (meminfo != null);
       }
    }
    

    위와 같이 init() 메소드를 이용해 context를 받을 수 있다.

    참고사이트  : http://velocity.apache.org

    출처 :http://technet.ui2.co.kr/wiki/index.php/Velocity

    Posted by 1010
    98..Etc/velocity2009. 1. 23. 15:04
    반응형

    Velocity 무엇인가?

    Velocity 자바 기반의 템플릿 엔진이다.

    Velocity 페이지 디자이너들이 자바 코드안에서 정의된 메소들에 접근하는 것을 도와준다. 이것은 페이지 디자이너들이 자바 개발자들과 함께 Model-View-Controller(MVC) 아키텍쳐에 따른 사이트를 각자의 영역에서 최선의 결과를 가져오도록 도와준다는 것을 의미한다.

    Velocity 페이지로부터 자바 코드를 분리할 있고, 웹사이트를 계속 오랫동안 유지할 있으며, 자바 서버 페이지(JSP) 실용적인 대안을 제공한다.

    Velocity 무엇을 있나?

    당신이 진흙(Mud) 판매하는 "온라인 진흙 가게" 페이지 디자이너 이라고 가정해보자. 그리고 고객들은 다양한 종류와 많은 수량의 진흙을 주문하여 당신의 가게는 날로 번성하고 있다.

    고객들은 사용자 이름과 패스워드를 입력하고 당신의 사이트에 로그인하여 자신이 이전에 주문했던 주문목록을 조회하고, 다른 진흙을 수도 있다. 모든 고객에 관한 정보는 당신의 데이타 베이스안에 저장되고 있다.

    데이타 베이스에 따르면 특별히 설악산에서 만든 진흙이 매우 인기가 좋으며, '설악산 진흙'보다 인기가 일본산 빨간 진흙도 정기적으로 일본에서 수입하고 있다.

    그러던 어느날 당신은 '설악산 진흙' 흥미를 느끼는 수많은 고객들과의 특별한 거래를 찾는데 Velocity 사용하지 않는 지에 대한 의문을 갖게된다.

    Velocity 웹페이지를 통한 당신의 온라인 방문객들에게 진흙 판매를 쉽게 해준다. 진흙 가게의 웹사이트 디자이너인 당신은 고객이 사이트 로그인 후에 보게 특별한 페이지를 원하고 있다.

    명심하라. 당신은 개발자들이 데이터베이스에서 필요한 정보를 어떻게 추출하는지에 대해 걱정할 필요가 없다. 당신은 단지 그것이 올바르게 작동한다는 것만 기억하면 된다. 그렇게 되면 당신은 당신만의 페이지 디자인을 하게 되고, 개발자들은 그들만의 일을 하게 된다.

    이런 결과로, 당신은 로그인한 사용자에게 나타낼 동적인 정보를 아래와 같이 velocity Template Language(VTL) 문장을 사용해 웹페이지에 넣을 있게 된다.

     
    Hello, $customer.Name! <br>
    $flogger.getPromotion( $mud )

    $customer 현재 로그인한 사용자에 대한 정보를 가지고 있고, $promotion 로그인한 고객별로 데이타 베이스를 조회에 해당 고객에 맞는 추천 상품을 소개하는 일을 한다.

    그래서 '설악산 진흙' 오랫동안 구입해온 기록을 가진 고객이 로그인 했을 '설악산 진흙 현재 대폭 세일중!!' 이라는 메시지를 정면에서 보게 것이다.

    Velocity 힘과 유연함은 이렇게 VTL 레퍼런스와 함께 당신에게 제공된다.

    VTL (Velocity Template Language)

    VTL Velocity에서 템플릿 개발에 사용되는 언어로 레퍼런스(Reference), 디렉티브(Directive), 그리고 주석(Comment)으로 구성된다.

    레퍼런스

    ${variable}

    컨텍스트에서 제공되는 변수에 대한 레퍼런스

    ${variable.property}

    속성에 대한 레퍼런스

    ${variable.method(args)}

    메소드 대한 레퍼런스

    디렉티브

    #set

    레퍼런스의 값을 설정

    #if #elseif #else

    조건문 제어

    #foreach

    반복문 제어

    #include

    파싱되지 않는 로컬 파일 출력

    #parse

    파싱되는 로컬 템플릿 출력

    #stop

    템플릿 엔진의 동작 정지

    #macro

    반복적으로 사용될 매크로 정의

    주석

    ##

    줄짜리 주석

    #* .... *#

    여러 줄에 걸친 주석

    VTL 표에서 정리한 것처럼 너무나 단순하기 때문에 흔히 성냥갑 표지에 적을 있을 만큼 작은 API라고 불려진다.

    이는 작업을 개발자와 디자이너가 함께 진행해 나간다는 점을 감안하면 매우 바람직한 일이라고 있다.

    VTL 통해 작성된 벨로시티 템플릿(vm 파일) 다음과 같은 패턴을 통해 처리 된다.

    // 벨로시티 템플릿 엔진의 초기화
    //
    초기화 설정은 velocity.properties 파일을 사용함
    Velocity.init("velocity.properties");

    //
    자바 클래스와 템플릿간의 정보 전달에 사용할 컨텍스트 객체 생성
    //
    컨텍스트 객체는 해시 테이블을 상속받으므로 (, ) 순서쌍 형태로 값을 저장 
    //
    ) context.put("members", memberDAO.getMembers());
    //
    이렇게 해서 컨텍스트에 저장된 값들은 템플릿에서 레퍼런스를 이용해서 참조됨
    //
    컨텍스트에 담긴 값이 컬렉션일 경우 #foreach 디렉티브를 통해 하나씩 참조 가능 
    VelocityContext context = new VelocityContext();
    Template template = null;

    //
    로직과 연결되어 사용될 템플릿 파일을 선택
    template = Velocity.getTemplate("HelloWorld.vm");
    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));

    //
    템플릿과 컨텍스트를 렌더링해서  결과를 출력 
    if ( template != null)
      template.merge(context, writer);

    writer.flush();
    writer.close();

    템플릿 엔진이 동작하는 방식을 정리해 보면, 개발자는 사용자에게 보여 디자인을 위해 VTL 이용한 템플릿 파일을 작성하고, 처리를 위한 코드를 개발한다.

    자바 코드와 템플릿 간의 필요한 정보 전달은 컨텍스트 객체를 통해 이루어진다.

    이러한 2개의 파일을 입력받아 벨로시티는 템플릿을 토대로 렌더링한 결과 페이지를 출력하게 되는 것이다.

    템플릿에 어떤 내용이 담겨 있느냐에 따라 결과 페이지는 일반 텍스트가 수도 있고, HTML이나 SQL, PostScript, XML 등도 있다.

     

     

    Velocticy 템플릿 언어 (VTL)

    Velocticy 템플릿 언어(velocity Template Language : VTL) 페이지에서 동적인 내용을 구체화하기 가장 쉽고, 가장 간결하고 가장 확실한 방법을 제공하는 수단이다.

    심지어 프로그래밍 해본 경험이 적거나 전혀 없는 페이지 개발자도 웹사이트에서 동적인 내용를 구체화 하는데 VTL 금방 사용할 있다.

    VTL 웹사이트에서 동적인 내용을 끼워넣는데 필요한 레퍼런스를 사용한다. 레퍼런스의 타입은 variable이다.

    Variables 자바 코드에서 정의된 것에 대해 언급할 있는 레퍼런스의 타입 이거나, 또는 웹페이지 자체의 VTL 에서 지원하는 타입일 있다.

    아래는 HTML 문서안에 삽입될 있는 VTL문의 예제다.

     
    #set ( $a = "velocity" ) 

    VTL문은 모든 VTL문처럼 #기호로 시작하고 set 명령어를 포함하고 있다. 온라인 고객이 당신의 페이지를 요청할 , Velocticy 템플릿 엔진은 당신의 페이지에 명시된 모든 #기호를 검색한다. VTL 시작할 #기호와 VTL에서 아무일도 않는 #기호들을 분리한다.

    예제에 표시된 set 명령어는 둥근괄호 안에서 사용하며 특정 변수에 값를 부여하는 일을 한다. 변수는 좌변에, 변수의 값는 우변에 나열되며 좌변과 우변은 = 기호로 구분되어 진다.

    위의 예에서, 변수는 '$a'이고 변수에 할당된 값은 'Velocity'이다. 변수는 다른 모든 레퍼런스들처럼 $기호로 시작한다. 값은 항상 인용부호 사이에 존재한다.

    Velocticy 문자열(String) 타입만 변수에 할당할 있기 때문에 다른 데이타 타입들과의 혼란은 없다.

    정리해보면 아래와 같다.

    *      레퍼런스 $ 시작하고 어떤 것을 얻는데 사용된다.

    *      명령어 # 시작하고 어떤 동작을 수행하는데 사용된다.

    예제에서 #set 변수에게 값을 할당하는데 사용되고 $a 변수는 템플릿에서 "velocity" 출력하는데 사용되었다.

    안녕 velocity

    변수에 값을 할당했으면, 당신의 HTML 문서내 어디서나 변수를 레퍼런스할 있다. 다음의 예에서 $foo 값이 할당되고 레퍼런스 되는 모습을 있다.

     
    #set ($ foo = "velocity" )
    Hello #foo World!

    문장은 결국 웹페이지에 "Hello Velocity World!" 출력할 것이다.

    VTL 명령어들을 포함한 문장들을 좀더 읽기 쉽게 만들기 위해, 굳이 그럴 필요는 없지만 가급적 VTL문장을 새로운 줄에서 시작하도록 권장한다.

    set 명령어는 나중에 매우 세부적으로 다시 살펴보게 것이다.

    주석 처리

    주석은 velocity 템플릿 엔진에 의해 해석되지 않는 설명문이다. 주석은 당신의 오래된 기억을 상기시키거나, 당신의 VTL문이 무엇을 하고 있는지, 또는 당신이 찾는 다른 다른 목적들을 설명하기에 유용한 방법이다.

    아래에 VTL 주석의 예가 있다.

     
    ##This is a single line Comment.

    한줄 주석문은 ## 시작하고 라인의 끝에서 끝난다. 당신이 여러 줄의 주석을 사용한다면, 다수의 한줄 주석을 여러 줄에 필요는 없다.

    문장이 #* 시작하고 *# 끝나는 Multi-line 주석이 이런 상황에 매우 유용하다.

     
    #*
    Thus begins a multi-line comment. Online visitors won't
    see this text because the velocity Templating Engine will
    ignore it.
    *#

    아래 나오는 번째 타입의 주석은 문서의 저자와 버전정보와 같은 메타정보를 저장하는데 사용될 있다.

     
    #**
    This is a VTL comment block and
    may be used to store such information
    as the document author and versioning
    information:
    @author
    @version 5
    *#

    참조 (References)

    VTL 에서 지원하는 세가지 타입의 레퍼런스가 있다.

    *      변수

    *      속성

    *      메소드

    개발자들은 디자이너가 VTL 이용하는 템플릿에서 개발자가 설정한 레퍼런스를 정확히 사용하기 위해 레퍼런스의 특별한 이름을 지어주어야 한다.

    레퍼런스로 오고 가는 모든 것은 문자열(String) 객체로 처리된다. 만약 $foo(Integer 타입이라 가정한다) 표현하는 객체가 있다면 Velocity 문자열 객체를 얻기위한 매소드로 .toString() 요청 것이다.

    변수 (Variables)

    변수의 표기법은 VTL 식별자로부터 불려온 '$'기호로 시작된다. VTL 식별자는 알파벳 (a...z, or A...Z)으로 시작해야 하며 나머지는 아래의 문자들로 제한된다.

    *      alphabetic (a .. z, A .. Z)

    *      numeric (0 .. 9)

    *      hyphen ("-")

    *      underscore ("_")

    여기 VTL안에서 유효한 변수 레퍼런스의 예가 나온다.

     
    $foo
    $mudSlinger
    $mud-slinger
    $mud_slinger
    $mudSlinger1

    VTL 변수가 $foo로써 레퍼런스 , 변수는 템플릿안의 set 명령어나 자바 코드로부터 값을 얻을 있다.

    예를 들어 자바 변수 $foo "value bar"라는 값을 가지고 있다면, "value bar" 웹페이지내에 정의된 모든 $foo 대체 하게 된다.

    만약 다음 문장이 웹페이지 내에 정의된다면....

     
    #set ( $foo = "bar" )

    결과는 명령어 하위에 나오는 모든 $foo "bar" 대체할 것이다.

    속성 (properties)

    VTL 레퍼런스의 두번째 특징은 속성이다.

    속성은 특유의 포맷을 가진다. 표기법은 기호(".") 다른 VTL 식별자가 뒤에 따르는 '$' 기호로 구성된다. 아래는 VTL안의 유효한 속성 레퍼런스의 예이다.

     
    $customer.Address
    $purchase.Total

    예제에서 $customer.Address 두가지 의미을 가질 있다.

    *      customer 객체의 멤버 변수 Address 레퍼런스 한다.

    *      customer 객체의 메소드 getAddress() 레퍼런스 한다.

    , $customer.getAddress() $customer.Address 생략해서 사용할 있다. 페이지가 요청될 , Velocity 이들 가능성을 이치에 맞는지 분별하여 적당한 값은 반환하게 된다.

    메소드 (Method)

    메소드는 자바코드 안에서 정의되며, 계산을 하거나 어떤 값을 얻는 것과 같이 유용한 무언가를 수행한다. 아래는 유효한 메소드 레퍼런스의 예이다.

     
    $customer.getAddress()
    $purchase.getTotal()
    $page.setTitle( "My Home page" )
    $person.setAttributes( ["Strange", "Weird", "Excited"] )

    예제에서 나온 $customer.getAddress() $purchase.getTotal() 앞선 예제에서 나온 $customer.Address $purchase.Total 레퍼런스의 결과와 정확히 일치한다.

    그러나 $page.setTitle( "My Home page" ) 같이 메소드에서는 인자를 넘길 있다는 점이 속성과 다르다. 참고로 $person.setAttributes( "Strange", "Weird", "Excited"? ) 인자로 문자열 배열을 넘기고 있다.

    형식적인 레퍼런스 표기법 (Formal Reference Notation)

    앞서 나온 것은 레퍼런스에 대한 속기 표기법이었다. 이제 형식적 표기법에 대해 살펴보자.

     
    ${mudSlinger}
    ${customer.Address}
    ${purchase.getTotal()}

    거의 모든 경우에 당신은 레퍼런스를 위하여 앞서 나온 속기 표기법을 사용할 것이지만, 어떤 경우에는 형식적 표기법이 정확한 프로세스를 위하여 필요할 수도 있다.

    만약 당신이 $vice라는 변수를 사용하는데 변수 바로 뒤에 "fly"라는 문장이 뒤따른다고 생각해보자. 속기 표기법을 사용할 경우의 다음 예제를 살펴보면....

     
    Jack is a $vicefly

    예제에 나온 $vicefly라는 변수는 우리가 희망한 변수가 아니다. 결과로 Velocity $vice 아닌 $vicefly 변수로 가정해서 처리하게 된다. 결국 화면에는 우리가 예상하지 못한 $vicefly 그대로 표시될 것이다.

    아래 형식적 표기법을 통해 문제를 해결할 있다.

     
    Jack is a ${vice}fly

    이제 Velocity $vicefly 아닌 $vice 변수라는 것을 알게 된다. 기억하자. 형식적 표기법은 레퍼런스들이 템플릿 안에서 텍스트에 직접 붙어 있을 유용하게 사용된다.

    숨겨진 레퍼런스 표기법 (Quiet Reference Notation)

    Velocity 사전에 정의되지 않은 변수를 만나게 되면, 변수값을 그대로 화면에 출력하게 된다.

    다음의 예제를 살펴보자.

     
    <input type="text" name="email" value="$email" />

    위에 나온 $email 사전에 정의되지 않았을 경우 화면에 나오는 텍스트필드의 초기값에는 $email이라는 값이 그대로 표시될 것이다. 이것은 우리가 원하는 결과가 아니다.

    이제 다음처럼 예제를 바꿔보자.

     
    <input type="text" name="email" value="$!email"/>

    이제 화면에는 텍스트필드의 값이 공백이 출력될 것이다. 형식적 표기법을 사용한 다음 예제도 같은 결과를 가져온다.

     
    <input type="text" name="email" value="$!{email}"/>

    값이 설정되지 않은 변수를 화면에 출력하지 않을 경우 숨겨진 레퍼런스 표기법은 아주 유용하다.

    Dollar($)표시의 경우는 어떻게 하는가?

    만약 당신이 페이지 내에서 "나는 농부의 가게에서 $2.50 주고 4파운드의 감자를 샀습니다.!" 라는 문자열을 표시해야 한다고 가정하자.

    VTL에서는 앞서 보았듯이 $ # 같은 특별한 캐릭터들을 사용하고 있어서 언뜻 보면 문자열이 제대로 표시가 안될 수도 있을 같다.

    그러나 VTL 식별자는 항상 대문자나 소문자의 영문자로 시작하기 때문에 문장은 아무런 문제가 없다.

    escape 캐릭터의 사용

    만약 당신이 화면에 $email 출력해야 한다고 가정하자. 그러나 이미 $email 값이 설정된 상태라고 하자. 그러면 화면에는 당신이 원하지 않는 $email 대한 설정값이 화면에 표시될 것이다.

    아래 예제가 있다.

     
    #set ( $email = "foo" )
    $email

    경우 화면에는 foo라는 문자열이 출력되어 당신이 원하는 $email이라는 문자는 출력할 없게 된다.

    이경우 다음과 같이 escape 캐릭터를 사용하면 된다.

     
    #set( $email = "foo" )
    $email
    \$email
     
    \\$email
    \\\$email

    결과는 아래와 같이 나올 것이다.

     
    foo
    $email
     
    \foo
    \$email

    만약 $email 사전에 정의되지 않았다고 가정해보면 어떻게 될까? 결과는 아래와 같을 것이다.

     
    $email
    \$email
    \\$email
    \\\$email

     

     

    Velocity 문법(지시어)

    앞서 배운 레퍼런스(변수) 디자이너들이 페이지에 동적인 내용을 생성할 있도록 도와준다.
    반면에 이번에 살펴볼 디렉티브(명령어) 디자이너들이 실제적으로 웹사이트의 뷰와 컨텐츠를 관리하도록 도와준다.

    #set

    명령어 #set 레퍼런스의 값을 설정할 사용된다. 값은 변수 레퍼런스나 속성 레퍼런스 모두에 할당될 있고, 이것은 아래에 보이는 것처럼 괄호 안에서 명명된다.

    #set( $primate = "monkey" )
    #set( $customer.Behavior = $primate )

    괄호안의 좌측에 위치하는 변수(이하 LHS 표기, 우측 변수는 RHS 표기) 아래에 나오는 레퍼런스 또는 속성 타입이어야 한다.

    *       Variable reference

    *       String literal

    *       Property reference

    *       Method reference

    *       Number literal

    *       ArrayList

    아래는 위의 타입들에 예제이다.

    #set( $monkey = $bill ) ## variable reference
    #set( $monkey.Friend = "monica" ) ## string literal
    #set( $monkey.Blame = $whitehouse.Leak ) ## property reference
     
    #set( $monkey.Plan = $spindoctor.weave($web) ) ## method reference
    #set( $monkey.Number = 123 ) ## number literal
    #set( $monkey.Say = ["Not", $my, "fault"] ) ## ArrayList

    마지막 줄에서 대괄호로 표시된 element ArrayList class 요소를 정의한다. 그래서 예를 들면, 당신은 $monkey.Say.get(0) 이용해서 첫번째 배열요소(여기서는 "Not") 접근할 있다.

    또한 간단한 수학적 표현도 가능하다.

    #set( $value = $foo + 1 )
    #set( $value = $bar - 1 )
    #set( $value = $foo * $bar )
    #set( $value = $foo / $bar )

    null 체크

    만약 RHS 속성 또는 값이 null 메소드 레퍼런스 라면, LHS 할당되지 않을 것이다. 문맥에서 현재의 레퍼런스를 매커니즘으로 제거하는 것은 불가능하다. 이런 점은 Velocity 초보자들이 흔히 혼동 하는 실수다.

    예를 들면....

    #set( $result = $query.criteria("name") )
    The result of the first query is $result
     
    #set( $result = $query.criteria("address") )
    The result of the second query is $result

    위에서 만약 $query.criteria("name") 문자열 "bill" return되고, $query.criteria("address") null return되면, VTL 결과는 아래와 같이 출력될 것이다.

    The result of the first query is bill
     
    The result of the second query is bill

    이것은 property 또는 매소드 레퍼런스를 거쳐 #set 레퍼런스를 시도한 ,

    1.    foreach 반복문을 만드는 초보자들을 혼동케하는 경향이 있다.

    이때는 아래와 같이 null 의심가는 레퍼런스를 #if 명령어를 가지고 시험한다.

    #set( $criteria = ["name", "address"] )
     
    #foreach( $criterion in $criteria )
     
        #set( $result = $query.criteria($criterion) )
     
        #if( $result )
            Query was successful
        #end
     
    #end

    위의 예에서, query 성공하였는지 결정하는데 있어 $result 결과값에 의존하는 것은 현명한 결정이 아니다. $result 위에서 처럼 조건절 이전에 #set 통해 설정 되어진 후에는 $result null 다시 되돌릴 없다. (#if #foreach 명령어의 세부사항들이 문서의 뒤에 다루어질 것이다.)

    이에대한 하나의 해결책은 $reult false 사전에 설정하는 방법이다. 그런 다음 $query.criteria( ) 호출이 실패하면, 당신은 $result null임을 체크할 있게 된다.

    #set( $criteria = ["name", "address"] )
     
    #foreach( $criterion in $criteria )
     
        #set( $result = false )
        #set( $result = $query.criteria($criterion) )
     
        #if( $result )
            Query was successful
        #end
     
    #end

    몇몇의 다른 Velocity 명령어들과 다르게, #set 디렉티브는 #end 문을 가지지 않는다는 점도 참고하라.

    문자열 (String literals)

    명령어 #set 사용할 따옴표로 지정된 문자열은 아래 예제처럼 파싱되어 출력된다.

    #set( $directoryRoot = "www" )
    #set( $templateName = "index.vm" )
    #set( $template = "$directoryRoot/$templateName" )
    $template

    당연하겠지만, 결과는 아래와 같다.

    www/index.vm

    그러나 문자열이 작은 따옴표일 때는 파싱되지 않는다.

    #set( $foo = "bar" )
    $foo
    #set( $blargh = '$foo' )
    $blargh

    결과는 아래와 같다.

    bar
    $foo

    Velocity에서 파싱되지 않은 텍스트를 출력하기 위해 위에서 처럼 작은 따옴표를 사용할 있다.
    설정은 velocity.properties 설정파일에서 stringliterals.interpolate=false 설정함에 따라 기본설정을 바꿀 수도 있다.

    조건절 (If / ElseIf / Else)

    Velocity에서 #if 명령어는 문장이 참인 조건에서 웹페이지가 생성될 포함될 문자열을 지정할 있다.

    #if( $foo )
       Velocity!
    #end

    위에서 #if 명령어는 변수 $foo 참인지 결정하기 위해 사용되며 아래 2가지 상황일 있다.

    *       $foo 참인 값을 갖는 boolean(true/false)이다.

    *       $foo null 아니다.

    Velocity 문맥은 항상 객체(Object)로써 유지된다는 것을 기억하라. 그래서 우리가 boolean이라고 말할 , 그것은 Boolean(class)으로 표현될 것이다.

    예제에서 #if #end 사이에 들어있는 content 참이면 결과가 나올 것이다. 여기서는 $foo 참이면, "Velocity!" 출력될 것이고, 반대로, $foo null값이거나 false이면 아무런 내용도 표시되지 않을 것이다.

    명령어 #elseif 또는 #else #if 요소와 함께 사용될 있다. 다음의 예제에서, $foo 15 값를 갖고 $bar 6 값을 갖는다고 가정해보자.

    #if( $foo > 10 )
        Go North
    #elseif( $foo == 10 )
        Go East
    #elseif( $bar == 6 )
        Go South
    #else
        Go West
    #end

    예제에서 $foo 10보다 크면 첫번째 비교들이 실패하게 된다. 다음 $bar 6 비교되어 참이 되고, 그래서 결과는 "Go South" 된다.

    참고 : '==' 비교되는 변수는 같은 Object 타입이어야 한다. 그렇지 않으면 결과는 항상 false 것이다.

    논리 연산

    Velocity 논리 연산자 AND, OR, NOT 지원한다. 아래 예제가 나온다.

    ## logical AND
     
    #if( $foo && $bar )
       This AND that
    #end

    위에서 #if() 명령은 단지 $foo $bar 참인지만 평가할 것이다. 만약 $foo false라면, 결과는 false 되며 $bar 평가되지 않을 것이다. 만약 $foo 참이라면, Velocity $bar 값을 체크하게 된다. 만약 $bar 참이면, 결과는 true 되고 화면에는 "This And that" 나타날 것이다. $bar false라면, 그때 결과는 false이므로 결과는 없을 것입니다.

    논리 연산자 OR 같은 방법으로 작동한다. 아래 예제가 나온다.

    ## logical OR
     
    #if( $foo || $bar )
        This OR that
    #end

    OR 연산에 대해 별도의 설명은 하지 않는다. 아래는 부정연산의 예제다.

    ##logical NOT
     
    #if( !$foo )
      NOT that
    #end

    여기서, $foo 참이라면, !$foo false 평가하고, 아무런 출력이 없게된다. 만약에 $foo false라면, !$foo 참으로 평가되어 화면에서 "NOT that" 출력될 것이다.

    주의 : 이것을 완전하게 앞서 배운 숨긴(quiet) 레퍼런스와 혼동하지 않도록 조심하라. 숨긴 레퍼런스의 형식은 $!foo 이다.

    반복문 (Loops)

    명령어 #foreach 반복문을 사용할 필요하다.

    <ul>
    #foreach( $product in $allProducts )
        <li>$product</li>
    #end
    </ul>

    예제에서 #foreach loop $allProducts 컬렉션(object) List 안의 전체 product 대해 반복문을 수행하도록 한다. loop 통해서 $allProducts 내에 담긴 Object $product 변수로써 레퍼런스하게 된다.

    위에 나온 $allProducts 변수에 사용되는 타입은 아래와 같다.

    *       Vector

    *       Hashtable

    *       Array

    이제 $allProduct Hashtable이라고 가정하자.
    만약 당신이 Hashtable 담긴 키값을 검색해야 한다면, 아래와 같은 코드를 사용하면 된다.

     
    <ul>
    #foreach( $key in $allProducts.keySet() )
        <li>Key : $key -> value : $allProducts.get($key)</li>
    #end
    </ul>

    또한 Velocity 당신이 반복문의 횟수(loop counter) 얻을 있는 간단한 방법을 제공한다.

    <table>
    #foreach( $customer in $customerList )
        <tr><td>$velocityCount</td><td>$customer.Name</td></tr>
    #end
    </table>

    velocity.properties 파일에 명시되어있는, loop counter 변수 레퍼런스를 위한 기본값은 $velocityCount이다. 기본값에 따라 카운터가 1에서 시작하지만, 이것은 velocity.properties 파일안에서 0 이나 1 모두로 설정할 있다. 아래는 velocity.properties 파일에 지정된 관련 설정 내용이다.

    # Default name of the loop counter
    # variable reference.
    directive.foreach.counter.name = velocityCount
     
    # Default starting value of the loop
    # counter variable reference.
    directive.foreach.counter.initial.value = 1

    인클루드 (Include)

    명령어 #include 템플릿에 local 파일을 끼워넣을 있도록 해준다. local file #include 명령이 정의된 위치에 정확히 삽입된다.

    아래는 #include 참고할 사항이다.

    *       파일의 내용은 템플릿 엔진을 통해 파싱되지 않는다.

    *       안전상의 이유로, 파일은 오직 TEMPLATE ROOT 아래에만 위치해야 한다.

    #include( "one.txt" )

    위에서 처럼 #include 명령이 요청한 파일은 따옴표로 지정된다. 만약 하나 이상의 파일이 포함된다면, 콤마(,) 구분되어야 한다.

    #include( "one.gif", "two.txt", "three.htm" )

    포함되는 파일은 파일 이름 대신에 변수를 사용할 수도 있다. 아래 파일이름과 변수 모두를 지정하는 에제가 나온다.

    #include( "greetings.txt", $seasonalstock )

    파싱 (Parse)

    명령어 #parse 템플릿 디자이너가 VTL 지정되어 있는 동적인 템플릿을 포함하는 local file 끼워넣도록 해준다. Velocity 파일에 명명된 VTL 분석하고 평가된 결과를 #parse 명령이 정의된 위치에 정확히 삽입한다.

    아래는 #parse 참고할 사항이다.

    *       파일의 내용은 템플릿 엔진을 통해 파싱된다.

    *       안전상의 이유로, 파일은 오직 TEMPLATE ROOT 아래에만 위치해야 한다.

    #parse( "me.vm" )

    앞서 나온 #include 명령처럼, #parse 역시 변수를 취할 있다. 주의해야 것은 #include 명령과 다르게, #parse 단지 하나의 파일만을 취할 있다는 점이다.

    Velocity 또한 #parse 문장을 포함하고 있는 템플릿을 #parse 인자로 가질 있다.
    파싱되는 파일의 제한을 위한 최적의 기본값은 10이며 velocity.properties 파일내에 directive.maxdepth=10 이라는 설정을 통해 이를 제어할 있다.

    아래 예제를 보자.
    1) default.vm

    Count down.
    #set( $count = 8 )
    #parse( "parsefoo.vm" )
    All done with dofoo.vm!

    2) parsefoo.vm

    #set( $count = $count - 1 )
    #if( $count > 0 )
        #parse( "parsefoo.vm" )
    #else
        All done with parsefoo.vm!
    #end

    예제에 따라 default.vm에서 $count 8부터 count down하면서 parsefoo.vm 파싱하게 된다.

    그리고 count 0 도달할 , Velocity "All done with parsefoo.vm!" 이라는 메세지를 표시하고, 시점에서, 제어권은 default.vm으로 돌아가 "All done with dofoo.vm!" 이라는 메시지를 출력할 것이다.

    중지 (Stop)

    명령어 #stop 템플릿 엔진의 실행과 return 강제로 멈추도록 하는데 사용한다.
    보통 디버깅(debugging) 목적으로 사용된다.

    #stop

    다음으로 Velocity 나머지 특징과 기타 살펴볼 내용들에 대해 설명을 계속한다.

    수학적인 기능 (Math)

    Velocity #set 명령어를 가지고 템플릿들에서 사용될 있는 수학적인 기능들을 제공한다. 다음의 식들은 각각 덧셈, 뺄셈, 곱샘 그리고 나눗셈에 대한 예제이다.

    #set( $foo = $bar + 3 )
    #set( $foo = $bar - 4 )
    #set( $foo = $bar * 6 )
    #set( $foo = $bar / 2 )
     
    #set( $foo = $bar % 5 )

    수학적인 기능은 오직 정수만 (.... -2, -1, 0, 1, 2 ....) 가능하다는 점에 주의하라.

    범위 연산 (Range Operator)

    범위 연산은 #set #foreach 구문 사이에서 이용될 있다. 범위연산자는 다음의 구조를 가진다.

    [n..m]

    예제에서 n m 모두 정수여야 한다. m 큰지 n 작은지는 문제가 되지 않는다. n m사이에서 반복문이 순환될 것이기 때문이다.

    다음은 범위연산의 사용 예제를 보여주고 있다.

    First example:
    #foreach( $foo in [1..5] )
    $foo
    #end
     
    Second example:
    #foreach( $bar in [2..-2] )
    $bar
    #end
     
    Third example:
    #set( $arr = [0..1] )
    #foreach( $i in $arr )
    $i
    #end
     
    Fourth example:
    [1..3]

    결과는 아래와 같다.

    First example:
    1 2 3 4 5
     
    Second example:
    2 1 0 -1 -2
     
    Third example:
    0 1
     
    Fourth example:
    [1..3]

     

     

    Velocity 문법(매크로)

    매크로

    명령어 #macro VTL 템플릿에서 반복되는 문장을 정의하는데 사용된다.

    매크로는 간단하고 복잡한 시나리오 모두에서 매우 유용하게 쓰인다. 매크로는 keystrokes 저장하고 typographic error 최소화할 목적으로 만들어졌다.

    #macro( d )
    <tr><td></td></tr>
    #end

    예제에서 정의되는 Velocimacro d 이다. 매크로는 아래와 같은 방법으로 호출된다.

    #d()

    템플릿이 불려질 , Velocity 아래와 같은 결과로 #d() 대체하게 된다.

    <tr><td></td></tr>

    또한 Velocimacro 인자의 수를 취할 수도 있다. 심지어 앞선 예제에서 보여진 zero argument 조차 하나의 옵션이다.

    그러나 Velocimacro 불려질 , 그것은 정의된 수만큼의 argument 함께 불려야 합니다. 많은 Velocimacros 위에서 정의된 하나보다 많이 관련됩니다. 여기 색과 array, 개의 argument 취한Velocimacro 있습니다.

    #macro( tablerows $color $somelist )
            #foreach( $something in $somelist )
                   <tr><td bgcolor=$color>$something</td></tr>
            #end
    #end

    예제에서 정의되는 매크로, #tablerow 개의 argument 취한다. 첫번째 argument $color 대체하고 두번째 argument $somelist 대체하게 된다.

    VTL 템플릿 안으로 넣어질 있는 것은 모두 매크로 안으로 지정될 있다. 위에서 #tablerows 매크로는 foreach 명령어를 사용했다. #tablerows 매크로 정의를 보면 두개의 #end 명령이 있다. 예상하겠지만 첫번째는 #foreach 속하고, 두번째는 매크로 정의를 마치는데 사용되는 것이다.

    아래에 위에서 정의한 #tablerow 매크로를 사용하는 예제가 나온다.

    #set( $greatlakes = ["Superior","Michigan","Huron","Erie","Ontario"] )
    #set( $color = "blue" )
    <table>
        #tablerows( $color $greatlakes )
    </table>

    변수 $greatlakes $somelist 대체함에 유의하면서 아래 결과를 살펴보자.

    <table>
            <tr><td bgcolor="blue">Superior</td></tr>
            <tr><td bgcolor="blue">Michigan</td></tr>
            <tr><td bgcolor="blue">Huron</td></tr>
            <tr><td bgcolor="blue">Erie</td></tr>
            <tr><td bgcolor="blue">Ontario</td></tr>
    </table>

    매크로는 하나의 Velocity 템플릿 안에서 inline으로 정의될 있으나 이렇게 정의한 매크로는 다른 템플릿에서는 사용할 없다. 매크로가 모든 템플릿들에 공유될 있도록 정의하기 위해서 velocity.properties 설정파일 내에 template library (velocimacro.library) 지정하도록 한다.

    공유되는 매크로의 이점은 많은 템플릿 들에서 매크로를 재정의할 필요를 줄여 작업량을 줄이고, 오류가 발생할 있는 기회를 줄인다는 점이다.

    매크로 인자 (Arguments)

    매크로에 정의되는 argument 다음의 VTL 요소들을 모두 취할 있다.

    Reference : anything that starts with '$' 
     
    String literal : something like "$foo" or 'hello' 
     
    Number literal : 1, 2 etc 
     
    IntegerRange : [ 1..2] or [$foo .. $bar] 
     
    ObjectArray : [ "a", "b", "c"] 
     
    boolean value true 
     
    boolean value false 

    velocity.properties에서의 매크로 관련 설정

    *       velocimacro.library - 콤마(,) 구분된 모든 템플릿 라이브러리 목록. VM_global_library.vm.설정된 template path Velocimacro library 찾는데 사용됩니다.

    *       velocimacro.permissions.allow.inline - true(기본값)/false. 속성은 매크로가 표준 템플릿 내에서 inline으로 정의될 있는지를 결정한다.

    *       velocimacro.permissions.allow.inline.to.replace.global - true/false(기본값). 만약 템플릿 내에서 inline으로 정의된 매크로가 velocimacro.library 설정된 라이브러리의 매크로를 대체할 지를 설정한다. 만약 false라면 템플릿에 inline으로 정의된 매크로가 컨테이너 구동시 로드된 라이브러리의 매크로를 교체하는 것을 막는다.

    *       velocimacro.permissions.allow.inline.local.scope - true/false(기본값). 속성은 inline으로 정의된 매크로가 정의하는 template 대해 'visible'인지 아닌지를 조절한다. 속성을 true 하면, 템플릿은 단지 정의되는 템플릿에 한해서만 유용한 inline VM 정의할 있게 된다.

    *       velocimacro.context.localscope - true/false(기본값). true라면 매크로를 통한 #set() 명령으로 문맥의 모든 modification 매크로에 대해 'local' 고려되며 영구적으로 영향을 끼치지 않게 된다.

    *       velocimacro.library.autoreload - true/false(기본값). 속성은 자동 로드되는 매크로를 조절한다. true 설정되면 요청된 매크로에 대한 원본 매크로 설정파일의 변화를 체크하여 필요시 해당 매크로를 리로드한다. 이것은 컨테이너 재기동 없이 매크로 라이브러리를 바꾸고 테스트 하도록 해준다. 모드는 오직 caching resource 안에서 off일때만 작동한다. ( : file.resource.loader.cache = false). 속성은 운영단계가 아닌 개발단계에서만 사용하도록 권장한다.

    매크로의 인자로서 다른 매크로나 디렉티브(명령어) 이용할 있나?

    다음 처럼 말이다.

    #center( #bold("hello") ) 

    그럴 없다. 명령은 타당하지 않다.

    그러나 당신은 아래 예제처럼 문제를 우회하여 해결할 있다.

    #set($stuff = "#bold('hello')" )
    #center( $stuff )
    #center( "#bold( 'hello' )" )

    결과는 동일하다.

    다른 예제를 살펴보자.

    #macro( inner $foo )
      inner : $foo
    #end
     
    #macro( outer $foo )
       #set($bar = "outerlala")
       outer : $foo
    #end
     
    #set($bar = 'calltimelala')
    #outer( "#inner($bar)" )

    결과는 아래와 같다.

    outer : inner : outerlala

    어떻게 문자열을 연결해야 하나?

    당신은 단순히 연결해야 문자열들을 같이 놓으면 된다. 아래 예제를 통해 살펴보라.

    #set( $size = "Big" )
    #set( $name = "Ben" )
     
    The clock is $size$name.
    #set( $size = "Big" )
    #set( $name = "Ben" )
     
    #set($clock = "$size$name" )
     
    The clock is $clock.
    #set( $size = "Big" )
    #set( $name = "Ben" )
     
    #set($clock = "${size}$name" )
     
    The clock is $clock.

    결과는 모두 동일하게 "The clock is BigBen' 된다.

     

    프레임워크 내장 객체의 사용

    TDF2에서 지원하는 Velocity 템플릿에서 사용가능한 내장 객체 레퍼런스를 소개한다.

    *      $actionInstanceVariable

    *      $req - 현재 HttpServletRequest

    *      $res - 현재 HttpServletResponse

    *      $stack - 현재 OgnlValueStack

    *      $ognl - OgnlTool

    *      $webwork - WebWorkUtil 인스탄스

    *      $action - 현재 WebWork action

    *      $taglib (또는 이와 유사한 ) - Velocity 매크로를 통한 JSP tag 라이브러리에 접근 가능

    $actionInstanceVariable

    당신이 만든 Action 클래스의 멤버변수들에 대해 $actionInstanceVariableName 으로써 Velocity 템플릿이 접근할 있도록 해준다.

    만약 당신의 Action 클래스에서 아래와 같은 멤버변수를 가진다고 하자.

    public class ProcessEditTableRowAction extends ActionSupport {
     
            private String fooString;
            ....
     
            public String getFooString() { 
                   return fooString; 
            }
            ....

    경우, Velocity 템플릿에서 아래와 같은 레퍼런스를 통해 멤버변수의 값을 꺼낼 있다.

    $fooString

    $req

    당신이 사용하는 서블릿 환경(Tomcat, Resin, etc....)에서 생성되어 관리되는 현재의 HttpServletRequest 인스탄스

    $res

    당신이 사용하는 서블릿 환경(Tomcat, Resin, etc....)에서 생성되어 관리되는 현재의 HttpServletResponse 인스탄스

    $stack

    com.opensymphony.xwork.util.OgnlValueStack 인스탄스

    $ognl

    com.opensymphony.webwork.views.jsp.ui.OgnlTool 인스탄스

    Jason/Patrick 의하면, OgnlTool static 클래스 멤버에 접근할 있는 아주 멋진 Tool이다. Velocity에서는 Context 설정되지 않은 클래스 변수나 메소드에 접근하는 기능을 제공하지 않는다. 그래서 당신은 템플릿 내에서 다음과 같은 메소드를 호출할 없다.

    $java.lang.Math.random()

    그러나 $ognl 이용하면 아래와 같은 구문이 가능해진다.

    $ognl.findValue("@java.lang.Math@random()")

    $webwork

    com.opensymphony.webwork.util.WebWorkUtil 인스탄스

    Mathew 따르면 $webwork 다른 객체를 인스탄스화(초기화) 있는 기능을 제공한다. Velocity에서는 Context 설정되지 않은 객체를 초기화하는 방법을 제공하지 않기 때문에 기능은 매우 유용하다.

    객체를 초기화하기 위해 당신은 템플릿 내에서 다음과 같은 문장을 사용할 있다.

    #set($object = $webwork.bean("com.foo.ClassName"))

    $action

    현재 템플릿을 호출한 Action 컨텍스트의 인스탄스

    $taglib

    TDF2에서는 디자이너와의 혼선을 피하기 위해 taglib 사용을 권장하지 않는다. 대부분의 지원 태그가 (form) 관련된 내용이고, 이것의 사용으로 많은 이점을 제공한다고 보기 어렵기 때문에 TDF2에서는 가급적 익숙한 HTML 표준 태그를 이용하기를 권장한다.

    $taglib 대한 자세한 정보를 알고 싶다면 http://wiki.opensymphony.com/display/WW/UI+Tags?showChildren=true#children 방문하라.

     

    아파치 벨로시티를 사용한 템플릿 기반의 자동 코드 생성 - 1

    05/05/2004

    상업적으로나 오픈소스로나 여러가지 형태로 제공되는 코드 생성기는 템플릿과 템플릿 엔진을 사용하고 있다. 기사에서 필자는 템플릿 기반의 코드 생성과 템플릿과 변환 방법, 그리고 그런 것들을 사용함으로써 얻게 막대한 이득에 대해 설명해보고자 한다. 그리고 벨로시티를 사용한 간단한 자바 코드 생성기를 만들어 것이다. 코드 생성기는 클래스를 XML 표현한 XML 파일을 입력으로 받아들여 XML 명시하고 있는 자바 코드를 생성하는 기능을 가지게 것이다. 생성과정은 결과물 코드로 뽑아낼 언어의 문법(신택스) 내부에 포함하고 있는 각각의 템플릿들에 의해 결정된다. 그리고 또한 다른 코드를 생성해내기 위하여 템플릿을 어떻게 사용하는지도 주목해서 보라.

    템플릿과 변환

    템플릿을 기반으로 변환을 소프트웨어 개발에 있어 엄청나게 광범위하게 사용된다. 많은 툴들이 문서의 포맷을 변환시키기 위하여 사용하기도 한다. XML 파일을 다른 특정 포맷으로 변환시키기 위하여 XSL 템플릿을 기반으로 하여 XSLT 사용하는 것이 예라고 있다. 그림1 템플릿 변환 과정에 있어 관계있는 4개의 컴포넌트를 보여주고 있다. 그것들은 다음과 같다:

    데이터 모델: 특정한 구조를 이루며 데이터를 포함하고 있다. 데이터는 변환되어야 것들이며 변환 과정 중에 이용된다.
    템플릿: 데이터 모델을 특정한 결과 코드로 포맷팅한다. 물론 그것을 위해서 템플릿은 내부에 데이터 모델의 레퍼런스를 가지고 사용하게 된다.
    템플릿 엔진: 변환 과정을 직접 수행하는 어플리케이션이다. 입력으로 데이터 모델과 템플릿을 받아들여 템플릿에 적힌 데이터 모델의 레퍼런스를 실제 데이터 모델의 값으로 치환하여 템플릿을 통한 변환 과정을 수행한다.
    결과물: 변환 과정을 거친 나오는 결과물

    그림 1.템플릿 기반 변환

    다음의 데이터 모델의 예를 한번 보자.:

    #person.txt
     
    $name=
    길동
    $surname=


    길동씨의 이름과 성을 포함하고 있는 텍스트 파일이다. 우리는 다음과 같은 형태의 템플릿을 통해 이것을 변환시키고 싶어졌다.:

    #person.template


    안녕하시오. $surname 가고 이름은 $name 이오. 템플릿또한 텍스트 파일이다. 두개의 데이터 모델에 대한 레퍼런스를 포함하고 있는데 $name $surname이란 레퍼런스가 그것이다.

    만약 템플릿 엔진 어플리케이션 이름이 transform이라면 다음과 같이 데이터 모델과 위의 템플릿을 넘겨주어 다음과 같이 변환을 수행할 수가 있다.:

    > transform person.txt person.template
    결과물은:

     

    안녕하시오. 가고 이름은 길동 이오. 템플릿 엔진은 데이터 모델로부터 얻어낸홍길동이라는 값을 $name $surname 레이블을 치환하였다.

    한마디: 템플릿 기반의 변환에서 가장 중요한 점은 어떠한 결과물을 뽑아내는 프로그램 자체를 건드리지 않고도 결과물의 포맷을 맘대로 바꿀 있다는 점이다. 결과물을 바꾸고 싶으면 단지 해야 일은 템플릿을 조금 수정하는 뿐이다. 여기 다음의 템플릿을 한번 보라.:

    #person2.template
     
    ***********************
    이름 = $name
     = $surname
    ***********************


    여기서는 위에서 사용했던 같은 데이터 모델과 새로운 템플릿 사용하여 변환 과정을 수행해 보겠다.:

    > transform person.txt person2.template


    결과로는:

    ***********************
    이름 = 길동
     =
    ***********************


    위에서 보았던 것과 같이 단지 템플릿만 수정함으로 결과를 조작할 수가 있다.

    템플릿 기반 코드 생성

    코드 생성과정또한 분명하게 위에서와 같은 변환 과정이다. 데이터 모델은 뽑아낼 코드의 중심이 되는 엔티티의 정보를 담고 있는 것이라고 수가 있고 템플릿을 뽑아낼 결과물 코드의 언어 문법을 표현한다고 수가 있다.

    또다른 작은 예로는 언어 독립적인 코드 생성을 보여준다. 여기 예를 보라.:

    #student.txt
     
    $name=Student
    $base=Person


    파일은 클래스 이름과 클래스의 베이스 클래스(부모 클래스) 명시하고 있다. 이것을 기반으로 자바 코드 Student 클래스를 뽑고 싶으면 다음과 같은 템플릿을 사용하면 된다.:

    #javaclass.template
     
    public class $name extends $base {
    }


    위의 데이터 모델과 템플릿을 입력받은 템플릿 엔진은 다음과 같은 변환 결과를 출력할 것이다.:

    public class Student extends Person {
    }


    Student
    클래스의 정의 코드다. 우리는 데이터 모델과 템플릿으로부터 코드 생성을 시작할 수가 있다.

    인터페이스를 만들려면 템플릿을 조금만 바꾸면 된다.:

    #javainterface.template
     
    public interface $name implements $base {
    }


    위의 템플릿을 템플릿 엔진에다 넣으면 다음과 같은 결과가 출력된다.

    public interface Student implements Person {
    }


    엔진은 Student 클래스가 아닌 인터페이스로도 뽑게 준다. 여기에서의 장점은 데이터 모델이나 템플릿 엔진 둘다 건드릴 필요 없이 작업을 했다는 것이다.

    그리고 언어 독립성을 보여주기 위해 C++코드를 만들 있게 템플릿을 작성해 보자.:

    #cpp.template
     
    class $name : public $base
    {
    }


    결과물은:

    class Student : public Person
    {
    }


    C++
    에서의 Student클래스 정의가 나왔다. 물론 데이터 모델이나 엔진을 고치지 않았다. 우리는 같은 것을 기반으로 템플릿만 바꿔서 다른 언어의 코드를 만들어 것이다! 이건 주목할만한 것인데 디자인되고 템플릿을 기반으로 하는 코드 생성기는 단지 템플릿만 바꿔도 다른 언어의 코드를 생성할 있도록 준다. 그래서 우리는 언어에 종속적이지 않고 디자인된 객체 모델을 만들어야 하는 것이다.

    아파치 벨로시티

    이전 예제에서 $ 시작되는 문자열을 데이터 모델로 치환시켜주는 가상의 간단한 템플릿 엔진을 가정하고 설명을 해왔다. 이제 진짜 코드를 생성하기 위해서 진짜 템플릿 엔진을 사용해 보도록 하자.

    아파치 벨로시티 템플릿 엔진은 자카르타 오픈 소스 툴이다. VTL(벨로시티 템플릿 랭귀지) 라고 불리는 간단한 템플릿 언어를 기반으로 동작한다. 벨로시티는 자바를 기반으로 동작하도록 제작되었으며 벨로시티 컨텍스트에 연결된 일반 자바 클래스를 데이터 모델로써 사용한다. 변환 과정은 템플릿과 컨텍스트를 입력으로 받아 템플릿에 명시된 포맷대로의 결과물을 내는 것으로 이루어진다. 변환 과정 중에 템플릿의 레이블들은 컨텍스트에 포함된 실제 데이터로 치환된다.

    나는 샘플 코드를 J2SE 1.4.2 벨로시티 1.4 기반으로 작성했고 테스트도 보았다. 이를 사용하기 위해서는 클래스패스에 개의 jar 파일 - velocity-1.4-rc1.jar and velocity-dep-1.4-rc1.jar. – 포함해야 한다.

    실전에서의 벨로시티

    다음 예제는 벨로시티를 사용한 간단한 코드 생성기인데 멤버 변수와 접근자 메소드(get/set 메소드) 포함한 간단한 자바 클래스를 생성하는 기능을 갖고 있다. 데이터 모델은 클래스들의 이름과 클래스들의 애트리뷰트 이름을 명시하고 있는 XML 파일로써 제공된다 여기 입력 데이터 모델 파일을 한번 보라.:

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- order.xml --!>
    <Content>  
           
      <Class name="Customer">
        <Attribute name="code" type="int"/>
        <Attribute name="description" type="String"/>
      </Class>
       
      <Class name="Order">
        <Attribute name="number" type="int"/>
        <Attribute name="date" type="Date"/>        
        <Attribute name="customer" type="Customer"/>        
      </Class>    
     
    </Content>

     

    XML 파일 구조는 말할 것도 없이 쉽다. 엘레먼트는 클래스들 의미하며 요소는 클래스의 데이터 멤버를 의미한다. 예제는 Customer 클래스와 Order 클래스를 명시하고 있다. 코드 생성기는 문서를 읽어들여 Customer클래스와 Order클래스를 생성해낼 것이다.

    다음으로 생성기를 구현해 보자. 첫번째 일은 XML데이터 구조를 표현하기 위한 내부 구조를 만드는 것이다. 그러기 위해 두개의 자바 클래스를 만들 것인데 위의 요소를 표현하기 위한 것이다. 표현하기 위한 디스크립터 클래스는 다음과 같다.:

    // ClassDescriptor.java
    package com.codegenerator.example1;
     
    import java.util.*;
     
    public class ClassDescriptor {
      private String name;
      private ArrayList attributes = new ArrayList();
      public void setName(String name) {
        this.name = name;
      }
      public String getName() {
        return this.name;
      }
      public void addAttribute(AttributeDescriptor attribute) {
        attributes.add(attribute);
      }
      public ArrayList getAttributes() {
        return attributes;
      }
    }


    ClassDescriptor
    클래스는 요소에 명시된 데이터를 담기 위해 사용된다. Name 애트리뷰트는 클래스 이름을 담기 위해 사용하고 attributes 여러 개의 AttributeDescriptor 담기 위하여 사용되는데 AttributeDescriptor클래스는 ClassDescriptor 마찬가지로 요소의 내용을 담기 위해 사용되는 클래스이다. 다음을 보라:

    // AttributeDescriptor.java
     
    package com.codegenerator.example1;
     
    import java.util.*;
    public class AttributeDescriptor {
      private String name;
      private String type;
      public void setName(String name) {
        this.name = name;
      }
      public String getName() {
        return this.name;
      }
      public void setType(String type) {
        this.type = type;
      }
      public String getType() {
        return this.type;
      }
    }

    XML파일을 디스크립터 클래스들에 담기 위해 SAX파서를 사용하는데 다음과 같이 한다.:

    package com.codegenerator.example1;
     
    import java.util.*;
    import javax.xml.parsers.*;
    import org.xml.sax.*;
    import org.xml.sax.helpers.*;
     
    public class ClassDescriptorImporter extends DefaultHandler {
     
      private ArrayList classes = new ArrayList();
     
      public ArrayList getClasses() {
        return classes;
      }
     
      public void startElement(String uri, String name,
        String qName, Attributes attr) throws SAXException {
     
        // Imports <Class>  
        if (name.equals("Class")) {
          ClassDescriptor cl = new ClassDescriptor();
          cl.setName(attr.getValue("name"));
          classes.add(cl);
        }
     
        // Imports <Attribute>
        else if (name.equals("Attribute")) {
          AttributeDescriptor at = new AttributeDescriptor();
          at.setName(attr.getValue("name"));
          at.setType(attr.getValue("type"));
          ClassDescriptor parent = 
            (ClassDescriptor) classes.get(classes.size()-1);
          parent.addAttribute(at);
     
        }
     
        else if (name.equals("Content")) {
        }
     
        else throw new SAXException("Element " + name + " not valid");
      }  
    }

     

    ClassDescriptorImport 클래스가 하는 일은 SAX 기본 핸들러를 익스텐즈하여 XML로부터 디스크립터 클래스로 데이터를 변환하는 것이다. 위에서 있듯이, 요소가 한번씩 처리될 때마다 ClassDescriptor 클래스의 새로운 인스턴스를 만들어내고 핸들러의 ArrayList 삽입한다. 또한 파서는 요소를 처리할 때마다 새로운 ClassAttribute클래스를 생성해내고 부모 ClassDescriptor 인스턴스에 그것을 삽입한다. 파싱 작업의 마지막에 classes변수는 XML문서에 명시된 모든 클래스들의 디스크립터 클래스를 가지게 된다.getClasses 메소드는 ArrayList 반환한다.

    시점에서 벨로시티가 등장한다. 자바 클래스와 get/set메소드를 만들어내기 위해 작성된 VTL템플릿은 다음과 같다.:

    ## class.vm
     
    import java.util.*;
     
    public class $class.Name {
     
    #foreach($att in $class.Attributes)  
      // $att.Name
      private $att.Type $att.Name;
      public $att.Type get$utility.firstToUpperCase($att.Name)() {
        return this.$att.Name;
      }    
      public void set$utility.firstToUpperCase($att.Name)($att.Type $att.Name) {
        this.$att.Name = $att.Name;
      }
           
    #end
    }


    $class
    라는 레이블은 ClassDescriptor 인스턴스를 가리킨다. 따라서 $class.Name 결국 ClassDescriptor.getName 호출함으로 얻어내는 결과를 출력하는 것이다. ( 실제로 $class.Name $class.getName() 축약형인데 모든 get 으로 시작하는 메소드에 대하여 이런 축약형이 적용된다.). 해당 ClassDescriptor 속한 AttributeDescriptor들의 리스트를 참조하기 위해서는 $class.Attributes 라는 레이블을 사용하면 된다. #foreach 구문은 List $class.Attributes 포함된 모든 항목에 대해 루프를 실행한다. 루프 안쪽의 구문은 $att.Name $att.Type 따른 데이터 멤버와 get/set 메소를 정의하고 있다.

    $utility.firstToUpperCase 레이블은 사용자가 정의한 유틸리티 클래스를 호출하게 하는데 인자로 받은 문자열의 글자를 대문자로 바꿔주는 기능을 가지고 있따. 메소드는 매우 유용한데 예를 들면 number라는 데이터 멤버로부터 getNumber라는 메소드명을 얻어 사용하면 된다.

    코드 생성기

    이제 남은건 메인 어플리케이션이다. 그것은 XML파일을 읽어서 디스크립터 클래스에 값을 집어넣고 벨로시티를 호출해 템플릿을 통한 변환 작업을 수행하게 된다.

    기사에서 ClassGenerator라는 전체 어플리케이션의 소스를 얻어낼 수가 있다. 가장 중요한 메소드는 start() 메소드다. 여기에 구현체가 있으니 한번 보라.:

    public static void start(String modelFile, String templateFile)
      throws Exception {
     
      // Imports XML
      FileInputStream input = new FileInputStream(modelFile);
      xmlReader.parse(new InputSource(input));
      input.close();
      classes = cdImporter.getClasses(); // ClassDescriptor Array
     
      // Generates Java classes source code
      // by using Apache Velocity
      GeneratorUtility utility = new GeneratorUtility();
      for (int i = 0; i < classes.size(); i++) {
     
        VelocityContext context = new VelocityContext();
        ClassDescriptor cl = (ClassDescriptor) classes.get(i);
        context.put("class", cl);
        context.put("utility", utility);
     
        Template template = Velocity.getTemplate(templateFile);
     
        BufferedWriter writer =
          new BufferedWriter(new FileWriter(cl.getName()+".java"));
     
        template.merge(context, writer);
        writer.flush();
        writer.close();
     
        System.out.println("Class " + cl.getName() + " generated!");
      }
    }


    메소드는 입력으로 XML 템플릿 파일명을 받는다. 메소드 내에서는 이전에 설명된 ClassDescriptorImporter 클래스의 cdImporter 인스턴스와 관계지어진 xmlReader 사용하여 데이터를 읽어들이게 된다. 당신이 있듯이 getClasses메소드를 통하여 클래스로 뽑아내어질 클래스들의 디스크립터 클래스들을 얻어낼 수가 있다. 루핑 코드 안에서 생성되어지는 context객체는 특히 중요한데 왜냐하면 그것은 디스크립터 클래스 인스턴스와 템플릿간의 연결을 제공하기 때문이다. 사실 Context.put 메소드는 자바 객체를 템플릿 레이블과 매핑을 시키게 된다. 다음과 같은 구문을 실행하는 것이 그런 매핑을 수행한다.:

    context.put("class", cl);
    context.put("utility", utility);


    클래스 디스크립터의 인스턴스인 cl 객체는 템플릿에서 $class 레이블로 접근할 수가 있고 유틸리티 클래스는 $utility 레이블을 이용해서 접근할 수가 있다. 마지막의 유틸리티 클래스는 GeneratorUtility 클래스의 인스턴스로 filrstInUpperCase() 메소드를 사용하기 위하여 컨텍스트에 삽입한다.

    컨텍스트에 템플릿에서 처리할 데이터를 put 다음에는 start() 메소드에서 제공받은 대로 특정 템플릿 파일에 대한 Template 객체를 생성하고 merge 메소드를 호출한다. 그러면 템플릿 기반의 변환 작업이 수행된다. 컨텍스트의 데이터는 템플릿에 의해 처리되고 결과는 결과 witer 인스턴스의 스트림에 쓰여지게 된다.

    아래 예제에서 코드생성기를 데이터 모델로 ordedr.xml , 템플릿으로 class.vm 입력으로 사용하여 돌려보면 Customer.java 파일을 얻게 것이다. 실제 구현 코드를 한번 보자:

    import java.util.*;
     
    public class Customer {
     
      // code
      private int code;
      public int getCode() {
        return this.code;
      }    
      public void setCode(int code) {
        this.code = code;
      }
           
      // description
      private String description;
      public String getDescription() {
        return this.description;
      }    
      public void setDescription(String description) {
        this.description = description;
      }
     
    }

     

    import java.util.*;
     
    public class Order {
     
      // number
      private int number;
      public int getNumber() {
        return this.number;
      }    
      public void setNumber(int number) {
        this.number = number;
      }
           
      // date
      private Date date;
      public Date getDate() {
        return this.date;
      }    
      public void setDate(Date date) {
        this.date = date;
      }
     
      // customer
      private Customer customer;
      public Customer getCustomer() {
        return this.customer;
      }    
      public void setCustomer(Customer customer) {
        this.customer = customer;
      }
    }

     

    결론

    템플릿 기반의 코드 생성기를 개발하면 가지 경우에 그것을 사용할 수가 있다.:

    1.    다른 클래스의 생성을 위해 데이터 모델을 변경할 .

    2.    다른 프로그래밍 언어에 맞는 템플릿을 제공하여 다른 언어의 코드를 뽑아내고 싶을 .

    두가지 사용예는 코드 생성기 자체를 건드리지 않고 수행할 있다. 따라서 템플릿 기반의 코드 생성기는 특정 언어의 코드만 뽑아내게 설계된 생성기에 비해 훨씬 유연하다.

    기사의 2장에서는 훨씬 복잡한 상황에서의 템플릿 코드 생성을 알아 것이다. 특별히 필자는 Internal Model Object(아래 참고자료 7) 사용한 템플릿의 사용법에 대해 알아볼 것이며 특정 언어의 코드 생성에 종속적인 벨로시티 컨텍스트를 비종속적인 컨텍스트로 작성하는 방법에 대한 패턴을 알아볼 것이다.

     

    Posted by 1010
    98..Etc/velocity2009. 1. 23. 14:59
    반응형
    VTL (Velocity Template Language)에 대해서는 여지껏 접해본바 없는 상황인지라 문법 익히기에도 급급하다.
    대충 문법 정의 문서를 살펴보니 그리 어려운 언어는 아니라는 결론을 얻었다.

    HTML 사용 하는거야 그냥 똑같이 쓰면 되고, 그 안에 스크립트를 끼워 넣는 것인데...
    좀 더 쓰다 보면 익숙해지겠지... :-)

    자.. 이제 익숙해지는 단계 이전까지는 뭔가 도움이 될만한 것들을 찾아봐야 하는데, 역시나 이클립스를 무시할 수가 없다. Velocity 코드 작성을 위한 Plug-In이 분명 존재할 것이란걸 믿고 찾아봤더니...
    세상에나... 정말로 있다!!

    Eclipse 사이트의 Plug-In Central 화면 캡춰



    이제 설치를 해보자.

    Velocity WebEditor - Eclipse Plugin : 아래 다운로드 클릭
    상단에 링크된 파일을 다운받아서 압축을 해제하면 plugin 디렉토리가 생성되고 그 안에 실제로 설치에 필요한 디렉토리 및 파일들이 존재한다.


    com.hudson.velocityweb_1.0.8 디렉토리를 Eclipse 설치 디렉토리 아래 plugins 디렉토리 하위에 복사.

    Eclipse가 실행 중이었다면 재실행 해야 반영된다.


    VM 파일을 수정하는 화면이다. 가장 도움이 되는 기능이 Syntex Coloring 과 Code Assist 기능이 지원된다는 것.
    이제 눈을 부릅뜨고 코딩하는 일만 남았다.

    조금이라도 빨리 퇴근하길 바라는 마음에서... ㅠ_ㅠ
    Posted by 1010
    98..Etc/velocity2009. 1. 23. 14:50
    반응형

    JSTL과 Velocity를 활용한 UI 레이어 구현 방법

    Table of Contents

    JSTL

    소개

    • J2EE 소형 클라이언트 기술인 JSP(JavaServer Pages)가 지난 몇 년 동안 널리 일반화되면서 독립적인 개발자들은 많은 사용자 정
      의 JSP 태그 라이브러리를 만들었습니다. 이러한 태그 라이브러리는 대부분 서로 다른 목표를 달성하도록 작성되었지만 반복, 조건 등의 일
      반적인 작업을 위한 유사한 솔루션을 제공하는 경향이 있습니다.
      유사하고 일반적이 문제점을 해결하는 독립적인 태그 라이브러리에 대한 필요성을 줄이기 위해 Java Community Process(JSR 52)의 지
      원하에 JSTL(JavaServer Pages Standard Tag Library)이 개발되었습니다. JSTL은 이러한 일반 기능을 처리하는 하나의 표준 솔루션
      을 제공합니다. (말그대로 표준태그라이브러리)
    • JSTL의 주요 강점 중 하나는 서블릿 컨텍스트에 저장된 데이타 같은 애플리케이션 데이타를 액세스 및 조작하는 쉬운 방법을 제공하는 간
      단한 EL을 사용할 수 있다는 것입니다.

    EL 에 대하여

    설치 방법

    • http://cvs.apache.org/builds/jakarta-taglibs/nightly/ 에서 다운
      \jakarta-taglibs-20051024\jakarta-taglibs\standard\lib
      에서 jstl 과 standard 파일 을 이 두개의 jar 파일을 우리의 웹애플리케이션의 /WEB-INF/lib 폴더에 넣습니다
      그 다음 tld 폴더의 tld 파일을 /WEB-INF/lib/tld 폴더 아래 넣습니다.
    • web.xml 에
       
          <!-- jstl 1.2 taglig -->
           <taglib>
             <taglib-uri>jstl-c</taglib-uri>
             <taglib-location>/WEB-INF/tlds/jstl/c.tld</taglib-location>
          </taglib>
          <taglib>
             <taglib-uri>jstl-fmt</taglib-uri>
             <taglib-location>/WEB-INF/tlds/jstl/fmt.tld</taglib-location>
          </taglib>
          <taglib>
            <taglib-uri>jstl-fn</taglib-uri>
            <taglib-location>/WEB-INF/tlds/jstl/fn.tld</taglib-location>
          </taglib>
          

      를 추가한다.

    • jsp 에 추가
       
           <%@ taglib uri="jstl-c" prefix="c" %>
          <%@ taglib uri="jstl-fmt" prefix="fmt" %>
          <%@ taglib uri="jstl-fn" prefix="fn" %>
           

    사용 예(기본 문법)

    Area Subfunction Prefix Description
    Core Variable support c 변수지원
    Core Flow control c 흐름제어
    Core URL management c URL 처리
    Core Miscellaneous c  
    XML Core x XML 코어
    XML Flow control x 흐름 제어
    XML Transformation x XML 변환
    I18n Locale fmt 지역
    I18n Message formatting fmt 메시지 형식
    I18n Number and date formatting fmt 숫자 및 날짜 형식
    Database SQL sql SQL
    Functions Collection length fn 콜렉션 처리
    Functions String manipulation fn String 처리

    http://java.sun.com/products/jsp/jstl/1.1/docs/tlddocs/index.html 참고

    • 변수지원태그
      set: <c:set var="varName" scope="session" value="someValue">
      var속성은 값을 지정할 변수의 이름
      <c:set t a r g e t ="" property="userName" value="someValue">
      target : 빈 프로퍼티나 맵 값을 설정한다.(Object)
      var와 target을 동시에 사용할 수 없다.
      scope속성은 변수가 위치하는 영역(page,request,session,application)
      value :저장하는 값
      remove :<c:remove var="varName" scope="session">
      var :삭제할 변수의 이름
      scope 속성은 삭제할 변수의 영역
      out : <c:out value="">
      value속성은 출력하려는 값
      catch : <c:catch var="">
      </c:catch>
      예외사항이 한번이라도 발생시 </c:catch>로 점프
      var에 정의 된 객체를 페이지 생존범위에 자동으로 묶어 나중에 var에 정의된 변수이름을 사용할 수 있다.
      예외 발생시
      : var 속성 사용시 exception 객체를 설정.
      <c:catch> 문 밖으로 제어가 떨어진다
     
        <c:set var="num1" value="${20}" />
    	<c:set var="num2">
    		10.5
    	</c:set>
    	
    	<c:set var="today" value="<%= new java.util.Date()%>" /><br>
    
    	변수 num1 = ${num1} <br>
    	변수 num2 = ${num2} <br>
    	num1 + num2 = ${num1+num2}<br>
    	오늘은 ${today}입니다.
    	
    	<c:remove var="num1" scope="page" />
    	
    	<p>
    	삭제한 후의  num1=${num1} <br>
    	삭제한 후의 num1 + num2 = ${num1 + num2}
       
     
           <c:catch var="myException">
         	It's catch
             <% int x = 10/0; %>
             실행안됨.
           </c:catch>
           <c:if test="${myException != null}">
               발생된 예외는 : ${myException.message} <br>
           </c:if>
         
    • URL 관련
      import : <c:import url=""/>
      url속성에 명기한 파일을 현재 컨텐츠에 포함
      param : <c:param name="" value=""/>
      <jsp:param />과 같은 역할
      url : <c:url value="" var=""/>
      value에 들어있는 상대 경로 뒤에 jsessionid를 추가한다.(쿠키를 사용 못하는 경우)
      var : 옵션 속성으로 url을 참조하기 위해쓴다.
      redirect :<c:redirect url="' context=""/>
      context : url경로의 이름
     
        <c:import url="Header.jsp" >
    	<c:param name="subTitle" value="This is subTitle"/>
        </c:import>
       
    • 흐름제어 태그
      if : <c:if test="조건"> </c:if>
      test속성의 값에는 "조건"이 오는데 이 조건문의 결과값이 true 면 처리
       
         <c:if test="true">
           무조건 수행<br>
          </c:if>
      
          <c:if test="${param.name == 'bk'}">
            name 파라미터의 값이 ${param.name}입니다 <br>
          </c:if>
      
          <c:if test="${param.name eq 'bk'}">
            name 파라미터의 값이 ${param.name}입니다 <br>
          </c:if>
      
          <c:if test="${18 < param.age}">
      	 당신의 나이는 18세 이상입니다.
          </c:if>   
         

      choose,when,otherwise : <c:choose>
      <c:when test="조건">
      </c:when>
      <c:otherwise>
      </c:otherwise>
      </c:choose>
      choose 태그는 자바의 switch 문과 if-else 의 혼합한 형태, 다수의 조건문을 하나의 블록에서 수행하고자 할때 사용
      -> switch문과의 차이점은 중간에 빠져 나가지 못한다는 것이다.
      -> when 의 어느 하나에도 실행되지 않을때 otherwise 실행
      -> otherswise 태그가 반드시 있어야 하는것은 아니다.

     
         <c:choose>
           <c:when test="${param.name == 'bk' }">
    	<li>당신의 이름은 ${param.name}입니다.
         </c:when>
         <c:when test="${param.age > 18 }">
    	<li>당신은 18세 이상입니다.
         </c:when>
    
         <c:otherwise>
    	<li> 당신은 'bk'가 아니고 18세 이상이 아닙니다.
         </c:otherwise>
         </c:choose> 
        

    forEach : <c:forEach var="변수" items="아이템" begin="시작값" end="끝값" step="증가값">
    </c:forEach>
    item 속성에 올수 있는 것들로는 Map,배열,Collection 이 있다.
    varStatus는 javax.servlet.jsp.jstl.core.LoopTagStatus 객체 인스턴스변수를 만들며 count라는 프로퍼티가 있어 몇번의 회전인지 알 수있다.

     
           <c:forEach var="i" begin="1" end="9">
    	<li>4 *${i} = ${4 *i}
           </c:forEach>
    
           <h4>int 형 배열</h4>
    
           <c:forEach var="i" items="${intArray}" begin="2" end="4">
    	[${i}]
           </c:forEach>
    
           <h4>Map</h4>
           <c:forEach var="i" items="${map}">
    	  ${i.key} = ${i.value}<br>
           </c:forEach>
    
           <c:forEach var="member" items="${memberList}" varStatus="memberLoopCount">
    	  회원 $(memberLoopCount.count} : ${member} <br>
           </c:forEach>
         

    forTokens : <c:forTockens var="token" items="문자열" delins="구분자">
    </c:forTockens>
    forTokens 태그는 StringTokenizer 와 같은 기능을 제공한다.

     
           <c:forTokens var="token" items="빨강색, 주황색, 노란색, 초록색, 파랑색, 남색, 보라색" delims=",">
         	${token}<br>
           </c:forTokens>
         
    • 숫자 및 날짜 지원 형식
      The JSTL formatting actions allow various data elements in a JSP page, such as numbers,dates and times
      to be formatted and parsed in a locale-sensitive or customized manner.

    formatNumber : 숫자 형식을 표현

     
     
          number  : <fmt:formatNumber value="9876543.61" type="number"/>
          currency: <fmt:formatNumber value="9876543.61" type="currency"/>
          percent : <fmt:formatNumber type="percent">9876543.61</fmt:formatNumber>
    
          pattern=".000"    :<fmt:formatNumber value="9876543.61" pattern=".000" />
          pattern="#,#00.0#":<fmt:formatNumber value="9876543.612345" pattern="#,#00.0#"/>
        

    parseNumber : 정해진 패턴을 문자열에서 수치를 파싱해내는 태그
    formatDate :날짜 형식을 표현

     
          <jsp:useBean id="now" class="java.util.Date"/>
    	
             <c:out value="${now}"/>
               date: <fmt:formatDate value="${now}" type="date"/>
               time: <fmt:formatDate value="${now}" type="time"/>
               both: <fmt:formatDate value="${now}" type="both"/>
    
               default:<fmt:formatDate value="${now}"
                            type="both" dateStyle="default" timeStyle="default"/>
               short  :<fmt:formatDate value="${now}"
                            type="both" dateStyle="short"   timeStyle="short"  />
               medium :<fmt:formatDate value="${now}"
                            type="both" dateStyle="medium"  timeStyle="medium" />
               long   :<fmt:formatDate value="${now}"
                            type="both" dateStyle="long"    timeStyle="long"   />
               full   :<fmt:formatDate value="${now}"
                            type="both" dateStyle="full"    timeStyle="full"   />
    
              pattern="yyyy년MM월dd일 HH시mm분ss초"
                 <fmt:formatDate value="${now}" type="both"
                                 pattern="yyyy년MM월dd일 HH시mm분ss초"/>
                
             <fmt:formatDate value="${now}" pattern="yyyy/MM/dd" />

    parseDate :정해진 패턴의 문자열에서 날짜를 파싱해내는 태그
    timeZone : <fmt:timeZone value=""/>

    setTimeZone : <fmt:timeZone value="" var="" scope=""/>

    • 국제화
      message <fmt:message
      setLocale <fmt:setLocale
      bundle <fmt:bundle
      setBundle <fmt:setBundle
      param <fmt:param
      requestEncoding <fmt:requestEncoding
    • SQL
      <sql:query sql="sqlQuery" var="varName" [scope="{page|request|session|application}"]
      [dataSource="dataSource"] [maxRows="maxRows"] [startRow="startRow"]>
      <sql:param>
      </sql:query>
           <sql:query var="customers" dataSource="${dataSource}">
            SELECT * FROM customers
            WHERE country ='China'
            ORDER BY lastname
           </sql:query>
           
           <table>
            <c:forEach var="row" items="">
               <tr>
                 <td><c:out value="${row.lastName}"/></td>
                 <td><c:out value="${row.firstName}"/></td>
                 <td><c:out value="${row.address}"/></td>
               </tr>
            </c:forEach>
           </table>
         

    <sql:update>
    <sql:setDataSource>
    <sql:param>
    <sql:dateParam>

    • XML 코어
      <x:parse>
      <x:out>
      <x:set>
    • 흐름제어
      <x:if>
      <x:choose>
      <x:when>
      <x:otherwise>
      <x:forEach>
    • XML 변환
      <x:transform>
      <x:param>
    • function
      contains
      containsIgnoreCase
      endsWith
      escapeXml
      indexOf
      join
      length
      replace
      split
      startsWith
      substring
      substringAfter
      substringBefore
      toLowerCase
      toUpperCase
      trim
           <c:if test="${fn:contains(name, searchString)}">
           <c:if test="${fn:containsIgnoreCase(name, searchString)}">
           <c:if test="${fn:endsWith(filename, ".txt")}">
           ${fn:escapeXml(param:info)}
           ${fn:indexOf(name, "-")}
           ${fn:join(array, ";")} 
           You have ${fn:length(shoppingCart.products)} in your shopping cart.
           ${fn:replace(text, "-", "•")}
           ${fn:split(customerNames, ";")}
           <c:if test="${fn:startsWith(product.id, "100-")}">
           P.O. Box: ${fn:substring(zip, 6, -1)}
           P.O. Box: ${fn:substringAfter(zip, "-")}
           Zip (without P.O. Box): ${fn:substringBefore(zip, "-")}
           Product name: ${fn.toLowerCase(product.name)}
           Product name: ${fn.UpperCase(product.name)}
           Name: ${fn.trim(name)}
         

    Velocity

    Velocity

    소개

    • 벨로시티란 자바 기반의 템플릿 엔진입니다.
      벨로시티를 활용하면 간단하면서도 강력한 템플릿 언어를 통하여 자바 코드에 정의된 객체를 액세스할 수 있습니다.
      벨로시티를 웹 개발에 사용하면, 웹 디자이너는 자바 프로그래머와 병렬로 작업을 할 수 있으며 MVC(모델-뷰-컨트롤러) 모델에 따라 웹 사이트를 개발할 수 있습니다. 더 자세히 설명하면 웹 페이지 디자이너의 경우 보기 좋은 사이트를 만드는 데만 집중하면 되고, 프로그래머는 잘 동작하는 코드를 만드는 데만 집중하면 된다는 뜻입니다.
      벨로시티는 웹 페이지와 자바 코드를 분리하여, 장기적인 측면에서 볼 때 웹 사이트를 손쉽게 유지보수할 수 있도록 하고, 자바 서버 페이지 (JSP) 또는 PHP를 대체할 수 있는 방안을 제시합니다. 벨로시티의 쓰임새는 웹 사이트에 국한되지 않습니다. 예를 들면, 템플릿으로부터 SQL이나 포스트스크립트, 또는 XML(XML 변환에 대해서는 벨로시티 툴 중 하나인 아나키아(Anakia)를 참조)문서를 생성하는 데 쓰일 수 있습니다. 벨로시티는 스탠드얼론 유틸리티처럼 사용하여 소스 코드나 리포트를 생성할 수도 있고, 다른 시스템의 컴포넌트로 통합할 수도 있습니다. 또한 벨로시티는 터빈 (또다른 자카르타 서브 프로젝트 중 하나) 웹 애플리케이션 프레임웍에 템플릿 서비스를 제공합니다. 벨로시티와 터빈을 조합하면 진정한 MVC 모델에 따라 웹 애플리케이션을 개발할 수 있습니다

    설치 방법

    • web.xml 수정
       
         <servlet>
           <servlet-name>velocity</servlet-name>
              <servlet-class>org.apache.velocity.tools.view.servlet.VelocityViewServlet
           </servlet-class>
           <init-param>
              <param-name>org.apache.velocity.toolbox</param-name>
              <param-value>/WEB-INF/velocity-toolbox.xml</param-value>
           </init-param>
           <init-param>
              <param-name>org.apache.velocity.properties</param-name>
              <param-value>/WEB-INF/velocity.properties</param-value>
             </init-param>
           <load-on-startup>10</load-on-startup>
         </servlet>
         <servlet-mapping>
            <servlet-name>velocity</servlet-name>
            <url-pattern>*.vm</url-pattern>
         </servlet-mapping>
       
    • 파일 생성
      velocity.properties 파일
      velocity-toolbox.xml 을 생성 한 후 web_inf/lib 아래 둡니다.
      velocity-toolbox.xml
      <tool>
         <key>date</key>
         <scope>application</scope>
         <class>org.apache.velocity.tools.generic.DateTool</class>
       </tool>
      
        <tool>
        <key>math</key>
        <scope>application</scope>
        <class>org.apache.velocity.tools.generic.MathTool</class>
      </tool>
       ...
      

    사용 예(기본 문법)

    Velocity Template Language(VTL) 은 Template 에서 사용되는 Velocity 고유의 언어를 의미합니다.

    • References(참조형)
      Variables(변수) - 다음과 같이 $를 먼저 쓰고 그 뒤에 식별자를 적어주는 방식으로 사용
      ex) $foo
      Property(특성) - $ 다음에 식별자를 쓰고, 마침표(.)후에 다시 식별자의 형태로 사용
      ex) $foo.name
      Method(메소드) - $다음에 식별자를 쓰고 마침표 후에 호출할 메소드의 이름을 적는다
      ex)$foo.getName()
    • Directive(지시형)
      #set - reference 의 값을 설정한다.
      #if/elseif/else - 조건문 제어
      #foreach ---- 제어
      #include - velocity 로 파싱되지 않는 파일의 출력
      #parse -velocity 로 파싱된 파일 출력
      #stop -template 엔진의 정지
      #macro - 반복적으로 사용할 vm정의
    • Comment (주석)
        ## - 한줄짜리 주석
        #* ... *# 여러줄 짜리 주석
        
         ##This is an example velocity template
         #set($this = "Velocity")
           $this is great! But It's so hard.
    
         #foreach($name in $list)
           $name is great!
         #end
    
         #set($condition = true)
         #if ($condition)
            The condition is true!
         #else
           The condition is false
         #end
      

    http://jakarta.apache.org/velocity/docs/vtl-reference-guide.html

    Tool box 에 대해

    VelocityTools is a collection of Velocity subprojects with a common goal of creating tools and infrastructure for building both web and non-web applications using the Velocity template engine.

    • Generic Tool (http://jakarta.apache.org/velocity/tools/generic/)
      *DateTool : A tool for manipulating and formatting dates
      *MathTool :A tool for performing floating point math.
      *NumberTool :A tool for formatting numbers
      *IteratorTool :A convenience tool to use with #foreach loops. It wraps a list to let the designer specify a
      condition to terminate the loop, and reuse the same list in different loops.
      *RenderTool:A tool to evaluate and render arbitrary strings of VTL (Velocity Template Language).
            Example uses:
        $date                         -> Oct 19, 2003 9:54:50 PM
        $date.long                    -> October 19, 2003 9:54:50 PM PDT
        $date.medium_time             -> 9:54:50 PM
        $date.full_date               -> Sunday, October 19, 2003
        $date.get('default','short')  -> Oct 19, 2003 9:54 PM
        $date.get('yyyy-M-d H:m:s')   -> 2003-10-19 21:54:50
       
        $myDate                        -> Tue Oct 07 03:14:50 PDT 2003
        $date.format('medium',$myDate) -> Oct 7, 2003 3:14:50 AM 
      
      
          
    • VelocityView (http://jakarta.apache.org/velocity/tools/view/)

    JSTL 과 Velocity

    같은 로직에 대해 두가지를 사용하여 각각 구현

    다양한 View Technology에 대한 실행 속도 비교.

    현재 개발중 우리들이 많이 사용하는 View 기술들을 이용하여 실행속도를 비교해 보면 다음 그래프와 같다.

    이 그래프는 100명의 동시 접속자에 대한 테스트를 진행한 결과이다. 이 그래프는 Expert One-on-One J2EE Design and Development 책의 Chapter 15의 Web-Tier Performance Issues에서 인용하였다.

    위와 같이 테스트를 진행한 결과 JSP는 초당 54페이지, Velocity는 초당 112페이지, XMLC는 초당 128 페이지, XSLT는 6,7페이지를 서비스하였다. 이 부분에서 눈여겨 볼 부분은 Velocity에 대한 결과라할 수 있다. 국내에서는 아직까지 많이 사용되지 않는 기술이지만 위의 실행 결과를 보면 사용할만한 가치가 있다는 것을 확인할 수 있다.

    참고문헌

    문서에 대하여

    최초작성자 : 박재성
    최초작성일 : 2005년 10월 15일
    버전 : 1.0
    문서이력 :

    • 2005년 10월 15일 박재성 문서 최초 생성 : 강좌 문서 템플릿 및 JSP와 Velocity에 대한 속도 비교문서 추가
    Posted by 1010
    98..Etc/velocity2009. 1. 23. 14:49
    반응형
    http://technet.ui2.co.kr/wiki/index.php/Velocity  velocity wiki 페이지

    velocity 를 기본적으로 사용하기 위한 jar  파일 목록이다.
    velocity-dep-*.jar : velocity 그리고 관련된 클래스 파일
    velocity-tools-*.jar : velocity tool
    commons-digester
    commons-collections
    commons-beanutils

    1. VTL(Velocity Template Language) 장점
    @ UI 디자이너와 개발자의 병렬 개발 가능
    @ 각각의 영역에 집중가능
    @ 유지보수 용의
    @ JSP,PHP 대체방안 제시

    2. VTL 문장은 # 으로 시작하며  변수명은 $ 로 표시한다.
    # set( $foo = "Velocity")

    3. 주석처리방법
    한줄 : ##
    여러줄 : #*  *#

    4. 자바객체사용해서 하위 객체 접근이 가능하다
    $ custom.Address
    $ custom.getAddress()

    5. 값을 불러오는 여러가지 방법
    $ customer.address 를 다음과 같이 표현할수 있다.
    $ getaddress()
    $ getAddress()
    $ get("address")
    $ isAddress()

    6. 중간에 변수가 들어가서 잘못 파싱되는것을 방지하기위해
    쓰는 방식인데
    기본적으로 이렇게 처리하는 버릇을 들이자.
    Jack is a $vicemaniac.
    Jack is a ${vice}maniac.

    7. 값이 없을 시에 공백처리를 원할때
    <input type="text" name="email" value="$!email>
    좀더 안전하기를 원하면 value="$!{email}"

    8. #set 지시자 사용시 큰따옴포("") 안의 내용은 파싱되어 그 결과물을 출력한다.
    #set( $template = "$directoryRoot / $templateName")

    9. '' 작은 따옴표는 파싱되지 않고 내용이 그대로 출력되지만
    velocity.properties 안의 Stringliterals.interpolote = false 값을 바꿈으로서 파싱이 되도록 설정한다.

    10. for 문으로 반복문을 처리하고 싶을때
    iterator 와 비슷한 형태의 구조이다.
    #foreach($page in $boardList)
    <!-- 처리하고자 하는 내용 -->
    #end

    11. if 문을 쓰고싶을때
    #if($velocityCount <= 3)
       $item
    #end
    Posted by 1010