You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java函数中调用TypeScript脚本并传递事务状态参数?

Java中调用前端输入的TypeScript脚本并处理参数与返回值的解决方案

嘿,我懂你之前用GroovyClassLoader结合javax.script在Java里跑无参Groovy脚本的场景,现在要换成TypeScript对吧?刚好我琢磨出一套靠谱的方案,完美适配你说的「前端输入TS脚本、后端Java调用并传事务状态参数、接收返回的Map/对象」需求。

核心思路

Java本身不直接支持TypeScript执行,所以我们的核心逻辑是:利用GraalVM的多语言支持直接执行TS(或者先把TS转成JS再执行),通过脚本上下文绑定参数,最后把TS返回的对象转换成Java的Map结构。

具体实现步骤

1. 引入依赖(Maven为例)

优先推荐用GraalVM的JavaScript/TypeScript引擎,比老的Nashorn性能强,还支持ES6+语法。在pom.xml里加这些依赖:

<!-- GraalVM JavaScript 核心依赖 -->
<dependency>
    <groupId>org.graalvm.js</groupId>
    <artifactId>js</artifactId>
    <version>21.3.0</version>
</dependency>
<!-- 让Java通过ScriptEngine API调用GraalVM JS -->
<dependency>
    <groupId>org.graalvm.js</groupId>
    <artifactId>js-scriptengine</artifactId>
    <version>21.3.0</version>
</dependency>
<!-- GraalVM原生TypeScript支持 -->
<dependency>
    <groupId>org.graalvm.typescript</groupId>
    <artifactId>typescript</artifactId>
    <version>21.3.0</version>
</dependency>

2. 编写Java执行逻辑

这里写一个工具类,负责创建GraalVM上下文、绑定参数、执行TS脚本、转换返回值:

import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;
import java.util.HashMap;
import java.util.Map;

public class TsScriptExecutor {

    public Map<String, Object> execute(String userTsScript, Map<String, Object> transactionState) {
        // 创建GraalVM上下文,启用TS和JS支持
        try (Context context = Context.newBuilder("ts", "js")
                // 生产环境务必缩小权限范围,这里为了演示放开所有权限
                .allowAllAccess(true)
                .build()) {

            // 把事务状态参数绑定到TS脚本的全局上下文
            context.getBindings("ts").putMember("transactionState", transactionState);

            // 执行用户输入的TS脚本,拿到返回结果
            Value tsResult = context.eval("ts", userTsScript);

            // 把GraalVM的Value对象转成Java的Map
            return convertTsResultToJavaMap(tsResult);
        } catch (Exception e) {
            throw new RuntimeException("执行TypeScript脚本失败:" + e.getMessage(), e);
        }
    }

    // 递归转换GraalVM Value到Java对象
    private Map<String, Object> convertTsResultToJavaMap(Value value) {
        Map<String, Object> resultMap = new HashMap<>();
        if (!value.hasMembers()) {
            return resultMap;
        }

        for (String key : value.getMemberKeys()) {
            Value member = value.getMember(key);
            if (member.isBoolean()) {
                resultMap.put(key, member.asBoolean());
            } else if (member.isNumber()) {
                resultMap.put(key, member.asDouble());
            } else if (member.isString()) {
                resultMap.put(key, member.asString());
            } else if (member.hasMembers()) {
                // 如果返回的是嵌套对象,递归转换
                resultMap.put(key, convertTsResultToJavaMap(member));
            }
        }
        return resultMap;
    }
}

3. 前端输入的TS脚本约定

用户在前端输入的TS脚本需要遵循简单约定:使用全局的transactionState参数,最终返回一个对象。举个例子:

// 前端输入的TS脚本示例
const processTransaction = (state: { orderId: string, amount: number, status: string }) => {
    const isEligible = state.status === 'PENDING' && state.amount >= 50;
    return {
        approve: isEligible,
        reason: isEligible ? '符合交易条件' : '交易状态或金额不满足要求',
        adjustedAmount: state.amount * 0.98 // 扣除2%手续费
    };
};

// 必须调用函数并返回结果,让Java引擎能拿到输出
processTransaction(transactionState);

关键注意事项

  • 权限控制:生产环境绝对不能用allowAllAccess(true),要通过allowIO(false)、allowHostAccess(false)等方法严格限制脚本的权限,避免恶意脚本搞破坏。
  • 性能优化:如果需要频繁执行脚本,可以缓存GraalVM的Context对象,或者预编译脚本,减少重复初始化的开销。
  • 错误处理:要捕获脚本的语法错误、运行时错误,把具体错误信息返回给前端,方便用户调试。
  • 类型兼容:TS的类型注解在执行时会被移除,所以后端传递的transactionState只要结构和TS预期一致就行,不需要严格的类型匹配。

替代方案(不用GraalVM的情况)

如果项目没法用GraalVM,也可以用传统的Nashorn引擎,但步骤会麻烦点:

  1. 后端接收TS代码后,用ProcessBuilder调用Node.js的tsc命令把TS转成ES5版本的JS(Nashorn对ES6+支持有限)。
  2. 用Nashorn执行转好的JS代码,绑定参数并处理返回值。
    不过这种方案需要后端安装Node.js,维护成本更高,还是优先推荐GraalVM方案。

内容的提问来源于stack exchange,提问作者tgkprog

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:38:05