准备工作
下载并安装Maven插件 https://maven.apache.org/install.html 下载并安装JDK1.8
安装开发IDE(例如IDEA、VSCode、Eclipse等)
申请开发者证书(目前先联系吴俊文申请)
- 申请证书时需要给企业ID、员工ID,该证书会与租户以及员工进行绑定
- 每次申请的证书有效期为30天
- 证书绑定的员工如果停用、禁止登录或者修改密码,该证书都会立即失效
下载脚手架 https://a9.fspage.com/FSR/base/apl/template.zip
- 解压脚手架,建议解压到企业帐号/企业信息目录下,例如D:\workspace\facishare, 得到以下目录结构
|-- lib
apl-sdk-maven-plugin.jar maven插件
fs-paas-function-api.jar 代码依赖的api包
|-- src
|-- main
|-- java
|-- fx
|-- custom
|-- apl
|-- jar
代码示例
|-- resources
application.properties 租户开发证书
pom.xml
README.md 本说明文件
- 打开IDE导入项目
环境准备工作
修改pom.xml中的 artifactId为Jar包ApiName
apiName 命名规则:
1.只允许英文字母开头
2.中间允许使用英文字母,数字,下划线
3.必须以__c结尾
4.除结尾的 __c 外下划线不允许连续出现
5.不能超过50个字符
设置开发者证书
- 将准备工作中的开发者证书,设置到application.properties中
安装apl插件
- IDE进入控制台
- 在控制台输入以下命令
mvn install:install-file "-Dpackaging=maven-plugin" "-Dfile=lib/apl-sdk-maven-plugin.jar" "-DgroupId=com.facishare" "-DartifactId=apl-sdk-maven-plugin" "-Dversion=1.0-SNAPSHOT"
安装sdk
- 在控制台输入以下命令
mvn install:install-file "-Dpackaging=jar" "-Dfile=lib/fs-paas-function-api.jar" "-DgroupId=com.facishare" "-DartifactId=fs-paas-function-api" "-Dversion=1.0-DEBUG-SNAPSHOT" "-Dsources=lib/fs-paas-function-api-sources.jar"
- 命令执行成功,会看到下图
开始开发
新建代码
在fx.custom.apl.jar下新建代码
实现函数的命名空间对应的接口,所有已支持的接口在 com.fxiaoke.functions.template, 如下图
一个新的APL代码新建就好了,如下图所示
增加main函数,以方便进行代码调试
DebugHelper helper = new DebugHelper(); //构造一个调试器
helper.init(); //对调试器进行初始化
FunctionContext context = helper.context("AccountObj", "63100e7915d6a300017121cc"); //获取一个调试上下文,以方便写代码
Map argument = Maps.newHashMap(); //如果函数需要有其他参数,可以构造一个Map,进行参数传递
最后效果如下图
开始开发
- 在代码中,可以使用Fx进行对象的查询、修改、以及新增,例如 QueryResult ret = Fx.object.select(String.format("SELECT _id, name FROM AccountObj WHERE name = '%s'", search)).result();
- 在代码需要按照接口的约定,进行参数返回,如下图所示
调试
- 点击main函数最左边绿色的箭头,可以对进行项目的编译以及调试
- 可以通过IDE,对代码进行断点分析,如下图所示
将代码发布到租户
发布
当代码开发完成,则需要对代码进行打包并上线
- 打开IDE的Maven插件
- 找到jar插件中的,jar:Jar进行打包,如图所示
- 找到apl-sdk插件,点击apl-sdk:pushJar,进行Jar包上传,如图所示
启用Jar包
- Jar包首次上传后,是未安装状态,需要登录管理后台,安装该Jar包
- 登录管理后台,搜索《开发Jar包管理》
- 根据artifactId,找到刚才开发Jar的ApiName
- 点击安装,安装刚才上传的Jar
关联场景
- 找到需要执行代码的地方,新建函数
- 选择Jar包函数
- ApiName输入 类名 + __c结尾,以便定位到具体类名
- 新建函数的命名空间、返回值与类对应的接口必须一致,否则会执行失败
- 新建完成后,就可以进行验证
注意事项
- 首次安装成功后,第二次推送Jar包,会直接更新Jar包内容,同时也会直接影响租户使用
- 实施/用户按照标准代码管理规范,进行代码分支管理
- Jar限制大小为10兆,切勿将第三方Jar包一并打包上传,如需上传第三方Jar包,请到管理后台进行上传
- APL自带FastJson以及Guava等通用工具包,如果上传了通用工具包,会以APL优先
- 用户证书30天有效,如果用户停用、禁止登录、修改密码会失效,需要重新申请
代码Demo
按钮前验证代码示例
package fx.custom.apl.jar;
import com.fxiaoke.functions.FunctionContext;
import com.fxiaoke.functions.Fx;
import com.fxiaoke.functions.client.DebugHelper;
import com.fxiaoke.functions.model.ButtonValidateResult;
import com.fxiaoke.functions.model.QueryResult;
import com.fxiaoke.functions.template.IButtonBeforeAction;
import com.fxiaoke.functions.utils.Maps;
import com.google.common.collect.ImmutableMap;
import com.mycompany.pkg.MyTest;
import java.io.IOException;
import java.util.Map;
import static com.fxiaoke.functions.Fx.log;
/**
* 1. 根据命名空间以及返回,选择对应的Action
* 2. 这个Action是函数触发入口,对象勾子触发时,会到Jar包中查找这个类并且检查接口以及接口提供的方法
* <p>
* <p>
* 全部已支持的action详见以下package
*
* @author APL
* @see com.fxiaoke.functions.template
*/
public class ButtonBlockAction implements IButtonBeforeAction {
MyTest test = new MyTest();
@Override
public ButtonValidateResult validate(FunctionContext context, Map<String, Object> map) {
//从模拟的上下文获取到调试的name字段
String name = (String) context.getData().get("name");
//可以自定义包名以及类名,执行逻辑
String testName = test.DemoFunc(name);
//使用APL平台提供的 log.info 进行日志输出
//切勿使用 System.out.println(); 或者其他日志组件进行打印日志
log.info(testName);
//假设我们需要从代码里查询名字为test的客户
String search = "test";
QueryResult ret = Fx.object.select(String.format("SELECT _id, name FROM AccountObj WHERE name = '%s'", search)).result();
Map<String, Object> obj = (Map<String, Object>) ret
.getDataList()
.stream()
.findFirst()
.orElseGet(() -> ImmutableMap.of("name", "测试"));
return new ButtonValidateResult(
true,
"客户名字是:" + obj.get("name"),
true);
}
/**
* 调试入口
*/
public static void main(String[] args) throws IOException {
//调试器
DebugHelper helper = new DebugHelper();
//调试器初始化,包括身份以及服务器的地址
//身份信息联系APL平台获取,具体查看application.properties配置
helper.init();
//构造当前执行类
ButtonBlockAction example = new ButtonBlockAction();
//模拟调试的上下文,例如开发时想模拟一个客户对象的上下文,以方便开发
FunctionContext context = helper.context("AccountObj", "63100e7915d6a300017121cc");
//构造被触发时的参数
Map<String, Object> argument = Maps.newHashMap();
//执行函数
example.validate(context, argument);
}
}
按钮前验证代码示例
package fx.custom.apl.jar;
import com.fxiaoke.functions.FunctionContext;
import com.fxiaoke.functions.Fx;
import com.fxiaoke.functions.client.DebugHelper;
import com.fxiaoke.functions.model.APIResult;
import com.fxiaoke.functions.template.IFlowAction;
import com.fxiaoke.functions.tools.ActionAttribute;
import com.fxiaoke.functions.utils.Maps;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import static com.fxiaoke.functions.Fx.log;
public class FlowActionExample implements IFlowAction {
public static void main(String[] args) throws IOException {
//调试器
DebugHelper helper = new DebugHelper();
//调试器初始化,包括身份以及服务器的地址
//身份信息联系APL平台获取,具体查看application.properties配置
helper.init();
//构造当前执行类
FlowActionExample example = new FlowActionExample();
//模拟调试的上下文,例如开发时想模拟一个客户对象的上下文,以方便开发
FunctionContext context = helper.context("AccountObj", "63100e7915d6a300017121cc");
//构造被触发时的参数
Map<String, Object> argument = Maps.newHashMap();
//执行函数
example.execute(context, argument);
}
@Override
public void execute(FunctionContext functionContext, Map<String, Object> map) {
ActionAttribute attribute = ActionAttribute.create();
//使用APL平台提供的 log.info 进行日志输出
//切勿使用 System.out.println(); 或者其他日志组件进行打印日志
log.info(functionContext);
HashMap<Object, Object> account = new HashMap<>();
account.put("name", System.currentTimeMillis());
APIResult result = Fx.object.create("AccountObj", account, Maps.newHashMap(), attribute);
log.info(result);
}
}
范围规则代码示例
package fx.custom.apl.jar;
import com.fxiaoke.functions.FunctionContext;
import com.fxiaoke.functions.client.DebugHelper;
import com.fxiaoke.functions.model.QueryTemplate;
import com.fxiaoke.functions.template.IRangeRuleTemplateAction;
import com.fxiaoke.functions.tools.QueryOperator;
import com.fxiaoke.functions.utils.Lists;
import com.fxiaoke.functions.utils.Maps;
import java.io.IOException;
import java.util.Map;
import static com.fxiaoke.functions.Fx.log;
/**
* 返回规则的Demo,注意返回值选择的是QueryTemplate
*/
public class RangeRuleExample implements IRangeRuleTemplateAction {
public static void main(String[] args) throws IOException {
//调试器
DebugHelper helper = new DebugHelper();
//调试器初始化,包括身份以及服务器的地址
//身份信息联系APL平台获取,具体查看application.properties配置
helper.init();
//构造当前执行类
RangeRuleExample example = new RangeRuleExample();
//模拟调试的上下文,例如开发时想模拟一个客户对象的上下文,以方便开发
FunctionContext context = helper.context("AccountObj", "63100e7915d6a300017121cc");
//构造被触发时的参数
Map<String, Object> argument = Maps.newHashMap();
//执行函数
example.execute(context, argument);
}
@Override
public QueryTemplate execute(FunctionContext context, Map<String, Object> args) {
//使用APL平台提供的 log.info 进行日志输出
//切勿使用 System.out.println(); 或者其他日志组件进行打印日志
log.info(context);
return QueryTemplate.AND(
Maps.of("life_status", QueryOperator.NE(Lists.newArrayList("invalid"))
));
}
}