直接跳到内容

流程事件

流程事件是在流程实例运行过程中产生,在流程事件中我们可以配置远程接口调用、远程消息通知、以及一些复杂业务逻辑性处理。

事件类型

事件在类型上分为全局和节点,他们在配置内容上相同,粒度上不同。下面将介绍各个事件的配置

全局事件

全局事件的配置是在流程插件上,执行上支持指定时机。

界面预览界面预览

流程结束事件

流程结束事件是在流程结束时触发,执行上有两种场景:

正常结束:流程实例正常结束,无人工终止。

人工终止:人为原因操作了 人工终止、撤销、超管终止 等触发

界面预览

开始事件

开始事件位于流程的开始处,流程实例启动触发

界面预览

用户任务

界面预览

服务任务

界面预览

结束事件

流程正常结束触发

界面预览

事件内容配置

数据模型

传输变量

json
{
  // 业务对象
  "busData": {},
  // 流程实例
  "bpmInstance": {
    // 实例ID
    "id": "",
    // 标题
    "title": "",
    // 定义ID
    "defId": "",
    // Activiti实例ID
    "actInstId": "",
    // 父实例Id
    "parentId": "",
    // 流程KEY
    "defKey": "",
    // 业务ID
    "bizId": "",
    // 状态
    "status": "",
    // 是否支持移动端  1:是 0:否
    "supportMobile": 1,
    // 创建时间
    "createTime": "",
    // 完成时间
    "endTime": "",
    // 创建人ID
    "createBy": ""
  },
  // 流程任务
  "bpmTask": {
    // 任务ID
    "id": "",
    // 任务名称
    "name": "",
    // 节点KEY
    "nodeKey": "",
    // 标题
    "title": "",
    // 实例ID
    "instId": "",
    // activiti任务ID
    "actTaskId": "",
    // activiti执行ID
    "actExecutionId": "",
    // 流程定义ID
    "defId": "",
    // 任务状态  normal:普通  designate:指派 lock:锁定  sign:会签  hang:挂起  turn:转办  agent:代理 reject:驳回  drag:捞单
    "status": "",
    // 挂起状态  1:是   0:否
    "suspensionState": 0,
    // 任务执行人说明
    "assigneeNames": "",
    // 任务紧急程度
    "priority": 50,
    // 支持移动端  1:是  0:否
    "supportMobile": 0,
    // 驳回后返回节点
    "backNode": "",
    // 到期时间
    "dueTime": "",
    // 任务类型   userTask:用户任务   serviceTask:服务任务   signTask:会签任务  signSource:会签源任务  agentTask:代理任务
    "taskType": "",
    // 父任务ID
    "parentId": "",
    // 任务分类编码
    "typeCode": ""
  },
  // 流程意见
  "submitOpinion": "",
  // 流程按钮
  "submitActionName": "",
  // 流程按钮名称
  "submitActionDesc": "",
  // 流程变量
  "variables": {},
  // 事件类型
  "eventType": "",
  // 当前用户
  "currentUser": {
    // 用户ID
    "id": "",
    // 用户名
    "username": "",
    // 用户姓名
    "fullName": ""
  }
}

远程 HTTP 调用

事件执行方式上通过远程HTTP调用

图示

服务端接口定义规范

TIP

如提供接口服务端使用的 Java 语言,可引入 AgileBPM 提供的依赖来接收参数

引入依赖

xml
<dependency>
  <groupId>com.dstz</groupId>
  <artifactId>ab-wf-client</artifactId>
  <version>xxx</version>
</dependency>

接收类

com.dstz.bpm.api.dto.invoke.BpmPluginGlobalInvokeDataDTO

响应类

com.dstz.base.api.vo.ApiResponse
com.dstz.bpm.api.vo.BpmPluginGlobalInvokeVO

请求方式:POST

请求类型:application/json;charset=UTF-8

请求体:事件内容配置-数据模型-传输变量

响应内容

json
{
  "isOk": true,
  "code": "Success",
  "message": "操作成功",
  // 此处未同步返回
  "data": {
    // 是否跳过当前任务
    "skipCurrentTask": false,
    // 设置流程变量
    "newVariables": {},
    // 设置流程标题
    "resetInstanceSubject": null,
    // 服务任务支持多种形式的反馈 throw businessExcetion 为中断操作 mark success 为默认操作,即反馈调用成功,如果marked error 则流程图,意见列表均提示异常
    "serviceTaskMark": "success",
    // 服务任务时支持通过该参数标记调用结果的备注信息
    "serviceTaskMarkMsg": "",
    // 业务数据
    "resetBusData": {},
    // 业务主键为流程实例与业务关联字段,bizKey会替换URL表单的主键标识,所以请合理设置
    "bizKey": ""
  }
}

接口地址

接口地址是一个 URL,在微服务下服务间调用需要使用lb://服务名/处理器路径编写。地址中支持变量编写,运行中将对编写的变量做实际值替换。接口地址可支持多个,执行上顺序调用

地址变量

变量语法:{xxx[.xxx]}

  • {bizId} 流程示例绑定的业务主键

  • {token} 请求 Token,从请求头 Authoziation 中获取

  • {bpmDefinition.xxx} 获取流程定义属性,参考类com.dstz.bpm.core.entity.BpmDefinition;示例:流程名称:{bpmDefinition.name}、流程 KEY:{bpmDefinition.key}、流程 ID:{bpmDefinition.id}

  • {bpmInstance.xxx} 获取流程实例属性,参考类com.dstz.bpm.core.entity.BpmInstance;示例:流程实例 ID:{bpmInstance.id}、关联业务 ID:{bpmInstance.bizId}

  • {bpmProperty.xxx} 获取系统属性定义值,参考菜单系统 》系统属性;示例:某系统访问 token:{bpmProperty.xxx_token}

  • {requestCookie.xxx} 从当前请求 Cookie 中获取值;示例:{requestCookie.JSESSIONID}

  • {requestHeader.xxx} 从当前请求头中获取值;示例:{requestHeader.Authorization}

接口地址示例

http://{bpmProperty.bizApiServer}/flowRpc/{bpmDefinition.key}

异步

  1. 异步的使用需要搭配事务消息组件,请求将在整个事务执行成功后调用,关于事务消息参考事务消息文档。
  2. 同步调用需要等待结果返回。

传输变量选择

订阅接口需要的数据

指定执行时机

订阅只在指定时机下执行

使用示例

示例中我们将使用 NodeJS 搭建一个服务接口,并配置流程事件调用服务接口

创建 NODEJS 服务接口

shell
# 创建目录
$ mkdir webserver

# 安装express
$ cnpm install express

$ vim index.js
const express = require("express")

const app = express()
app.use(express.json())

app.post('/flow-event/:defKey', function (req, res) {
    console.log(['*'.repeat(50), `请求地址:${req.url}`, `请求参数:${JSON.stringify(req.params)}`, `请求体:${JSON.stringify(req.headers)}`, `请求体:${JSON.stringify(req.body)}`, '*'.repeat(50),].join('\n'))
    res.send({isOk: true, code: 'Success', 'message': '执行成功'})
})

app.listen(5000, () => {
    console.log(`服务已启动,监听端口:5000`)
})

# 运行服务
$ node index.js

配置流程事件

界面预览

启动流程实例

接口服务端输出日志

界面预览

事务消息

使用事务消息需要提前启用事务消息组件,有关如何启用事务消息组件请查询事务消息文档。

BpmPluginGlobalInvokeDataDTO 参数依赖于流程模块,编写处理方法前需提前在模块的 pom.xml 中引入依赖

xml
<dependency>
    <groupId>com.dstz</groupId>
    <artifactId>ab-wf-client</artifactId>
    <version>${project.version}</version>
</dependency>

使用示例

  1. 编写处理方法

com.dstz.AbSpringBootApp

java
@AbMessage(subscribeKey = "flowEvent")
public void flowEvent(com.dstz.bpm.api.dto.invoke.BpmPluginGlobalInvokeDataDTO dataDTO) {
    logger.info("流程事件-事务消息(flowEvent)处理:{}", JsonUtils.toJSONString(dataDTO));
}
  1. 流程事件配置

界面预览

  1. 启动流程

  2. 控制台查看日志

2023-03-21 17:46:41.400  INFO 23185 --- [ trxredo-pool-1] com.dstz.AbSpringBootApp                 : 流程事件-事务消息(flowEvent)处理:{"busData":{"wbb":{"zfc2":"1","zfc1":"1","zfc3":"1","id":"1638114895946207232"}},"bpmInstance":{"id":"1638114895572914176","title":"系统管理员发起的流程事件","defId":"1638064724775600128","actInstId":"1638114896202059776","parentId":"","defKey":"lcsj","bizId":"1638114895946207232","status":"running","supportMobile":0,"suspensionState":0,"typeCode":"bglc","createTime":"2023-03-21 17:46:40","createBy":"1602918114232172634","createOrgId":"1602918114232172544","updater":"系统管理员"},"bpmTask":{"id":"1638114897389047808","name":"用户任务1","nodeKey":"UserTask1","title":"系统管理员发起的流程事件","instId":"1638114895572914176","actTaskId":"1638114897389047808","actExecutionId":"1638114896252391424","defId":"1638064724775600128","status":"normal","assigneeNames":"系统管理员","priority":50,"supportMobile":0,"taskType":"userTask","parentId":"","typeCode":"bglc"},"submitOpinion":"","submitActionName":"create","eventType":"TASK_CREATED","currentUser":{"id":"1602918114232172634","username":"admin","fullName":"系统管理员"}}

ServiceBean

包含业务处理的 Spring Bean,使用语法:beanId.methodName,入参为com.dstz.bpm.engine.action.model.ActionModel

ActionModel 依赖于流程模块,编写处理方法前需提前在模块的 pom.xml 中引入依赖

xml
<dependency>
    <groupId>com.dstz</groupId>
    <artifactId>ab-spring-boot-wf-starter</artifactId>
    <version>${project.version}</version>
</dependency>

使用示例

  1. 编写处理方法
java
package com.dstz;

import com.dstz.bpm.core.entity.BpmTask;
import com.dstz.bpm.engine.action.model.ActionModel;
import com.dstz.bpm.engine.action.model.TaskActionModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component("bpmServiceBean")
public class BpmServiceBean {
    private static final Logger logger = LoggerFactory.getLogger(BpmServiceBean.class);

    public void execute(ActionModel actionModel) {
        // 转换为任务
        if (actionModel instanceof TaskActionModel) {
            TaskActionModel taskActionModel = (TaskActionModel) actionModel;
            BpmTask bpmTask = taskActionModel.getBpmTask();
            logger.info("ServiceBean 节点KEY:{}, 节点名称:{}", bpmTask.getNodeKey(), bpmTask.getName());
        }
    }
}
  1. 流程事件配置

界面预览

  1. 启动流程

  2. 控制台查看日志

2023-03-21 18:39:38.716  INFO 24363 --- [nio-8080-exec-9] com.dstz.BpmServiceBean                  : ServiceBean 节点KEY:UserTask1, 节点名称:用户任务1

Groovy 脚本

Groovy 脚本,一种对 Java 扩展了语法的脚本语言。可使用纯 Java 编写,也可以使用 Groovy 特性来编写。

Groovy 文档:https://groovy-lang.org

内置变量

  • bpmInstance

    流程实例,对应类com.dstz.bpm.core.entity.BpmInstance

  • bpmTask

    流程任务(只在是任务节点时有值),对应类com.dstz.bpm.core.entity.BpmTask

  • isTask

    是否任务,取值:true/false

  • variableScope

    流程变量,对应类org.activiti.engine.delegate.VariableScope;示例:获取流程变量 variableScope.getVariable("xxx")

  • submitOpinion

    提交意见

  • actionModel

    处理模型,当为任务节点对应类com.dstz.bpm.engine.action.model.ActionModel,否则对应com.dstz.bpm.engine.action.model.ActionModel

  • currentUser

    当前用户,对应类com.dstz.base.common.script.variables.UserGroovyVariable

  • submitActionName

    提交动作 KEY

  • startUser

    申请人,对应类com.dstz.base.common.script.variables.UserGroovyVariable

示例

  1. 远程接口调用
java
import com.dstz.base.common.enums.GlobalApiCodes
import com.dstz.base.common.exceptions.BusinessMessage
import com.dstz.base.common.utils.AbRestTemplateUtil

// 获取RestTemplate,微服务下参数传递true
final restTemplate = AbRestTemplateUtil.getRestTemplate(false)

// 发送请求 POST application/json
def apiResponse = restTemplate.postForObject("http://localhost:3000/flow-event", [taskName: bpmTask.getName(), taskKey: bpmTask.getNodeKey()], Map.class)

// 发送请求 POST application/x-www-form-urlencoded
def apiResponse = restTemplate.postForObject(
        "http://localhost:3000/flow-event",
        new LinkedMultiValueMap().tap {
            add("taskKey", bpmTask.getNodeKey())
            add("taskName", bpmTask.getName())
        },
        Map.class
)

// 发送请求 GET 占位符
def apiResponse = restTemplate.getForObject("http://localhost:3000/flow-event?taskKey={0}&taskName={1}", Map.class, bpmTask.getNodeKey(), bpmTask.getName())

// 发送请求 GET 命名占位符
def apiResponse = restTemplate.getForObject("http://localhost:3000/flow-event?taskKey={taskKey}&taskName={taskName}", Map.class, [taskKey: bpmTask.getNodeKey(), taskName: bpmTask.getName()])


// 处理请求返回
if (!apiResponse?.isOk) {
    throw new BusinessException(GlobalApiCodes.REMOTE_CALL_ERROR.formatDefaultMessage(apiResponse.message))
}
  1. 修改流程实例标题
java
bpmInstance.setTitle("xxxxx")
bpmInstance.setHasUpdate(true)
  1. 修改数据表
java
import com.dstz.base.utils.AbDataSourceUtils

def jdbcTemplate = AbDataSourceUtils.getCurrentDataSource().getJdbcOperations()

jdbcTemplate.update("UPDATE xxx SET col = ? WHERE tak_id_ = ?", ['xxx', bpmTask.getId()])
  1. 流程变量
java
// 获取流程变量
variableScope.getVariable("xxx")

// 设置流程变量
variableScope.setVariable("orderNo", "xxx")
  1. 常用信息获取
java
// 是否任务,用在全局插件中判断是否任务节点;在用户任务节点事件中可直接使用 bpmTask, 无需判断
if (isTask) {
    // 任务ID
    final String taskId = bpmTask.getId()

    // 任务名称
    final String taskName = bpmTask.getName()

    // 任务KEY
    final String nodeKey = bpmTask.getNodeKey()

    // 任务类型 userTask: 用户任务  serviceTask: 服务任务  signTask: 会签任务   signSource: 会签源任务   agentTask: 代理任务
    final String taskType = bpmTask.getTaskType()
}


// 流程实例ID
final String instId = bpmInstance.getId()
// 流程标题
final String title = bpmInstance.getTitle()
// 关联业务主键
final String bizId = bpmInstance.getBizId()
// 流程分类编码
final String typeCode = bpmInstance.getTypeCode()
// 是否支持移动端
final boolean supportMobile = bpmInstance.getSupportMobile() as boolean


// 流程定义KEY
final String defKey = bpmInstance.getDefKey()
// 流程定义ID
final String defId = bpmInstance.getDefId()

// 当前用户ID
final String currentUserId = currentUser.getId()
// 当前用户名
final String currentUsername = currentUser.getUsername()

// 当前用户-组织ID
final String currentOrgId = currentUser.getOrgId()
// 当前用户-组织编码
final String currentOrgCode = currentUser.getOrgCode()
// 当前用户-组织名称
final String currentOrgName = currentUser.getOrgName()


// 发起人-用户ID
final String startUserId = startUser.getId()
// 发起人-用户名
final String startUsername = startUser.getUsername()
// 当前用户-组织ID
final String startUserOrgId = startUser.getOrgId()
// 当前用户-组织编码
final String startUserCode = startUser.getOrgCode()
// 当前用户-组织名称
final String startUserName = startUser.getOrgName()
全局事件插件 has loaded