工作中我们经常会遇到这样的需求:
1.发送一段消息并在web前端展示(例如工作台就是一个很好的场景)
solution 1:
String message="xx"; sender.send(message);
这个方法第一个硬伤,如果xx包含中文或者其他字符呢?
前端看到的内容可能会出现乱码。
第二个问题,如果message内容更很长,代码的可读性就变得很差了。
solution 2:
String message=MessageResultCode.SHORT_MESSAGE.getMessage(); sender.send(message);
既然有中文的问题,我们就使用配置文件,ResultCode可以帮助我们解决这个问题,虽然如果内容长了配置文件
会有些难看,但也还可以接受。甚至如果内容含有样式,链接,等等,我们也可以通过CDATA来解决。
这个方法暂时看起来不错,不过pd似乎不让我们这么容易的完成任务。“那么我想在消息里显示下链路信息,比如链路名”。这个需求很合理,但是我们的solution 2似乎办不到。
solution 3:
我们知道webx3使用了velocity作为模板渲染引擎,所以何不把消息像velocity模板一样的渲染出来
String template="message.vm"; TemplateContext context = new MappedTemplateContext(); context.put("link", link); context.put("chain", chain); //merge模板 String message = templateService.getText(template, context); sender.send(message);
代码其实很简单,新建一个模板,把所有变量放到context中去,再使用templateService渲染出来。
我们看看供应链服务一个任务模板的例子:
请审核供应链<a href="$!{link}">[$!{chain.name}]</a>编号[$!{chain.id}]-商家[$!{chain.supplierName}]-商品[$!{chain.productTitle}]
那么template路径到底怎么指定呢?这是一个问题。在回答这个问题之前我们看看templateService是如何配置的
<services:template xmlns="http://www.alibaba.com/schema/services/template/engines" searchExtensions="true"> <velocity-engine templateEncoding="UTF-8" strictReference="false" path="/templates/${component}"> <global-macros> <name>macros.vm</name> </global-macros> <plugins> <vm-plugins:fasttext-support /> <vm-plugins:renderable-support /> </plugins> </velocity-engine> </services:template>
事实上templateService 在渲染vm模板的时候使用velocity引擎来完成的
我们看看templateService实现类的这个方法
private boolean findTemplateInTemplateEngine(TemplateMatcher matcher) { TemplateEngine engine = getTemplateEngine(matcher.getExtension()); matcher.setEngine(engine); if (engine == null) { return false; } String templateName = matcher.getTemplateName(); getLogger().trace("Searching for template \"{}\" using {}", templateName, engine); return engine.exists(templateName); }
所以路径如何设置取决 于TemplateEngine 的path参数。我们看到path="/templates/${component}",${component}这个变量是webx3
给每个子容器的名字,例如供应链服务叫chain。我们看下pipeline的配置
<when> <pl-conditions:target-extension-condition extension="null, vm, jsp" /> <performAction /> <performTemplateScreen /> <renderTemplate /> </when>
renderTemplate这个valve也是使用templateService来渲染模板。
例如输入的模板名叫screen/detail.vm
那么 templateService就会找/template/chain/screen/detail.vm这个文件。
webx3的资源加载使用ResourceLoadingService
而由于resources.xml文件里有如下配置
<resource pattern="/templates"> <res-loaders:file-loader basedir="${alibaba_lp_lpscm_templates}" /> </resource>
因此这个地址也就变成了${alibaba_lp_lpscm_templates}/template/chain/screen/detail.vm,
${alibaba_lp_lpscm_templates}是我们antx文件里配置的模板路径。
这个工作原理适用于web层的东西,biz层使用templateService稍微有点区别,
因为biz层使用了root容器的templateService因此,$component 的值取决于这段配置
<services:property-placeholder> <services:property key="component">common</services:property> </services:property-placeholder>
因此刚刚那个例子,我们需要把文件放在 ${alibaba_lp_lpscm_templates}/template/common/message.vm.
当然你也可以修改配置以改变模板的位置,例如把common改成message
<services:property-placeholder> <services:property key="component">message</services:property> </services:property-placeholder>
那么文件需要放在 ${alibaba_lp_lpscm_templates}/template/mesage/message.vm.
结束语
pd说:“我想要显示下链路的创建时间,这个需要多少时间"
开发说:"没问题,修改的话两分钟就够!"