java 如何把vm模板渲染成并执行
场景:
1、告警模板:采用vm定义模板内容,传入告警上下文动态执行
实现:
直接调用 SelfTemplateEngine#generateByObj(java.lang.String, java.util.Map
public final class SelfTemplateEngine extends VelocityEngine {
/** logger*/
private static final Logger logger = LoggerFactory.getLogger(SelfTemplateEngine.class);
/** 模板引擎自身对象*/
private static SelfTemplateEngine engine = new SelfTemplateEngine();
/**
* 私有构造
*/
private SelfTemplateEngine() {
initVe();
}
/** 获取当前实例 */
private static SelfTemplateEngine getInstance() {
return engine;
}
/***
* Velocity模板引擎 初始化
*/
private void initVe() {
Properties p = new Properties();
String charset = System.getProperty("file.encoding");
if (null == charset) {
charset = "GBK";
}
p.put("input.encoding", charset);
p.put("output.encoding", "UTF-8");
p.put("resource.loader", "srl");
/**
velocimacro.permissions.allow.inline.to.replace.global参数含义
允许标明是否允许在常规模板内定义的Velocimacro代替在模板库中定义并通过velocimacro.library属性在启动时装入的全局宏。默认设置为false。
参考:https://wizardforcel.gitbooks.io/velocity-doc/content/31.html
*/
// 注意这里必须put 字符串"true",而不是 boolean类型,否则会空指针异常。
p.put("velocimacro.permissions.allow.inline.to.replace.global", "true");
//p.put("velocimacro.permissions.allow.inline.local.scope", true);
//p.put("velocimacro.library.autoreload", true);
//p.put("file.resource.loader.cache", true);
//p.put("velocity.engine.resource.manager.cache.enabled", false);
p.put("srl.resource.loader.class", "com.alipay.lego.util.velocity.loader.SelfDefinedResourceLoader");
p.put(
"userdirective",
"com.alipay.lego.util.velocity.directive.DateFromatDirective,com.alipay.lego.util.velocity.directive.StringFormatDirective,com.alipay.lego.util.velocity.directive.URLFormatDirective,com.alipay.lego.util.velocity.directive.StringArrConcatDirective");
try {
LoggerUtil.info(logger, "DynamicTemplateEngine初始化开始。。。");
super.init(p);
} catch (Exception e) {
LoggerUtil.error(logger, "DynamicTemplateEngine初始化出错:自定义Velocity模板解析引擎初始化失败", e);
}
}
/**
* 根据动态模板内容和传入的k-v map生产最终内容
*
* @param vmContent 动态模板内容
* @param paramMap k-v map
* @return 最终内容字符串: 如果转换出错,返回null
*/
public static String generate(String vmContent, Map<String, String> paramMap) {
try {
SelfTemplateEngine engine = getInstance();
Template template = engine.getTemplate(vmContent);
VelocityContext context = new VelocityContext();
if (!CollectionUtils.isEmpty(paramMap)) {
Iterator<String> iterator = paramMap.keySet().iterator();
while (iterator.hasNext()) {
String keyName = iterator.next().toString();
context.put(keyName, paramMap.get(keyName));
}
StringWriter writer = new StringWriter();
template.merge(context, writer);
return writer.toString();
}
} catch (Exception e) {
logger.error("SelfTemplateEngine动态模板替换失败", e);
}
return null;
}
/**
* 根据动态模板内容和传入的k-v map生产最终内容
*
* @param tempalteContent 动态模板内容
* @param paramMap k-v map
* @return 最终内容字符串: 如果转换出错,返回null
*/
public static String generateByObj(String tempalteContent, Map<String, Object> paramMap) {
try {
SelfTemplateEngine engine = getInstance();
Template template = engine.getTemplate(tempalteContent);
VelocityContext context = new VelocityContext();
if (!CollectionUtils.isEmpty(paramMap)) {
Iterator<String> iterator = paramMap.keySet().iterator();
while (iterator.hasNext()) {
String keyName = iterator.next().toString();
context.put(keyName, paramMap.get(keyName));
}
StringWriter writer = new StringWriter();
template.merge(context, writer);
return writer.toString();
}
} catch (Exception e) {
logger.error("SelfTemplateEngine动态模板替换失败,tempalteContent=" + tempalteContent, e);
}
return null;
}
/**
* 根据动态模板内容和传入的Object生产最终内容
*
* @param tempalteContent 动态模板内容:注意模板中的占位key需要增加“ctx.”前缀
* @param paramObj 参数对象
* @return 最终内容字符串: 如果转换出错,返回null
*/
public static String generateByObj(String tempalteContent, Object paramObj) {
try {
SelfTemplateEngine engine = getInstance();
Template template = engine.getTemplate(tempalteContent);
VelocityContext context = new VelocityContext();
if (null != paramObj) {
StringWriter writer = new StringWriter();
context.put("ctx", paramObj);
template.merge(context, writer);
return writer.toString();
}
} catch (Exception e) {
logger.error("SelfTemplateEngine动态模板替换失败,tempalteContent=" + tempalteContent, e);
}
return null;
}
}
模板缓存问题(被一个技术问题阻塞了怎么办)
提升自己的技术自信
今天碰到一个技术问题搞了一下午。
【问题描述】
采用velocity模板时,macro宏定义函数具有缓存。导致更新模板中的函数体之后,没有立即生效。
【解决方式】
init时增加参数设置:velocimacro.permissions.allow.inline.to.replace.global=true
详见volecity中文文档:https://wizardforcel.gitbooks.io/velocity-doc/content/31.html
问题的阻塞点主要还不在这里,而在于设置这个参数的时候抛了空指针。
Properties p = new Properties();
p.put("velocimacro.permissions.allow.inline.to.replace.global", "true");
注意这里必须put 字符串”true”,而不是 boolean类型,否则会空指针异常。
其实定位这个空指针异常非常简单,只是debug多走一步就可以了。但自己总是觉得一旦debug到第三方库里面的逻辑,对自己而言就很难排查了,最终放弃,求助他人。
所以,建立自己的技术自信,靠自己多花点儿时间解决一个问题,值得。
这里也有一个点要注意,工作过程中一旦花较长时间解决一个问题就会焦躁
引用小狗钱钱里的一句话,其实说的是一个道理
吉娅,你真的认真找过工作了吗?我是说,你有没有用一整个下午的时间来考虑如何挣到钱的问题呢?”
我不得不承认,我考虑这个问题的时间加起来甚至还不到一个小时。其实每次想这件事,我总是很快就认定自己是不会有机会的
其他踩坑记录
vm最后一行不能是注释? 遇到报错,解析有问题。