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= ...
随机推荐
- 初学python笔记----字符串
---恢复内容开始--- 1.在python中,用引号括起来的都是字符串,引号可以是单引号,也可以是双引号 2.修改字符串的大小写 3.字符串拼接用“+” 4.制表符("\t"), ...
- 求1!+2!+3!+......+n!的和 -----C++-----
#include<iostream> using namespace std; int function(int x) { ; ;i<=x;i++) sum=sum*i; retur ...
- 如何利用webpack4.0搭建一个vue项目
作为一个初学者,记录自己踩过的坑是个好的习惯.我本身比较懒,这里刚好有时间把自己的搭建过程记录一下这里是参考文章 https://www.jianshu.com/p/1fc5b5151abf文章里 ...
- Java框架spring Boot学习笔记(六):Spring Boot事务管理
SpringBoot和Java框架spring 学习笔记(十九):事务管理(注解管理)所讲的类似,使用@Transactional注解便可以轻松实现事务管理.
- Oracel递归查询start with ...connect by prior在Mysql中的实现
Oracle是一个强大的数据库,有很多的函数和语法可以带来很多便利,有些函数和语法在Mysql中有代替的,但是有些没有现成可用的方法,比如Oracle的递归,在Mysql中怎么实现呢? 例子: Ora ...
- Node.js 薄荷网爬取
Node.js:是一个基于前端的服务器,主要的特点:单线程,异步I/O(对这个没有了解,开发起来真的会踩很多坑),事件驱动 前言:本人主要是一个以使用.Net平台下的语言,进行开发的一个菜鸡,之前面试 ...
- Java Enum 枚举类的values方法
Enum类和enum关键字定义的类型都有values方法,但是点进去会发现找不到这个方法.这是因为java编译器在编译这个类(enum关键字定义的类默认继承java.lang.Enum)的时候 自动插 ...
- Python学习笔记4基本数据类型
start:16:00 1.Python基本数据类型 (1)数字类型及其操作 整数类型 浮点数类型 浮点数间运算存在不确定尾数,不是bug 复数类型 数值运算操作符 (2)数值运算函数 . 2. ...
- 控制台 console.write 中文为问号
原因: 因为你当前环境代码页是437,是美国英语的字符编码 解决方式: 你把你环境设置成936就是简体中文字符编码环境了 Console.OutputEncoding = Encoding.GetEn ...
- CSS中的字体描边
兴趣使然,突然看见网上的一些带有描边的字体,觉得有点意思,便尝试去做了下 不是什么很厉害的技巧,当然也有参考张鑫旭大神写的文章 只能感叹,css的世界还很大,很广阔 直入主题: 对于文字的描边,一般都 ...