package com.dhcc.finance.util; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Hashtable; import java.util.Map; import org.codehaus.groovy.control.CompilerConfiguration; import groovy.lang.Binding; import groovy.lang.GroovyShell; import groovy.lang.Script; import lombok.extern.slf4j.Slf4j; /** * 功能描述:财务字符串表达式计算工具类 * @author dml * @date 2019年5月22日 上午11:29:47 * @修改日志: */ @Slf4j public class FinanceExpUtil { private static final Object lock = new Object(); private static final GroovyShell shell; private static Hashtable cache = new Hashtable(); static { CompilerConfiguration cfg = new CompilerConfiguration(); cfg.setScriptBaseClass(MyBaseScript.class.getName()); shell = new GroovyShell(cfg); } /** * 功能描述:获取金额表达式计算结果(含自定义函数) * @param expStr 字符串表达式 * @param parameterMap 表达式中参数 * @return BigDecimal 返回BigDecimal保留两位小数 * @author dml * @date 2019年8月2日 下午2:37:01 * @修改日志: */ public static BigDecimal getExpResult(String expStr,Map parameterMap) { try { Object parseExpr = parseExpr(expStr, parameterMap); // 默认保留两位 return getBigDecimal(2,parseExpr); } catch (Exception e) { log.error("表达式计算异常>>>>>>>>>>>>",e); return null; } } /** * 功能描述:获取表达式计算结果(没有参数) * @param expr * @return Object * @author dml * @date 2019年8月2日 下午2:33:59 * @修改日志: */ public static Object parseExpr(String expr) { Script s = getScriptFromCache(expr); return s.run(); } /** * 功能描述:获取表达式计算结果(包含自定义函数) * @param expr * @return Object * @author dml * @date 2019年8月2日 下午2:33:59 * @修改日志: */ public static Object parseExpr(String expr, Map map) { Binding binding = new Binding(map); Script script = getScriptFromCache(expr); script.setBinding(binding); return script.run(); } /** * 功能描述:缓存中获取已解析表达式 * @param expr * @return Script * @author dml * @date 2019年8月2日 下午2:37:01 * @修改日志: */ private static Script getScriptFromCache(String expr) { if (cache.contains(expr)) { return cache.get(expr); } synchronized (lock) { if (cache.contains(expr)) { return cache.get(expr); } Script script = shell.parse(expr); cache.put(expr, script); return script; } } /** * 功能描述:获取表达式计算结果(不含自定义函数) * @param expStr 字符串表达式 * @param parameterMap 表达式中参数 * @return BigDecimal * @author dml * @date 2019年5月22日 上午11:34:37 * @修改日志: */ // 该方法暂时作废 @Deprecated public static BigDecimal getExpResultOld(String expStr,Map parameterMap) { try { Binding binding = new Binding(); parameterMap.forEach((x,y)->{ binding.setVariable(x, y); }); binding.setVariable("language", "Groovy"); GroovyShell shell = new GroovyShell(binding); String scriptText = "return " + expStr; Object res =shell.evaluate(scriptText); return getBigDecimal(2,res); } catch (Exception e) { log.error("表达式计算异常>>>>>>>>>>>>",e); return null; } } /** * 功能描述:Object转BigDecimal并四舍五入保留指定小数位数 * @param newScale 保留位数 * @param value 需转换的值 * @return BigDecimal * @author dml * @date 2019年5月22日 上午11:56:48 * @修改日志: */ public static BigDecimal getBigDecimal(int newScale,Object value) { BigDecimal ret = null; if (value != null) { if (value instanceof BigDecimal) { ret = (BigDecimal) value; } else if (value instanceof String) { ret = new BigDecimal((String) value); } else if (value instanceof BigInteger) { ret = new BigDecimal((BigInteger) value); } else if (value instanceof Number) { ret = new BigDecimal(((Number) value).doubleValue()); } else { throw new ClassCastException("Not possible to coerce [" + value + "] from class " + value.getClass() + " into a BigDecimal."); } } return ret.setScale(newScale, BigDecimal.ROUND_HALF_UP); } }