Pergunta

Eu estou usando motor de templates Velocity do Apache, e eu gostaria de criar uma directiva personalizado. Ou seja, eu quero ser capaz de escrever "#doMyThing ()" e tê-lo invocar algum código java que eu escrevi, a fim de gerar o texto.

Eu sei que eu posso registrar uma directiva personalizado, adicionando uma linha

userdirective=my.package.here.MyDirectiveName

para o meu arquivo velocity.properties. E eu sei que eu posso escrever uma classe estendendo o classe directiva. O que eu não sei é como para estender a classe Directiva - algum tipo de documentação para o autor de uma nova directiva. Por exemplo, eu gostaria de saber se o meu getType () método de retorno "BLOCK" ou "LINE" e eu gostaria de saber o que deve o meu método setLocation () deve fazer?

Existe alguma documentação lá fora, que é melhor do que apenas " Use a fonte , Lucas "?

Foi útil?

Solução

Eu coloquei um pouco artigo sobre como escrever directivas velocidade costume (e ferramentas). Talvez alguém vai encontrá-lo útil.

Outras dicas

No wiki Velocity, há uma apresentação e código de exemplo a partir de uma palestra que dei chamado de " Hacking Velocity ". Ele inclui um exemplo de uma directiva personalizado.

Também estava tentando chegar a uma directiva personalizado. Não foi possível encontrar qualquer documentação em tudo, então eu olhei para algumas directivas usuário criado: IfNullDirective ( agradável e fácil um), MergeDirective , bem como velocidade de build-in directivas.

Aqui está o meu directiva bloco simples que retorna conteúdo (projeto completo comprimido com algumas instruções de instalação directiva está localizado aqui ):

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;

    }

}
directivas

Bloco sempre aceitar um corpo e deve terminar com #end quando usado em um modelo. por exemplo. #foreach ($ i in $ foo), este tem um corpo! #end

directivas

Linha não tem um corpo ou um #end. por exemplo. #parse ( 'foo.vtl')

Você não precisa ambos com setLocation () em tudo. Os usos do analisador isso.

quaisquer outros detalhes que eu possa ajudar?

Além disso, você já pensou em usar uma abordagem "ferramenta"? Mesmo se você não usar VelocityTools para automaticamente fazer a sua ferramenta disponível e outros enfeites, você pode simplesmente criar uma classe ferramenta que faz o que você quer, colocá-lo no contexto e quer ter um método que você chama para gerar conteúdo, ou então apenas tem a sua toString () método de gerar o conteúdo. por exemplo. $ Tool.doMyThing () ou apenas US $ MYTHing

directivas são os melhores para quando você precisa para mexer com internos Velocity (acesso a InternalContextAdapter ou Nodes reais).

Antes de v1.6 velocidade Eu tinha um #blockset ($ v) directiva #end para ser capaz de lidar com uma #set multilinha ($ v), mas esta função agora é tratada pela directiva #define. directivas bloco personalizado são uma dor com IDEs modernas porque não analisar a estrutura corretamente, assumindo que o seu #end associado com #userBlockDirective é um extra e pinta o arquivo inteiro RED. Eles devem ser evitados se possível.

Copiei algo semelhante a partir do código-fonte de velocidade e criou uma directiva (multiline) "blockset".

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

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

public class BlockSetDirective extends Directive {
    private String blockKey;

    /**
     * Return name of this directive.
     */
    public String getName() {
        return "blockset";
    }

    /**
     * Return type of this directive.
     */
    public int getType() {
        return BLOCK;
    }

    /**
     * simple init - get the blockKey
     */
    public void init( RuntimeServices rs, InternalContextAdapter context,
                      Node node )
        throws TemplateInitException {
        super.init( rs, context, node );
        /*
         * first token is the name of the block. I don't even check the format,
         * just assume it looks like this: $block_name. Should check if it has
         * a '$' or not like macros.
         */
        blockKey = node.jjtGetChild( 0 ).getFirstToken().image.substring( 1 );
    }

    /**
     * Renders node to internal string writer and stores in the context at the
     * specified context variable
     */
    public boolean render( InternalContextAdapter context, Writer writer,
                           Node node )
        throws IOException, MethodInvocationException,
        ResourceNotFoundException, ParseErrorException {
        StringWriter sw = new StringWriter(256);
        boolean b = node.jjtGetChild( 1 ).render( context, sw );
        context.put( blockKey, sw.toString() );
        return b;
    }

}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top