1 import javax.script.Invocable;
2 import javax.script.ScriptEngine;
3 import javax.script.ScriptEngineManager;
4 import javax.script.ScriptException;
5 import java.util.Map;
6 import java.util.regex.Matcher;
7 import java.util.regex.Pattern;
8
9 public class JavaScriptUtil {
10
11 public static Object calculateRatio(Map<String, Object> column,Map<String, Object> row) throws ScriptException, NoSuchMethodException {
12 ScriptEngineManager manager = new ScriptEngineManager();
13 ScriptEngine engine = manager.getEngineByName("nashorn");
14 // 如果还是没有引擎可用,抛出明确异常
15 if (engine == null) {
16 if(column.get("filed") != null){
17 return row.get(column.get("filed"));
18 }
19 return "";
20 }
21 // 注入数据到JS环境
22 engine.put("row", row);
23 // 根据引擎类型使用不同的语法
24 String formatter = column.get("formatter").toString();
25 String converted = "function calculateRatio(row) {"+convertJsForNashorn(formatter)+"}";
26 engine.eval(converted);
27 // 调用函数
28 Object result = ((Invocable)engine).invokeFunction("calculateRatio", row);
29 return result.toString();
30 }
31
32 public static void main(String[] args) throws ScriptException, NoSuchMethodException {
33 Map<String, Object> column = Map.of("formatter", "let { Z, V } = row; // Z=计划品, V=检验量 \n" +
34 "if(Z == 0){\n" +
35 " return 0; \n" +
36 "}else{\n" +
37 " return parseFloat((((Z/V) * 100)).toFixed(3));\n" +
38 "}", "V", 100);
39 Map<String, Object> row = Map.of("Z", 20, "V", 100);
40 System.out.println(calculateRatio(column,row)); // 输出 25.0
41 }
42
43 /**
44 * 转换JavaScript代码为Nashorn兼容格式
45 * @param jsCode 原始JavaScript代码
46 * @return 转换后的JavaScript代码
47 */
48 public static String convertJsForNashorn(String jsCode) {
49 // 1. 转换let/const为var
50 String converted = convertVariableDeclarations(jsCode);
51
52 // 2. 处理解构赋值
53 converted = convertDestructuringAssignments(converted);
54
55 // 3. 其他可能的转换可以在这里添加
56
57 return converted;
58 }
59
60 /**
61 * 将let和const转换为var
62 */
63 private static String convertVariableDeclarations(String jsCode) {
64 // 替换所有let和const为var,但排除函数声明中的情况
65 String pattern = "(?<!(function\\s+|\\w+\\s*\\.))\\b(let|const)\\b";
66 return jsCode.replaceAll(pattern, "var");
67 }
68
69 /**
70 * 处理解构赋值转换为传统赋值
71 */
72 private static String convertDestructuringAssignments(String jsCode) {
73 // 匹配类似 let { Z, V } = row; 的模式
74 Pattern pattern = Pattern.compile("var\\s*\\{([^}]+)\\}\\s*=\\s*(\\w+)\\s*;");
75 Matcher matcher = pattern.matcher(jsCode);
76
77 StringBuffer sb = new StringBuffer();
78 while (matcher.find()) {
79 String variables = matcher.group(1).trim();
80 String sourceObject = matcher.group(2).trim();
81
82 // 处理每个解构变量
83 String[] vars = variables.split(",");
84 StringBuilder replacements = new StringBuilder();
85
86 for (String var : vars) {
87 var = var.trim();
88 if (var.isEmpty()) continue;
89
90 // 处理可能的别名情况,如 { Z: alias }
91 if (var.contains(":")) {
92 String[] parts = var.split(":");
93 String original = parts[0].trim();
94 String alias = parts[1].trim();
95 replacements.append("var ").append(alias).append("=")
96 .append(sourceObject).append(".").append(original).append(";");
97 } else {
98 replacements.append("var ").append(var).append("=")
99 .append(sourceObject).append(".").append(var).append(";");
100 }
101 }
102
103 matcher.appendReplacement(sb, replacements.toString());
104 }
105 matcher.appendTail(sb);
106
107 return sb.toString();
108 }
109 }