Skip to content

服务端脚本

概述

织信使用javascript语言作为脚本语言,在织信使用脚本可以实现无法配置的高级功能,在脚本中通过访问informat对象可以使用系统 提供的功能函数。脚本运行在服务器端,运行时状态会根据应用做隔离。对于复杂的应用场景,脚本比自动化程序有更加强的灵活性,并且性能上也更加优秀。 在API或者是复杂计算场景下建议使用脚本实现。

终止脚本运行

如果脚本执行时间过长未执行完或逻辑产生了死循环,可通过应用运行状态监控功能来终止脚本运行

模块化

织信支持使用javascript ES6版本的语法格式。不支持Promise setTimeout等异步操作。所有的函数调用都是同步调用。需要注意的是虽然使用方式上织信的脚本引擎和nodejs很类似,但是两者是完全不同的实现。在织信中也不可以使用浏览器的window document对象,织信的脚本运行在服务器端

对于大型项目建议按照文件夹将不同功能的脚本文件分组,脚本之间使用 importexport 语法导入导出,以下示例展示了这种用法

注意事项

导入的文件路径必须是从根目录开始的全路径,织信不支持使用相对路径导入文件

npm包管理

在织信中可以使用npm包管理器加载npmjs.com仓库中的软件包,npm的使用可以极大的扩充脚本的能力,除了使用社区开发的高质量的代码以外,开发者也可以将自己开发的公用脚本打包成npm包发布到仓库中,在多个应用中引用。 对于通过npm包方式引用的库需要使用require语法导入。下面是一个例子

  1. 企业级后台管理开启NPM配置

企业级后台管理开启NPM配置

配置路径:系统信息=>参数设置

npmSetting.png

配置说明

  1. 在脚本根目录下新建package.json文件,管理依赖的软件包
json
{
  "dependencies": {
    "crypto-js": "4.1.1"
  }
}
  1. 在脚本中使用require方法引用软件包

织信对于npm包的支持现阶段还不够完善,如果软件包中引用了nodejs的内建库,例如fs events等,这些包不能正常运行。另外npm包也不支持使用import语法导入。

使用Java对象

脚本中可以使用Java对象,以下文档向您展示如何实现与 Java 的互操作性以及可能的 JavaScript 到 Java 嵌入场景。

类访问

要访问 Java 类,脚本引擎 支持以下Java.type(typeName)功能:

js
var FileClass = Java.type('java.io.File');

java默认情况下,Java 类不会自动映射到全局变量,例如, 脚本引擎 中没有全局属性。现有的访问代码,例如java.io.File,应该重写以使用该Java.type(name)函数:

js
//脚本引擎 compliant syntax
var FileClass = Java.type("java.io.File");

构造 Java 对象

new Java对象可以用JavaScript的关键字构造:

js
var FileClass = Java.type('java.io.File');
var file = new FileClass("myFile.md");

字段和方法访问

Java 类的静态字段或 Java 对象的字段可以像 JavaScript 属性一样进行访问:

js
var JavaPI = Java.type('java.lang.Math').PI;

Java 方法可以像 JavaScript 函数一样被调用:

js
var file = new (Java.type('java.io.File'))("test.md");
var fileName = file.getName();

方法参数的转换

JavaScript 被定义为对double数字类型进行操作。出于性能原因(例如类型int),脚本引擎 可能会在内部使用其他 Java 数据类型。

调用 Java 方法时,可能需要进行值转换。当 Java 方法需要一个long参数,并且int由脚本引擎提供时,就会发生这种情况。如果此转换导致有损转换,TypeError则会抛出:

java
//Java
void longArg   (long arg1);
void doubleArg (double arg2);
void intArg    (int arg3);
js
//JavaScript
javaObject.longArg(1);     //widening, OK
javaObject.doubleArg(1);   //widening, OK
javaObject.intArg(1);      //match, OK

javaObject.longArg(1.1);   //lossy conversion, TypeError!
javaObject.doubleArg(1.1); //match, OK
javaObject.intArg(1.1);    //lossy conversion, TypeError!

选择方法

Java 允许通过参数类型重载方法。当从 JavaScript 调用到 Java 时,会选择实际参数可以无损转换为的最窄可用类型的方法:

java
//Java
void foo(int arg);
void foo(short arg);
void foo(double arg);
void foo(long arg);
js
//JavaScript
javaObject.foo(1);              // will call foo(short);
javaObject.foo(Math.pow(2,16)); // will call foo(int);
javaObject.foo(1.1);            // will call foo(double);
javaObject.foo(Math.pow(2,32)); // will call foo(long);

要覆盖此行为,可以使用javaObject['methodName(paramTypes)']语法选择显式方法重载。参数类型需要以逗号分隔且不带空格,并且对象类型需要完全限定(例如,'get(java.lang.String,java.lang.String[])')。

js
javaObject['foo(int)'](1);
javaObject['foo(long)'](1);
javaObject['foo(double)'](1);

请注意,参数值仍然必须适合参数类型。您可以使用自定义目标类型映射来覆盖此行为。

当方法重载不明确且无法自动解析以及您想要覆盖默认选择时,显式方法选择也很有用:

java
//Java
void sort(`List<Object>` array, Comparator<Object> callback);
void sort(`List<Integer>` array, IntBinaryOperator callback);
void consumeArray(`List<Object>` array);
void consumeArray(Object[] array);
js
//JavaScript
var array = [3, 13, 3, 7];
var compare = (x, y) => (x < y) ? -1 : ((x == y) ? 0 : 1);

// throws TypeError: Multiple applicable overloads found
javaObject.sort(array, compare);
// explicitly select sort(List, Comparator)
javaObject['sort(java.util.List,java.util.Comparator)'](array, compare);

// will call consumeArray(List)
javaObject.consumeArray(array);
// explicitly select consumeArray(Object[])
javaObject['consumeArray(java.lang.Object[])'](array);

请注意,当前无法显式选择构造函数重载。

数组访问

脚本引擎 支持从 JavaScript 代码创建 Java 数组。支持两种模式:

js
//模式1 pattern
var JArray = Java.type('java.lang.reflect.Array');
var JString = Java.type('java.lang.String');
var sarr = JArray.newInstance(JString, 5);

//模式2  pattern
var IntArray = Java.type("int[]");
var iarr = new IntArray(5);

创建的数组是 Java 类型,但可以在 JavaScript 代码中使用:

js
iarr[0] = iarr[iarr.length] * 2;

Map访问

在脚本引擎中,您可以创建和访问 Java Map,例如java.util.HashMap:

js
var HashMap = Java.type('java.util.HashMap');
var map = new HashMap();
map.put(1, "a");
map.get(1);

脚本引擎 支持迭代此类映射:

js
for (var key in map) {
    print(key);
    print(map.get(key));
}

列表访问

在脚本引擎中,您可以创建和访问 Java 列表,例如java.util.ArrayList:

js
var ArrayList = Java.type('java.util.ArrayList');
var list = new ArrayList();
list.add(42);
list.add("23");
list.add({});

for (var idx in list) {
    print(idx);
    print(list.get(idx));
}

字符串访问

脚本引擎可以创建具有 Java 互操作性的 Java 字符串。字符串的长度可以通过属性查询length(注意length是一个值属性,不能作为函数调用):

js
var javaString = new (Java.type('java.lang.String'))("Java");
javaString.length === 4;

请注意,脚本引擎 在内部使用 Java 字符串来表示 JavaScript 字符串,因此上面的代码和 JavaScript 字符串文字"Java"实际上是无法区分的。

迭代属性

Java 类和 Java 对象的属性(字段和方法)可以使用 JavaScript for..in 循环进行迭代:

js
var m = Java.type('java.lang.Math')
for (var i in m) { 
    print(i);
}
// > E
// > PI
// > abs
// > sin
// > ...

脚本里使用Java对象的完整例子

js

//调用Java graphics画一个矩形图片,并返回图片base64编码
export function createImage() {
	let width=100;
	let height=100;
	var BufferedImage = Java.type("java.awt.image.BufferedImage");
	var ByteArrayOutputStream=Java.type("java.io.ByteArrayOutputStream");
	var ImageIO=Java.type("javax.imageio.ImageIO");
	var Base64=Java.type("java.util.Base64");
	var Color=Java.type("java.awt.Color");
	//
	var image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_BGR);
	var graphics = image.getGraphics();
	graphics.setColor(new Color(255, 0, 0));
	graphics.fillRect(1, 1, width - 1, height - 1);
	var os=new ByteArrayOutputStream();
	ImageIO.write(image, "jpg", os);
	let content=os.toByteArray();
	let base64=Base64.getEncoder().encodeToString(content);
	return base64;
}

补充说明

  • 使用VsCodeWebStorm开发脚本时,下载https://next.informat.cn/types/informat.d.ts获取调用函数描述文件来解决代码报错问题。

  • 在使用git同步时,不会同步以.开始头的隐藏文件

  • 将下载的informat.d.ts导入编辑器后,若依旧提示informat调用报错,可在工程根目录创建jsconfig.json空文件重启编辑器。文件内容设置成一个空对象,内容如下

    json
    {}