V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Jokerboozp
V2EX  ›  Java

怎么在 Java 后端执行 Node.js 代码并且返回结果给前端

  •  
  •   Jokerboozp · 2023-08-14 15:51:20 +08:00 · 3057 次点击
    这是一个创建于 428 天前的主题,其中的信息可能已经有所发展或是发生改变。

    单位之前用的 Thingworx 物联网平台,里面有一个编写 Node.js 代码的编辑器,编辑之后可以直接运行显示结果。最近让我整体搬到新项目里面,说是前端没办法运行,要把 js 代码传给后端让后端运行。 里面有一些自定义的语法,我的想法是关键字匹配,如果匹配到关键字,就执行对应的操作,然后再把执行之后的结果和剩下的 js 拼接起来。 但是这样做的话就有点像一个 js 翻译器了,而且效率并不高。 我找了半天,实在没有好办法。各位大佬有没有好一点的解决方法。https://ice.frostsky.com/2023/08/14/3f6c0074202ec7d325673a21efe90f31.png

    第 1 条附言  ·  2023-08-14 21:26:08 +08:00
    各位大佬说的都看了,感觉最优解应该还是写一个 Node 服务器来的方便。但是还有一个问题:
    js 里面会有“let dataInfo = Things["Localhost.PostgreSQL.Database.Thing"].Update({
    updateString: sql /* STRING */
    });”这样的代码,它需要连接数据库进行查询找到对应的 Update 方法的内容,我在 Node 服务器里面应该怎么执行这个操作呢?
    44 条回复    2023-08-28 10:15:10 +08:00
    biubiuGolang
        1
    biubiuGolang  
       2023-08-14 15:56:03 +08:00
    GraalVM
    gitignore
        2
    gitignore  
       2023-08-14 16:00:52 +08:00
    直接执行 shell 命令不行吗

    ```sh
    node --eval="JavaScript 脚本"
    ```
    brucedone
        3
    brucedone  
       2023-08-14 16:00:53 +08:00
    一般都是 node.js 封装成 http 服务,java 后端来调用,尽量别同进程跨解释器,会有一定的兼容问题。
    mmdsun
        4
    mmdsun  
       2023-08-14 16:02:40 +08:00
    Java 有 ScriptEngine 能执行一些简单的 js 代码,表达式之类的。
    复杂的话,你用 Java 运行 node 命令,读取流返回结果也行吧?
    pkoukk
        5
    pkoukk  
       2023-08-14 16:03:08 +08:00
    如果只是简单的脚本的话,1# 的就可以
    如果需要解析依赖,或者 import 标准库的话,可以搞个 node 服务,把编辑后的脚步发到那个服务去执行
    mightybruce
        6
    mightybruce  
       2023-08-14 16:06:05 +08:00
    如果是复杂的服务,还是通过服务调用服务的方式

    简单的执行逻辑可以通过一些 js runtime 以及 js ast 解析来做。
    virusdefender
        7
    virusdefender  
       2023-08-14 16:06:16 +08:00
    runtime.getRuntime().exec 应该是最佳选择了
    drvDPqg5nO7kZWhv
        8
    drvDPqg5nO7kZWhv  
       2023-08-14 16:07:43 +08:00
    远程调用最省心吧
    mightybruce
        9
    mightybruce  
       2023-08-14 16:09:27 +08:00
    有一些 Java 实现的 JavaScript 引擎,可以直接被 java 调用,比如 Rhino 和 Nashorn
    Jokerboozp
        10
    Jokerboozp  
    OP
       2023-08-14 16:13:59 +08:00
    @biubiuGolang
    @mmdsun
    @mightybruce
    javascript 引擎我试过,但是目前单位的 js 代码里会有一些例如“let dataInfo = Things["Localhost.PostgreSQL.Database.Thing"].Update({
    updateString: sql /* STRING */
    });”
    这样的内容,中括号里面的内容是数据库中的,然后他有一个 Update 方法,参数是用户写的 sql ,我想要执行 js 的话还需要把这段代码执行,然后再把上面那段代码替换成 sql 的执行结果。
    我觉得这样有点太不符合编码常理了
    Jokerboozp
        11
    Jokerboozp  
    OP
       2023-08-14 16:15:28 +08:00
    @brucedone 意思是用 Node.js 写一个 http 服务器,然后我把 js 代码直接发给 Node 服务器,接收服务器返回的结果,然后再转发给前端这样嘛
    mightybruce
        12
    mightybruce  
       2023-08-14 16:18:14 +08:00
    像这样的不是简单的 js 翻译,涉及到数据库驱动了, 不是表达式,正则,规则匹配引擎。你要么用 java 重写这部分逻辑,要么改装 node.js 变成 node.js 微服务调用 java 服务的形式。
    Jokerboozp
        13
    Jokerboozp  
    OP
       2023-08-14 16:20:26 +08:00
    @mightybruce 嗯嗯。就是涉及到的东西实在太多,我才有点不知所措。目前看来最优解貌似是写一个 Node 服务器,然后我用 Java 转发结果。
    biubiuGolang
        14
    biubiuGolang  
       2023-08-14 17:18:59 +08:00
    @pkoukk 复杂的也可以 import 标准和第三方都 ok
    biubiuGolang
        15
    biubiuGolang  
       2023-08-14 17:20:25 +08:00
    @Jokerboozp 了解一下 esprima 提取出来执行 sql
    cl903254852
        16
    cl903254852  
       2023-08-14 17:26:04 +08:00
    搞个 node 的服务,获取到编辑器的代码丢给 node 服务去执行,执行完通知 java ,java 把结果给前端。

    java 就是个中间人,负责传话的
    Jokerboozp
        17
    Jokerboozp  
    OP
       2023-08-14 17:32:06 +08:00
    @cl903254852 两个问题:
    1 、如果 Java 只是一个传话的,那为什么还需要 Java 嘞。直接让前端把 js 代码传给 node 服务器就可以了吗不是?
    2 、js 里面会有“let dataInfo = Things["Localhost.PostgreSQL.Database.Thing"].Update({
    updateString: sql /* STRING */
    });”这样的代码,它需要连接数据库进行查询找到对应的 Update 具体是什么,我在 node 服务器里面应该怎么办呢?
    Jokerboozp
        18
    Jokerboozp  
    OP
       2023-08-14 17:33:34 +08:00
    @biubiuGolang 可以,我去研究研究
    sofukwird
        19
    sofukwird  
       2023-08-14 17:33:37 +08:00 via Android
    quickjs ?
    Jokerboozp
        20
    Jokerboozp  
    OP
       2023-08-14 17:37:47 +08:00
    @sofukwird 这个好像不可以,js 代码里会有连接数据库或者查找数据之类的操作
    shyangs
        21
    shyangs  
       2023-08-14 17:48:00 +08:00
    把 Java 寫的後端扔了,改用 Node.js 寫後端。
    cl903254852
        22
    cl903254852  
       2023-08-14 17:55:29 +08:00
    @Jokerboozp 因为你是执行 node 代码,那肯定 node 环境是最稳妥的。 我的意思是,node 服务只针对你这个编辑器的场景即可,项目其他该用 java 用 java 。node 既然是服务端肯定能连数据库
    des
        23
    des  
       2023-08-14 18:04:21 +08:00
    换 Nodejs 来搞吧,感觉其实都差不多,都要写 Things 相关的驱动
    不过我有点好奇,你这 12 行怎么是个同步操作?
    des
        24
    des  
       2023-08-14 18:09:06 +08:00
    不建议提取 SQL 来执行,你这前端是个编辑器,鬼知道前端会传什么东西过来

    用 javascript 引擎来做也行,前提也是你得补足“ Things["Localhost.PostgreSQL.Database.Thing"] ” 相关的东西
    wganbleuthall
        25
    wganbleuthall  
       2023-08-14 18:10:10 +08:00
    包装成一个 http 服务吧
    WispZhan
        26
    WispZhan  
       2023-08-14 20:06:44 +08:00
    lisongeee
        27
    lisongeee  
       2023-08-14 20:21:43 +08:00
    可以使用 webcontainer 直接在浏览器运行一个小型的 linux nodejs 进程

    https://webcontainers.io/guides/quickstart

    它由 https://stackblitz.com/ 开发,现在很多文档/问题讨论上的在线 demo 都是基于这个
    lisongeee
        28
    lisongeee  
       2023-08-14 20:25:28 +08:00
    艹,你们这个还要连接数据库?那看起来是一个阉割版的远程 nodejs console ,那只能用 远程 nodejs 去执行了
    zhuangzhuang1988
        29
    zhuangzhuang1988  
       2023-08-14 20:31:53 +08:00
    包装个 grpc?
    kid1412621
        31
    kid1412621  
       2023-08-14 21:12:44 +08:00
    graal
    Jokerboozp
        32
    Jokerboozp  
    OP
       2023-08-14 21:19:28 +08:00
    @zhuangzhuang1988 grpc 我还没学明白,有点难度。哈哈哈哈哈哈
    Jokerboozp
        33
    Jokerboozp  
    OP
       2023-08-14 21:21:45 +08:00
    @lisongeee 就是因为要连数据库,然后还有一堆自定义的语法,所以我才头大。看了各位大佬的回复看来只有写一个 node 服务才行了
    Jokerboozp
        34
    Jokerboozp  
    OP
       2023-08-14 21:28:14 +08:00
    @cl903254852 明白了明白了,多谢大佬
    musi
        35
    musi  
       2023-08-14 22:19:19 +08:00 via iPhone
    看了一圈回复都没说到点子上,你这只需要实现 ecma262 规范的引擎也可以认为是 js 引擎基本上就可以执行代码了,你的自定义语法无非是 Thing 这个对象,那你在执行代码的时候提前去定义这个对象就好了,就你给出的代码来说,中括号是属性获取语法,其实就是在获取 Thing 对象的 Localhost.PostgreSQL.Database.Thing 属性,可以用 proxy 语法拦截 getter ,获取到这个 key ,然后是.update ,也就是 Thing 对象的 Localhost.PostgreSQL.Database.Thing 属性值是个对象,对象里面有个 update 方法,你再实现一下就行。
    musi
        36
    musi  
       2023-08-14 22:21:01 +08:00 via iPhone
    另外就这个代码来说,只要做好鉴权前端是完全可以执行的
    Jokerboozp
        37
    Jokerboozp  
    OP
       2023-08-14 22:32:36 +08:00
    @musi 但是我给出的这个是其中一个的代码,还有其他的 Thing 对象的属性,是由用户自定义来写的,每个属性有哪些方法也是用户自定义来写的。如果按照您说的这样,每一个属性我都实现方法的话,感觉不太能实现诶。刚开始写的时候我是用 jvm 的 js 引擎来写的,我觉得应对这种情况不太可行。
    musi
        38
    musi  
       2023-08-14 22:35:09 +08:00 via iPhone
    @Jokerboozp 你还是没理解,属性不管是谁定义它只要定义了就行,平台方和用户方无所谓,你只需要封装特定的 sdk 就行
    musi
        39
    musi  
       2023-08-14 22:42:56 +08:00 via iPhone
    @Jokerboozp 你中括号里面的内容,完全是语义化的,host.数据库类型.Datebase.表名,你用 proxy 拦截到 key 时就去找对应的数据库就行了,这也不是说一个属性定义一个方法,完全就是一个通用的方法
    Jokerboozp
        40
    Jokerboozp  
    OP
       2023-08-14 22:48:33 +08:00 via iPhone
    @musi 不是的,他有的会写成 Things[thing]这样,这里面不一定是数据库,可能是另一个方法集合的名字,然后他又用里面的某一个方法
    musi
        41
    musi  
       2023-08-14 23:12:56 +08:00 via iPhone
    @Jokerboozp 这就相当于一个参数了,不管你是用什么方式你都得自己去实现对应的参数应该执行的方法,不是说你用个 node.js 什么东西写个服务它就自己有这些东西,这个平台是你们自己定义的不是么
    musi
        42
    musi  
       2023-08-14 23:16:38 +08:00 via iPhone
    我劝你也别折腾了,让你们公司前端做吧,专业的人做专业的事
    biubiuGolang
        43
    biubiuGolang  
       2023-08-17 10:24:46 +08:00
    @Jokerboozp 在 GraalVM 上使用 polyglot 执行多语言是没啥问题的,这里面包括多语言事务和 sandbox 控制,以及在 js 中调用 java java 调用 js ,你如果有了后续的更新可以回一下贴 ~
    Jokerboozp
        44
    Jokerboozp  
    OP
       2023-08-28 10:15:10 +08:00
    @biubiuGolang 单位用的 jdk8 ,GraalVM 的新版本不支持,只能用老版本,但是我电脑是 M1 pro 的 MacBook ,又跑不起来老版本的 GraalVM 。所以现在在试着用 J2V8 写
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3083 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 12:16 · PVG 20:16 · LAX 05:16 · JFK 08:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.