Flowable是BPMN的一个基于java的软件实现,不过Flowable不仅仅包含BPMN,还有BMN决策表和CMMN Case管理引擎,并且有自己的用户管理、微服务API等一系列功能,是一个微服务平台。
官方:Flowable BPMN 用户手册 (v 6.3.0)
引入依赖
获取流程引擎对象
public class Test01 {/*** 获取流程引擎对象*/@Testpublic void testProcessEngine() {// 获取 ProcessEngineConfiguration 对象ProcessEngineConfiguration configuration = new StandaloneProcessEngineConfiguration();// 配置 相关的数据库连接信息configuration.setJdbcDriver("com.mysql.cj.jdbc.Driver");configuration.setJdbcUsername("root");configuration.setJdbcPassword("zq@123456");// UTC是统一标准世界时间configuration.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn?serverTimezone=UTC");// 如果数据库中的表结构不存在就新建configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);// 通过 ProcessEngineConfiguration 构建 processEngine 对象ProcessEngine processEngine = configuration.buildProcessEngine();}
}
控制台提示日志没有正确配置:
Flowable使用SLF4J作为内部日志框架。因此在pom.xml文件中添加下列依赖:
Log4j需要一个配置文件。
在src/main/resources文件夹下添加log4j.properties文件,并写入下列内容:
log4j.rootLogger=DEBUG, CAlog4j.appender.CA=org.apache.log4j.ConsoleAppender
log4j.appender.CA.layout=org.apache.log4j.PatternLayout
log4j.appender.CA.layout.ConversionPattern= %d{hh:mm:ss,SSS} [%t] %-5p %c %x - %m%n
重新运行应用,可以看到关于引擎启动与创建数据库表结构的提示日志:
flowable-engine6.3.0生成的表:
flowable-engine6.7.2生成的表:
数据库表名说明:
Flowable的所有数据库表都以ACT_开头。第二部分是说明表用途的两字符标示符。服务API的命名也大略符合这个规则。
ACT_RE_*: 'RE’代表repository
。带有这个前缀的表包含“静态”信息,例如流程定义与流程资源(图片、规则等)。
ACT_RU_*: 'RU’代表runtime
。这些表存储运行时信息,例如流程实例(process instance)、用户任务(user task)、变量(variable)、作业(job)等。Flowable只在流程实例运行中保存运行时数据,并在流程实例结束时删除记录。这样保证运行时表小和快。
ACT_HI_*: 'HI’代表history
。这些表存储历史数据,例如已完成的流程实例、变量、任务等。
ACT_GE_*: 通用数据。在多处使用。
我们要构建的流程是一个非常简单的请假流程。
Flowable引擎需要流程定义为BPMN 2.0格式,这是一个业界广泛接受的XML标准。 在Flowable术语中,我们将其称为一个流程定义(process definition)。一个流程定义可以启动多个流程实例(process instance)。流程定义可以看做是重复执行流程的蓝图。
在这个例子中,流程定义定义了请假的各个步骤,而一个流程实例对应某个雇员提出的一个请假申请。
BPMN 2.0存储为XML,并包含可视化的部分:使用标准方式定义了每个步骤类型(人工任务,自动服务调用,等等)如何呈现,以及如何互相连接。这样BPMN 2.0标准使技术人员与业务人员能用双方都能理解的方式交流业务流程。
我们要使用的流程定义为:
将下面的XML保存在src/main/resources文件夹下名为holiday-request.bpmn20.xml的文件中。
ProcessEngineConfiguration configuration = null;@Before// import org.junit.Before; 在一个类中最先执行的方法public void before(){// 获取 ProcessEngineConfiguration 对象configuration = new StandaloneProcessEngineConfiguration();// 配置 相关的数据库连接信息configuration.setJdbcDriver("com.mysql.cj.jdbc.Driver");configuration.setJdbcUsername("root");configuration.setJdbcPassword("zq@123456");// UTC是统一标准世界时间configuration.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn?serverTimezone=UTC");// 如果数据库中的表结构不存在就新建configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);}/*** 部署流程*/@Testpublic void testDeploy(){// 1、获取 ProcessEngine 对象ProcessEngine processEngine = configuration.buildProcessEngine();// 2、获取RepositoryServiceRepositoryService repositoryService = processEngine.getRepositoryService();// 3、完成流程的部署操作Deployment deploy = repositoryService.createDeployment().addClasspathResource("holiday-request.bpmn20.xml") // 关联要部署的流程文件.name("请假流程").deploy(); // 部署流程System.out.println("deploy.getId() = " + deploy.getId());System.out.println("deploy.getName() = " + deploy.getName());}
act_ge_bytearray、act_re_deployment、act_re_procdef表可查看到相关信息。
/*** 查询流程定义的信息*/@Testpublic void testDeployQuery() {ProcessEngine processEngine = configuration.buildProcessEngine();RepositoryService repositoryService = processEngine.getRepositoryService();// 查询单个ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId("1").singleResult();System.out.println("processDefinition.getName() = " + processDefinition.getName());System.out.println("processDefinition.getId() = " + processDefinition.getId());System.out.println("processDefinition.getDeploymentId() = " + processDefinition.getDeploymentId());System.out.println("processDefinition.getDescription() = " + processDefinition.getDescription());}
/*** 删除流程定义*/@Testpublic void testDeleteDeploy() {ProcessEngine processEngine = configuration.buildProcessEngine();RepositoryService repositoryService = processEngine.getRepositoryService();// 删除部署的流程 第一个参数id,如果部署的流程启动了就不允许删除
// repositoryService.deleteDeployment("1");// 第二个参数是级联删除,如果部署的流程启动了 相关的任务会一并被删除repositoryService.deleteDeployment("1", true);}
删除后:act_ge_bytearray、act_re_deployment、act_re_procdef表相关信息都被删除
/*** 启动流程实例*/@Testpublic void testRunProcess() {ProcessEngine processEngine = configuration.buildProcessEngine();// 通过RuntimeService启动流程实例RuntimeService runtimeService = processEngine.getRuntimeService();// 构建流程变量Map
act_ru_variable、 act_ru_task、act_ru_execution表可查看到相关信息。
此流程的deploymentId为5001,此流程已启动,删除时需级联删除。
如:repositoryService.deleteDeployment("5001", true);
在更实际的应用中,会为雇员及经理提供用户界面,让他们可以登录并查看任务列表。
其中可以看到作为流程变量存储的流程实例数据,并决定如何操作任务。
在这个例子中,我们还没有为用户任务配置办理人。我们想将第一个任务指派给"经理(managers)"组,而第二个用户任务指派给请假申请的提交人。
为第一个任务添加candidateGroups属性(’managers’使用的静态值):
为第二个任务添加assignee属性(使用一个流程变量动态指派,这个流程变量是在流程实例启动时传递的):
部署流程:
启动流程实例:
/*** 测试任务查询*/@Testpublic void testQueryTask() {ProcessEngine processEngine = configuration.buildProcessEngine();TaskService taskService = processEngine.getTaskService();// 查询“managers”组的任务List
在BPMN 2.0 XML中,这是一个服务任务(service task):
创建一个相关类填入org.flowable作为包名,CallExternalSystemDelegate作为类名。让这个类实现org.flowable.engine.delegate.JavaDelegate接口,并实现execute方法:
package org.flowable;import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;public class CallExternalSystemDelegate implements JavaDelegate {@Overridepublic void execute(DelegateExecution execution) {// 触发执行的逻辑 请假申请通过System.out.println("请假申请通过");System.out.println("Calling the external system for employee "+ execution.getVariable("employee"));}
}
创建一个相关类填入org.flowable作为包名,SendRejectionMail 作为类名。让这个类实现org.flowable.engine.delegate.JavaDelegate接口,并实现execute方法:
package org.flowable;import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;public class SendRejectionMail implements JavaDelegate {@Overridepublic void execute(DelegateExecution execution) {// 触发执行的逻辑 被拒绝的员工发送通知的邮件System.out.println("不好意思,你的请假申请被拒绝......安心工作");}
}
任务完成,并会在离开排他网关的两条路径中,基于’approved’流程变量选择一条。
/*** 完成当前任务*/@Testpublic void testCompleteTask() {ProcessEngine processEngine = configuration.buildProcessEngine();TaskService taskService = processEngine.getTaskService();Task task = taskService.createTaskQuery().processDefinitionId("holidayRequest:1:10003").taskCandidateGroup("managers").singleResult();// 创建流程bianlMap
当执行到达服务任务时,会初始化并调用BPMN 2.0 XML中所引用的类。
现在执行这个例子的时候,就会显示出日志信息,说明已经执行了自定义逻辑:
/*** 完成当前任务*/@Testpublic void testCompleteTask() {ProcessEngine processEngine = configuration.buildProcessEngine();TaskService taskService = processEngine.getTaskService();Task task = taskService.createTaskQuery().processDefinitionId("holidayRequest:3:20003").taskCandidateGroup("managers").singleResult();// 创建流程bianlMap
日志信息:
选择使用Flowable这样的流程引擎的原因之一,是它可以自动存储所有流程实例的审计数据或历史数据。这些数据可以用于创建报告,深入展现组织运行的情况,瓶颈在哪里,等等。
例如,如果希望显示流程实例已经执行的时间,就可以从ProcessEngine获取HistoryService,并创建历史活动(historical activities)的查询。
/*** 获取流程任务的历史数据*/@Testpublic void testHistory() {ProcessEngine processEngine = configuration.buildProcessEngine();HistoryService historyService = processEngine.getHistoryService();List
下载最新稳定版本的Apache Tomcat。
下载最新稳定版本的Flowable 6。
将Flowable发行包中,wars文件夹下的flowable-admin.war、flowable-idm.war、flowable-modeler.war与flowable-task.war文件,复制到Tomcat的webapps文件夹下。
运行bin/startup.sh(在Mac OS或Linux下),或bin/startup.bat(在Windows下)脚本,启动Tomcat服务器。
打开web浏览器,访问Flowable IDM,默认账号admin 密码test