Java 脚本 引擎 jsr223 与 javascript 文件交互

来源:互联网 发布:录音软件 比特率 编辑:程序博客网 时间:2024/06/05 21:14

JDK1.6开始,Java引入了jsr223,就是可以用一致的形式在JVM上执行一些脚本语言,如js脚本,本文详细说明了java脚本引擎的使用方式,并贴出了大量的经过实际测试的java源代码,请各位参考:

Java 脚本引擎技术相关内容,都已经在Java代码中以注释的形式说明了,请测评:


package jaas;import javax.naming.Context;import javax.naming.InitialContext;import javax.script.*;import java.io.File;import java.util.*;public class Test {    /**     * 文中的某些示例用到了 JNDI,需要提供 JNDI 实现者,参数:-Djava.naming.factory.initial=org.apache.naming.java.javaURLContextFactory     * 使用了 Tomcat 的 JNDI 实现,添加依赖:     * <dependency>     * <groupId>org.apache.tomcat</groupId>     * <artifactId>tomcat-catalina</artifactId>     * <version>8.5.6</version>     * </dependency>     */    public static void main(String[] args) throws Exception {        // 获取脚本引擎管理器        ScriptEngineManager manager = new ScriptEngineManager();        List<ScriptEngineFactory> engineFactories = manager.getEngineFactories();        System.out.println("当前 JVM 支持的脚本引擎:");        for (ScriptEngineFactory sef : engineFactories) {            System.out.println("引擎名称:" + sef.getEngineName());            System.out.println("\t 别名:" + sef.getNames());            System.out.println("\t MimeTypes:" + Arrays.asList(sef.getMimeTypes()));        }        System.out.println();        // 获取指定的 js 脚本引擎        ScriptEngine jsEngine = manager.getEngineByName("js");//        ScriptEngine jsEngine = manager.getEngineByName("javascript");//        ScriptEngine jsEngine = new ScriptEngineManager().getEngineByMimeType("text/javascript");        // 引擎测试        /**         * 脚本语言支持API使用语言绑定对象实现Java语言编写的程序与脚本语言间的数据传递。         * 语言绑定对象实际上就是一个简单的哈希表,用来存放和获取需要共享的数据,         * 其定义的接口为javax.script.Bindings,继承自java.util.Map接口。         * 一个脚本引擎在执行过程中可能会使用多个语言绑定对象,不同语言绑定对象的作用域不同。         * ScriptEngine类提供out和get方法对脚本引擎中特定作用域的默认语言绑定对象进行操作。         */        testEngine(jsEngine);        //        testContext_Java_Params(jsEngine);    }    public static void testEngine(ScriptEngine engine) throws Exception {        engine.put("name", "张三");// 参数        engine.eval("var msg = '你好, ' + name;");// 使用某作用域的参数        engine.eval("println('js println: '+msg);");// 使用某作用域的参数        Object obj = engine.get("msg");// java 可获取到 js 脚本返回的对象        System.out.println("java println: " + obj);        System.out.println();        // 自定义语言绑定对象(如语言绑定对象中包含程序自己独有的数据等情形……)        Bindings bindings = new SimpleBindings();        bindings.put("fruit", "Apples");        engine.eval("println('I like ' + fruit);", bindings);        System.out.println();        ScriptContext context = engine.getContext();// 获取引擎默认的上下文        // 重定向输出到文件//        context.setWriter(new FileWriter("/home/conquer/Desktop/a.txt"));        engine.eval("println('Hello World, I am from Js script.');");        System.out.println();        // 绑定对象作用域1        context.setAttribute("name", "张三", ScriptContext.GLOBAL_SCOPE);//从同一引擎工厂中创建的所有脚本引擎对象        context.setAttribute("name", "李四", ScriptContext.ENGINE_SCOPE);//当前的脚本引擎对象        Object name = context.getAttribute("name");//值按优先级为 李四        System.out.println(name);        System.out.println();        // 绑定对象作用域2        Bindings bindings1 = engine.createBindings();        bindings1.put("name", "张三");        context.setBindings(bindings1, ScriptContext.GLOBAL_SCOPE);        Bindings bindings2 = engine.createBindings();        bindings2.put("name", "李四");        context.setBindings(bindings2, ScriptContext.ENGINE_SCOPE);        engine.eval("println('脚本按优先级得到参数:'+name);");    //李四        System.out.println();        Bindings bindings3 = context.getBindings(ScriptContext.ENGINE_SCOPE);// 直接获取当前引擎作用域参数集合        Bindings bindings4 = context.getBindings(ScriptContext.GLOBAL_SCOPE);// 直接获取所有引擎作用域参数集合        context.setAttribute("name", "张三", ScriptContext.GLOBAL_SCOPE);// 属性设置也具有作用域的选择//        engine.eval("println(name);");        // b编译运行,提升脚本运行效率        if (engine instanceof Compilable) {            String performanceTest = "var a = 100;\n" +                    "var b = 100+a;\n" +                    "var c = a+b;\n" +                    "println(c);" +                    "println('');";            Compilable compilable = (Compilable) engine;            CompiledScript compiledScript = compilable.compile(performanceTest);            compiledScript.eval();        }        // 脚本中 调用 java 方法        File file = new File("/home/conquer/mine/work_space/idea/Eden/jse/src/main/java/jaas/loginscript.js");        engine.put("file", file);        Bindings engineBindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);        engineBindings.put("file2", file);        engine.eval("println('脚本中执行java对象方法:'+file.getAbsoluteFile())");        engine.eval("println('脚本中执行java对象方法2:'+file.getAbsoluteFile())");        engine.eval("println(file.getAbsolutePath());");        Object eval1 = engine.eval("file.getAbsolutePath();");        System.out.println("打印js从java得到的数据:" + eval1);        engine.eval("println(file.isHidden());");        Properties temp = new Properties();        temp.setProperty("aaa", "aaaaa");        engineBindings.put("properties", temp);        engine.eval("println(properties.toString());");        Object eval2 = engine.eval("properties.toString();");        System.out.println("打印js从java中读取Properties:" + eval2);        engine.eval("println(properties.getProperty('aaa'));");        Object eval3 = engine.eval("properties.getProperty('aaa');");        System.out.println("打印js从java中读取Properties,key 为 aaa:" + eval3);        SayHello sayHello = new SayHello();        engine.put("sayHello1", sayHello);        engine.getBindings(ScriptContext.ENGINE_SCOPE).put("sayHello2", sayHello);        engine.eval("println(sayHello1.hello('张三111'))");// 注意类必需声明为 public的        Object hello = engine.eval("sayHello2.hello('张三222')");// 注意类必需声明为 public的        System.out.println("js 获取到的java返回:" + hello);// ok        // 也可以通过下面的方式将 实参 放到 jndi 上下文中获取,脚本中仍然使用形式参数        ScriptContext scriptContext = new SimpleScriptContext();        Bindings bindings5 = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE);        bindings5.put("name", "张三");        Context ctx = new InitialContext();// 这里是启动之前设置的 tomcat的 jndi 实现        ctx.bind("jndiObj", sayHello);        Object eval = engine.eval("var ctx = new javax.naming.InitialContext();\n" +                "var myBean = ctx.lookup(\"jndiObj\");\n" +                "myBean.hello(name);", scriptContext);//                "myBean.hello('name');", scriptContext);// 使用 jndi 保存参数,这里不需要传递 实际参数        System.out.println("js 调用 java 方法返回值:" + eval);        System.out.println();        // 方法调用,Java 调用 脚本中定义的方法        /**         * 虚拟机支持脚本的意义在于实现函数式的编程,脚本中最重要的便是方法,         * 脚本引擎允许使用者单独调用脚本中的某个方法,         * 支持此操作的脚本引擎可以通过实现javax.script.Invocable接口。         * JavaSE中的JavaScript引擎已实现了Invocable接口。         */        if (engine instanceof Invocable) {            String scriptText = "function greet(name) { println('Hello, ' + name); } ";            engine.eval(scriptText);// 这里是在定义 greet 方法,只有定义以后才能进行调用:invokeFunction            Invocable invocable = (Invocable) engine;            invocable.invokeFunction("greet", "张三");// 调用方法,并传递参数            // 调用成员方法            String scriptText2 = "var obj = { getGreeting : function(name) { return 'Hello, ' + name; } }; ";            engine.eval(scriptText2);// 定义脚本对象,并且定义对象成员方法            Object scriptObj = engine.get("obj");//获取到脚本中的实例化的对象            Object result = invocable.invokeMethod(scriptObj, "getGreeting", "张三");   //第一个参数为方法所属对象,后面调用对象的方法和参数            System.out.println(result);            // 脚本方法 Java 化 !!! 是指将 java 的调用自动映射到脚本中方法执行上,            // 需要用到java 接口,接口的方法定义和脚本中方法定义一致,即:脚本作为 接口 的实现类            String scriptText3 = "function getGreeting(name) { " +                    "println('我是 Java 定义的 Greet 接口的具体实现哦...');" +                    "return '你好, ' + name; } ";            engine.eval(scriptText3);            Greet greet = invocable.getInterface(Greet.class);            System.out.println(greet.getGreeting("Alex"));        }    }    interface Greet {        String getGreeting(String name);    }    public static void testContext_Java_Params(ScriptEngine engine) throws Exception {        Map<String, String> params = new HashMap() {{            // 脚本中需要的形参名称及对应的实参值            put("user", "admin");// 必需包含 js 脚本中调用的LoginBean.authenticate类方法需要的参数            put("password", "pwd");// 必需包含 js 脚本中调用的LoginBean.authenticate类方法需要的参数        }};        // 脚本需要的 ScriptContext 对象,脚本中引起的参数都需要从这个对象里面获取        ScriptContext scriptContext = new SimpleScriptContext();//也可以在这里直接 new 出来//        ScriptContext scriptContext = engine.getContext();// 构造参数里面也是直接 new 出来的        /**         * 绑定参数两个作用域:         * ScriptContext.ENGINE_SCOPE(当前的脚本引擎)         * ScriptContext.GLOBAL_SCOPE(从同一引擎工厂中创建的所有脚本引擎对象)         */        // 绑定方式1        Bindings bindings = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE);        // 脚本中需要的形参名称及对应的实参值//        bindings.put("user", "admin");//        bindings.put("password", "pwd");        bindings.putAll(params);        // 绑定方式2//        for (Map.Entry<String, String> e : params.entrySet()) {//            scriptContext.setAttribute(e.getKey(), e.getValue(), ScriptContext.GLOBAL_SCOPE);//        }        // 写自己的这个 JNDI 上下文,是因为 js 脚本中的内容要用到 应用自定义的对象,而在脚本中不能创建 非 java 的对象        // 所以我们事先创建好,放到 JNDI 上下文,以供脚本中 lookup 查找并使用对象        InitialContext context = new InitialContext();        context.bind("script_ref_obj", new LoginBean());        String scriptText = getScriptText();        System.out.println("脚本内容:");        System.out.println(scriptText);        System.out.println();        List<String> myGroups = (List<String>) engine.eval(scriptText, scriptContext);// 脚本的最后以后具有返回值的可以在这里获取到!!        System.out.println("脚本执行后的返回值:");        System.out.println(myGroups);    }    /**     * Scanner 类用于扫描、接收、分段处理字符串,可以指定分割符号,     * 通过 一系列的 nextXXX() 可以依次获取到分割的内容片段     * <p>     * Scanner 可以接入一个 InputStream 或者一个 File(内部转为FileInputStream)以作为字符输入端     */    private static String getScriptText() throws Exception {//        测试的话,可以将脚本内容直接硬编码写在这里:        String jsText = "println(\"js begin invoke...\");\n" +                "var ctx = new javax.naming.InitialContext();\n" +                "var myBean = ctx.lookup(\"script_ref_obj\");\n" +                "myBean.authenticate(user, password);";        return jsText;//        从文件中读取脚本//        Scanner 可以采用正则表达式分段读取字符串内容,分段符合可以使用 useDelimiter 方法指定//        如果不写,默认是空格分割 scanner.useDelimiter(",") 表示以“,”分割读取内容//        File script = new File("/home/conquer/mine/work_space/idea/Eden/jse/src/main/java/jaas/loginscript.js");//        Scanner scanner = new Scanner(script).useDelimiter("\\Z");//        return scanner.next();    }}

package jaas;import javax.security.auth.login.FailedLoginException;import java.util.Arrays;import java.util.List;public class LoginBean {    public List<String> authenticate(String user, String password) throws FailedLoginException {        System.out.println("从 js 脚本调入进来的 java 方法开始执行...");        System.out.println("user:" + user);        System.out.println("password:" + password);        if (true) {// test            return Arrays.asList("adminRole", "tomcatRole");        }        if ("paul".equals(user) && "michelle".equals(password)) {            return Arrays.asList("Manager", "rockstar", "beatle");        }        if ("eddie".equals(user) && "jump".equals(password)) {            return Arrays.asList("Employee", "rockstar", "vanhalen");        }        throw new FailedLoginException("Bad user or password!");    }}

package jaas;public class SayHello {    public String hello(String name) {        System.out.println("java 方法执行");        return "你好," + name;    }}

loginscript.js 脚本文件内容:

println("js begin invoke...");var ctx = new javax.naming.InitialContext();var myBean = ctx.lookup("script_ref_obj");myBean.authenticate(user, password);


原创粉丝点击