JAVA中执行JavaScript代码并获取返回值
场景描述
今天在CSDN上偶然看到一个帖子对于一段字符串 “var p=‘xxxx’” 怎么在java里获得p的值,我想起了以前一个很有意思的场景,我的一位很NB的前同事做了一件很了不起的事,他当时配置acitiviti流程引擎的时候为了做变量控制,把变量控制的条件写成了一个javascript的表达式,大概类似于groupNumber==1&&hasRead&&ticketType==1这种表达式,然后再JAVA代码中把这些表达式执行了一下获取一个布尔值作为流程控制的依据,我当时觉得思想很不错!
后来,我在同一个项目中遇到了另外一个场景,在计算一个报表的某个值的时候需要使用对象中的一个参数,这个参数是用户通过页面配置的,大概是这种样子100*23或230这种,我在看到了我这位前辈的思想之后,我采用的方式是这样的,把这个字段作为字符串让用户在页面上输入,然后通过前辈的思想把这个字符串作为一个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方法用来处理一下这个问题,但是自我感觉这个方法并不很合适
改进空间
- 语句中如果包含参数是无法执行的,等有空的时候研究一下如何传参
- 目前只试验了
Integer,String,Boolean这三个常用的类型,如果是如Person等复杂类型,不知道代码运行情况如何 executeForFirstAttribute方法不知道如何改进才能满足大多数情况
JAVA中执行JavaScript代码并获取返回值的更多相关文章
- 尚学堂 215 在java中执行JavaScript代码
package com.bjsxt.test; import java.io.FileReader; import java.net.URL; import java.util.List; impor ...
- UWP 在 WebView 中执行 JavaScript 代码(用于模拟用户输入等) - walterlv
原文:UWP 在 WebView 中执行 JavaScript 代码(用于模拟用户输入等) - walterlv UWP 在 WebView 中执行 JavaScript 代码(用于模拟用户输入等) ...
- Java中运行javascript代码
Java中运行javascript代码 1.Java 代码 2.JS代码 2.1demoWithParams.js 2.2demoWithListParams.js 原文作者:russle 原文地址: ...
- python中执行javascript代码
python中执行javascript代码: 1.安装相应的库,我使用的是PyV8 2.import PyV8 ctxt = PyV8.JSContext() ctxt.enter() ...
- java中执行js代码
要在java中执行js代码,首先明白,java不支持浏览器本身的方法.支持自定义的js方法,否则会报错 先新建一个js文件:jsss.js 内容如下: function aa(a,b){ return ...
- 在Java中执行js代码
在某些特定场景下,我们需要用Java来执行Js代码(如模拟登录时,密码被JS加密了的情况),操作如下: ScriptEngineManager mgr = new ScriptEngineManage ...
- UWP 在 WebView 中执行 JavaScript 代码(用于模拟用户输入等)
UWP 中使用 WebView 时可以在网页中额外执行一些代码.于是你几乎可以在网页上做任何事情,那些你可以在浏览器控制台中做的事情. 本文将介绍做法. 本文内容 准备环境 执行 JavaScript ...
- java中执行javascript案例
Nashorn js engine官方文档 https://docs.oracle.com/javase/7/docs/technotes/guides/scripting/programmer_gu ...
- python 利用python的subprocess模块执行外部命令,获取返回值
有时执行dos命令需要保存返回值 需要导入库subprocess import subprocess p = subprocess.Popen('ping www.baidu.com', shell= ...
随机推荐
- Form-encoded method must contain at least one @Field.
https://blog.csdn.net/liunian823/article/details/80290855 记得之前遇到过这个问题,并且记录笔记了,这次再翻笔记,却没有找到...搜索 了下. ...
- Windows+Apache+mod_wsgi+Flask部署方法
环境:windows7 64bit 1.python版本3.6.5,32位 2.下载Apache,版本httpd-2.4.33-o102o-x86-vc14-r2,32位,vc14编译 3.下载mod ...
- [LINQ] group by 与连接查询
//副表 树种-品名-折材率 汇总 var listNeed = (from t in dtNeed.AsEnumerable() group t by new { t1 = t.Field<s ...
- Rust2018
Rust已经有2本中文书了 <<深入浅出Rust>> <<Rust编程之道>> 带着aync的rust 2019会更精彩 看async , 在这里htt ...
- cacti 流量图合并
cacti 安装:https://www.cnblogs.com/weijie0717/p/4072711.html 一.需求介绍 由于交换机的多端口跑同一种流量,需要汇总统计.因此需要见多个端口的流 ...
- 在windows下使用jenkins部署docker容器
在windows下使用jenkins部署docker容器最近在学习jenkins,docker部署来实现集成部署,所以想在windows下面实现测试,但是发现在windows下docker支持不是很好 ...
- 52-2018 蓝桥杯省赛 B 组模拟赛(一)java
最近蒜头君喜欢上了U型数字,所谓U型数字,就是这个数字的每一位先严格单调递减,后严格单调递增.比如 212212 就是一个U型数字,但是 333333, 9898, 567567, 313133131 ...
- nio编程
NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector.传统IO基于字节流和字符流进行操作,而NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从 ...
- 分布式ID方案有哪些以及各自的优劣势,我们当如何选择
作者介绍 段同海,就职于达达基础架构团队,主要参与达达分布式ID生成系统,日志采集系统等中间件研发工作. 背景 在分布式系统中,经常需要对大量的数据.消息.http请求等进行唯一标识,例如:在分布式系 ...
- Linux-01初级学习
刚刚接触 Linux学习中的一点笔记`02 ps:自己学习过程中的记录,略菜,给没学过的纯小白 配置网络 1.虚拟网卡 2.虚拟机服务 我的电脑-->管理-->服务 3.修改网络配置文件 ...