6

ApacheのVelocityテンプレートエンジンを使用していますが、カスタムディレクティブを作成したいと思います。つまり、「#doMyThing()」を記述して、テキストを生成するために記述したJavaコードを呼び出せるようにしたいのです。

行を追加することでカスタムディレクティブを登録できることを知っています

userdirective=my.package.here.MyDirectiveName

私のvelocity.propertiesファイルに。そして、 Directiveクラスを拡張することで、そのようなクラスを記述できることを知っています。私が知らないのは、ディレクティブクラスを拡張する方法です。これは、新しいディレクティブの作成者向けのある種のドキュメントです。たとえば、getType()メソッドが「BLOCK」または「LINE」を返すかどうかを知りたいのですが、setLocation()メソッドは何をすべきか知りたいのですが。

「ソースを使用してください、ルーク」よりも優れたドキュメントはありますか?

4

5 に答える 5

8

カスタムの速度ディレクティブ (およびツール) の作成に関する短い記事をまとめました。多分誰かがそれが役に立つと思うでしょう。

于 2009-09-10T18:57:51.333 に答える
4

Velocity wiki には、私が行った " Hacking Velocity "という講演のプレゼンテーションとサンプル コードがあります。カスタム ディレクティブの例が含まれています。

于 2009-08-09T16:20:06.067 に答える
4

また、カスタム ディレクティブを考え出そうとしていました。ドキュメントがまったく見つからなかったので、ユーザーが作成したディレクティブをいくつか調べました。

圧縮されたコンテンツを返す単純なブロック ディレクティブを次に示します (ディレクティブのインストール手順を含む完全なプロジェクトは、ここにあります)。

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

import org.apache.velocity.context.InternalContextAdapter;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.exception.TemplateInitException;
import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.runtime.directive.Directive;
import org.apache.velocity.runtime.parser.node.Node;
import org.apache.velocity.runtime.log.Log;

import com.googlecode.htmlcompressor.compressor.HtmlCompressor;

/**
 * Velocity directive that compresses an HTML content within #compressHtml ... #end block.
 */
public class HtmlCompressorDirective extends Directive {

    private static final HtmlCompressor htmlCompressor = new HtmlCompressor();

    private Log log;

    public String getName() {
        return "compressHtml";
    }

    public int getType() {
        return BLOCK;
    }

    @Override
    public void init(RuntimeServices rs, InternalContextAdapter context, Node node) throws TemplateInitException {
        super.init(rs, context, node);
        log = rs.getLog();

        //set compressor properties
        htmlCompressor.setEnabled(rs.getBoolean("userdirective.compressHtml.enabled", true));
        htmlCompressor.setRemoveComments(rs.getBoolean("userdirective.compressHtml.removeComments", true));
    }

    public boolean render(InternalContextAdapter context, Writer writer, Node node) 
            throws IOException, ResourceNotFoundException, ParseErrorException, MethodInvocationException {

        //render content to a variable
        StringWriter content = new StringWriter();
        node.jjtGetChild(0).render(context, content);

        //compress
        try {
            writer.write(htmlCompressor.compress(content.toString()));
        } catch (Exception e) {
            writer.write(content.toString());
            String msg = "Failed to compress content: "+content.toString();
            log.error(msg, e);
            throw new RuntimeException(msg, e);

        }
        return true;

    }

}
于 2009-07-09T20:47:55.913 に答える
2

ブロック ディレクティブは常に本文を受け入れ、テンプレートで使用する場合は #end で終了する必要があります。例 #foreach( $i in $foo ) これには本体があります! #終わり

行ディレクティブには本体も #end もありません。例 #parse( 'foo.vtl' )

setLocation() で両方を行う必要はまったくありません。パーサーはそれを使用します。

私が助けることができる他の詳細はありますか?

また、「ツール」アプローチの使用を検討しましたか? ツールを自動的に利用可能にするために VelocityTools を使用しない場合でも、必要なことを実行するツール クラスを作成し、それをコンテキストに配置して、コンテンツを生成するために呼び出すメソッドを用意するか、または単にtoString() メソッドでコンテンツを生成します。例: $tool.doMyThing() または単に $myThing

ディレクティブは、Velocity 内部 (InternalContextAdapter または実際のノードへのアクセス) をいじる必要がある場合に最適です。

于 2008-10-17T22:52:59.723 に答える