Flowable工作流引擎
Flowable工作流引擎
Flowable-基础篇(根据BV1Pb4y1p7Ku整理)
一、简介
Flowable是BPMN的一个基于java的软件实现,不过Flowable不仅仅包括BPMN,还有DMN决策表和CMMN Case管理引擎,并且有自己的用户管理、微服务API等一系列功能,是一个服务平台。
官方手册:https://tkjohn.github.io/flowable-userguide/# introduction
二、数据库解析(数据库为代码创建,先看第三点:实例前的示例(官方文档的例子))
1、act_evt_log:日志表
2、act_ge_bytearray:二进制资源表
3、act_ge_bytearray:引擎属性表
4、act_hi_actinst:历史活动信息表
5、act_hi_attachment:流程历史附件表
6、act_hi_comment:历史审批意见表
7、act_hi_detail:历史详情表
8、act_hi_identitylink:历史参与的人员表
9、act_hi_procinst:历史流程记录表
10、act_hi_taskinst:历史任务表
11、act_hi_varinst:历史流程变量表
12、act_id_bytearray:用户组部署内容表
用户组的部署内容
13、act_id_group:所有用户组信息表
所有用户组的信息
14、act_id_info:所有用户信息表
所有用户的信息,账号密码
15、act_id_membership:用户和用户组关系表
用户和用户组的关系
16、act_id_priv:权限表
17、act_id_priv_mapping:用户权限关系表
18、act_id_property:用户变量表
用户的变量,存了版本号
19、act_id_token:用户访问记录表
20、ct_id_user:用户基本信息表
用户基本信息,包括邮箱等
21、act_procdef_info:流程定义信息表
22、act_re_deployment:流程部署表
23、act_re_model:流程模型表
24、act_re_procdef:流程定义表
25、act_ru_deadletter_job:运行时死信作业表
26、act_ru_event_subscr:运行时事件订阅表
27、act_ru_execution:运行时流程执行实例表
28、atc_ru_history_job:运行时历史信息表
29、act_ru_identitylink:运行时身份连接表
30、act_ru_job:运行时作业表
31、act_ru_suspended_job:运行时挂起的定时作业表
32、act_ru_task:运行时任务表
33、act_ru_timer_job:运行时定时作业表
34、act_ru_variable:运行时流程变量表
三、实例前的示例(官方文档的例子)
1、创建项目
●创建一个maven项目
●填写pom依赖
2、配置依赖
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-engine</artifactId>
<version>6.3.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
3、Test01
●先创建数据库
●创建Test01
public class Test01 {
/*获取流程引擎对象*/
@Test
public void testProcessEngine(){
// 获取ProcessEngineConfiguration对象
ProcessEngineConfiguration configuration = new StandaloneInMemProcessEngineConfiguration();
// 配置相关数据库连接信息(做演示就不封装了)
configuration.setJdbcDriver("com.mysql.cj.jdbc.Driver");
configuration.setJdbcUsername("root");
configuration.setJdbcPassword("root");
configuration.setJdbcUrl("jdbc:mysql://localhost:3306/flowable_learn?serverTimezone=UTC");
// 如果数据库中的表结构不存在就新建
configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
// 通过ProcessEngineConfiguration构建我们需要的processEngine对象
ProcessEngine processEngine = configuration.buildProcessEngine();
}
}
运行程序
红色提示是由于没配置日志文件,运行完成后到数据库查看
可以看到已经创建了数据库表,这里使用的是5.7版本的数据库,值得注意的是,如果使用8.0版本的数据库,可能出现如下问题
●添加日志配置
先添加pom依赖
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
再添加log4j.properties
log4j.rootLogger=DEBUG, CA
log4j.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
再次运行就可以看到已经有日志信息的输出
4、流程部署
●流程部署定义
●流程部署布置:配置文件:holiday-request.bpmn20.xml
将下面的XML保存在src/main/resources文件夹下名为holiday-request.bpmn20.xml的文件中。
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
xmlns:flowable="http://flowable.org/bpmn"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.flowable.org/processdef">
<process id="holidayRequest" name="Holiday Request" isExecutable="true">
<startEvent id="startEvent"/>
<sequenceFlow sourceRef="startEvent" targetRef="approveTask"/>
<userTask id="approveTask" name="Approve or reject request"/>
<sequenceFlow sourceRef="approveTask" targetRef="decision"/>
<exclusiveGateway id="decision"/>
<sequenceFlow sourceRef="decision" targetRef="externalSystemCall">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[
${approved}
]]>
</conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="decision" targetRef="sendRejectionMail">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[
${!approved}
]]>
</conditionExpression>
</sequenceFlow>
<serviceTask id="externalSystemCall" name="Enter holidays in external system"
flowable:class="org.flowable.CallExternalSystemDelegate"/>
<sequenceFlow sourceRef="externalSystemCall" targetRef="holidayApprovedTask"/>
<userTask id="holidayApprovedTask" name="Holiday approved"/>
<sequenceFlow sourceRef="holidayApprovedTask" targetRef="approveEnd"/>
<serviceTask id="sendRejectionMail" name="Send out rejection email"
flowable:class="org.flowable.SendRejectionMail"/>
<sequenceFlow sourceRef="sendRejectionMail" targetRef="rejectEnd"/>
<endEvent id="approveEnd"/>
<endEvent id="rejectEnd"/>
</process>
</definitions>
我们来添加些备注以便看懂整个逻辑
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
xmlns:flowable="http://flowable.org/bpmn"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.flowable.org/processdef">
<!--process:流程,id:流程主键,name:名称,可以修改,比如改为"请假流程"-->
<process id="holidayRequest" name="Holiday Request" isExecutable="true">
<startEvent id="startEvent"/>
<!--targetRef:目标引用,走到下面的approveTask-->
<sequenceFlow sourceRef="startEvent" targetRef="approveTask"/>
<!--name="同意或者拒绝请假"-->
<userTask id="approveTask" name="Approve or reject request"/>
<!--targetRef目标引用为下面的排他网关decision-->
<sequenceFlow sourceRef="approveTask" targetRef="decision"/>
<!--排他网关(id:decision),有两个流程-->
<exclusiveGateway id="decision"/>
<!--流程1:targetRef="外部系统调用",就是走到管理员审批的流程中-->
<sequenceFlow sourceRef="decision" targetRef="externalSystemCall">
<!--条件表达式:${approved}如果为真就走这里-->
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[
${approved}
]]>
</conditionExpression>
</sequenceFlow>
<!--targetRef="发送拒绝邮件",就是直接走拒绝策略,就跳转到下面id="sendRejectionMail"-->
<sequenceFlow sourceRef="decision" targetRef="sendRejectionMail">
<!--条件表达式:${!approved}:!表示取反,如果参数不为真就走这里-->
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[
${!approved}
]]>
</conditionExpression>
</sequenceFlow>
<!--name="在外部系统中输入假日"-->
<serviceTask id="externalSystemCall" name="Enter holidays in external system"
flowable:class="org.flowable.CallExternalSystemDelegate"/>
<sequenceFlow sourceRef="externalSystemCall" targetRef="holidayApprovedTask"/>
<!--name="假期获批",targetRef="approveEnd"就是走到最下面结束-->
<userTask id="holidayApprovedTask" name="Holiday approved"/>
<sequenceFlow sourceRef="holidayApprovedTask" targetRef="approveEnd"/>
<!--name="发送拒绝邮件",flowable:class就是用来处理发送邮件的操作,targetRef="rejectEnd"就是走到最下面结束-->
<serviceTask id="sendRejectionMail" name="Send out rejection email"
flowable:class="org.flowable.SendRejectionMail"/>
<sequenceFlow sourceRef="sendRejectionMail" targetRef="rejectEnd"/>
<endEvent id="approveEnd"/>
<endEvent id="rejectEnd"/>
</process>
</definitions>
我们再次对照下图来看,xml中从process id="holidayRequest"开始,就是对应下图的发起请假申请;然后走到approveTask,approveTask走到排他网关,排他网关有两个分支,根据$ {approved}和$ {!approved}来判断走哪个分支,就是对应下图的网关同意和拒绝两个分支:拒绝的话走到sendRejectionMail发送拒绝邮件,再跳转到rejectEnd结束;同意的话就是走到externalSystemCall,对应下图进入人事系统,然后走到holidayApprovedTask假期获批,最后跳转到approveEnd结束流程。
●流程部署布置:代码实现
回到test01中
ProcessEngineConfiguration configuration = null;
@Before
public void before(){
/*配置数据库设置*/
configuration = new StandaloneInMemProcessEngineConfiguration();
configuration.setJdbcDriver("com.mysql.cj.jdbc.Driver");
configuration.setJdbcUsername("root");
configuration.setJdbcPassword("root");
configuration.setJdbcUrl("jdbc:mysql://localhost:3306/flowable_learn?serverTimezone=UTC");
// 如果数据库中的表结构不存在就新建
configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
}
/**
* 部署流程
* */
@Test
public void testDeploy(){
// 1.获取ProcessEngine对象
ProcessEngine processEngine = configuration.buildProcessEngine();
// 2.获取RepositoryService
RepositoryService 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());
}
运行测试程序
到数据库中查看
还需要注意ProcessEngine和四个Service之间的关系
●流程部署布置:查询流程定义的信息
在test01中添加如下代码并运行
/**
* 查询流程定义的信息
* */
@Test
public void testDeployQuery(){
// 获取ProcessEngine对象
ProcessEngine processEngine = configuration.buildProcessEngine();
// 获取RepositoryService资源管理服务
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
// deploymentId要查找现有的id(可以去数据库中查看deployment中查看),否则会报空指针异常
.deploymentId("2501")
.singleResult();
System.out.println("processDefinition.getDeploymentId():" + processDefinition.getDeploymentId());
System.out.println("processDefinition.getName():" + processDefinition.getName());
System.out.println("processDefinition.getDescription():" + processDefinition.getDescription());
System.out.println("processDefinition.getId():" + processDefinition.getId());
}
运行结果如下
若查询不存在的id
●流程部署布置:删除流程定义
在test01中添加如下代码并运行
/**
* 删除流程定义
* */
@Test
public void testDeleteDeploy(){
// 获取ProcessEngine对象
ProcessEngine processEngine = configuration.buildProcessEngine();
// 获取RepositoryService资源管理服务
RepositoryService repositoryService = processEngine.getRepositoryService();
// 删除部署的流程(第一个参数是id,如果部署的流程启动了就不允许删除了;第二是参数是级联删除,若为true,则若流程启动了,相关的任务会一并被删除)
repositoryService.deleteDeployment("1", false);
}
运行后,查看日志信息可以得知数据库数据已被删除
四、启动流程实例(官方文档的例子)
在test01中继续添加代码
/**
* 启动流程实例
* */
@Test
public void testRunProcess(){
ProcessEngine processEngine = configuration.buildProcessEngine();
// 我们需要通过RuntimeService来启动流程实例
RuntimeService runtimeService = processEngine.getRuntimeService();
//构建流程变量
Map<String, Object> variables = new HashMap<>();
variables.put("employee", "张三");
variables.put("nrOfHolidays", "3");
variables.put("description", "工作累了,出去玩玩");
// 启动流程实例
ProcessInstance holidayRequest = runtimeService.startProcessInstanceByKey("holidayRequest", variables);
System.out.println("holidayRequest.getProcessDefinitionId():" + holidayRequest.getProcessDefinitionId());
System.out.println("holidayRequest.getActivityId():" + holidayRequest.getActivityId()); // 当前活跃
System.out.println("holidayRequest.getId():" + holidayRequest.getId());
}
运行结果如下图所示(第二个参数:当前活跃的为0)
●查询任务(查询自己需要审批的业务)
上面一步中员工发起了一个请假流程,接下里就会流转到经理这里来,我们现在指定这个经理为处理人
然后我们先删除掉之前的,即用“删除流程定义”方法把表act_ge_bytearray里面的数据都删除掉
删除完之后再执行一遍"部署流程"方法
然后运行"启动流程实例"方法
最后我们来添加一个查询任务方法,指定查询manager需要审批的任务
/**
* 查询任务
* */
@Test
public void testQueryTask(){
ProcessEngine processEngine = configuration.buildProcessEngine();
TaskService taskService = processEngine.getTaskService();
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey("holidayRequest") // 指定查询的流程编程
.taskAssignee("manager") // 查询这个任务的处理人
.list();
for (Task task: list) {
System.out.println("task.getProcessDefinitionId():" + task.getProcessDefinitionId());
System.out.println("task.getName():" + task.getName());
System.out.println("task.getAssignee():" + task.getAssignee());
System.out.println("task.getDescription():" + task.getDescription());
System.out.println("task.getId():" + task.getId());
}
}
●执行任务(拒绝)
根据sendRejectionMail中的flowable:class创建类
写入拒绝流程
public class SendRejectionMail implements JavaDelegate {
/**
* 这是一个flowable的触发器
* */
@Override
public void execute(DelegateExecution execution) {
// 触发执行的逻辑,按照我们在流程中的定义应该给被拒绝的员工发送通知的邮件
// 这里面可以通过邮件发送之类的,这里做模拟就只是写一个sout
System.out.println("请假申请不通过,请安心工作");
}
}
回到test01中书写"执行任务"方法
/**
* 执行任务
* */
@Test
public void testCompleteTask(){
ProcessEngine processEngine = configuration.buildProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery()
.processDefinitionKey("holidayRequest")
.taskAssignee("manager") //指定是经理
.singleResult();
// holiday-request.bpmn20.xml中${!approved}表示走拒绝策略,我们这里传一个${!approved}
Map<String, Object> map = new HashMap<>();
map.put("approved", false);
// 完成任务
taskService.complete(task.getId(), map);
}
运行发现已经出现拒绝提示
回到数据库中查看,发现只剩历史记录有数据了,因为已经执行完一个流程了
●历史任务查询
/**
* 获取流程任务的历史数据
* */
@Test
public void testHistory(){
ProcessEngine processEngine = configuration.buildProcessEngine();
HistoryService historyService = processEngine.getHistoryService();
List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
.processDefinitionId("holidayRequest:1:17503") // 从act_hi_actinst中获取
.finished() // 查询的历史记录的状态是已完成
.orderByHistoricActivityInstanceEndTime().asc() //指定排序的字段和顺序
.list();
for (HistoricActivityInstance history: list) {
System.out.println(history.getActivityName() + ":" + history.getAssignee() + "--" + history.getActivityId() + ":" + history.getDurationInMillis() + "毫秒");
}
}
运行代码,结果如下
到此一个完整流程结束
完整的Test01如下:
package com.ghost.flowable.test;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.impl.HistoricActivityInstanceQueryImpl;
import org.flowable.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.junit.Before;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* flowable测试01
*
* @author ghost
* @date 2022-09-06
*/
public class Test01 {
/*获取流程引擎对象*/
@Test
public void testProcessEngine(){
// 获取ProcessEngineConfiguration对象
ProcessEngineConfiguration configuration = new StandaloneInMemProcessEngineConfiguration();
// 配置相关数据库连接信息(做演示就不封装了)
configuration.setJdbcDriver("com.mysql.cj.jdbc.Driver");
configuration.setJdbcUsername("root");
configuration.setJdbcPassword("root");
configuration.setJdbcUrl("jdbc:mysql://localhost:3306/flowable_learn?serverTimezone=UTC");
// 如果数据库中的表结构不存在就新建
configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
// 通过ProcessEngineConfiguration构建我们需要的processEngine对象
ProcessEngine processEngine = configuration.buildProcessEngine();
System.out.println("processEngine" + processEngine);
}
ProcessEngineConfiguration configuration = null;
@Before
public void before(){
/*配置数据库设置*/
configuration = new StandaloneInMemProcessEngineConfiguration();
configuration.setJdbcDriver("com.mysql.cj.jdbc.Driver");
configuration.setJdbcUsername("root");
configuration.setJdbcPassword("root");
configuration.setJdbcUrl("jdbc:mysql://localhost:3306/flowable_learn?serverTimezone=UTC");
// 如果数据库中的表结构不存在就新建
configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
}
/**
* 部署流程
* */
@Test
public void testDeploy(){
// 1.获取ProcessEngine对象
ProcessEngine processEngine = configuration.buildProcessEngine();
// 2.获取RepositoryService
RepositoryService 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());
}
/**
* 查询流程定义的信息
* */
@Test
public void testDeployQuery(){
// 获取ProcessEngine对象
ProcessEngine processEngine = configuration.buildProcessEngine();
// 获取RepositoryService资源管理服务
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
// deploymentId要查找现有的id(可以去数据库中查看deployment中查看),否则会报空指针异常
.deploymentId("15001")
.singleResult();
System.out.println("processDefinition.getDeploymentId():" + processDefinition.getDeploymentId());
System.out.println("processDefinition.getName():" + processDefinition.getName());
System.out.println("processDefinition.getDescription():" + processDefinition.getDescription());
System.out.println("processDefinition.getId():" + processDefinition.getId());
}
/**
* 删除流程定义
* */
@Test
public void testDeleteDeploy(){
// 获取ProcessEngine对象
ProcessEngine processEngine = configuration.buildProcessEngine();
// 获取RepositoryService资源管理服务
RepositoryService repositoryService = processEngine.getRepositoryService();
// 删除部署的流程(第一个参数是id,如果部署的流程启动了就不允许删除了;第二是参数是级联删除,若为true,则若流程启动了,相关的任务会一并被删除)
repositoryService.deleteDeployment("5001", true);
}
/**
* 启动流程实例
* */
@Test
public void testRunProcess(){
ProcessEngine processEngine = configuration.buildProcessEngine();
// 我们需要通过RuntimeService来启动流程实例
RuntimeService runtimeService = processEngine.getRuntimeService();
//构建流程变量
Map<String, Object> variables = new HashMap<>();
variables.put("employee", "张三");
variables.put("nrOfHolidays", "3");
variables.put("description", "工作累了,出去玩玩");
// 启动流程实例
ProcessInstance holidayRequest = runtimeService.startProcessInstanceByKey("holidayRequest", variables);
System.out.println("holidayRequest.getProcessDefinitionId():" + holidayRequest.getProcessDefinitionId());
System.out.println("holidayRequest.getActivityId():" + holidayRequest.getActivityId()); // 当前活跃
System.out.println("holidayRequest.getId():" + holidayRequest.getId());
}
/**
* 查询任务
* */
@Test
public void testQueryTask(){
ProcessEngine processEngine = configuration.buildProcessEngine();
TaskService taskService = processEngine.getTaskService();
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey("holidayRequest") // 指定查询的流程编程
.taskAssignee("manager") // 查询这个任务的处理人
.list();
for (Task task: list) {
System.out.println("task.getProcessDefinitionId():" + task.getProcessDefinitionId());
System.out.println("task.getName():" + task.getName());
System.out.println("task.getAssignee():" + task.getAssignee());
System.out.println("task.getDescription():" + task.getDescription());
System.out.println("task.getId():" + task.getId());
}
}
/**
* 执行任务
* */
@Test
public void testCompleteTask(){
ProcessEngine processEngine = configuration.buildProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery()
.processDefinitionKey("holidayRequest")
.taskAssignee("manager") //指定是经理
.singleResult();
// holiday-request.bpmn20.xml中${!approved}表示走拒绝策略,我们这里传一个${!approved}
Map<String, Object> map = new HashMap<>();
map.put("approved", false);
// 完成任务
taskService.complete(task.getId(), map);
}
/**
* 获取流程任务的历史数据
* */
@Test
public void testHistory(){
ProcessEngine processEngine = configuration.buildProcessEngine();
HistoryService historyService = processEngine.getHistoryService();
List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
.processDefinitionId("holidayRequest:1:17503") // 从act_hi_actinst中获取
.finished() // 查询的历史记录的状态是已完成
.orderByHistoricActivityInstanceEndTime().asc() //指定排序的字段和顺序
.list();
for (HistoricActivityInstance history: list) {
System.out.println(history.getActivityName() + ":" + history.getAssignee() + "--" + history.getActivityId() + ":" + history.getDurationInMillis() + "毫秒");
}
}
}
五、Flowable UI应用
1、安装
查看官网,可以看到有各种工具安装地址
由于官网的Flowable 6显示30天试用,就从百度找了flowable-6.7.2:https://blog.csdn.net/newposte/article/details/124329777,解压完如下
下载一个tomcat,我们把flowable-6.7.2里面的两个war包丢到tomcat的webapps里面去
我们找到startup.bat,运行它
然后发现有乱码
这时我们需要修改一下配置文件
java.util.logging.ConsoleHandler.encoding = GBK
再次启动startup.bat,发现乱码问题解决了
回到tomcat的webapp中查看,发现多出两个flowable文件
到这里我们就可以运行了,输入网址http://localhost:8080/flowable-ui
初始密码为 admin test,我们登录进去查看
这里就对应简介里面的几种应用
2、任务应用程序
●创建流程
●部署流程
点击右上角的一键导出按钮
然后文件就会被下载下来
然后我们复制这个文件到idea里,可以看到代码已经生成好了
●代码
然后我们根据这个xml再书写一次代码,我们把Test01的代码全部复制,修改名称为TestMyHolidayUI
修改如下地方
然后我们运行部署流程方法,发现报错找不到我们新加进来的xml,我们删掉target再运行部署流程方法,让他生成新的target
如上图,在成功运行的同时就说明新的target生成好了,然后我们到数据库中查看
我们发现task表里面还没有东西,我们来运行testRunProcess方法,记得修改如下地方为procdef表中的数据且修改方法为ById
回到表中发现有数据了
3、建模器应用程序
4、管理员应用程序
5、身份管理应用程序
还可以添加、设置分组