1. QLExpress 中使用 stack 解决函数参数个数和参数类型合法性校验错误提示:
如果公式有问题,QLExpress 默认只是报错,并且是很没有规律的原始的错误信息,靠解析错误信息给页面提示不太可行,发现QLExpress 有
一个获取表达式指令集合的 api,是以前缀表达式格式顺序存储的,即假设角标 i 处存储的是一个 两数相加的 函数指令,则 i-1、i-2处存储的就是该加法指令
的两个参数( 如果表达式正确的话 ),只需要定义一个栈,然后遍历 该指令集合,遇到 操作数( 变量 和 常量 ) 指令 就压栈,遇到 函数指令根据 函数的类型决定从 栈顶
弹出 指定个数据,判断函数的类型 和 个数,做出相应错误提示
import com.ql.util.express.InstructionSet;
import com.ql.util.express.OperateData;
import com.ql.util.express.instruction.detail.Instruction;
import com.ql.util.express.instruction.detail.InstructionCallSelfDefineFunction;
import com.ql.util.express.instruction.detail.InstructionConstData;
import com.ql.util.express.instruction.detail.InstructionLoadAttr;
import com.ql.util.express.instruction.detail.InstructionOperator;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Stack;
@Slf4j
@Component
public class FormulaExpressionValidateService {
@Getter
@Setter
public static class MyOperateData {
public static final Double DOUBLE_CONST_VALUE = 1.1d;
public static final Integer INTEGER_CONST_VALUE = 1;
public static final String STRING_CONST_VALUE = "string";
public static final Boolean BOOLEAN_CONST_VALUE = true;
public static final String CONST_VALUE_TYPE_DOUBLE = "double"; // double 类型常量
public static final String CONST_VALUE_TYPE_INTEGER = "integer"; //int类型常量
public static final String CONST_VALUE_TYPE_STRING = "string"; // String类型常量
public static final String CONST_VALUE_TYPE_BOOLEAN = "boolean"; // 布尔类型常量
private String attrName; // dataType 如果是属性名,则 attrName 表示的是 属性名称的值
private String constValueType; //dateType 如果是 常量,则 constValueType 表示的是常量的类型( double、integer、string、boolean )
}
@Autowired
private QLExpressRunner qlExpressRunner;
// todo 检测是否 有 pop 的参数 顺序弄反的地方!!!!
/**
* 校验 表达式是否合法
* @param express
* @return
*/
public String verifyFormulaExpress( String express ){
if( StringUtils.isBlank( express ) ){
return "公式不能为空";
}
InstructionSet instructionSet = this.qlExpressRunner.parseInstructionSet(express);
if( instructionSet == null ){
return null;
}
// 校验每个函数的参数长度是否合法
String illegalMessage = this.verityFunctionArgsSize( instructionSet );
if( illegalMessage != null ){
return illegalMessage;
}
// 校验每个函数的参数类型是否合法
return this.verityFunctionArgsType( instructionSet );
}
private String verityFunctionArgsType(InstructionSet instructionSet) {
// 遇到 属性参数( 比如 LCOE1、PIRR、LCOE ) 和 常量参数( 比如: 1、100、'Y'、'A' )
// 遇到 加减乘除 操作符等
// 遇到自定义函数,从栈顶取出需要的 参数,检测类型,如果类型不对则报错,然后将计算结果压栈( 其实是假计算,压一个和该函数返回值类型相同的样本数据 )
int instructionLength = instructionSet.getInstructionLength();
Stack stack = new Stack<>();
String errorMessage = null;
for( int i = 0;i < instructionLength;i++ ){
Instruction instruction = instructionSet.getInstruction( i );
if( instruction instanceof InstructionLoadAttr){
// 属性名,如 LCOE1
InstructionLoadAttr instructionLoadAttr = (InstructionLoadAttr) instruction;
String attrName = instructionLoadAttr.getAttrName();
MyOperateData myOperateData = new MyOperateData();
myOperateData.setAttrName( attrName );
stack.push( myOperateData );
}else if( instruction instanceof InstructionConstData){
// 常量,如 1,100, 'Y','A','true','false'
InstructionConstData instructionConstData = (InstructionConstData) instruction;
OperateData operateData = instructionConstData.getOperateData();
Class> orgiType = operateData.getOrgiType();// double 字符串 布尔
MyOperateData myOperateData = new MyOperateData();
// todo 测试是否只有这几种类型
if( orgiType == Double.class || orgiType == BigDecimal.class ){
myOperateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_DOUBLE );
}else if( orgiType == Boolean.class ){
myOperateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_BOOLEAN );
}else if( orgiType == String.class ){
myOperateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_STRING );
}else if( orgiType == Integer.class ){
myOperateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_INTEGER );
}
stack.push( myOperateData );
}else if( instruction instanceof InstructionOperator){
InstructionOperator instructionOperator = (InstructionOperator) instruction;
String operatorName = instructionOperator.getOperator().getName();
if( "+".equals( operatorName ) ||
"-".equals( operatorName ) ||
"*".equals( operatorName ) ||
"/".equals( operatorName ) ){
errorMessage = this.validateAddSubMultiDivideOperates( operatorName,stack,"double" );
if( errorMessage == null ){
continue;
}
break;
}
if( ">".equals( operatorName ) ||
">=".equals( operatorName ) ||
"<".equals( operatorName ) ||
"<=".equals( operatorName ) ||
"==".equals( operatorName ) ){
errorMessage = this.validateCompareOperates( operatorName,stack );
if( errorMessage == null ){
continue;
}
break;
}
if( "IF".equals( operatorName ) ){
errorMessage = this.validateIfFunctions( operatorName,stack );
if( errorMessage == null ){
continue;
}
break;
}
if( "AND".equals( operatorName ) ){
try{
Field opDataNumberField = InstructionOperator.class.getDeclaredField("opDataNumber");
opDataNumberField.setAccessible( true );
// 该函数实际传递的参数个数
Integer argSize = (Integer) opDataNumberField.get(instructionOperator);
errorMessage = this.validateAndFunctions( argSize,operatorName,stack );
if( errorMessage == null ){
continue;
}
break;
}catch ( Exception e ){
e.printStackTrace();
return "函数 AND 的参数有问题";
}
}
if( "ROUND_UP".equals( operatorName ) || "ROUND_DOWN".equals( operatorName ) || "ROUND".equals( operatorName ) ){
errorMessage = this.validateRoundUpRoundDownRoundFunctions( operatorName,stack );
if( errorMessage == null ){
continue;
}
break;
}
if( "ABS".equals( operatorName ) || "INT".equals( operatorName ) ){
errorMessage = this.validateAbsIntFunctions( operatorName,stack );
if( errorMessage == null ){
continue;
}
break;
}
if( "MAX".equals( operatorName ) ||
"MIN".equals( operatorName ) ||
"SUM".equals( operatorName ) ||
"AVERAGE".equals( operatorName ) ){
errorMessage = this.validateMaxMinSumAverageFunctions( operatorName,stack );
if( errorMessage == null ){
continue;
}
break;
}
// todo 对于 多个参数的 函数 貌似 参数顺序取反了?????
if( "RANK".equals( operatorName ) ){
errorMessage = this.validateRankFunctions( operatorName,stack );
if( errorMessage == null ){
continue;
}
break;
}
if( "KSMALL".equals( operatorName ) ||
"KLARGE".equals( operatorName ) ){
errorMessage = this.validateKsmallKlargeFunctions( operatorName,stack );
if( errorMessage == null ){
continue;
}
break;
}
}
}
return errorMessage;
}
// 抽取一个 根据函数类型 和 返回值一样的公共方法
/**
* RANK( 三个参数,第一个为数字常量 或者 LCOE PIRR 等规定的几个 数字类型的属性,第二个 为 LCOE1 PIRR1 等规定的几个集合属性,第三个为1/2 )
* @param functionName
* @param stack
* @return
*/
private String validateRankFunctions(String functionName, Stack stack ) {
// 第三个参数必须为 Integer 类型常量
MyOperateData operateData = stack.pop();
String constValueType = operateData.getConstValueType();
if( constValueType == null || !MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) ){
return "函数 " + functionName + " 的第三个参数必须为整数";
}
// 第二个参数必须为 double 集合 类型 属性名
operateData = stack.pop();
String attrName = operateData.getAttrName();
if( attrName == null || !RuleTempServiceImpl.doubleCollectionAttrNames.contains( attrName ) ){
return "函数 " + functionName + " 第二个参数必须为 " + RuleTempServiceImpl.doubleCollectionAttrNames.toString() + " 之一";
}
// 第一个参数必须为 Double 类型常量 或 double 类型属性名
operateData = stack.pop();
attrName = operateData.getAttrName();
if( attrName == null ){
constValueType = operateData.getConstValueType();
if( !( MyOperateData.CONST_VALUE_TYPE_DOUBLE.equals( constValueType ) || MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) ) ){
return "函数 " + functionName + " 第一个参数必须为一个数字 或者 可选属性 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 中的其一";
}
}else {
if( !RuleTempServiceImpl.doubleAttrNames.contains( attrName ) ){
return "函数 " + functionName + " 第一个参数必须为一个数字 或者 可选属性 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 中的其一";
}
}
//压栈一个 Integer 常量
operateData = new MyOperateData();
operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_INTEGER );
stack.push( operateData );
return null;
}
/**
* KSMALL、KLARGE( 2个参数,第一个 为 LCOE1 PIRR1 等规定的几个集合属性,第二个为 数字 )
* @param functionName
* @param stack
* @return
*/
private String validateKsmallKlargeFunctions(String functionName, Stack stack) {
// 第二个参数必须为 Integer 常量
MyOperateData operateData = stack.pop();
String constValueType = operateData.getConstValueType();
if( constValueType == null || !MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) ){
return "函数 " + functionName + " 的第二个参数必须为整数";
}
// 第一个参数必须为 double 类型的集合属性
operateData = stack.pop();
String attrName = operateData.getAttrName();
if( attrName == null || !RuleTempServiceImpl.doubleCollectionAttrNames.contains( attrName ) ){
return "函数 " + functionName + " 的第一个参数的可选值为 " + RuleTempServiceImpl.doubleCollectionAttrNames.toString() + " 之一";
}
// 压栈一个 doule 类型的常量
operateData = new MyOperateData();
operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_DOUBLE );
stack.push( operateData );
return null;
}
/**
* ROUND_UP 、ROUND_DOWN、ROUND 函数( 2个参数,第一个为数据类型,第二个为整数类型 )
* @param functionName
* @param stack
* @return
*/
private String validateRoundUpRoundDownRoundFunctions(String functionName, Stack stack) {
//第二个参数必须为 integer 常量
MyOperateData operateData = stack.pop();
String constValueType = operateData.getConstValueType();
if( constValueType == null || !MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) ){
return "函数 " + functionName + " 的第二个参数类型必须为整数类型";
}
//第一个参数必须为 数字类型 的 属性 或者 常量
operateData = stack.pop();
String attrName = operateData.getAttrName();
if( attrName == null ){
constValueType = operateData.getConstValueType();
if( !( MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) || MyOperateData.CONST_VALUE_TYPE_DOUBLE.equals( constValueType ) ) ){
return "函数 " + functionName + " 的第一个参数类型必须为数字类型";
}
}else {
if( !RuleTempServiceImpl.doubleAttrNames.contains( attrName ) ){
return "函数 " + functionName + " 的第一个参数类型必须为数字类型";
}
}
//压栈 一个 double 类型常量
operateData = new MyOperateData();
operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_DOUBLE );
stack.push( operateData );
return null;
}
private String verityFunctionArgsSize(InstructionSet instructionSet ) {
int instructionLength = instructionSet.getInstructionLength();
if( instructionLength == 0 ){
return null;
}
for( int i = 0;i < instructionLength; i++ ){
Instruction instruction = instructionSet.getInstruction( i );
if( instruction instanceof InstructionOperator){
InstructionOperator instructionOperator = (InstructionOperator) instruction;
Integer gotOpDataNumber = 0;
try{
Field opDataNumberField = InstructionOperator.class.getDeclaredField("opDataNumber");
opDataNumberField.setAccessible( true );
// 该函数实际传递的参数个数
gotOpDataNumber = (Integer) opDataNumberField.get(instructionOperator);
}catch ( Exception e ){
log.error( "Exception is ",e );
}
String currOperatorName = instructionOperator.getOperator().getName();
// 该函数期望的 参数个数
Integer expectedOpDataNumber = 0;
if( RuleTempServiceImpl.selfFunctionNamesWith1Arg.contains( currOperatorName ) ){
expectedOpDataNumber = 1;
}else if( RuleTempServiceImpl.selfFunctionNamesWith2Args.contains( currOperatorName ) ){
expectedOpDataNumber = 2;
}else if( RuleTempServiceImpl.selfFunctionNamesWith3Args.contains( currOperatorName ) ){
expectedOpDataNumber = 3;
}else if( "AND".equals( currOperatorName ) ){
if( gotOpDataNumber.intValue() < 2 ){
return "表达式不合法,函数 AND 期望 2 个以上参数,实际传递 " + gotOpDataNumber + " 个参数";
}
return null;
}else if( RuleTempServiceImpl.baseOperatorNames.contains( currOperatorName ) ){
expectedOpDataNumber = 2;
}
if( !expectedOpDataNumber.equals( gotOpDataNumber ) ){
return "表达式不合法,函数 " + currOperatorName + " 期望 " + expectedOpDataNumber+ " 个参数,实际传递 " + gotOpDataNumber + " 个参数";
}
}else if( instruction instanceof InstructionCallSelfDefineFunction){
// 未定义的函数,程序走到这 说明一定是用了 未定义的函数 ,直接报错
InstructionCallSelfDefineFunction instructionCallSelfDefineFunction = (InstructionCallSelfDefineFunction) instruction;
String functionName = instructionCallSelfDefineFunction.getFunctionName();
return "表达式不合法,使用了未知函数 " + functionName;
}
}
return null;
}
/**
* MAX、MIN、SUM、AVERAGE( 一个参数 ,值为 LCOE1,PIRR1 等 要求的几个属性类型参数 )
* @param functionName
* @param stack
* @return
*/
private String validateMaxMinSumAverageFunctions( String functionName,Stack stack ){
// 参数必须为 double 集合类型的 属性名称
MyOperateData operateData = stack.pop();
String attrName = operateData.getAttrName();
if( attrName == null || !RuleTempServiceImpl.doubleCollectionAttrNames.contains( attrName ) ){
return "函数 " + functionName + " 的参数可选值为 " + RuleTempServiceImpl.doubleCollectionAttrNames.toString() + " 之一";
}
// 压栈 一个 double 类型常量
operateData = new MyOperateData();
operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_DOUBLE );
stack.push( operateData );
return null;
}
/**
* ABS、INT ( 一个参数,都为数字 )
* @param functionName
* @param stack
* @return
*/
private String validateAbsIntFunctions(String functionName,Stack stack ){
// 参数必须为 数字类型的 常量 或 属性
MyOperateData operateData = stack.pop();
String attrName = operateData.getAttrName();
if( attrName == null ){
String constValueType = operateData.getConstValueType();
if( !( MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) || MyOperateData.CONST_VALUE_TYPE_DOUBLE.equals( constValueType ) ) ){
return "函数 " + functionName + " 的参数必须为数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 其一";
}
}else{
if( !RuleTempServiceImpl.doubleAttrNames.contains( attrName ) ){
return "函数 " + functionName + " 的参数必须为数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 其一";
}
}
// 压栈一个 double 类型常量
operateData = new MyOperateData();
operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_DOUBLE );
stack.push( operateData );
return null;
}
/**
* IF 函数( 三个参数,第一个为布尔值,第二、三个为 数据类型 )
* @param functionName
* @param stack
* @return
*/
private String validateIfFunctions(String functionName,Stack stack ){
//第三个参数必须为数字类型 常量 或 属性
MyOperateData operateData = stack.pop();
String attrName = operateData.getAttrName();
if( attrName == null ){
String constValueType = operateData.getConstValueType();
if( !( MyOperateData.CONST_VALUE_TYPE_DOUBLE.equals( constValueType ) || MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) ) ){
return "函数 IF 的第三个参数必须为 一个数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 其一";
}
}else{
if( !RuleTempServiceImpl.doubleAttrNames.contains( attrName ) ){
return "函数 IF 的第三个参数必须为 一个数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 其一";
}
}
//第二个参数必须为数字类型 常量 或 属性( todo 判断逻辑和 第三个参数的一模一样( 提示信息不一样 ),考虑重用 )
operateData = stack.pop();
attrName = operateData.getAttrName();
if( attrName == null ){
String constValueType = operateData.getConstValueType();
if( !( MyOperateData.CONST_VALUE_TYPE_DOUBLE.equals( constValueType ) || MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) ) ){
return "函数 IF 的第二个参数必须为 一个数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 其一";
}
}else{
if( !RuleTempServiceImpl.doubleAttrNames.contains( attrName ) ){
return "函数 IF 的第二个参数必须为 一个数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 其一";
}
}
// 第一个参数必须为布尔常量
operateData = stack.pop();
String constValueType = operateData.getConstValueType();
if( constValueType == null || !MyOperateData.CONST_VALUE_TYPE_BOOLEAN.equals( constValueType ) ){
return "函数 IF 的第一个参数必须为一个布尔值";
}
//压栈 一个 double 类型常量
operateData = new MyOperateData();
operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_DOUBLE );
stack.push( operateData );
return null;
}
/**
* AND 函数( 多于2个的布尔值 )
* @param argSize
* @param functionName
* @param stack
* @return
*/
private String validateAndFunctions(Integer argSize,String functionName,Stack stack ){
MyOperateData operateData = null;
String constValueType = null;
//参数类型 必去全为布尔常量
for( int i = 0;i < argSize;i++ ){
operateData = stack.pop();
constValueType = operateData.getConstValueType();
if( constValueType == null || !MyOperateData.CONST_VALUE_TYPE_BOOLEAN.equals( constValueType ) ){
return "函数 AND 的参数必须是布尔类型";
}
}
//压栈一个布尔类型常量
operateData = new MyOperateData();
operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_BOOLEAN );
stack.push( operateData );
return null;
}
/**
* 加减乘除操作符
* @param operateName
* @param stack
* @return
*/
private String validateAddSubMultiDivideOperates(String operateName, Stack stack, String resultType ){
//第二个操作数必须是数字 类型的 常量 或者 属性
MyOperateData operateData = stack.pop();
String attrName = operateData.getAttrName();
if( attrName == null ){
String constValueType = operateData.getConstValueType();
if( !( MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) || MyOperateData.CONST_VALUE_TYPE_DOUBLE.equals( constValueType ) ) ){
return "操作符 " + operateName + " 右边的操作数应该是一个数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 之一";
}
}else{
if( !RuleTempServiceImpl.doubleAttrNames.contains( attrName ) ){
return "操作符 " + operateName + " 右边的操作数应该是一个数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 之一";
}
}
//第一个操作数必须是数字 类型的 常量 或者 属性( todo 和 前面一样 考虑重用 )
operateData = stack.pop();
attrName = operateData.getAttrName();
if( attrName == null ){
String constValueType = operateData.getConstValueType();
if( !( MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) || MyOperateData.CONST_VALUE_TYPE_DOUBLE.equals( constValueType ) ) ){
return "操作符 " + operateName + " 左边的操作数应该是一个数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 之一";
}
}else{
if( !RuleTempServiceImpl.doubleAttrNames.contains( attrName ) ){
return "操作符 " + operateName + " 左边的操作数应该是一个数字 或者 可选参数 " + RuleTempServiceImpl.doubleAttrNames.toString() + " 之一";
}
}
// 压栈 一个 ${ resultType } 类型的常量
operateData = new MyOperateData();
if( "double".equals( resultType ) ){
operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_DOUBLE );
}else if( "boolean".equals( resultType ) ){
operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_BOOLEAN );
}
stack.push( operateData );
return null;
}
/**
* 比较运算操作符
* @param operateName
* @param stack
* @return
*/
private String validateCompareOperates(String operateName,Stack stack ){
// 如果是大小比较 则两边必须是数字,和 加减乘除的一样
if( !"==".equals( operateName ) ){
return this.validateAddSubMultiDivideOperates( operateName,stack,"boolean" );
}
// 如果是等值比较 则两边可以是数字 也可以是字符串 ,但是必须一样
MyOperateData operateData1 = stack.pop();
String attrName1 = operateData1.getAttrName();
MyOperateData operateData2 = stack.pop();
String attrName2 = operateData2.getAttrName();
// 第一个 和 第二个必须同时是字符串 或 数字
String arg1Type = null; // "number" "string" "boolean" 分表表示数字 字符串 布尔值
if( attrName1 == null ){
String constValueType = operateData1.getConstValueType();
if( MyOperateData.CONST_VALUE_TYPE_DOUBLE.equals( constValueType ) || MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) ){
// 第一个是常量 数字
arg1Type = "number";
}else if( MyOperateData.CONST_VALUE_TYPE_STRING.equals( constValueType ) ){
// 第一个是常量 字符串
arg1Type = "string";
}else if( MyOperateData.CONST_VALUE_TYPE_BOOLEAN.equals( constValueType ) ){
// 第一个是常量 布尔值
arg1Type = "boolean";
}else{
return "操作符 == 两边必须为 数字或字符串或布尔类型";
}
}else{
if( RuleTempServiceImpl.doubleAttrNames.contains( attrName1 ) ){
// 第一个是属性 数字
arg1Type = "number";
}else if( RuleTempServiceImpl.stringAttrNames.contains( attrName1 ) ){
// 第一个是属性 字符串
arg1Type = "string";
}else{
return "操作符 == 两边必须为 数字或字符串或布尔类型";
}
}
// todo 和上面逻辑差不多 ,考虑重用
String arg2Type = null; // "number" "string" "boolean" 分表表示数字 字符串 布尔值
if( attrName2 == null ){
String constValueType = operateData2.getConstValueType();
if( MyOperateData.CONST_VALUE_TYPE_DOUBLE.equals( constValueType ) || MyOperateData.CONST_VALUE_TYPE_INTEGER.equals( constValueType ) ){
// 第一个是常量 数字
arg2Type = "number";
}else if( MyOperateData.CONST_VALUE_TYPE_STRING.equals( constValueType ) ){
// 第一个是常量 字符串
arg2Type = "string";
}else if( MyOperateData.CONST_VALUE_TYPE_BOOLEAN.equals( constValueType ) ){
// 第一个是常量 布尔值
arg2Type = "boolean";
}else{
return "操作符 == 两边必须为 数字或字符串或布尔类型";
}
}else{
if( RuleTempServiceImpl.doubleAttrNames.contains( attrName2 ) ){
// 第一个是属性 数字
arg2Type = "number";
}else if( RuleTempServiceImpl.stringAttrNames.contains( attrName2 ) ){
// 第一个是属性 字符串
arg2Type = "string";
}else{
return "操作符 == 两边必须为 数字或字符串或布尔类型";
}
}
if( arg1Type == null || arg2Type == null ){
return "操作符 == 两边必须为 数字或字符串或布尔类型";
}
if( !arg1Type.equals( arg2Type ) ){
return "操作符 == 两边必须同时为 数字或字符串或布尔类型";
}
//压栈 一个 布尔值类型的常量
MyOperateData operateData = new MyOperateData();
operateData.setConstValueType( MyOperateData.CONST_VALUE_TYPE_BOOLEAN );
stack.push( operateData );
return null;
}
}