Apache Velocity是一个用于简化Java应用程序开发的开源模板引擎。它允许开发人员使用模板文件来生成文本文件,例如HTML网页、XML文件、邮件、SQL语句等。Velocity模板文件包含静态文本和用于填充数据的变量、条件语句和循环语句等。
目前Apache Velocity最新的版本为 2.3
,最后更新时间为2021年3月7日。目前已经停止维护。
1 2 3 4 5 6
| <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.3</version> </dependency>
|
Apache Velocity中引用变量的几种方式
${var}
$var
$!{var}
$!var
提取变量
以下面这个模板为例:
1
| #if($todoType == 1)aa#{else}bb#end 和 ${okk} $name ${serviceData.key} $!serviceData.value #userName($serviceData.operationManager)
|
此模板中使用了多种变量引用方式,还包含了条件判断和指令的使用。涵盖了模板使用的大部分场景。
其中 #userName
为一个自定义指令。
具体实现代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| @Slf4j public class VelocityVariableExtractor { private static final RuntimeInstance RI = new RuntimeInstance();
private VelocityVariableExtractor() { }
public static Set<String> extractVariables(String templateContent) { try { Template template = new Template(); StringReader reader = new StringReader(templateContent); SimpleNode node = RI.parse(reader, template); VariableExtractingVisitor visitor = new VariableExtractingVisitor(); node.jjtAccept(visitor, null); return visitor.getVariables(); } catch (ParseException e) { log.error(e.getMessage(), e); return Collections.emptySet(); } }
@Getter private static class VariableExtractingVisitor extends BaseVisitor { private final Set<String> variables = new HashSet<>();
@Override public Object visit(ASTReference node, Object data) { variables.add(node.literal()); return super.visit(node, data); } }
}
|
这里用到了访问这模式。访问者的结构如下:
ParserVisitor
提供了很多访问方法,这里我们只用Object visit(ASTReference node, Object data);
这个方法。ASTReference
就是引用节点的类型,在遍历模板节点时所有引用类型的节点都会经过这个方法。
使用
1 2 3 4 5 6 7 8
| public class Main {
public static void main(String[] args) { String tpl = "#if($todoType == 1)aa#{else}bb#end 和 ${okk} $name ${serviceData.key} $!serviceData.value #userName($serviceData.operationManager)"; Set<String> vars = VelocityVariableExtractor.extractVariables(tpl); System.out.println(StringUtils.join(vars, ",")); } }
|
输出结果
1
| $todoType,$name,${okk},${serviceData.key},$serviceData.operationManager,$!serviceData.value
|
去掉变量中的表达式前缀和后缀
从上面的结果中可以看出,提取的变量中都带了表达式的前缀和后缀。现在只需要对 VariableExtractingVisitor
稍作修改即可去掉这些前后缀。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| @Getter private static class VariableExtractingVisitor extends BaseVisitor { private final Set<String> variables = new HashSet<>();
@Override public Object visit(ASTReference node, Object data) { String varStr = tripIdentifier(node.literal()); if (!isFunction(varStr)) { variables.add(varStr); } return super.visit(node, data); }
private static String tripIdentifier(String varStr) { if (varStr.startsWith("$!{")) { return varStr.replace("$!{", "").replace("}", ""); } else if (varStr.startsWith("${")) { return varStr.replace("${", "").replace("}", ""); } else if (varStr.startsWith("$!")) { return varStr.replace("$!", ""); } else { return varStr.replace("$", ""); } }
private static boolean isFunction(String varStr) { return varStr.contains("(") && varStr.contains(")"); } }
|
本例中使用 replace
方法将这些标识替换为空串。
运行结果:
1
| todoType,serviceData.value,name,serviceData.key,okk,serviceData.operationManager
|