CLOVER🍀

That was when it all began.

FreeMarkerのnoparse的な、Velocity VTL

最近、仕事でVelocityを使っていまして、その時にテンプレートの一部を評価しないみたいなことができないかなーと思って調べてみました。

Webアプリの画面テンプレートに使っているので、jQuery

$('#id');

みたいな表記と、すごい相性悪いわけで…。

まあ、なんでVelocity使ってるの?なんでFreeMarkerじゃないの?とかいう話もあるかと思いますけど、今回はVelocityなんですよ。

で、やりたいことはFreeMarkerのnoparseディレクティブ的なことですね。
http://freemarker.sourceforge.net/docs/ref_directive_noparse.html

<#noparse>
  <#list animals as being>
  <tr><td>${being.name}<td>${being.price} Euros
  </#list>
</#noparse>

Velocityにも、調べてみたらありました。
http://velocity.apache.org/engine/releases/velocity-1.7/vtl-reference-guide.html

こんなVTLらしいです。

#[[
...
#]]

Velocity 1.7からの機能みたいです。2010年リリースとはいえ、最新版で入った機能なんですねー。
http://velocity.apache.org/news.html#engine17

せっかくなので、FreeMarkerと合わせて使ってみました。

build.gradle

apply plugin: 'java'
apply plugin: 'application'

group = 'littlewings'
version = '0.0.1-SNAPSHOT'

mainClassName = "TemplateEngineNoParse"

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.apache.velocity:velocity:1.7'
    compile 'org.freemarker:freemarker:2.3.19'
}

FreeMarkerテンプレート。
src/main/resources/template.ftl

My Name is ${name}!!

Say, [${keyword}]

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

<#noparse>
My Name is ${name}!!

Say, [${keyword}]
</#noparse>

Velocityテンプレート。
src/main/reslate.vm

My Name is ${name}!!

Say, [${keyword}]

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

#[[
My Name is ${name}!!

Say, [${keyword}]
]]#

両方とも、同じ意味のテンプレートで、前半後半でパースする方としない方に分かれています。

Javaソースコード
src/main/java/TemplateEngineNoParse.java

import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;
// import freemarker.template.Template;
import freemarker.template.TemplateException;

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;

public class TemplateEngineNoParse {
    public static void main(String[] args) {
        evalFreeMarker();
        evalVelocity();
    }

    public static void evalFreeMarker() {
        System.out.println("================== FreeMarker Start ==================");

        Configuration config = new Configuration();
        config.setTemplateLoader(
            new ClassTemplateLoader(
                TemplateEngineNoParse.class, ""));

        try {
            freemarker.template.Template template
                = config.getTemplate("template.ftl");
            StringWriter writer = new StringWriter();

            template.process(createBindData(), writer);

            System.out.println(writer.toString());
        } catch (IOException | TemplateException e) {
            e.printStackTrace();
        }

        System.out.println("================== FreeMarker End ==================");
    }

    public static void evalVelocity() {
        System.out.println("================== Velocity Start ==================");

        Velocity.setProperty("resource.loader", "classpath");
        Velocity.setProperty("classpath.resource.loader.class",
                             "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");

        Velocity.init();

        VelocityContext context = new VelocityContext();
        for (Map.Entry<String, String> entry : createBindData().entrySet()) {
            context.put(entry.getKey(), entry.getValue());
        }

        try {
            org.apache.velocity.Template template
                = Velocity.getTemplate("template.vm");
            StringWriter writer = new StringWriter();

            template.merge(context, writer);

            System.out.println(writer.toString());
        } catch (ResourceNotFoundException | ParseErrorException | MethodInvocationException e) {
            e.printStackTrace();
        }

        System.out.println("================== Velocity End ==================");
    }

    public static Map<String, String> createBindData() {
        Map<String, String> data = new HashMap<>();
        data.put("name", "Kazuhira");
        data.put("keyword", "Hello Template Engine!!");
        return data;
    }
}

おおちゃくしてFreeMarkerとVelocityを両方書いたら、Templateのクラス名が被った…。

実行結果。

$ gradle --daemon run
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:run
================== FreeMarker Start ==================
My Name is Kazuhira!!

Say, [Hello Template Engine!!]

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

My Name is ${name}!!

Say, [${keyword}]

================== FreeMarker End ==================
================== Velocity Start ==================
My Name is Kazuhira!!

Say, [Hello Template Engine!!]

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


My Name is ${name}!!

Say, [${keyword}]

================== Velocity End ==================

BUILD SUCCESSFUL

Total time: 2.295 secs

ちゃんと、動いてそうですね。