Workflow-api

接口定义

接口主要约定如下功能

使用方式

引用接口

<dependency>
  <groupId>cn.cfit.ctas.workflow</groupId>
  <artifactId>workflow-api</artifactId>
  <version>1.0.0</version>
</dependency>

引用嵌入实现

 <dependency>
  <groupId>cn.cfit.ctas.workflow</groupId>
  <artifactId>workflow-embeded</artifactId>
  <version>1.0</version>
</dependency>

micro services 调用

通过register center查找服务,然后透过gateway 进行访问,访问过程中使用 micro services framework 包装请求,使用了Restful或者RPC方式访问,无需单独引用依赖包。

使用场景

下面是几种典型场景下使用流程的方法,下面的场景中,我们假定在使用对象 WorkflowService之前,它已经通过Spring Dependency Injection 进行了注入

模拟应用启动过程的调用

@Autowired
WorkflowService workflowService;
public void useOnStartup(){
    // 获取部署服务,这样就可以使用部署服务对流程定义做操作了
    WorkflowDefineService defineService = workflowService.getDefineService();
    //  
    // 不建议使用流程定义直接部署到数据库上线,原因是因为不同发布代码有各自开发测试对应的流程定义,如果数据库部署的
    // 流程定义于代码不匹配,则会出现问题,因此建议代码启动的时候,主动发起一次自己的流程定义和版本的部署申请
    // 这样如果流程定义及其版本一致,不会被部署,否则会部署。
    //


    // === 下面整段代码均用于部署,可以多次循环调用 ===
        InputStream bpmnStream=null;
    // 这是流程定义文件的 FileInputStream ,可以以任何方式创建

    try {bpmnStream=new FileInputStream("D:\\tmp\\CTAS.V2.BPS.SIPT.5271.bpmn");}catch(Exception ex){}

    // 部署前文读入的bpmn流程定义

        defineService.build(bpmnStream).deploy(false);  
    }
    // === 部署结束,后面可以直接使用流程 ===

模拟开启一个新的流程

/**
* 假定要启动的流程对应的定义为  "CTAS.V2.BPS.SIPT.5271" ,使用的版本是  "0.01"
* 可以用下面的方法找到对应的定义,使用该定义可以创建流程的实例,(创建实例就是启动流程)
*/

String defineKey= "CTAS.V2.BPS.SIPT.5271";
String versionTag= "0.01" ;

//获取流程定义服务对象
WorkflowDefineService defineService = workflowService.getDefineService();

//查找需要启动的流程
WorkflowDefine define = defineService.find(defineKey, defineVersionTag);
//启动流程,并得到流程实例
WorkflowInstance instance = define.startProcess("CTAS001", "20230830162700000000009962142001", "20230830", null);
}

WorkflowDefine 调用 startProcess 启动流程,这里有几个参数需要说明: * roleid 标明启动流程的角色,这个角色暂无控制,但是语义上可以和我们的资金岗、明细岗对应起来,统一约定一下,如果为空,服务端使用缺省的roleid代替。(可为空,不报错) * businessKey 业务流水号,可以使用用进入系统的报文编号或者其它唯一标识作为此编号,也可以自行编制,如果为空,服务端使用缺省的的唯一业务流水号生成算法自动生成并回填给instance对象。(可为空,不报错) * bizzDate 业务日期,即业务的账务日期,格式为 yyyyMMdd ,,如果为空,服务端使用服务器当前自然日期作为业务日期并回填给instance对象,不报错。(可为空,不报错) * parameters 流程参数,需要通过流程方式传递给后续处理任务的信息,流程对他不做强制约定,不过是以 Map 方式存放的,使用的时候需要留意,如果为空,视为没有参数。(可为空,不报错)

模拟自动获取任务并执行

假定这个处理程序是针对某一个任务节点的,比如 审核,这个任务在对应的bpmn中会定义一个任务ID,这个ID在这里作为参数 taskDefineId 提供,程序需要提前知道,获取任务的时候需要用这个taskDefineId来查找对应的任务,查找任务的时候,有另一个参数,叫 roleId,这个和前面启动流程里的roleid含义一样。

String roleId="CTAS001";
String taskDefineId="T001P002F001";

//获取任务服务对象
WorkflowTaskService  taskService = workflowService.getTaskService();

//获取任务,此时非阻塞,需要做 非null判断   [1]
WorkflowTask task = Optional.ofNullable(
taskService.first(roleId,taskDefineId,false)
).orElseThrow(()->new RuntimeException("没有获得任务"));

//获取任务,此时阻塞  [2]
task =  taskService.first(roleId,taskDefineId,true);

获取单一任务的时候使用接口WorkflowTaskServicefirst last两个方法,方法的参数有三个: * roleid 表明操作任务的角色,这个角色暂无控制,但是语义上可以和我们的资金岗、明细岗对应起来,统一约定一下,如果为空,服务端使用缺省的roleid代替。(可为空,不报错) * taskDefineId 表明操作任务的定义ID,不可为空,系统需要通过它来查找对应的任务 * isBlocking 用于限定这个方法调用是否会被阻塞,如果是 true,则是阻塞,则获取不到会被挂起,直到获得任务才会返回,如果是不阻塞,后面的则立刻返回,但是没有任务的时候会返回null

//  模拟程序代码处理任务
String taskId=task.getId();                        // 这里此任务的唯一标识
String  bizzKey=task.getBusinessKey();            // 这里此任务的对应的业务流水号
Map<String, String> parameters = task.getParameters();  // 这里是从上游任务传递过来的参数
...
...  处理任务
...

如果这一步不对任务的状态进行修改,只是增加或者删除、修改一些变量,则使用下面的方法,这个操作会用给定的parameter去覆盖原来记录在流程中的parameter,如果参数为 false 重复的会覆盖,不存在的会增加,反正删除原来的parameter,使用新的替换

task.update(roleId,null,false);

如果这一步操作完成要修改任务的状态的时候使用下面三个方法来操作 * 任务完成,并赋予特定含义的信号量,告知流程的走向

    task.complete("",20,null);
  • 任务完成,告知流程处理正常,正向进入下一个环节
   task.success(roleId,null);
  • 任务完成,告知流程处理失败,逆向回到上一个环节
    task.rollback(roleId,null); 

手动获取任务列表,并逐一处理

假定这个处理程序是针对某一个任务节点的,比如 审核,这个任务在对应的bpmn中会定义一个任务ID,这个ID在这里作为参数 taskDefineId 提供,程序需要提前知道,获取任务的时候需要用这个taskDefineId来查找对应的任务,查找任务的时候,有另一个参数,叫 roleId,这个和前面启动流程里的roleid含义一样。

这个接口可以使用 list 方法来直接获取列表,也可以通过 getPageable 方法来得到一个分页查询来分别查找

String roleId="CTAS001";
String taskDefineId="T001P002F001";

// 获得任务服务对象
WorkflowTaskService  taskService = workflowService.getTaskService();
  • 使用list方法获得该任务定义ID下面的所有代办任务,需要留意的地方是,此方法适用于数据量较小的情况,数据量超过阈值会抛出异常
    List<WorkflowTask> list = taskService.list(roleId, taskDefineId, false);
  • 使用WorkflowTaskPageable对象获得该任务定义ID下面的所有代办任务查询的分页对象,适用于数据量较大的情况,通过此对象获得分页数据
   WorkflowTaskPageable taskPageable = taskService.getPageable(roleId, taskDefineId);

   // 通过分页查询对象获取查询结果,获取的方法有三个参数,即页码、单页记录数量和排序方式,参数不足,则使用缺省值 
       list=  taskPageable.list();
       list=  taskPageable.list(1);
       list=  taskPageable.list(1,20);
       list=  taskPageable.list(1,20,false);
  • 通过前面的方法调用,获得WorkflowTaskList后,就可以逐一处理了,比如获取对象的属性展示等操作
//在界面中显示数据
list.stream().forEach(task -> {
//  模拟程序代码处理任务,输出任务信息
  String taskId=task.getId();                        // 这里此任务的唯一标识
  String  bizzKey=task.getBusinessKey();            // 这里此任务的对应的业务流水号
  Map<String, String> parameters = task.getParameters();  // 这里是从上游任务传递过来的参数 
  });
  • 前面这一段是模拟的展示界面显示信息,如果是用户选择后,则通过ID作为参数进行后续处理
 // 通过这个ID后获得任务对象
 task=taskService.find(roleId,taskId);

 // 使用任务对象完成处理
 task.success(roleId,null);    

日终的时候清理资源

  • 把给定业务日期的所有非终态实例全部作废
  WorkflowInstanceService instanceService = workflowService.getInstanceService();
  instanceService.Closeout();

日间的时候第三方系统监控

获取服务的传感服务,用于流程平台的信息探测获取,所有接口功能都是针对预警或者统计的,数据均为只读,且不透露具体的实例或任务的数据

  • 通过 WorkflowService 获得 WorkflowSensorService,然后再通过 WorkflowSensorService获得WorkflowDefineSensorWorkflowInstanceSensorWorkflowTaskSensor 探测服务对象

 WorkflowSensorService SensorService = workflowService.getSensorService();

 WorkflowDefineSensor workflowDefineSensor = SensorService.getWorkflowDefineSensor();
 WorkflowInstanceSensor workflowInstanceSensor = SensorService.getWorkflowInstanceSensor();
 WorkflowTaskSensor workflowTaskSensor= SensorService.getWorkflowTaskSensor();
  • 使用WorkflowDefineSensor获得流程定义的探测信息

    String roleId="CTAS001";
    String taskDefineId="T001P002F001"; 
    String namespace="http://ctas.cfit.cn/schema/v2";
    String tenant="CTASv2";

    /** 列出部署的所有流程定义,返回值是 流程定义的key和version , boolean的参数 allVersion 表示是否包含所有版本  */
    Map<String,String> Defines=workflowDefineSensor.getDefines(true);

    /** 列出部署的所有流程中namespace为给定值的,返回值是 流程定义的key和version */
    Map<String,String> Defines=workflowDefineSensor.getDefines(taskDefineId);

    /**  列出部署的所有流程中namespace和 tenant为给定值的,返回值是 流程定义的key和version  */
    Defines=workflowDefineSensor.getDefines(namespace,tenant);

    /**统计所有流程定义中 definekey 的活动实例数量, 返回结果是 definekey 和 活动实例数量 组成的map  */
    Map<String,Integer> DefineSummary=workflowDefineSensor.getDefineSummary();

    /** 统计所有流程定义中 definekey的活动实例数量,返回结果是 versionTag 和 活动实例数量 组成的map */
    Map<String,Integer> DefineSummary=workflowDefineSensor.getDefineSummary(taskDefineId);

    /** 统计所有流程定义中 definekey在给定日期后启动流程实例的数量,返回结果是 versionTag 和 活动实例数量 组成的map */
    Map<String,Integer> DefineSummary=workflowDefineSensor.getDefineSummary("",new Date());

    /** 统计所有流程定义中 definekey在给定日期范围内启动流程实例的数量, 返回结果是 versionTag 和 活动实例数量 组成的map */
    Map<String,Integer> DefineSummary=workflowDefineSensor.getDefineSummary("",new Date(),new Date());
  • 使用workflowInstanceSensor获得流程实例的探测信息

    /**  获取当前活动的流程实例(非终态的实例), 返回信息是 流程的ID 和 对应的驻留节点 */
    Map<String,String> instanceMap=workflowInstanceSensor.getInstances();

    /** 获取当前活动的流程实例(非终态的实例),返回信息是 流程的ID 和 对应的驻留节点  */
    Map<String,String> instanceMap=workflowInstanceSensor.getInstances("defineKey");

    /** 获取当前活动的流程实例(非终态的实例), 返回信息是 流程的ID 和 对应的驻留节点  */
    Map<String,String> instanceMap= workflowInstanceSensor.getInstances("defineKey","versiontag");

    /**  获取当前流程实例汇总信息(非终态的实例),返回信息是 流程的ID 和 流程下面等待处理的任务数量 */
    Map<String,Integer>     instanceSummary=  workflowInstanceSensor.getInstanceSummary();

    /**  获取当前流程实例汇总信息(非终态的实例) ,参数是流程ID集合(), 返回信息是 流程的ID 和 流程下面等待处理的任务数量 */
    Map<String,Integer>   instanceSummary=  workflowInstanceSensor.getInstanceSummary(null);

  • 使用workflowTaskSensor获得流程任务的探测信息
            /** 获取给定Task定义ID下面的活动的任务数量(非终态的实例),返回信息是 Task的DefineId 和 对应的数量 */
            Map<String,Integer>        taskSummary=  workflowTaskSensor.getTasks("");

            /** 获取当前活动的任务(非终态的实例), 返回信息是 Task的DefineId 和 对应的数量  */
            Map<String,Integer>     taskSummary=  workflowTaskSensor.getTaskSummary();