一、背景现象
为了支持灵活的、可自定义的脱敏规则,工程拟采用velocity实现该目的,为此,自定义了:
mask、substr两个指令,其中
mask实现
public class MaskDirective extendsDirective {
@OverridepublicString getName() {return "mask";
}
@Overridepublic intgetType() {returnLINE;
}
@Overridepublic boolean render(InternalContextAdapter ctx, Writer writer, Node node) throwsIOException, 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= newStringBuilder();for(int i = 0; i < count; i++) {
buff.append(maskChar);
}
writer.write(buff.toString());return true;
}
}
substr实现
public class SubstrDirective extendsDirective {
@OverridepublicString getName() {return "substr";
}
@Overridepublic intgetType() {returnLINE;
}
@Overridepublic boolean render(InternalContextAdapter ctx, Writer writer, Node node) throwsIOException, 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= newStringBuilder();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 classVelocityHelper {private SetuserExtDirective ;private final static String K_USERDIRECTIVE = "userdirective";private final static VelocityHelper VH = newVelocityHelper();privateVelocityHelper(){
}public static finalVelocityHelper getInstance(){returnVH;
}/*** 初始化*/
public void init() throwsException{
Properties prop= newProperties();
StringBuilder buff= newStringBuilder();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");
}/*** 根据报文模板和VelocityContext
,渲染出实际的业务报文
*
*@paramcontext 业务上下文信息
*@paramtemplate 模板
*@return*@throwsIOException*/
public String evaluate(String template, final VelocityContext context) throwsIOException {
Writer writer= newStringWriter();try{
Velocity.evaluate(context, writer, StringUtil.EMPTY_STRING, template);returnwriter.toString();
}finally{
IOUtils.closeQuietly(writer);
}
}/***
*@paramuserExtDirective
**/
public void setUserExtDirective(SetuserExtDirective){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= newVelocityEngine(prop);
velocityEngine.evaluate(context, writer, StringUtil.EMPTY_STRING, template);
原文:https://www.cnblogs.com/frazeworld/p/10347496.html