在 Java 中执行 JScript 代码
最编程
2024-04-23 10:52:18
...
一、pom文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>me.ele</groupId>
<artifactId>test_invokeJS</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.mozilla/rhino -->
<dependency>
<groupId>org.mozilla</groupId>
<artifactId>rhino</artifactId>
<version>1.7R4</version>
</dependency>
</dependencies>
</project>
二、详细代码:
package me.ele;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.NativeJavaObject;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
/**
* @author LZJ
* @create 2018-09-17 20:02
**/
public class JsInvoker {
/**
* 执行JS返回string
*
* @param js js代码
* @param functionName js方法名称
* @param functionParams js方法参数
* @return
*/
public String runScript(String js, String functionName, Object[] functionParams) {
/**
* 在导入 Rhino JavaScript 的 Java 包之后,需要创建并进入 Context。
* 本步骤的作用在于构造 JavaScript 的运行环境,Context 中储存了脚本执行的全局环境信息
*/
Context rhino = Context.enter();
rhino.setOptimizationLevel(-1);
try {
/**
* 在使用 Rhino 执行脚本之前,必须初始化标准对象(Object,Function 等)
* 在 Java 中调用 JavaScript 变量就是通过该对象实现。
* 初始化标准化对象,需要调用上下文实例的 initStandardObjects 方法,
* 执行结果将会返回一个 Scriptable 实例化对象
*/
Scriptable scope = rhino.initStandardObjects();
ScriptableObject.putProperty(scope, "javaContext", Context.javaToJS(JsInvoker.this, scope));
/**
* (scope, string, error, num, null)
* JavaScript 脚本的执行是使用上下文示例中的 evaluateString 方法,执行脚本字符串 string,
* 当脚本中需要使用其它变量时,会在作用域 scope 中寻找所需要的变量,如果发生异常的话则会报告 error
* 错误信息和所在的行号 num,正确执行结束后会返回一个 Object 对象的运行结果
*/
rhino.evaluateString(scope, js, "MainActivity", 1, null);
Function function = (Function) scope.get(functionName, scope);
Object result = function.call(rhino, scope, scope, functionParams);
if (result instanceof String) {
return (String) result;
} else if (result instanceof NativeJavaObject) {
return (String) ((NativeJavaObject) result).getDefaultValue(String.class);
} else if (result instanceof NativeObject) {
return (String) ((NativeObject) result).getDefaultValue(String.class);
}
return result.toString();
} finally {
/**
* 束上下文是每次使用 Rhino 结束后必须要做的工作,
* 它将移除上下文和当前的线程并做垃圾回收
*/
Context.exit();
}
}
/**
* @param js js代码
*
* @return eval方法是执行js脚本,返回脚本的返回值
*/
public String runScriptS(String js) {
//创建 脚本引擎管理器
ScriptEngineManager factory = new ScriptEngineManager();
//获取一个指定的名称的脚本引擎
ScriptEngine engine = factory.getEngineByName("JavaScript");
String a = null;
try {
a = String.valueOf(engine.eval(js));
} catch (ScriptException e) {
e.printStackTrace();
}
return a;
}
/**
* 执行无参js
*
* @param js js内容
* @param functionName js方法名称
* @return js中执行方法的返回值
*/
public String runScript(String js, String functionName) {
//创建 脚本引擎管理器
ScriptEngineManager factory = new ScriptEngineManager();
//获取一个指定的名称的脚本引擎
ScriptEngine engine = factory.getEngineByName("JavaScript");
String value = null;
try {
engine.eval(js);
if (engine instanceof Invocable) {
Invocable inv = (Invocable) engine;
value = String.valueOf(inv.invokeFunction(functionName));
}
} catch (Exception e) {
e.printStackTrace();
}
return value;
}
/**
*
*
* @param js js代码
* @param functionName js方法名称
* @param functionParams js参数
* @return 调用js的返回值
*/
public String script(String js, String functionName, Object[] functionParams) {
if (functionParams == null
&& js != null
&& functionName != null) { //无参数
return this.runScript(js, functionName);
} else if (functionParams != null
&& js != null
&& functionName != null) { //一个参数
return this.runScript(js, functionName, functionParams);
} else if (js != null) { //只有js代码
return this.runScriptS(js);
}
return null;
}
}
推荐阅读
-
CVPR2021 新骨干网 | ReXNet 在 CV 全任务中以超低 FLOP 达到 SOTA 水平(在文章末尾下载论文和源代码)
-
贪婪算法在 Python、JavaScript、Java、C++ 和 C# 中的多种实现及其在硬币变化、分数骑士、活动选择和使用哈夫曼编码的最小生成树问题中的应用实例
-
模型在执行路径过程中的三.js 动画(tween.js)
-
在 Java 中输入单个字符的 2 种方法:
-
在 Java 中获取键盘输入值的三种方法
-
键在 Java 中的含义
-
在代码中创建和使用 java CA 证书
-
一种结构设计模式,允许在对象中动态添加新行为。它通过创建一个封装器来实现这一目的,即把对象放入一个装饰器类中,然后把这个装饰器类放入另一个装饰器类中,以此类推,形成一个封装器链。这样,我们就可以在不改变原始对象的情况下动态添加新行为或修改原始行为。 在 Java 中,实现装饰器设计模式的步骤如下: 定义一个接口或抽象类作为被装饰对象的基类。 公共接口 Component { void operation; } } 在本例中,我们定义了一个名为 Component 的接口,该接口包含一个名为 operation 的抽象方法,该方法定义了被装饰对象的基本行为。 定义一个实现基类方法的具体装饰对象。 公共类 ConcreteComponent 实现 Component { public class ConcreteComponent implements Component { @Override public void operation { System.out.println("ConcreteComponent is doing something...") ; } } 定义一个抽象装饰器类,该类继承于基类,并将装饰对象作为一个属性。 公共抽象类装饰器实现组件 { protected Component 组件 public Decorator(Component component) { this.component = component; } } @Override public void operation { component.operation; } } } 在这个示例中,我们定义了一个名为 Decorator 的抽象类,它继承了 Component 接口,并将被装饰对象作为一个属性。在操作方法中,我们调用了被装饰对象上的同名方法。 定义一个具体的装饰器类,继承自抽象装饰器类并实现增强逻辑。 公共类 ConcreteDecoratorA extends Decorator { public ConcreteDecoratorA(Component 组件) { super(component); } } public void operation { super.operation System.out.println("ConcreteDecoratorA 正在添加新行为......") ; } } 在本例中,我们定义了一个名为 ConcreteDecoratorA 的具体装饰器类,它继承自装饰器抽象类,并实现了操作方法的增强逻辑。在操作方法中,我们首先调用被装饰对象上的同名方法,然后添加新行为。 使用装饰器增强被装饰对象。 公共类 Main { public static void main(String args) { Component 组件 = new ConcreteComponent; component = new ConcreteDecoratorA(component); 组件操作 } } 在这个示例中,我们首先创建了一个被装饰对象 ConcreteComponent,然后通过 ConcreteDecoratorA 类创建了一个装饰器,并将被装饰对象作为参数传递。最后,调用装饰器的操作方法,实现对被装饰对象的增强。 使用场景 在 Java 中,装饰器模式被广泛使用,尤其是在 I/O 中。Java 中的 I/O 库使用装饰器模式实现了不同数据流之间的转换和增强。 让我们打开文件 a.txt,从中读取数据。InputStream 是一个抽象类,FileInputStream 是专门用于读取文件流的子类。BufferedInputStream 是一个支持缓存的数据读取类,可以提高数据读取的效率,具体代码如下: @Test public void testIO throws Exception { InputStream inputStream = new FileInputStream("C:/bbb/a.txt"); // 实现包装 inputStream = new BufferedInputStream(inputStream); byte bytes = new byte[1024]; int len; while((len = inputStream.read(bytes)) != -1){ System.out.println(new String(bytes, 0, len)); } } } } 其中 BufferedInputStream 对读取数据进行了增强。 这样看来,装饰器设计模式和代理模式似乎有点相似,接下来让我们讨论一下它们之间的区别。 第三,与代理模式的区别: 代理模式的目的是控制对对象的访问,它在对象外部提供一个代理对象来控制对原对象的访问。代理对象和原始对象通常实现相同的接口或继承相同的类,以确保两者可以相互替换。 装饰器模式的目的是动态增强对象的功能,而这是通过对象内部的包装器来实现的。在装饰器模式中,装饰器类和被装饰对象通常实现相同的接口或继承自相同的类,以确保两者可以相互替代。装饰器模式也被称为封装器模式。 在代理模式中,代理类附加了与原类无关的功能。
-
为什么UTF-8 和 GBK 会相互转换,为什么会一团糟?-锟斤拷 "是指在字节和字符的转换(编码和解码)过程中使用了不同的编码,找出编码和解码的编码,修改后使用同一种编码。 ===================== 补充 ========================== 在上面的文章中,其实一直回避了一个问题,那就是既然保存中的所有字符都需要转换成二进制,那么 java 是使用什么编码来保存字符的呢?这个问题我们其实可以不必深究,因为它对我们来说是透明的,我们只需假定 java 使用了某种可以表示所有字符的编码。由于这种透明性,我们可以假设 java 直接保存字符本身,就像上面所说的那样。 在 java 虚拟机中使用的是 unicode 字符集。
-
在 Android 中延迟执行任务和轮询定时任务的几种常见方法