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. AlphaGo的前世今生(三)AlphaGo Zero: AI Revolution and Beyond

    这是本专题的第三节,在这一节我们将以David Silver等人的Natrue论文Mastering the game of Go without human knowledge为基础讲讲AlphaG ...

  2. task 异步 进程与线程的区别

    用Wait方法(会以同步的方式来执行),不用Wait则会以异步的方式来执行 要在主线程中等待后台线程执行完毕,可以使用Wait方法(会以同步的方式来执行).不用Wait则会以异步的方式来执行. Tas ...

  3. crontab,定时任务执行找不到库or shell可执行,crontab 定时任务下就不能执行,tensorflow,ImportError: libcuda.so.1: cannot open shared object file: No such file or directory

    在线上启动一个定时任务,但是起来查看,发现任务执行找不到库,报cuda错误: ImportError: libcuda.so.1: cannot open shared object file: No ...

  4. HttpServletRequest 获取cookie

    request.getHeader("cookie") 得到的是a=b,c=d Cookie[] cookies = request.getCookies(); 访问方在heade ...

  5. iview table中使用Poptip

    h('Poptip', { props: { confirm: true, // 'ok-text':"yes", // 'cancel-text':"no", ...

  6. API权限设计总结

    最近在做API的权限设计这一块,做一次权限设计的总结. 1. 假设我们需要访问的API接口是这样的:http://xxxx.com/openapi/v1/get/user/?key=xxxxx& ...

  7. 对TCP三次握手的思考

    从第一次了解到TCP的连接方式到现在有一年半了,但好像一直没有把三次握手的由来弄透彻,解释上总有一些瑕疵在,现在来说说昨晚的思考. 对于一个通信链路,由于种种原因发送方发送的消息未必能传达到接收方,所 ...

  8. java中mysql查询报错java.sql.SQLException: Before start of result set

    异常:java.sql.SQLException: Before start of result set 解决方法:使用rs.getString();前一定要加上rs.next(); sm = con ...

  9. 某公司的U3D笔试题

    某公司的U3D笔试题   今天这套笔试题感觉做得一般. 随后是二对一的技术面试,但涉及的技术细节相对较少,更多的是对以前工作.项目经历的询问. 然后说今天先到这里,让我等通知. 我还特意问了一下,通知 ...

  10. Getting.Started.with.Unity.2018.3rd.Edition

    Getting Started with Unity 2018 - Third Edition: A Beginner's Guide to 2D and 3D game development wi ...