【技巧】ScriptEngine--Java动态执行JS Javascript脚本(可调用java的方法)

这篇具有很好参考价值的文章主要介绍了【技巧】ScriptEngine--Java动态执行JS Javascript脚本(可调用java的方法)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【技巧】ScriptEngine--Java动态执行JS Javascript脚本(可调用java的方法) 扩展性很强

JS引擎Nashorn

开发手册

Java Platform, Standard Edition Nashorn User's Guide, Release 14

用户手册

Nashorn User's Guide (oracle.com)

scriptengine,技巧心得,java,前端,开发语言,javascript

https://docs.oracle.com/en/java/javase/14/nashorn/

甚至可以让前端来写后端业务代码

可以通过js调用java的方法, 通过传参的方式将java对象传给js

可以单独写个JsUtil 让js来调用 里边写常用的方法 统一管理

也可以直接通过Spring去拿到对应的实例

JDK9+ 需要单独依赖

        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>3.6</version>
        </dependency>

相关工具类

        <!-- hutool工具类-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.20</version>
        </dependency>

代码例子

package com.xx.study.Script.Javascript;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.script.ScriptUtil;
import org.junit.jupiter.api.Test;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.HashMap;
import java.util.Map;

public class JavascriptDemo {

    
    private final static String js = """
            
            function test(){
                var a = 1;
                var b = 3;
                return a+b;
            }
            function 加法(a, b){
                return a+b;
            }
            
            
            function MAP传参(map){
            
                return map['a']+map['b'];
            }
            
            function 获取json(){
                var json = {
                    最大值:10,
                    最小值:3,
                    说明:'测试js方法'
                };
                return JSON.stringify(json);
            }
            
            
            """;

    /**
     * 可以考虑结合业务做成动态参数等
     * 将js存到数据库进行管理 也可以维护到redis缓存等
     * @param args
     */
    public static void main(String[] args) {

        Object test结果 = ScriptUtil.invoke(js, "test");

        System.out.println("test:================================");
        //4.0
        System.out.println(test结果);
        
        
        Object 加法结果 = ScriptUtil.invoke(js, "加法", 100, 200);
        System.out.println("加法:==============================");
        //300.0
        System.out.println(加法结果);
        
        
        Map<String, Integer> MAP参数 = new HashMap<>();
        MAP参数.put("a", 500);
        MAP参数.put("b", 500);
        Object MAP传参结果 = ScriptUtil.invoke(js, "MAP传参", MAP参数);

        System.out.println("MAP传参:======================================");
        //1000.0
        System.out.println(MAP传参结果);
        
        
        Object 获取json结果 = ScriptUtil.invoke(js, "获取json");
        JSONObject entries = JSONUtil.parseObj(获取json结果.toString());

        System.out.println("获取json:======================================");
        //10
        System.out.println(entries.getInt("最大值"));
        //测试js方法
        System.out.println(entries.getStr("说明"));
        //{"最大值":10,"最小值":3,"说明":"测试js方法"}
        System.out.println(entries);
        
    }


    /**
     * ScriptEngine.eval()
     */
    @Test
    public void jsEngineEvalTest() {
        ScriptEngineManager sem = new ScriptEngineManager();
        //查找并为给定的扩展创建ScriptEngine。也可用getEngineByName,查找并为给定名称创建ScriptEngine 
        ScriptEngine jsEngine = sem.getEngineByExtension("js");
        try {
            jsEngine.eval("var array = [1, 2, 3, 4, 5];for (var i = 0; i < array.length; i++) {print('index:' + i + ',value:' + array[i]);}");
        } catch (ScriptException e) {
            e.printStackTrace();
        }
    }

}
    /**
     * ScriptEngine.eval()
     */
    @Test
    public void jsEngineEvalTest() {
        ScriptEngineManager sem = new ScriptEngineManager();
        //查找并为给定的扩展创建ScriptEngine。也可用getEngineByName,查找并为给定名称创建ScriptEngine 
        ScriptEngine jsEngine = sem.getEngineByExtension("js");
        try {
            jsEngine.eval("var array = [1, 2, 3, 4, 5];for (var i = 0; i < array.length; i++) {print('index:' + i + ',value:' + array[i]);}");
        } catch (ScriptException e) {
            e.printStackTrace();
        }
    }

通过js创建java对象

jjs> var HashMap = Java.type("java.util.HashMap")
jjs> var mapDef = new HashMap()
jjs> var map100 = new HashMap(100)

访问类和实例成员

jjs> Java.type("java.lang.Math").PI
3.141592653589793
jjs> Java.type("java.lang.System").currentTimeMillis()
1375813353330
jjs> Java.type("java.util.Map").Entry
[JavaClass java.util.Map$Entry]

内部类也可以使用内部表示来访问,其中美元符号 () 作为分隔符或点,这与 Java 一致:$

jjs> Java.type("java.util.Map$Entry")
[JavaClass java.util.Map$Entry]
jjs> Java.type("java.util.Map.Entry")
[JavaClass java.util.Map$Entry]

要调用实例方法或访问对象的实例字段,请使用点运算符,类似于在 Java 中完成的方式。下面的示例演示如何在对象上调用该方法:toUpperCase()String

jjs> var String = Java.type("java.lang.String")
jjs> var str = new String("Hello")
jjs> str
Hello
jjs> var upper = str.toUpperCase()
jjs> upper
HELLO

使用 JavaBeans

Nashorn 使您能够将 JavaBeans 中的访问器和突变器方法视为等效的 JavaScript 属性。属性的名称是不带 or 后缀的 JavaBean 方法的名称,并以小写字母开头。getset

例如,您可以使用属性调用对象中的 and 方法,如下所示:getYear()setYear()java.util.Dateyear

jjs> var Date = Java.type("java.util.Date")
jjs> var date = new Date()
jjs> date.year + 1900
2013
jjs> date.year = 2014 - 1900
114
jjs> date.year + 1900
2014

扩展 Java 类

您可以使用将 Java 类型作为第一个参数的函数和将方法实现(以 JavaScript 函数的形式)作为其他参数的函数来扩展类。Java.extend()

以下脚本扩展接口并使用它来构造新对象:java.lang.Runnablejava.lang.Thread

var Run = Java.type("java.lang.Runnable");
var MyRun = Java.extend(Run, {
    run: function() {
        print("Run in separate thread");
    }
});
var Thread = Java.type("java.lang.Thread");
var th = new Thread(new MyRun());

访问 Java 类

使用 Nashorn 访问包和类有两种方法:传统方法是使用全局对象,推荐的方法是使用全局对象。本节介绍这两种方法。PackagesJava

预定义的顶级对象使您能够使用完全限定的名称访问 Java 包和类,就好像它们是对象的属性一样。以下示例演示如何访问包及其类(如果位于类路径中):PackagesPackagesMyPackageMyClassMyPackage.jar

jjs> Packages.MyPackage
[JavaPackage MyPackage]
jjs> Packages.MyPackage.MyClass
[JavaClass MyPackage.MyClass]

访问标准 Java 包和类比访问定制包和类更简单。为方便起见,为每个标准 Java 包定义了全局对象:、、、 和 。它们具有与对象的属性相对应的别名。下面的示例演示如何访问包和类:comedujavajavaxorgPackagesjava.langjava.lang.System

jjs> java.lang
[JavaPackage java.lang]
jjs> typeof java.lang
object
jjs> java.lang.System
[JavaClass java.lang.System]
jjs> typeof java.lang.System
function

报错

java.lang.NullPointerException: Script for [js] not support !

Cannot invoke "javax.script.ScriptEngine.eval(String)" because "jsEngine" is

项目中使用了 com.github.whvcse包的easy-captcha 验证码依赖,升级至Jdk17后,验证码接口报错:Cannot invoke "javax.script.ScriptEngine.eval(String)" because "engine" is null,错误原因很明显脚本引擎执行脚本语句报错,因为执行引擎为空。查询相关资料Jdk8自带的JavaScript引擎 nashorn 再升级到Jdk9后就被移除了,从而导致报错

解决办法:添加JavaScript引擎 nashorn依赖

<dependency>
    <groupId>org.openjdk.nashorn</groupId>
    <artifactId>nashorn-core</artifactId>
    <version>15.4</version>
</dependency>

动态代码 预留js hook

通过js动态调整业务逻辑  处理数据等  js代码存到数据库 或 缓存文章来源地址https://www.toymoban.com/news/detail-788576.html

到了这里,关于【技巧】ScriptEngine--Java动态执行JS Javascript脚本(可调用java的方法)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • c#动态执行脚本的3种方式

    在C#中,可以使用一些第三方库或内置类库实现动态执行脚本的功能。以下是几个常用的方案: 使用Roslyn编译器 Roslyn是微软推出的一个开源的.NET编译器平台,它可以在运行时动态编译C#代码并执行。通过Roslyn,可以实现对于代码的热更新。 示例代码: 在上面的示例代码中,

    2024年02月08日
    浏览(15)
  • 软件测试|selenium执行js脚本

    JavaScript是运行在客户端(浏览器)和服务器端的脚本语言,允许将静态网页转换为交互式网页。可以通过 Python Selenium WebDriver 执行 JavaScript 语句,在Web页面中进行js交互。那么js能做的事,Selenium应该大部分也能做。WebDriver是模拟终端用户的交互,所以就不能点击不可见的元素

    2024年02月05日
    浏览(31)
  • 基于Selenium模块实现无界面模式 & 执行JS脚本

    此篇文章主要介绍如何使用 Selenium 模块实现 无界面模式 执行JS脚本(把滚动条拉到底部),并以具体的示例进行展示。 创建浏览器对象之前,创建 options 功能对象 : options = webdriver.ChromeOptions() 添加无界面功能参数: options.add_argument(\\\"--headless\\\") 构造浏览器对象,打开浏览器,并

    2024年02月13日
    浏览(25)
  • 【前端灵魂脚本语言JavaScript⑤】——JS中数组的使用

    🐚 作者: 阿伟 💂 个人主页: Flyme awei 🐋 希望大家多多支持😘一起进步呀! 💬 文章对你有帮助👉关注✨点赞👍收藏📂 第一种: var 数组名 = new Array(); 创建一个空数组 第二种: var arr2 = new Array(10); 创建一个定长为10的数组 第三种 var arr3 = new Array(a,b,c); 创建时直接指定元素值

    2023年04月08日
    浏览(38)
  • 安卓手机怎么运行js脚本,手机的javascript怎么开

    大家好,小编为大家解答手机怎么启用javascript功能的问题。很多人还不知道安卓手机怎么运行js脚本,现在让我们一起来看看吧!         最近在研究c++与JavaScript的交互,有朋友问我安卓怎样与JavaScript交互,今天找到一个之前写的小demo,实现的是安卓webview里面的JavaScript和

    2024年01月23日
    浏览(39)
  • 【转】JavaScript 执行上下文——JS 的幕后工作原理

    转自译文: JavaScript 执行上下文——JS 的幕后工作原理 。 译文中图片不显示,要结合原文看,看着不方便。整理了一份含图片的。所以有了此篇的转载,以方便阅读。 以下是正文: 原文:JavaScript Execution Context – How JS Works Behind The Scenes,作者:Victor Ikechukwu 所有JavaScript代码

    2024年01月20日
    浏览(29)
  • 如何动态执行JS

    引言:随着行业发展,技术更新,生产结构发生变化,低代码技术又重新站上了舞台,开发者们成为了舞台幕后的操纵者。在web端的低代码开发工具中,js占据了重要的位置,而【动态执行】也成为了低代码开发工具中不可或缺的一部分。本文记录了js的动态执行方法,以备不

    2024年02月06日
    浏览(24)
  • js实用方法记录-js动态加载css、js脚本文件

    附送一个加载iframe,h5打开app代码 方法调用: dynamicLoadJs(\\\'http://www.yimo.link/static/js/main.min.js\\\',function(){alert(\\\'加载成功\\\')}); 方法调用:  dynamicLoadCss(\\\'http://www.yimo.link/static/css/style.css\\\') 参考:动态加载js和css - 猿客 - 博客园 方法调用: dynamicLoadIframe(\\\'http://www.yimo.link\\\',function(){alert(\\\'加载

    2024年02月13日
    浏览(31)
  • javascript设置指定年月日,js动态显示当前时间

    大家好,本文将围绕js中如何动态显示日期时间展开说明,javascript设置指定年月日是一个很多人都想弄明白的事情,想搞清楚js动态显示当前时间需要先了解以下几个事情。 创建showTime()函数,利用JavaScript中的Date对象的属性及方法获取时间,利用Window对象的 setInterval() 方法按

    2024年02月03日
    浏览(27)
  • 在java中使用javascript脚本

    在java中执行js脚本,首先感觉这种操作有点无意义,但是存在即合理,作者要设计这个功能应该是有他的使用场景。java中支持使用jsp写网页,估计是这个原因才有了脚本引擎。 一、java支持的脚本语言查看 我们可以通过下面的代码查看目前支持的脚本语言: 可以看到输出内

    2024年02月04日
    浏览(22)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包