今天在公司项目中,发现一个计算运费的妙招。由于运费规则各种各样,因此写一个公式存到数据库。下次需要计算运费时,直接取出这个公式,把公式的未知变量给替换掉,然后计算出结果就是ok了。
一、先看几张图
(1)数据库存的公式

(2)怎么在java代码中计算出结果,见下面2张图

这图,是在map集合中存了 key为"\$w" value为重量的参数。关键是下面这图

这图中方法接收参数为 (公式,公式中变量的真实内容的Map集合)
比较巧妙的地方是,它把这个公式字符串变成js形式的变量运算字符串;然后执行js脚本,这样就把结果算出来了。
就相当于在java中,把"1+2" 这个字符串给算出结果来了。而且它这里还巧妙的使用了js的Math的一些方法。
二、来写个demo
写个方法,实现传入公式和参数,计算出结果。直接上代码吧
package com.zxy.test;
import java.util.HashMap;
import java.util.Map;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import org.junit.Test;
/**
* 如何将一个字符串公式,计算出结果
* @author ZENG.XIAO.YAN
* @date Oct 26, 2017 7:34:08 PM
* @version V1.0
*/
public class RunJsOnJava {
@Test
public void test01() throws ScriptException {
String formula = "(a+b)*(a-b)";
HashMap<String,Object> map = new HashMap<String,Object>();
map.put("a", 20.1);
map.put("b", 11.1);
Double result = (Double) this.calculateResultByFormula(formula, map);
System.out.println(result); //280.80000000000007
}
/**
* 通过字符串公式,和参数,计算出结果
* @param formula
* @param paramMap
* @return
* @throws ScriptException
*/
public Object calculateResultByFormula (String formula,Map<String,Object> paramMap) throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine scriptEngine = manager.getEngineByName("js");
for (String key : paramMap.keySet()) {
formula = formula.replaceAll(key, paramMap.get(key).toString());
}
//此时 formula="(20.1+11.1)*(20.1-11.1)"
Object result = scriptEngine.eval(formula); // 运行js脚本
return result;
}
}x
1
package com.zxy.test;2
import java.util.HashMap;3
import java.util.Map;4
import javax.script.ScriptEngine;5
import javax.script.ScriptEngineManager;6
import javax.script.ScriptException;7
import org.junit.Test;8
9
/** 10
* 如何将一个字符串公式,计算出结果11
* @author ZENG.XIAO.YAN 12
* @date Oct 26, 2017 7:34:08 PM 13
* @version V1.0 14
*/15
16
public class RunJsOnJava {17
18
@Test19
public void test01() throws ScriptException {20
String formula = "(a+b)*(a-b)"; 21
HashMap<String,Object> map = new HashMap<String,Object>();22
map.put("a", 20.1);23
map.put("b", 11.1);24
Double result = (Double) this.calculateResultByFormula(formula, map);25
System.out.println(result); //280.8000000000000726
}27
28
/**29
* 通过字符串公式,和参数,计算出结果30
* @param formula31
* @param paramMap32
* @return33
* @throws ScriptException 34
*/35
public Object calculateResultByFormula (String formula,Map<String,Object> paramMap) throws ScriptException {36
ScriptEngineManager manager = new ScriptEngineManager();37
ScriptEngine scriptEngine = manager.getEngineByName("js");38
for (String key : paramMap.keySet()) {39
formula = formula.replaceAll(key, paramMap.get(key).toString());40
}41
//此时 formula="(20.1+11.1)*(20.1-11.1)"42
Object result = scriptEngine.eval(formula); // 运行js脚本43
return result;44
}45
}三、小结
通过百度,发现通过ScriptEngineManager相关api可以在java运行各种脚本。这种运行js脚本的方式,我们可以用来处理一些计算规则灵活多变的业务。就比如本项目中计算运费的模块,由于运费计算规则比较多变,所以就采用这种方式实现。