菜单

JAVA中执行JavaScript代码并获取返回值,JS中Eval解析JSON字符串的一个小问题

2019年9月22日 - 4166am金沙下载
JAVA中执行JavaScript代码并获取返回值,JS中Eval解析JSON字符串的一个小问题

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

之前写过一篇 关于 JSON 的介绍文章,里面谈到了 JSON
的解析。我们都知道,高级浏览器可以用 JSON.parse() API 将一个 JSON
字符串解析成 JSON 数据,稍微欠妥点的做法,我们可以用eval() 函数。

JavaScript基础语法

一、JavaScript概述:

1.JavaScript是什么?

JavaScript是一种基于对象(内置大量现成对象)和事件驱动的解释性(事先不编译,逐行执行)脚本语言,具有与JAVA和C语言类似的语法。

它是一种网页的编辑技术,用来向HTML页面添加交互行为,直接嵌入HTML页面,由浏览器解释执行代码,不进行预编译。

PS:

(1)
脚本语言:对环境的要求比较低,无提示,可以使用任何文本编辑工具编写。不需要编译,就可以直接执行的语言。

(2)
JavaScript的经历比较坎坷,它和Java没有联系,只是命名来历上比较特别而已。我们现在学的是ECMA组织维护的标准JavaScript,也就相当于是JDBC服务商,哪个公司用都可以编写自己独立的一套接口去实现。

(3)
JS是由引擎执行的,并不是由浏览器执行,浏览器能执行的原因也就是浏览器内置中有执行JS的引擎。

2.使用范围

(1)客户端数据计算

(2)客户端表单合法性验证

(3)浏览器事件的触发

(4)网页特殊显示效果制作

(5)服务器的异步数据提交

二、JS程序应用

1.JS程序编写种类分为以下三种:

(1)事件定义式:

在事件定义时直接写入JS脚本代码

(2)嵌入式

使用<script>标签

(3)文件调用式

##代码位于单独的.JS文件中

##在HTML页面引入.JS文件

2.JS中代码错误时:

##JS为解释性代码,代码错误,页面中无效果显示。

##使用IE浏览器时,利用状态栏和开发工具进行查看。

##Chrome浏览器时,使用错误控制台查看(F12).

三、JavaScript的基础语法

1.基本语法

由Unicode字符集编写,单行注释为//,多行注释为/*
*/,语句由表达式、关键字、运算符组成,大小写敏感,使用分号(推荐使用)或者换行结束。

2.标识符与关键字

2.1标识符:由不以数字开头的字母、数字、下划线和$组成,名称最好有明确的含义。

2.2标准关键字:

图片 1

JavaScript语言中代表特定含义的词称为保留字,不允许程序在定义为标识符,如class、float、int等。

网页显示如下图:

图片 2

Number:所有数字都采用64位浮点格式存储,不区分整型数值(默认为10进制的)和浮点型数值。

Boolean:false和true两个值,可以自动转型作为数值参与运算,运算时true=1,false=0.

优先级顺序为:字符串、数字、布尔。

3.2数据类型的隐式转换

JS中不同类型数据在计算过程中会自动进行转换。

数字+字符串:数字转换为字符串

数字+布尔值:true为1,false为0

字符串+布尔值:布尔值转换为字符串true或者false

布尔值+布尔值:布尔值转换为数字1或者0

3.3数据类型转换函数

toString:所有数据类型均可转换为String类型。

parseInt:强制转换为整数,如果不能转换(不是数字),则返回NaN.

parseFloat:强制转换为浮点数,如果不能转换,返回NaN.

typeof:查询当前类型,返回Number、String、Boolean、object、function、undefined.

isNaN:检测表达式不是数,返回true,是数返回false.

3.4特殊类型数据

null:代表“无值”或者“无对象”,可以通过给一个变量赋null,来清空变量的内容。

undefined:声明了变量但从未赋值,对象属性不存在。

4.运算符

4.1算数运算符:+(可表示加法也可表示字符串连接)、-(可表示减法也可表示负号)、*、/、%(求余)、++(递增)、–(递减)

PS:在JAVA中5/2=2,而在JS中5/2=2.5

4.2关系运算符:>、<、==(等于)、>=、<=、!=、===(全等)、!==(不全等)

PS:全等是类型相同、数值相同,不全等返回值类型为boolean型。

4.3逻辑运算:&&、!、”|

4.4条件运算:

表达式?表达式1:表达式2

先计算表达式的值,若为true,则整个表达式的值为表达式1的值,若为false,则整个表达式的值为表达式2的值。

四、流程控制

1.控制语句

任何复杂的程序逻辑都可以通过“顺序”、“分支”、“循环”三种基本的程序结构实现。(默认为顺序)

图片 3

2.分支结构(与JAVA中的语法相同)

If语句:在运行的过程中,根据不同的条件运行不同的语句。

swith-case:根据一个整数表达式的值,从不同的程序入口开始执行。

3.循环结构

for语句

for(表达式1;表达式2;表达式3){

语句块(循环体);

}

While语句:前测试循环,退出条件是在执行循环内部的代码之前计算的,循环主体可能不被执行。

While(表达式){

语句块

}

do-while语句:是后测试循环,退出条件在执行循环内部代码之后计算的,在计算表达式之前,至少会执行循环主体一次。

do{

语句块

}while(表达式)

4.JS中的条件表达式

Java中的表达式必须返回boolean值

Js中的表达式可以是任意表达式,也就是返回任何类型的值。

图片 4

一切表示空的值,均为false.

小案例:

1.计算平方。代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset=”UTF-8″>
<title>计算平方</title>
<script>
function pf() {
//打桩,在控制台调试(F12)查看是否有输出
console.log(1);
//获取文本框
var input=document.getElementById(“num”);
//获取span
var span=document.getElementById(“result”);
//打桩
console.log(input);
console.log(span);
//从文本框中取值
var n=input.value;
console.log(n);
//判断该值是否是数字
if(isNaN(n)){
//返回true,则不是数字,给予提示
span.innerHTML=”请输入数字”;
}else{
//是数字,计算平方后写入span
//文本框中读到的内容均为字符串,但是此处不需要转型,因为此处是乘法,字符串没有乘法,
//所以JS就会认为是数字,自动会转为数字运算,如果此处为加法,字符串也有加法,则必须进行强转。
span.innerHTML=n*n;
}

}
</script>
</head>
<body>
<input type=”text” id=”num”/>
<input type=”button” value=”平方” onclick=”pf();”/>
= <span id=”result”></span>
</body>
</html>

网页展示:

图片 5

补充内容:

(1)从表单控件(input/select/textare)中读写数据

读:input.value;

写:input.value=“值”;

PS:读框、读值如,<input type=“text”/>

(2)从文本(h/p/p/span……)中读写数据

读:span.innerHTML;

写:span.innerHTML=“值”;

PS:读内容,如<p>xxx</p>、<span>aaa</span>

(3)如何获取元素

document.ElementById(“id”);

##JS调试技巧

(1)看控制台的报错信息。

(2)打桩:看程序执行的步骤,看每一步变量的值。

(3)二分法+排除法,定位错误位置。

2.猜数字游戏,代码展示如下:

<!DOCTYPE html>
<html>
<head>
<meta charset=”UTF-8″>
<title>猜数字</title>
<script>
//在页面加载时,在body加载前,就生成随机数(0-99)
var ranNum=parseInt(Math.random()*100);
function guess() {
//打桩
//console.log(ranNum);
//获取文本框和span
var input=document.getElementById(“num”);
var span=document.getElementById(“result”);
//打桩
console.log(input);
console.log(span);
//获取框中的值
var n=input.value;
//判断该值是否为数字
if(isNaN(n)){
//不是数字,给予提示
span.innerHTML=”请输入数字”;
}else{
//是数字,和随机数比较
if(n>ranNum){
span.innerHTML=”大了”;
}else if(n<ranNum){
span.innerHTML=”小了”;
}else{
span.innerHTML=”对了”;
}
}
}
</script>
</head>
<body>
<input type=”text” id=”num”/>
<input type=”button” value=”猜”
onclick=”guess();”/>
<span id=”result”></span>
</body>
</html>

网页显示如下:

图片 6

3.计算阶乘。代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset=”UTF-8″>
<title>计算阶乘</title>
<script>
function jc() {
var input=document.getElementById(“num”);
var span=document.getElementById(“result”);
console.log(input);
console.log(span);
var n=input.value;
if(isNaN(n)”|n<1){
//若不是数或者小于1,则给予提示
span.innerHTML=”请输入大于0的整数”;
}else{
//是大于1的数,则计算阶乘。
var s=1;
for(var i=n;i;i–){
s*=i;
}
span.innerHTML=s;
}
}
</script>
</head>
<body>
<h1>n的阶乘=1*2*3*4*5……*n</h1>
<input type=”text” id=”num”>
<input type=”button” value=”计算”
onclick=”jc();”/>
= <span id=”result”></span>
</body>
</html>

网页显示如下:

图片 7

场景描述

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

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

JSON (JavaScript Object Notation)一种简单的数据格式,比xml更轻巧。
JSON 是 JavaScript 原生格式,这意味着在 JavaScript 中处理 JSON
数据不需要任何特殊的 API 或工具包。

实现思路

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

JSON的规则很简单:
对象是一个无序的“‘名称/值’对”集合。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’
对”之间使用“,”(逗号)分隔

技术要点

合理的使用JavaScript解析引擎

var str = '{"name": "hanzichi", "age": 10}';
var obj = eval('(' + str + ')');
console.log(obj); // Object {name: "hanzichi", age: 10}

代码实现

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;    }}

是否注意到,向 eval() 传参时,str 变量外裹了一层小括号?为什么要这样做?

测试方法

   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 ....");    }

我们先来看看 eval 函数的定义以及使用。

运行结果

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

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

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

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

eval() 的参数是一个字符串。如果字符串表示了一个表达式,eval()
会对表达式求值。如果参数表示了一个或多个 JavaScript 声明, 那么 eval()
会执行声明。不要调用 eval() 来为算数表达式求值; JavaScript
会自动为算数表达式求值。

改进空间

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

简单地说,eval 函数的参数是一个字符串,如果把字符串 “noString”
化处理,那么得到的将是正常的可以运行的 JavaScript 语句。

怎么说?举个栗子,如下代码:

var str = "alert('hello world')";
eval(str);

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图