背景

近几年,互联网企业从消费互联网向产业互联网转型。在消费互联网时期,企业面对的时C端消费者,而产业互联网面对的是B端用户。

产业互联网涉及方方面面,企业信息化的建设就是B端用户的业务之一,在企业就存在上下级关系,存在审批业务,需要流程管理。

在企业信息化建设中流程管理也是重要的一部分,如下基于flowable简单的分析流程定义。

流程的一点基本概念

开始节点,结束节点和人工任务节点

网关

自动服务任务

 顺序流

网关分支

  • 并行分叉 AND-split(Parallel Split)

    • 两个分支都需要执行
    • 如 下单后 发快递和开发票,两个动作都会做。
  • 排他分叉或叫异或 XOR-split(Exclusive Choice)

    • 后续分支二选一,只能走一条
    • 如 下单后的支付,选择银联支付,微信支付还是支付宝支付,只能选择一种支付方式。

网关合并

  • 同步AND-join(Synchronization)

    • 前面的所有的分支等待都需要完成
    • 如上面的下单,收快递和收发票,都收到了,流程才完成。
  • 简单合并XOR-join(Simple Merge)
    • 前面的分支只要有一个完成,流程就完成
    • 如上面的下单后支付,不管是银联,微信支付还是支付宝支付,只要有一个渠道支付成功,支付流程就完成。

Flowable相关说明

官网地址:https://flowable.com/

帮助文档:https://flowable.com/open-source/docs/bpmn/ch02-GettingStarted/

中文帮助文档:https://tkjohn.github.io/flowable-userguide/#_introduction

github代码:https://github.com/flowable/flowable-engine

flowable的发展

  • Flowable是来自从Activiti5.22
  • Activiti6.0的bug太多
  • Activiti7.0主要拥抱云
  • Flowable6版本开始按照模块进行拆分,社区比较活跃

如下是JBoss,Alfresco和Flowable三个团队的流程软件关键时间点描述:

Flowable安装和配置

Flow安装

第一步、从flowable的github地址上下载如下几个war,部署到apache的webapps下

flowable-admin.war
flowable-idm.war
flowable-modeler.war
flowable-rest.war
flowable-task.war

第二步、修改如上几个包的配置文件,配置mysql数据地址或者使用自身的h2数据库进行实验。

修改admin idm modeler rest和task这5个包的配置文件WEB-INF/classes/flowable-default.properties,本实验使用的是mysql数据库。

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/flowable?characterEncoding=UTF-8
spring.datasource.username=flowable
spring.datasource.password=flowable

配置后,启动tomcat服务器并登录。

Flowable modeler登录

访问flowable的流程设计器

地址:http://localhost:8080/flowable-modeler

账号密码:admin/test

登录后,可以访问flowable的管理页面

地址:http://localhost:8080/flowable-admin/#/engine

可以看到flowable流程由如下几个引擎组成

可以通过编辑REST端点检查对应的服务运行是否正常。

本例中以流程引擎为例简单的说明。

流程定义

定义一个简单的请假流程,包括一个开始节点,一个审批节点,经管排他网关后,审批通过后发送一个http通知,审批拒绝后也发送一个http通知。

如上流程定义使用bpmn2.0的xml表示大致如下所示

<?xml version="1.0" encoding="UTF-8"?>
<definitions>
<process id="flow_h1" name="holiday-new" isExecutable="true">
<documentation>请求流程描述</documentation>
<startEvent id="startEvent1" name="请假开始" flowable:formKey="formKey1" flowable:formFieldValidation="true">
<extensionElements>
<flowable:formProperty id="employee" name="请假人" type="string" required="true"></flowable:formProperty>
<flowable:formProperty id="noOfHolidays" name="天数" type="long" required="true"></flowable:formProperty>
</extensionElements>
</startEvent>
<userTask id="approveKey1" name="审批节点1" flowable:formFieldValidation="true"></userTask>
<exclusiveGateway id="sid-D7F080C0-BC9D-4C03-B9EB-2D81E4010CA6" name="审批是否通过"></exclusiveGateway>
<serviceTask id="AcceptKey1" name="通过" flowable:class="org.example.tut.flowable.handler.HolidayRejectionHandler"></serviceTask>
<serviceTask id="RejectKey1" name="拒绝" flowable:class="org.example.tut.flowable.handler.HolidayApprovalHandler"></serviceTask>
<endEvent id="sid-E86D23D8-DC24-44D0-B96D-BA3E8CF801C0"></endEvent>
<serviceTask id="RejectHttpKey1" name="HTTP测试节点" flowable:type="http">
<extensionElements>
<flowable:field name="requestMethod">
<flowable:string><![CDATA[POST]]></flowable:string>
</flowable:field>
<flowable:field name="requestUrl">
<flowable:string><![CDATA[http://127.0.0.1:9901/test]]></flowable:string>
</flowable:field>
<flowable:field name="requestBody">
<flowable:expression><![CDATA[Reject action, employee ${employee} apply ${noOfHolidays} days with reason ${description}]]></flowable:expression>
</flowable:field>
</extensionElements>
</serviceTask>
<sequenceFlow id="sid-84648711-833A-4ABE-AD08-3E32B026F247" sourceRef="RejectKey1" targetRef="RejectHttpKey1"></sequenceFlow>
<sequenceFlow id="sid-448B4748-A744-43D9-B3EB-FC0846035F20" sourceRef="RejectHttpKey1" targetRef="sid-E86D23D8-DC24-44D0-B96D-BA3E8CF801C0"></sequenceFlow>
<endEvent id="sid-683697FC-2E68-45C9-BE63-0F526FC2F3AB"></endEvent>
<serviceTask id="AcceptHttpKey1" name="审批通过的HTTP消息" flowable:type="http">
<extensionElements>
<flowable:field name="requestMethod">
<flowable:string><![CDATA[POST]]></flowable:string>
</flowable:field>
<flowable:field name="requestUrl">
<flowable:string><![CDATA[http://127.0.0.1:9901/test]]></flowable:string>
</flowable:field>
<flowable:field name="requestBody">
<flowable:expression><![CDATA[Accept Holiday employee ${employee} apply ${noOfHolidays} days with reason ${description}]]></flowable:expression>
</flowable:field>
</extensionElements>
</serviceTask>
<sequenceFlow id="sid-9788654A-171C-45B9-9A41-94A35C531AA8" sourceRef="AcceptHttpKey1" targetRef="sid-683697FC-2E68-45C9-BE63-0F526FC2F3AB"></sequenceFlow>
<sequenceFlow id="sid-C4456145-0531-492F-AA80-E733CD0C35C9" sourceRef="AcceptKey1" targetRef="AcceptHttpKey1"></sequenceFlow>
<sequenceFlow id="SeqFromStartToApprove" sourceRef="startEvent1" targetRef="approveKey1"></sequenceFlow>
<sequenceFlow id="SeqFromApproveToGW" sourceRef="approveKey1" targetRef="sid-D7F080C0-BC9D-4C03-B9EB-2D81E4010CA6"></sequenceFlow>
<sequenceFlow id="SeqRejectKey1" sourceRef="sid-D7F080C0-BC9D-4C03-B9EB-2D81E4010CA6" targetRef="RejectKey1">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${!approved}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="ReqAcceptKey1" sourceRef="sid-D7F080C0-BC9D-4C03-B9EB-2D81E4010CA6" targetRef="AcceptKey1">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${approved}]]></conditionExpression>
</sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_flow_h1">
... 省
</bpmndi:BPMNDiagram>
</definitions>

节点说明

这个简单的流程中使用了flowable的几个节点

流程定义的组成

process

  • startEvent 表示开始节点

    • 开始节点可以是空节点
    • 开始节点也可以是定时节点
  • userTask 表示人工审批节点
    • 可以通过 flowable:assignee="userId" 表示这个节点的审批人是谁
    • 可以通过 flowable:candidateGroups="managerGroup" 表示候选的审批组是什么,在这个组中的人都可以做为审批人。
    • 人工审批节点可以增加extensionElements增加自定义扩展属性,将流程定义的扩展信息保存到CDATA中
  • exclusiveGateway 表示排他网关
    • 人工审批后的审批结果做为排他网关的判断依据
  • serviceTask 表示自动节点
    • 有自定义的节点需要自定义一个Handler做为serviceTask节点的处理。
    • serviceTask也有一些系统内置实现(如HTTP服务 MAIL服务 MULE服务等)
    • 自动服务节点可以增加extensionElements增加自定义扩展属性,将流程定义的扩展信息保存到CDATA中
  • sequenceFlow 表示分支流
    • 在分支流上会存在一个条件,排他网关后会跟多个sequenceFlow,排他网关会根据各自sequenceFlow上的条件决定流程的流向。
    • 条件会使用conditionExpression来表示,这个表达式一般使用JUEL表达式实现。
  • endEvent 表示结束节点

bpmndi:BPMNDiagram

  • bpmndi:BPMNShape

    • omgdc:Bounds 表示图像的轮廓包含宽高

      • width 宽
      • height 高
  • bpmndi:BPMNEdge
    • pmgdi:waypoint

      • x 横轴坐标
      • y 纵轴坐标

startEvent的定时节点如何定义?

<startEvent id="timer_start1" name="定时器节点" isInterrupting="false">
<timerEventDefinition>
<timeDate>2021-06-30T15:01:02</timeDate>
<timeCycle>R/P1DT0S</timeCycle>
<timeDuration>P10DT0S</timeDuration>
</timerEventDefinition>
</startEvent>

时间定义参考ISO8601标准,可以参考@https://www.cnblogs.com/xdao/p/iso8601.html

格式解析
R2/2015-06-04T19:25:16.828696-07:00/P1DT10S 上面的字符串通过"/"分为了三部分即: 重复次数/开始时间/运行间隔 重复次数
R - 将永远重复
R1 - 将重复一次
R231 - 将重复231次。
开始时间
任务第一次运行的时间。如果开始日期时间已经过去,Kala将返回一个错误。 其中"T"用来分割日期和时间,时间后面跟着的"-07:00"表示西七区,注意"-"是连字符,不是减号。 时区默认是0时区,可以用"Z"表示,也可以不写。 对于我国,要使用"+08:00",表示东八区。
上面的字符串表示 2015年6月4日,19点25分16秒828696纳秒,西七区。 运行间隔
运行间隔以"P"开始,和上面一样也是用"T"分割日期和时间,如P1Y2M10DT2H30M15S P 开始标记
1Y - 一年
2M - 两个月
10D - 十天
T - 时间和日期分的割标记
2H - 两个小时
30M - 三十分钟
15S 十五秒钟
例子,注意如果没有年月日,"T"也不能省略 P1DT1M - 一天一分钟执行一次
P1W - 一周执行一次
PT1H - 一小时执行一次
PT10S - 十秒执行一次

启动流程

启动流程的代码:

  public ProcessInstanceResponse startProcessInstance(HolidayRequest holidayRequest) {

        Map<String, Object> variables = new HashMap<String, Object>();
variables.put("employee", holidayRequest.getEmpName());
variables.put("noOfHolidays", holidayRequest.getNoOfHolidays());
variables.put("description", holidayRequest.getRequestDescription());
variables.put("initiator", "admin"); ProcessInstance processInstance =
runtimeService.startProcessInstanceByKey(holidayRequest.getProcessKey(), variables); return new ProcessInstanceResponse(processInstance.getId(), processInstance.isEnded());
}

启动流程后,会在数据库中增加记录

ACT_RU_ACTINST 增加流程实例信息。

ACT_RU_VARIABLE 增加variables变量列表的变量,这个变量会贯穿流程实例的全程。

分配任务

分配任务的代码:

TaskService taskService;

// taskId是任务Id,userId是用户id,表示将任务分配给这个用户
taskService.setAssignee(taskId, userId);

分配任务后,会在数据库中设置审批人信息

ACT_RU_TASK 表的字段 ASSIGEE_表示审批人是谁

获取待办任务

获取待办任务的代码

// 跟进userId用户id查询分配给这个用户或将这个用户设为候选的任务列表
List<Task> taskList = taskService.createTaskQuery().taskCandidateOrAssigned(userId).list();

会查询ACT_RU_TASK表,获取审批人的任务。

完成任务

完成任务也叫做审批任务

taskService.complete(taskId, variables);

流程运行

流程运行时,实例和变量说明什么

可以在管理页面看到启动流程实例是填写的变量列表

启动流程增加的变量

variables.put("employee", holidayRequest.getEmpName());
variables.put("noOfHolidays", holidayRequest.getNoOfHolidays());
variables.put("description", holidayRequest.getRequestDescription());
variables.put("initiator", "admin");

人工节点审批时增加的变量是什么

variables.put("approved", approved);
taskService.complete(taskId, variables);

即:变量时贯穿流程实例的全声明周期,流程的很多自定义功能可以通过变量和扩展属性进行实现。

展示流程实例的运行图

 

done.

祝玩得开心~

【流程】Flowable流程定义总结的更多相关文章

  1. Gemini.Workflow 双子工作流入门教程三:定义流程:流程节点、迁移条件参数配置

    简介: Gemini.Workflow 双子工作流,是一套功能强大,使用简单的工作流,简称双子流,目前配套集成在Aries框架中. 下面介绍本篇教程:定义流程:流程节点.迁移条件参数配置. 一.普通节 ...

  2. activiti自己定义流程之自己定义表单(二):创建表单

    注:环境配置:activiti自己定义流程之自己定义表单(一):环境配置 在上一节自己定义表单环境搭建好以后,我就正式開始尝试自己创建表单,在后台的处理就比較常规,主要是针对ueditor插件的功能在 ...

  3. 信贷风控模型开发----模型流程&好坏样本定义

    第二章 模型开发流程&好坏样本定义 2.1模型开发流程 2.1.1 评分模型流程图 2.1.2流程图阐述 该小结提出了一些数据指标,如果不明白没有关系,往后的文章笔者会一个个地解释这些指标的含 ...

  4. activiti学习5:开启流程和流程前进

    目录 activiti学习5:开启流程和流程前进 一.流程和任务的关系 二.开启流程 2.1根据流程定义key开启流程 三.查询用户任务 3.1 TaskQuery 四.完成任务 activiti学习 ...

  5. IT的灵魂是流程,流程的灵魂是业务,业务的灵魂是战略

    IT的灵魂是流程,流程的灵魂是业务,业务的灵魂是战略.高效的IT平台不在于IT技术,而在于好的管理模式与流程设计 从以组织为核心转向以流程为核心 流程管理核心是从流程角度出发,关注流程是否增值,籍此建 ...

  6. jeecg bpm流程节点流程节点配置

    流程节点 流程节点 cgFormBuildController.do?ftlForm&tableName=jform_leave&mode=onbutton&ftlVersio ...

  7. 公司采购 流程flowable例子

    Name: Flowable BPMN 2.0 designer Location: http://flowable.org/designer/update/ 业务描述:1. 公司采购,因为办公用品价 ...

  8. Gemini.Workflow 双子工作流入门教程二:定义流程:流程节点介绍

    简介: Gemini.Workflow 双子工作流,是一套功能强大,使用简单的工作流,简称双子流,目前配套集成在Aries框架中. 下面介绍本篇教程:流程定义:流程节点属性. 流程节点: 左侧是节点工 ...

  9. activiti自己定义流程之自己定义表单(一):环境配置

    先补充说一下自己定义流程整个的思路,自己定义流程的目的就是为了让一套代码解决多种业务流程.比方请假单.报销单.採购单.协作单等等.用户自己来设计流程图. 这里要涉及到这样几个基本问题,一是不同的业务需 ...

随机推荐

  1. SaltStack 水平权限绕过漏洞(CVE-2020-11651)

    影响版本 SaltStack < 2019.2.4 SaltStack < 3000.2 poc git clone https://github.com/jasperla/CVE-202 ...

  2. 🔥 LeetCode 热题 HOT 100(31-40)

    75. 颜色分类 思路:将 2 往后放,0 往前放,剩余的1自然就放好了. 使用双指针:left.right 分别指向待插入的 0 和 2 的位置,初始 left 指向数组头,right 指向数组尾部 ...

  3. YsoSerial 工具常用Payload分析之Common-Collections7(四)

    前言 YsoSerial Common-Collection3.2.1 反序列化利用链终于来到最后一个,回顾一下: 以InvokerTranformer为基础通过动态代理触发AnnotationInv ...

  4. Feign远程调用

    有关微服务中,服务与服务如何通信,我已经给大家介绍了Ribbon远程调用的相关知识,不知道大家有没有发现Ribbon的问题呢? Ribbon的问题 在Ribbon中,如果我们想要发起一个调用,是这样的 ...

  5. 为了彻底搞懂 hashCode,我钻了一下 JDK 的源码

    今天我们来谈谈 Java 中的 hashCode() 方法--通过源码的角度.众所周知,Java 是一门面向对象的编程语言,所有的类都会默认继承自 Object 类,而 Object 的中文意思就是& ...

  6. Spring Security项目的搭建以及Spring Security的BCrypt加密

    .personSunflowerP { background: rgba(51, 153, 0, 0.66); border-bottom: 1px solid rgba(0, 102, 0, 1); ...

  7. 基于AOP和HashMap原理学习,开发Mysql分库分表路由组件!

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 什么?Java 面试就像造火箭 单纯了! 以前我也一直想 Java 面试就好好面试呗 ...

  8. [06 Go语言基础-包]

    [06 Go语言基础-包] 包 什么是包,为什么使用包? 到目前为止,我们看到的 Go 程序都只有一个文件,文件里包含一个 main 函数和几个其他的函数.在实际中,这种把所有源代码编写在一个文件的方 ...

  9. 位(bit)、字节(Byte)、字(Word)、双字(Dword)之间的关系

    位(bit): bit(简写:b),是计算机数据存储最小的单位,二进制中,0或者1就是一个位(比特位)bit. 字节: Byte(简写:B),是计算机信息技术用于计量存储容量的一种计量单位,通常情况下 ...

  10. Java入门姿势【面向对象3】构造方法及其重载_方法的调用

    上次我为大家写出啦"定义类与创建对象_了解局部变量",上篇文章代码可能较多,如没有了解透彻的话请打开下方文章在进行观看一下哦!! [Java入门姿势[面向对象2]定义类与创建对象_ ...