这几天在做公式计算的技术调研工作,在这里把收获记录一下吧,希望能帮助大家少走些弯路。

首先是SpEL,SpEl是Spring Expression的简称,是Spring框架的一个组件,可以实现一些基本的表达式解析或动态调用功能。

我这里用到的基本功能:

1、参数替换

2、无参函数替换

3、有参函数替换

具体实现方法见下面的代码:

import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.math.BigDecimal;

public class ExpressionUtil {
    public static void main(String[] args) throws NoSuchMethodException {
        // 1、从前端输入或从数据库读取出用户设置的计算公式,用户设置的所有参数都应是由系统提供的
        String orgiExpression = "四舍五入函数2位小数(四舍五入函数4位小数(实际出勤天数/应出勤天数)*岗位工资)";
        System.out.println(orgiExpression);
        String curExpression = orgiExpression;
        // 2、通过循环枚举值,将用户能理解的公式转换成系统能使用的变量或函数
        for (RelationEnum relationEnum : RelationEnum.values()) {
            curExpression = curExpression.replaceAll(relationEnum.getName(), "#" + relationEnum.getCodeName());
        }
        System.out.println(curExpression);

        StandardEvaluationContext ctx = new StandardEvaluationContext();
        ExpressionParser parser = new SpelExpressionParser();
        // 设置变量对应的参数
        ctx.setVariable("realDays", new Double(19));
        ctx.setVariable("needDays", 22);
        ctx.setVariable("salary", 5678);
        ctx.registerFunction("round", BigDecimal.class.getDeclaredMethod("valueOf", double.class));
        ctx.setVariable("half", BigDecimal.ROUND_HALF_UP);
        // 设置变量对应的函数
        ctx.registerFunction("halfUp2", ExpressionUtil.class.getDeclaredMethod("halfUp2", Double.class));
        ctx.registerFunction("halfUp4", ExpressionUtil.class.getDeclaredMethod("halfUp4", Double.class));
        BigDecimal result = parser.parseExpression(curExpression).getValue(ctx, BigDecimal.class);
        System.out.println("result="+result);

        ctx.setVariable("a", 10);
        ctx.setVariable("b", 2);
        Integer val = 0;
        ctx.setVariable("val", val);
        // 逻辑语句支持多层的三目运算符,但是不支持if else语句
        String aaa = "(#a>#b ? (10>2?(10>3?#val=5:3):2) : 1)";
        Object aaaR = parser.parseExpression(aaa).getValue(ctx);
        System.out.println(aaaR);
        System.out.println(val);
    }

    public static BigDecimal halfUp2(Double dValue) {
        BigDecimal result = new BigDecimal(dValue).setScale(2, BigDecimal.ROUND_HALF_UP);
        return result;
    }

    public static BigDecimal halfUp4(Double dValue) {
        BigDecimal result = new BigDecimal(dValue).setScale(4, BigDecimal.ROUND_HALF_UP);
        return result;
    }

    public enum RelationEnum {

        HALF_UP_2("四舍五入函数2位小数","halfUp2"),
        HALF_UP_4("四舍五入函数4位小数","halfUp4"),
        REALDAYS("实际出勤天数","realDays"),
        NEEDDAYS("应出勤天数","needDays"),
        SALARY("岗位工资","salary"),
        ;

        private String name;
        private String codeName;
        RelationEnum(String name,String codeName){
            this.name = name;
            this.codeName = codeName;
        }
        public String getCodeName(){
            return codeName;
        }
        public String getName(){
            return name;
        }
    }

}

这里说下SpEL的缺点,逻辑语句只支持简单的三目运算符,不支持ifelse语句,对分支中的多条语句无法支持。我们的项目在分支逻辑这块比较复杂,所以只能pass了。

参考文档:

1、https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/expressions.html

2、https://docs.spring.io/spring-framework/docs/5.2.x/spring-framework-reference/core.html#expressions

 

最后修改于 2020-05-15 16:20:40
如果觉得我的文章对你有用,请随意赞赏
扫一扫支付
上一篇