JAVA中执行JavaScript代码并获取返回值

场景描述

今天在CSDN上偶然看到一个帖子对于一段字符串 “var p=‘xxxx’” 怎么在java里获得p的值,我想起了以前一个很有意思的场景,我的一位很NB的前同事做了一件很了不起的事,他当时配置acitiviti流程引擎的时候为了做变量控制,把变量控制的条件写成了一个javascript的表达式,大概类似于groupNumber==1&&hasRead&&ticketType==1这种表达式,然后再JAVA代码中把这些表达式执行了一下获取一个布尔值作为流程控制的依据,我当时觉得思想很不错!

后来,我在同一个项目中遇到了另外一个场景,在计算一个报表的某个值的时候需要使用对象中的一个参数,这个参数是用户通过页面配置的,大概是这种样子100*23230这种,我在看到了我这位前辈的思想之后,我采用的方式是这样的,把这个字段作为字符串让用户在页面上输入,然后通过前辈的思想把这个字符串作为一个JavaScript代码段执行一下,获取返回值,用这个返回值作为计算参数参与报表计算.

实现思路

把入参作为JavaScript代码,通过JavaScript执行引擎执行这个代码,获取返回值

技术要点

合理的使用JavaScript解析引擎

代码实现

package com.hykj.util;

import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.Map;
import java.util.Set; /**
* java执行javaScript代码的工具类
*
* @author weizj
*/
public class JavaScriptUtil { /** 单例的JavaScript解析引擎 */
private static ScriptEngine javaScriptEngine; static {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine scriptEngine = manager.getEngineByName("js");
if (scriptEngine == null) {
throw new RuntimeException("获取JavaScript解析引擎失败");
}
javaScriptEngine = scriptEngine;
} /**
* 执行一段JavaScript代码
*
* @param script JavaScript的代码
* @return JavaScript代码运行结果的值
* @throws ScriptException JavaScript代码运行异常
*/
public static Object execute(String script) throws ScriptException {
return javaScriptEngine.eval(script);
} /**
* 运行一个JavaScript代码段,并获取指定变量名的值
*
* @param script 代码段
* @param attributeName 已知的变量名
* @return 指定变量名对应的值
* @throws ScriptException JavaScript代码运行异常
*/
public static Object executeForAttribute(String script, String attributeName) throws ScriptException {
javaScriptEngine.eval(script);
return javaScriptEngine.getContext().getAttribute(attributeName);
} /**
* 获取当前语句运行后第一个有值变量的值
*
* @param script 代码段
* @return 第一个有值变量的值
* @throws ScriptException JavaScript代码运行异常
*/
public static Object executeForFirstAttribute(String script) throws ScriptException { //这里重新获取一个JavaScript解析引擎是为了避免代码中有其他调用工具类的地方的变量干扰
//重新获取后,这个JavaScript解析引擎只执行了这次传入的代码,不会保存其他地方的变量
//全局的解析器中会保存最大200个变量,JavaScript解析引擎本身最大保存100个变量
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine scriptEngine = manager.getEngineByName("js");
if (scriptEngine == null) {
throw new RuntimeException("获取JavaScript解析引擎失败");
} scriptEngine.eval(script);
ScriptContext context = scriptEngine.getContext();
if (context == null) {
return null;
}
Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);
if (bindings == null) {
return null;
}
Set<Map.Entry<String, Object>> entrySet = bindings.entrySet();
if (entrySet == null || entrySet.isEmpty()) {
return null;
}
for (Map.Entry<String, Object> entry : entrySet) {
if (entry.getValue() != null) {
return entry.getValue();
}
}
return null;
}
}

测试方法

   public static void main(String[] args) throws ScriptException {
Integer testExecute = (Integer) execute("2*3");
String testExecuteForAttribute = (String) executeForAttribute("var value = 'a'+ 'dc'", "value");
Boolean testExecuteForFirstAttribute = (Boolean) executeForFirstAttribute("var a = 6==2*3"); System.out.println(testExecute);
System.out.println(testExecuteForAttribute);
System.out.println(testExecuteForFirstAttribute); System.out.println("test over ...."); }

运行结果

"C:\Program Files\Java\jdk1.8.0_191\bin\java.exe" -agentlib:...
com.hykj.util.JavaScriptUtil
Connected to the target VM, address: '127.0.0.1:56704', transport: 'socket'
6
adc
true
test over ....
Disconnected from the target VM, address: '127.0.0.1:56704', transport: 'socket' Process finished with exit code 0

从运行结果中可以看到,需求是可以实现的,包含了执行代码并获取值

新增的executeForAttribute是为了解答开篇的帖子的问题

后来我又想了一下,可能是运行语句的时候并不知道变量名于是增加了一个不太严谨的executeForFirstAttribute方法用来处理一下这个问题,但是自我感觉这个方法并不很合适

改进空间

  1. 语句中如果包含参数是无法执行的,等有空的时候研究一下如何传参
  2. 目前只试验了Integer,String,Boolean这三个常用的类型,如果是如Person等复杂类型,不知道代码运行情况如何
  3. executeForFirstAttribute方法不知道如何改进才能满足大多数情况

JAVA中执行JavaScript代码并获取返回值的更多相关文章

  1. 尚学堂 215 在java中执行JavaScript代码

    package com.bjsxt.test; import java.io.FileReader; import java.net.URL; import java.util.List; impor ...

  2. UWP 在 WebView 中执行 JavaScript 代码(用于模拟用户输入等) - walterlv

    原文:UWP 在 WebView 中执行 JavaScript 代码(用于模拟用户输入等) - walterlv UWP 在 WebView 中执行 JavaScript 代码(用于模拟用户输入等) ...

  3. Java中运行javascript代码

    Java中运行javascript代码 1.Java 代码 2.JS代码 2.1demoWithParams.js 2.2demoWithListParams.js 原文作者:russle 原文地址: ...

  4. python中执行javascript代码

    python中执行javascript代码: 1.安装相应的库,我使用的是PyV8 2.import PyV8 ctxt = PyV8.JSContext()     ctxt.enter()     ...

  5. java中执行js代码

    要在java中执行js代码,首先明白,java不支持浏览器本身的方法.支持自定义的js方法,否则会报错 先新建一个js文件:jsss.js 内容如下: function aa(a,b){ return ...

  6. 在Java中执行js代码

    在某些特定场景下,我们需要用Java来执行Js代码(如模拟登录时,密码被JS加密了的情况),操作如下: ScriptEngineManager mgr = new ScriptEngineManage ...

  7. UWP 在 WebView 中执行 JavaScript 代码(用于模拟用户输入等)

    UWP 中使用 WebView 时可以在网页中额外执行一些代码.于是你几乎可以在网页上做任何事情,那些你可以在浏览器控制台中做的事情. 本文将介绍做法. 本文内容 准备环境 执行 JavaScript ...

  8. java中执行javascript案例

    Nashorn js engine官方文档 https://docs.oracle.com/javase/7/docs/technotes/guides/scripting/programmer_gu ...

  9. python 利用python的subprocess模块执行外部命令,获取返回值

    有时执行dos命令需要保存返回值 需要导入库subprocess import subprocess p = subprocess.Popen('ping www.baidu.com', shell= ...

随机推荐

  1. 【译】深度双向Transformer预训练【BERT第一作者分享】

    目录 NLP中的预训练 语境表示 语境表示相关研究 存在的问题 BERT的解决方案 任务一:Masked LM 任务二:预测下一句 BERT 输入表示 模型结构--Transformer编码器 Tra ...

  2. 最大化系统并发连接数.Windows.reg

    最大化系统并发连接数.Windows.reg Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentContro ...

  3. Mysql的隔离级别

    一.首先什么是事务? 事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消.也就是事务具有原子性,一个事务中的一系列的操作要么全部成功,要么一个都不做. 事 ...

  4. python入门(十一):异常

     1.异常概念: >>> a Traceback (most recent call last): File "<stdin>", line 1, i ...

  5. Python 3之Django2部署(centos7+nginx+python3+django2.0)

    前置工具,系统为centos7.5,为了方便管理,可以安装宝塔免费版本 首先, yum install -y wget && wget -O install.sh http://dow ...

  6. 一些常用的 std 类型

    [std::allocator] 标准库中包含一个名为allocator的类,允许我们将分配和初始化分离.使用allocator通常会提供更好的性能和更灵活的内存管理能力. 标准库allocator类 ...

  7. JavaScript进度条(datalist/repeater等多个进度条)

    JS代码: function SingleProgressBar() { var iload = document.getElementById("iLoading"); var ...

  8. Java跨平台的原理

    使用Java语言编写应用程序最大的优点在于“一次编译,处处运行”,然而这并不是说所有的Java程序都具有Java跨平台的特性, 事实上,相当一部分的Java程序是不能在别的操作系统上正确运行的. Ja ...

  9. Jmeter启动默认中文

    打开Jmeter的安装目录,然后在bin目录下查找jmeter.properties  这个文件 打开文件,找到   #language=en   并改为  language=zh_CN     ,注 ...

  10. 100-days: twenty-six

    Title: The Guardian(英国卫报) view on the Notre Dame fire: we share France's terrible loss Notre Dame 巴黎 ...