背景

近几年,互联网企业从消费互联网向产业互联网转型。在消费互联网时期,企业面对的时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. koa踩坑记录

    1.koa热更新用nodemon 2.koa中暂不支持import/export 3.只发送options请求,没有后续请求   当ctx.set('Access-Control-Allow-Cred ...

  2. squid异常停止的排查步骤

    今天重启squid的时候发现,squid启动后,status 一会就stop了 whoami@blackman:~/script/AutoProxy-master/main/server$ sudo ...

  3. MSF使用OpenSSL流量加密

    MSF使用OpenSSL流量加密 前言 之前在博客里使用了Openssl对流量进行加密,这次我们来复现暗月师傅红队指南中的一篇文章,尝试用OpenSSL对Metasploit的流量进行加密,以此来躲避 ...

  4. 用传纸条讲 HTTPS

    我和小宇早恋了,上课的时候老说话. 老师把我们的座位分得很远,我在第一排,她在最后一排,我们中间隔了很多人. 但我们还是想通过传纸条的方式交流. 我们中间的那些同学,虽然坏心思比较多,但好在可以保证将 ...

  5. 【笔记】scikit-learn中的Scaler(归一化)

    scikit-learn中的数据归一化 在机器学习使用数据归一化的时候有一个重要的注意事项 我们对训练数据进行均值和方差的处理,得到mean_train以及std_train,但是在对测试数据进行归一 ...

  6. netty系列之:内置的Frame detection

    目录 简介 Frame detection DelimiterBasedFrameDecoder FixedLengthFrameDecoder LengthFieldBasedFrameDecode ...

  7. vim编辑文件时[O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort:

    ​​ ​ ​ 出现这个问题是因为你上次编辑的时候在没有保存的情况下退出了(如:电脑关机等)也有可能是有其他人在和你同时进行编辑行为(不同会话中).这是因为在用vim编辑的时候,vim会在打开文件目录下 ...

  8. 基于RT1052 Aworks 内存扩容记录(一)

    本文主要是通过迁移的思维,记录本人初次使用周立功的Aworks框架进行BSP开发 1. 首先阅读原理图 内存容量由32M扩容至64M. 2. 再则比较两颗芯片的参数 通过比较32M和64M SDRAM ...

  9. 【XXE学习】XML外部实体注入

    一.XML外部实体注入介绍 1.1 XXE简介 XML外部实体注入(XML External Entity Injection)也就是人们(mian shi guan )常说的XXE啦,见名知意,就是 ...

  10. 骨架屏css样式

    .chiaroscuro { background: #f2f2f2; animation-duration: 1.5s; animation-name: blink; animation-itera ...