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最后一行不能是注释? 遇到报错,解析有问题。
