今天在公司项目中,发现一个计算运费的妙招。由于运费规则各种各样,因此写一个公式存到数据库。下次需要计算运费时,直接取出这个公式,把公式的未知变量给替换掉,然后计算出结果就是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
@Test
19
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.80000000000007
26
}
27
28
/**
29
* 通过字符串公式,和参数,计算出结果
30
* @param formula
31
* @param paramMap
32
* @return
33
* @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脚本的方式,我们可以用来处理一些计算规则灵活多变的业务。就比如本项目中计算运费的模块,由于运费计算规则比较多变,所以就采用这种方式实现。