Appearance
服务端脚本
概述
织信使用javascript
语言作为脚本语言,在织信使用脚本可以实现无法配置的高级功能,在脚本中通过访问informat
对象可以使用系统 提供的功能函数。脚本运行在服务器端,运行时状态会根据应用做隔离。对于复杂的应用场景,脚本比自动化
程序有更加强的灵活性,并且性能上也更加优秀。 在API或者是复杂计算场景下建议使用脚本实现。
终止脚本运行
如果脚本执行时间过长未执行完或逻辑产生了死循环,可通过应用运行状态监控功能来终止脚本运行
模块化
织信支持使用javascript
ES6
版本的语法格式。不支持Promise
setTimeout
等异步操作。所有的函数调用都是同步调用。需要注意的是虽然使用方式上织信的脚本引擎和nodejs
很类似,但是两者是完全不同的实现。在织信中也不可以使用浏览器的window
document
对象,织信的脚本运行在服务器端
对于大型项目建议按照文件夹将不同功能的脚本文件分组,脚本之间使用 import
和 export
语法导入导出,以下示例展示了这种用法
注意事项
导入的文件路径必须是从根目录开始的全路径,织信不支持使用相对路径导入文件
npm包管理
在织信中可以使用npm包管理器加载npmjs.com
仓库中的软件包,npm
的使用可以极大的扩充脚本的能力,除了使用社区开发的高质量的代码以外,开发者也可以将自己开发的公用脚本打包成npm
包发布到仓库中,在多个应用中引用。 对于通过npm
包方式引用的库需要使用require
语法导入。下面是一个例子
- 企业级后台管理开启NPM配置
- 在脚本根目录下新建package.json文件,管理依赖的软件包
json
{
"dependencies": {
"crypto-js": "4.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;
}
补充说明
使用VsCode或WebStorm开发脚本时,下载https://next.informat.cn/types/informat.d.ts获取调用函数描述文件来解决代码报错问题。
在使用git同步时,不会同步以
.
开始头的隐藏文件将下载的informat.d.ts导入编辑器后,若依旧提示informat调用报错,可在工程根目录创建jsconfig.json空文件重启编辑器。文件内容设置成一个空对象,内容如下
json{}