Appearance
扩展库
概述
在开发过程中如果系统提供的功能不能满足要求,可以使用扩展库引入外部代码来实现,目前仅支持 java 代码的引入。需要将外部代码编译打包为zip
文件。 调用informat.system.invokeLibrary
方法就可以执行zip
文件中的代码。
为了保证在调用过程中保持系统的无状态
特性,只允许调用静态方法
。并且强烈建议在代码中不要使用静态变量保存状态。
在扩展库中暴露的方法有以下几点限制
- 方法名称必须保证唯一,不能通过返回值或者是参数类型进行方法重载
- 方法的参数和返回值必须是可序列化的
在调用扩展库的时候会根据方法名称和参数数量进行方法匹配。如果找不到方法会抛出异常,如果匹配到的方法不唯一也会抛出异常。
扩展库中的方法
java
static int add(int a,int b);//方法1
static int add(int a,int b,int c);//方法2
static int add(String a,String b);//方法3
在脚本中调用
js
informat.system.invokeLibrary('mylibrary','com.mycompany.MyLibaray','add',[1,2,3])//匹配到方法2
informat.system.invokeLibrary('mylibrary','com.mycompany.MyLibaray','add',[1,2])//会抛出异常
zip 包说明
- 将扩展库工程打包成一个名字为
main.jar
- 将工程依赖的 jar 包放入到
lib
目录(不支持多层级)下 - 将目录使用 zip 无密码压缩
- 将生成的 zip 包上传到应用设计器中的
应用扩展
中
zip 包结构示例
.
├──lib
│ ├── lib1.jar
│ └── lib2.jar
└──main.jar
示例
以下是一个简单的扩展库,我们将其标识符定义为mylibrary
java
package com.mycompany;
import cn.hutool.crypto.digest.DigestUtil;
public class MyLibaray {
public static int add(int a,int b) {
return a+b;
}
public static String md5(String input) {//引用第三方库
return DigestUtil.md5Hex(input);
}
}
调用扩展库
java
var result=informat.system.invokeLibrary('mylibrary','com.mycompany.MyLibaray','add',[1,2]);
//result 为3
var result=informat.system.invokeLibrary('mylibrary','com.mycompany.MyLibaray','md5',['111111']);
//result 为3
INFO
demo下载地址:https://next.informat.cn/types/informat-next-library-demo.zip
工程打包mvn install
后会在target目录下生成informat-next-library-demo-1.0.zip
应用设计->全局设计->高级设置->扩展库] 新增扩展库,上传informat-next-library-demo-1.0.zip文件
在扩展库中调用织信的接口
在扩展库中可以通过Informat
对象调用织信提供的API。 调用织信API需要引入informat-spi.jar
下载地址为 https://next.informat.cn/types/informat-spi-1.0.0.jar
下面是一个调用织信提供的接口的示例
java
package com.mycompany;
public class MyLibaray {
public static String getUser() {
String userId=Informat.app().userId();//获取当前用户
Informat.console().log("current userId is:"+userId);//将当前用户输出到应用控制台
return userId;
}
}
通过RPC方式调用Informat
对象
默认情况下,扩展库需要部署到织信环境中才可以调用织信提供的方法,织信也提供了通过RPC
远程调用织信提供的API。
INFO
使用远程方式调用API时,是上下文无关的,无法通过informat.app.userId()
当前的操作用户。
通过RPC调用API时,调用客户端和织信服务器之间是通过HTTP
请求的方式通讯,客户端会将参数序列化后发送给服务器,服务器将返回值序列化后返回给客户端。整个请求过程是基于request->response的方式进行,是无状态的。并且要求调用的函数参数和返回值必须是可序列化的,对于织信提供的某些API,例如informat.excel,informat.word等,在调用过程中会依赖一些上下文环境,并且参数或者是不可序列化的,在远程方式调用时会抛出异常。
使用RPC方式调用API需要设置以下参数
serverAddress
服务器的地址appId
APP的IDapiKey
APP的apikey
以下是通过HTTP方式调用的例子
java
package com.mycompany;
public class RemoteTest {
public static void main(String args[]) {
Informat.setServerAddress("https://next.informat.cn/web0");//织信API的调用地址
Informat.setAppId("appId");//APP ID
Informat.setApiKey("apiKey");//APP 的apikey
Map<String,Object>record=Informat.table().queryById("table","001");
System.out.println("record is "+record);
}
}
通过HTTP调用Informat
对象
如果您使用其它语言开发,也可以通过HTTP
POST
请求的方式调用织信API。请求方式如下
请求地址
https://next.informat.cn/web${cluster}/spi/invoke/${appId}?sign=${sign}
${cluster}
是集群部署的节点ID,默认为0,${appId}
是应用的ID${sign}
调用接口的签名
假设应用ID为app1
,那么完整的地址如下
https://next.informat.cn/web0/spi/invoke/app1
请求参数
请求体结构为
ts
{
method:string,//需要调用的方法,例如需要调用`console`的`log`方法,需要设置为`console.log`
args:object[];,//参数列表,如果参数为空值要设置为null,例如['abc',null,123]
timestamp:integer,//调用请求时的时间戳,需要确保客户端的时钟和服务器时钟的误差在15分钟之内,误差超过十五分钟的请求会被拒绝。
nonce:string,//请求ID,在返回结果中会返回此ID,建议使用UUID来生成nonce,以保证每个请求的id独立
}
请求体body的内容需要设置成上面描述的对象生成的JSON,下面是一个请求体的例子
json
{
"method":"console.log",
"args":["arg1"],
"timestamp":1670917594517,
"nonce":"001"
}
请求签名sign
传递请求签名的目的为了
- 校验请求者的合法性。
- 校验参数的完整性和是否被篡改。
- 防止重放攻击。
请求签名需要使用 SHA256withRSA
算法计算,计算方法为
js
let req //请求体
let json=JSON.stringify(req)//将请求体转换为JSON格式的字符串
let sign=SHA256withRSA(json,privateKey)//使用privateKey 计算签名,privateKey是应用的API Key
返回内容
服务器返回的结构如下
js
{
nonce:String,//请求参数中的nonce
ret:Object,//方法的返回值
exceptionClass:String,//方法抛出的异常
exceptionMessage:String//方法抛出的异常信息
}
服务器返回的内容为上述结构转换为JSON之后的字符串,Content-Type
为text/json