PebbleTemplates 自定义tag&filter&function 开发简单说明

PebbleTemplates 的扩展能力还是很强大的,开发起来也比较方便,以下是一个简单的说明,更加复杂的推荐查看官方源码学习

filter 开发

  • 参考代码
    此filter 直接返回rongfengliang
 
public class LoginFilter implements Filter {
    public LoginFilter() {
    }
    @Override
    public Object apply(Object input, Map<String, Object> args, PebbleTemplate self, EvaluationContext context, int lineNumber) throws PebbleException {
        return  "rongfengliang";
    }
 
    @Override
    public List<String> getArgumentNames() {
        return null;
    }
}

function 开发

  • 参考代码
    一个输入参数返回
 
public class MyFunction implements Function {
    private final List<String> argumentNames = new ArrayList<>();
    public MyFunction() {
        this.argumentNames.add("name");
    }
    @Override
    public Object execute(Map<String, Object> args, PebbleTemplate self, EvaluationContext context, int lineNumber) {
        String name = (String) args.get("name");
        return  name;
    }
 
    @Override
    public List<String> getArgumentNames() {
      return this.argumentNames;
    }
}

tag 开发

tag 相对比较复杂,包含了tag 解析树,tag node 处理,tag node 对应业务处理,以下是一个简单的include包装,代码部分服用了现有include 的处理

  • 参考代码
    token 处理,对应tag 名称为rongfengliang
 
public class MyTokenParser implements TokenParser {
    @Override
    public String getTag() {
        return "rongfengliang";
    }
 
    @Override
    public RenderableNode parse(Token token, Parser parser) {
        TokenStream stream = parser.getStream();
        int lineNumber = token.getLineNumber();
        // skip over the 'include' token
        stream.next();
        Expression<?> includeExpression = parser.getExpressionParser().parseExpression();
        stream.expect(Token.Type.EXECUTE_END);
        return new MyIncludeNode(lineNumber, includeExpression);
    }
}

MyIncludeNode node 处理

public class MyIncludeNode extends AbstractRenderableNode {
    private final Expression<?> includeExpression;
 
 
    public MyIncludeNode(int lineNumber, Expression<?> includeExpression) {
        super(lineNumber);
        this.includeExpression = includeExpression;
    }
 
    @Override
    public void render(PebbleTemplateImpl self, Writer writer, EvaluationContextImpl context)
            throws IOException {
        String templateName = (String) this.includeExpression.evaluate(self, context);
        Map<?, ?> map = Collections.emptyMap();
        if (templateName == null) {
            throw new PebbleException(
                    null,
                    "The template name in an include tag evaluated to NULL. If the template name is static, make sure to wrap it in quotes.",
                    this.getLineNumber(), self.getName());
        }
       // 此处代码复用了include 部分的,需要进行include 模版的处理
        self.includeTemplate(writer, context, templateName, map);
    }
 
    @Override
    public void accept(NodeVisitor visitor) {
        visitor.visit(this);
    }
 
    public Expression<?> getIncludeExpression() {
        return this.includeExpression;
    }
 
}

扩展开发

PebbleTemplates 提供了一个方便的扩展点,可以方便进行扩展的注册,实现AbstractExtension 就可以了

  • 参考代码
public class MyExtension extends AbstractExtension {
 
    @Override
    public Map<String, Filter> getFilters() {
        Map<String, Filter> filters = new HashMap<>();
        filters.put("rongfengliang",new LoginFilter());
        return  filters;
    }
 
    @Override
    public List<TokenParser> getTokenParsers() {
        List<TokenParser> parsers = new ArrayList<>();
        parsers.add(new MyTokenParser());
        return parsers;
    }
 
    @Override
    public Map<String, Function> getFunctions() {
        Map<String, Function> functionMap = new HashMap<>();
        functionMap.put("rongfengliang",new MyFunction());
        return  functionMap;
    }
}

注册扩展

PebbleTemplates 提供了比较方便的扩展注册方法,很简洁

  • 参考代码
MinioClient minioClient =
                MinioClient.builder()
                        .endpoint("http://127.0.0.1:9000")
                        .credentials("minio", "minio123")
                        .build();
DelegatingLoader delegatingLoader = new DelegatingLoader(Arrays.asList(new S3Loader(minioClient,"demoapp")));
// 初始化PebbleEngine, 并进行扩展的注册
PebbleEngine engine = new PebbleEngine.Builder().loader(delegatingLoader).extension(new MyExtension()).build();
PebbleTemplate compiledTemplate = engine.getTemplate("home.html");
Map<String, Object> context = new HashMap<>();
context.put("name", "Mitchell");
Writer writer = new StringWriter();
compiledTemplate.evaluate(writer, context);
String output = writer.toString();
System.out.println(output);

使用

  • 参考模版
// rongfengliang tag 使用
{%  rongfengliang "100/footer.html" %}
// rongfengliang 函数使用
this is demo  {{ rongfengliang('dalongdemoapp') }}
// filter 使用
 <div> {{ "demoapp" | rongfengliang }} <div>

说明

以上代码都放GitHub 上了,具体可以参考github ,PebbleTemplate实现提供的一些能力参考如下类图

 

 

参考资料

https://github.com/PebbleTemplates/pebble
https://pebbletemplates.io/
https://github.com/rongfengliang/pebbletemplates-learning.git

posted on 2023-03-16 20:14  荣锋亮  阅读(33)  评论(0编辑  收藏  举报

导航