一、背景现象

为了支持灵活的、可自定义的脱敏规则,工程拟采用velocity实现该目的,为此,自定义了:

  • mask、substr两个指令,其中
  • mask实现
public class MaskDirective extends Directive {

    @Override
public String getName() {
return "mask";
} @Override
public int getType() {
return LINE;
} @Override
public boolean render(InternalContextAdapter ctx, Writer writer, Node node) throws IOException, ResourceNotFoundException, ParseErrorException, MethodInvocationException { //fieldName
SimpleNode snField = (SimpleNode) node.jjtGetChild(0); String maskChar = (String)snField.value(ctx); snField = (SimpleNode) node.jjtGetChild(1);
int count = (int)snField.value(ctx); StringBuilder buff = new StringBuilder(); for(int i = 0; i < count; i++) {
buff.append(maskChar);
} writer.write(buff.toString()); return true; }
}
  • substr实现
public class SubstrDirective extends Directive {

    @Override
public String getName() {
return "substr";
} @Override
public int getType() {
return LINE;
} @Override
public boolean render(InternalContextAdapter ctx, Writer writer, Node node) throws IOException, ResourceNotFoundException, ParseErrorException, MethodInvocationException { //fieldName
SimpleNode snField = (SimpleNode) node.jjtGetChild(0); String fieldValue = (String)snField.value(ctx); if(fieldValue == null || fieldValue.length() == 0){
return false;
} int items = node.jjtGetNumChildren(); int startIdx = Integer.MIN_VALUE;
int endIdx = fieldValue.length(); if(items < 1){
return false;
} try{ snField = (SimpleNode) node.jjtGetChild(1);
startIdx = (int)snField.value(ctx); if(items > 2){
snField = (SimpleNode) node.jjtGetChild(2);
endIdx = (int)snField.value(ctx); if(endIdx > fieldValue.length()){
endIdx = fieldValue.length();
} } if(startIdx >= endIdx){
return false;
} StringBuilder buff = new StringBuilder(); if(items > 2){
writer.write(fieldValue.substring(startIdx,endIdx));
}else{ if(startIdx < 0){
startIdx = startIdx + fieldValue.length();
} writer.write(fieldValue.substring(startIdx));
} return true; }catch(Exception e){
return false;
}
}
}
  • velocity初始化方法:
public final class VelocityHelper {

    private Set<String> userExtDirective ;
private final static String K_USERDIRECTIVE = "userdirective"; private final static VelocityHelper VH = new VelocityHelper();
private VelocityHelper(){ } public static final VelocityHelper getInstance(){
return VH;
} /**
* 初始化
*/
public void init() throws Exception{ Properties prop = new Properties(); StringBuilder buff = new StringBuilder(); for(String s : userExtDirective){
buff.append(s.trim()).append(",");
} LogHelper.trace("start VelocityHelper.init[" + buff.toString() + "]"); prop.setProperty(K_USERDIRECTIVE, buff.toString().substring(0, buff.length()-1));
Velocity.init(prop); LogHelper.trace("end VelocityHelper.init"); } /**
* 根据报文模板和<code>VelocityContext</code>,渲染出实际的业务报文
*
* @param context 业务上下文信息
* @param template 模板
* @return
* @throws IOException
*/
public String evaluate(String template, final VelocityContext context) throws IOException {
Writer writer = new StringWriter();
try {
Velocity.evaluate(context, writer, StringUtil.EMPTY_STRING, template);
return writer.toString();
} finally {
IOUtils.closeQuietly(writer);
}
} /**
*
* @param userExtDirective
*
*/
public void setUserExtDirective(Set<String> userExtDirective){ this.userExtDirective = userExtDirective;
} }

部署到服务器后,以下表达式始终未得到替换:#substr($maskField, 0, 3)#mask('*', 4)#substr($maskField, -4) 

二、原因分析

开始怀疑是配置等问题,经过以下方法尝试均为解决问题:

1、怀疑spring xml配置问题----未解决

2、硬编码指令,在构造函数塞入指令----未解决

无奈,登录服务器grep velocity 得到了以下的输出(其中之一),茅塞顿开。

2019-02-02 07:49:52,315 [  - /// - ] INFO  assemble.VMRender - resource=class path resource [velocity/velocity.properties]

Velocity.ini及Velocity.evalute均是全局单一模式,既然有人捷足先登,自然不在做第二次初始化。

三、解决方案

采用VelocityEngine替换Velocity,实现jar包间隔离,独立管理自己的资源。

private VelocityEngine velocityEngine = null;
velocityEngine = new VelocityEngine(prop);
velocityEngine.evaluate(context, writer, StringUtil.EMPTY_STRING, template);

velocity自定义指令不生效问题解决之旅的更多相关文章

  1. vue自定义指令导致的内存泄漏问题解决

    vue的自定义指令是一个比较容易引起内存泄漏的地方,原因就在于指令通常给元素绑定了事件,但是如果忘记了解绑,就会产生内存泄漏的问题. 看下面代码: directives: { scroll: { in ...

  2. android中ListView点击和里边按钮点击不能同时生效问题解决

    今天遇到一个问题:android中ListView点击和里边button点击不能同时生效问题解决. 原因是: listView 在开始绘制的时候,系统首先调用getCount()函数,根据他的返回值得 ...

  3. Angularjs进阶笔记(2)-自定义指令中的数据绑定

    有关自定义指令的scope参数,网上很多文章都在讲这3种绑定方式实现的效果是什么,但几乎没有人讲到底怎么使用,本篇希望聊聊到底怎么用这个话题. 一. 自定义指令 自定义指令,是Angularjs用来实 ...

  4. 浅析AngularJS自定义指令之嵌入(transclude)

    AngularJS自定义指令的嵌入功能与vue的插槽十分类似,都可以实现一些自定义内容展现.在开始之前先简单介绍下自定义指令的transclude属性和AngularJS的内置指令ng-transcl ...

  5. 从零开始学 Web 之 Vue.js(二)过滤器,按键修饰符,自定义指令

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...

  6. angular自定义指令命名的那个坑

    Directive 先从定义一个简单的指令开始. 定义一个指令本质上是在HTML中通过元素.属性.类或注释来添加功能.AngularJS的内置指令都是以ng开头,如果想自定义指令,建议自定义一个前缀代 ...

  7. 移动端H5长按事件 vue自定义指令

    import Vue from 'vue' Vue.directive('longpress', function (el, binding){ var timer = null; var start ...

  8. vue 自定义指令的魅力

    [第1103期]vue 自定义指令的魅力 点点 前端早读课 2017-11-08 前言 很多事情不能做过多的计划,因为计划赶不上变化.今日早读文章由富途@点点翻译分享. 正文从这开始- 在你初次接触一 ...

  9. vue之自定义指令

    1.自定义指令的作用 除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令.注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件.然而,有的情况下,你仍 ...

随机推荐

  1. linux下目录简介——/proc

    1. /proc目录Linux 内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构.改变内核设置的机制.proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间.它以文 ...

  2. JSON数据、PHP数组 转换 Excel表格

    //excel输出 header("Content-type:application/vnd.ms-excel"); header("Content-Dispositio ...

  3. KiCad 一款强大的 BOM 和 装配图生成插件

    KiCad 一款强大的 BOM 和 装配图生成插件 可以生成 BOM 和在线的图形. https://github.com/openscopeproject/InteractiveHtmlBom In ...

  4. Taro 代码及功能,需要注意的地方

    Taro 代码不能使用的写法: 请注意无 AppID 关联下,调用 wx.operateWXData 是受限的, API 的返回是工具的模拟返回

  5. oracle报错 ORA-02290: 违反检查约束条件问题

    场景: 使用plsql/developer 将原本要求非空的字段   改为可以为空 然后在插入数据的时候 报错改字段约束条件还起作用 解决方案: 首先查询该表的约束条件 select * from u ...

  6. 关闭防火墙,selinux,交互式设置IP的脚本

    脚本内容: #!/bin/bash # ens=$(cat /proc/net/dev | awk '{if($2>0 && NR > 2) print substr($1 ...

  7. Spring Cloud Alibaba正式入驻Spring Cloud官方孵化器

    第一个版本发布内容如下: 开源组件(spring-cloud-alibaba开头): 服务发现(Service Discovery) 配置管理(Configuration Management) 高可 ...

  8. verilog中24LC04B iic(i2c)读写通信设计步骤,以及程序常见写法错误。

    板子使用的是黑金的是xilinx spartan-6开发板,首先准备一份24LC04B芯片资料,读懂资料后列出关键参数. 如下: 1.空闲状态为SDA和SCL都为高电平 2.开始状态为:保持SCL,S ...

  9. 用EM4305/T5557模拟EM4100的ID卡,原理解释

    用EM4305/T5557模拟EM4100,原理解释 来源: https://www.cnblogs.com/osnosn/p/10593297.html 来自osnosn的博客 写于: 2019-0 ...

  10. MapReduce作业的工作原理

    在Hadoop中,我们可以通过Job对象的submit()方法来运行MapReduce作业,也可以调用waitForCompletion()用于提交以前没有提交过的作业,并等待它的完成.其中,subm ...