延春的技术站 延春的技术站
首页
  • 前端文章

    • JavaScript
  • 页面

    • HTML
    • CSS
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • java
  • python
  • android
  • ois
  • 数据库
  • 中间件安装
  • Docker
  • Linux
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档

会痛的石头

IT界小学生
首页
  • 前端文章

    • JavaScript
  • 页面

    • HTML
    • CSS
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • java
  • python
  • android
  • ois
  • 数据库
  • 中间件安装
  • Docker
  • Linux
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
  • java

    • 集合
    • flowalbe使用手册
      • 1.Flowable数据库表命名规则
        • 1.0.actprocdefinfo:流程定义储存表
        • 1.1 ACTRE*
        • 1.2 ACTRU*
        • 1.3 ACTID*
        • 1.4 ACTHI*
        • 1.5 ACTGE*
        • 1.6 actevtlog:事件日志表
      • 2.Flowable使用SLF4J作为内部日志框架
      • 3.核心类:
        • 3.1 RepositoryService 流程存储服务
        • 3.2 RuntimeService 流程运行控制服务
        • 3.3 HistoryService 流程系统历史服务
        • 3.4 TaskService 任务管理服务
        • 3.5 IdentityService 用户管理服务
        • 3.6 FormService 表单管理服务
        • 3.7 managementService 工作管理服务
      • 4.flowable的使用
        • 4.0 学习示例
        • 4.1 部署流程定义(BPMN文件),获取流程定义文件对象
        • 4.2 挂起与恢复流程定义,挂起后发起流程实例就会抛出异常
        • 4.3 启动流程实例,并获取流程实例对象
        • 4.4 对流程实例的操作
        • 4.5 任务服务的操作
      • 5.flowable使用时的数据库变化
        • 5.1 流程模型
        • 5.2 部署
        • 5.3 发起申请,启动流程
        • 5.4 审批人甲批准
        • 5.5 审批人乙批准(流程结束)
  • 后端
  • java
quyanchun
2022-01-13

flowalbe使用手册

# 1.Flowable数据库表命名规则

# 1.0.act_procdef_info:流程定义储存表

流程定义更新信息,包含流程定义ID,版本号,内容等

# 1.1 ACT_RE_*

’RE’表示repository(存储)。RepositoryService接口操作的表。带此前缀的表包含的是静态信息,如,流程定义,流程的资源(图片,规则等)

# 1.1.1 act_re_deployment:部署信息表核心表

部署流程定义时需要被持久化保存下来的信息

# 1.1.2 act_re_model:流程设计模型部署表

流程设计器设计流程模型保存的数据,包含:创建时间,最后更新时间,元数据(META_INFO_:以json格式保存流程定义的信息),部署ID(DEPLOYMENT_ID_)

# 1.1.3 act_re_procdef:流程定义数据表核心表

1.1.3.1 提示
此表和ACT_RE_DEPLOYMENT是多对一的关系,即,一个部署的bar包里可能包含多个流程定义文件,每个流程定义文件都会有一条记录在ACT_REPROCDEF表内,每个流程定义的数据,都会对于ACT_GE_BYTEARRAY表内的一个资源文件和PNG图片文件。
1.1.3.2 和ACT_GE_BYTEARRAY的关联:
是通过程序用ACT_GE_BYTEARRAY.NAME与ACT_RE_PROCDEF.NAME_完成的,在数据库表结构中没有体现
1.1.3.3 包含
分类(CATEGORY_:流程定义的Namespace就是类别),部署ID(DEPLOYMENT_ID_),资源名称(RESOURCE_NAME_:流程bpmn文件名称),拥有开始表单标识(HAS_START_FORM_KEY_:start节点是否存在 formKey 0否 1是),挂起状态(SUSPENSION_STATE_:暂停状态 1激活 2暂停)

# 1.2 ACT_RU_*

’RU’表示runtime。这是运行时的表存储着流程变量,用户任务,变量,职责(job)等运行时的数据。
flowable只存储实例执行期间的运行时数据,当流程实例结束时,将删除这些记录。这就保证了这些运行时的表小且快。

# 1.2.1 act_ru_event_subscr:事件订阅

包含:流程定义ID,流程实例ID,执行实例ID,节点ID,创建时间等

# 1.2.2 act_ru_execution:运行时流程执行实例表核心表

包含:流程实例ID,流程定义ID,父级ID,父级的执行实例ID,节点ID,挂起状态(SUSPENSION_STATE_:1激活 2暂停),缓存状态(CACHED_ENT_STATE_:缓存的状态, 1 事件监听 2 人工任务 3 异步作业)

# 1.2.3 act_ru_identitylink:运行时流程人员表

主要存储当前节点参与者的信息,包含:用户组ID,用户ID,任务ID,流程实例ID,流程定义ID

# 1.2.4 act_ru_job:运行时定时任务数据表

# 1.2.4.1 包含:

锁定过期时间(LOCK_EXP_TIME_),挂起者(LOCK_OWNER_),是否唯一(EXCLUSIVE_),执行实例ID,流程实例ID,流程定义ID,重试次数(RETRIES_),截至时间(DUEDATE_)<br>

# 1.2.4.2 需要启用JOB组件

JobExecutor 是管理一组线程的组件,这些线程用于触发定时器(包括后续的异步消息)。在单元测试场景下,使用多线程会很笨重。<br>
ManagementService.createJobQuery 用于查询,<br>
ManagementService.executeJob 用于执行作业。<br>
这样作业的执行就可以在单元测试内部控制。为了避免作业执行器的干扰,可以将它关闭。<br>
默认情况下, JobExecutor 在流程引擎启动时激活。<br>
当你不希望 JobExecutor 随流程引擎启动时,设置:<br>
<property name="jobExecutorActivate" value="false" />
1

# 1.2.4.3 启用异步执行器 Async executor activation

AsyncExecutor 是管理线程池的组件,这个线程池用于触发定时器与异步任务。<br>
默认情况下,由于历史原因,当使用 JobExecutor 时, AsyncExecutor 不生效。然而我们建议使用新的 AsyncExecutor 代替JobExecutor ,通过定义两个参数实现
<property name="asyncExecutorEnabled" value="true" /><property name="asyncExecutorActivate" value="true" />
1

参数 asyncExecutorEnabled 用于启用异步执行器,代替老的作业执行器。
参数 asyncExecutorActivate 命令Activiti引擎在启动时启动异步执行器线程池。

# 1.2.5 act_ru_task:运行时任务节点表核心表

包含: 主键(任务ID),执行实例ID,流程实例ID,流程定义ID,父任务ID,被代理人(OWNER_:一般情况下为空,只有在委托时才有值),经办人(GNEE_:签收人或者委托人),委托状态(DELEGATION_:委托状态 PENDING委托中,RESOLVED已处理),优先级(PRIORITY_),创建时间,截至时间,挂起状态(SUSPENSION_STATE_:暂停状态 1激活 2暂停)_

# 1.2.6 act_ru_variable:运行时流程变量数据表*核心表

类型:jpa-entity、boolean、bytes、serializable、自定义type、CustomVariableType、date、double、integer、long、null、short、string<br>
包含:执行实例ID,流程实例ID,任务ID,资源ID(BYTEARRAY_ID_)<br>

# 1.3 ACT_ID_*

’ID’表示identity(组织机构)。这些表包含标识的信息,如用户,用户组,等等。

# 1.3.1 act_id_group:用户组表

自带的用户组表,用于组任务,包含:名称,类型,版本号<br>

# 1.3.2 act_id_info:用户扩展信息表

包含:用户ID,类型,key,value,密码,父级ID<br>

# 1.3.3 act_id_membership:用户与分组对应信息表

用来保存用户的分组信息,包含:用户ID,用户组ID<br>

# 1.3.4 act_id_user:用户信息表

包含:姓,名,邮箱,密码,版本号,头像ID<br>

# 1.4 ACT_HI_*

’HI’表示history。就是这些表包含着历史的相关数据,如结束的流程实例,变量,任务,等等。
####1.4.1 act_hi_actinst:历史活动信息
记录流程流转过的所有节点,包括流程定义ID,流程实例ID,执行节点的ID/名称,执行的指向箭头,办理人ID,开始时间,结束时间,删除原因等

# 1.4.2 act_hi_attachment:历史附件表

存放历史流程相关的附件的地址

# 1.4.3 act_hi_comment:历史审批意见表

存放历史流程的审批意见<br>

# 1.4.4 act_hi_detail:历史详情信息表

流程中产生的变量详细,包括控制流程流转的变量,业务表单中填写的流程需要用到的变量等<br>

# 1.4.5 act_hi_identitylink:历史流程人员表,

主要存储当前节点参与者的信息,比如参与者ID,参与的流程实例ID,任务ID,参与者扮演的角色类型{assignee(办理者)、candidate(候补者)、owner(委托的办理者)、starter(发起者) 、participant(参与者)}<br>

# 1.4.6 act_hi_procinst:流程实例历史核心表

存放历史的流程实例,包含流程实例ID,流程定义ID,开启人ID,开始节点ID,结束节点ID,父级流程实例ID,删除原因<br>

# 1.4.7 act_hi_taskinst:历史任务流程实例信息核心表

存放已经办理的任务,包含有任务ID,流程实例ID,流程定义ID,任务节点key和名字,办理人ID,最后修改时间<br>

# 1.4.8 act_hi_varinst:历史变量表

存放历史变量数据<br>

# 1.5 ACT_GE_*

普通数据,各种情况都使用的数据。

# 1.5.1 act_ge_bytearray:资源表

保存部署文件的大文本数据,文件位置,流程定义部署ID(deployment_id),是一个二进制文件数据,(存储流程定义相关的资源)–ByteArrayEntityImpl<br>

# 1.5.2 act_ge_property:属性表

全局配置文件,(保存流程引擎的kv键值属性)–PropertyEntityImpl<br>

# 1.6 act_evt_log:事件日志表

事件日志,默认不开启,如果不使用事件记录,可以删除这个表,

# 1.6.1 作用:

来源于引擎的事件会被捕获,并创建一个包含了所有事件数据(甚至更多)的映射,提供给org.activiti.engine.impl.event.logger.EventFlusher,由它将这些数据刷入其他地方;默认情况下,使用简单的基于数据库的事件处理/刷入,会使用Jackson将上述映射序列化为JSON,并将其作为EventLogEntryEntity接口存入数据库。

// 1.6.2 配置启用事件日志
processEngineConfiguration.setEnableDatabaseEventLogging(true);
// 1.6.3 运行时启用事件日志
databaseEventLogger = new EventLogger(processEngineConfiguration.getClock());
runtimeService.addEventListener(databaseEventLogger);

# 1.6.4 可以扩展EventLogger类。

如果默认的数据库记录不符合要求,需要覆盖createEventFlusher()方法返回一个org.activiti.engine.impl.event.logger.EventFlusher接口的实例。可以通过Activiti的managementService.getEventLogEntries(startLogNr, size)?获取EventLogEntryEntity实例。容易看出这个表中的数据可以通过JSON放入大数据NoSQL存储,例如MongoDB,Elastic Search,等等.也容易看出这里使用的类(org.activiti.engine.impl.event.logger.EventLogger/EventFlusher与许多其他 EventHandler类)是可插入的,可以按你的使用场景调整(例如不将JSON存入数据库,而是将其直接发送给一个队列或大数据存储)。请注意这个事件记录机制是额外于Activiti的“传统”历史管理器的。尽管所有数据都在数据库表中,但并未对查询或快速恢复做优化。实际使用场景是末端审计并将其存入大数据存储。

# 2.Flowable使用SLF4J作为内部日志框架

要看到关于引擎启动与创建数据库表结构的提示日志,在src/main/resources文件夹下添加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
1
2
3
4

# 3.核心类:

# 3.1 RepositoryService 流程存储服务

管理流程定义文件xml及静态资源的服务
对特定流程的暂停和激活
流程定义启动权限管理
类内部重要的成员有:
deploymentBuilder : 部署文件构造器,详见本文4.1
deploymentQuery : 部署文件查询器
ProcessDefinitionQuery : 流程定义文件查询对象
Deployment : 流程部署文件对象,详见本文4.1
ProcessDefinition : 流程定义文件对象,详见本文4.1
BpmnModel : 流程定义的java格式
学习博客:https://www.jianshu.com/p/96df1d449cc3

# 3.2 RuntimeService 流程运行控制服务

启动流程及对流程数据的控制
流程实例(ProcessInstance)与执行流(Execution)的查询,详见本文4.4
触发流程操作,接收消息和信号
启动流程及变量管理
启动流程的常用方法(id,key,message),详见本文4.3
启动流程可选参数(businessKey,variables,tenantId)
变量(variables)的设置和获取,详见本文4.4
学习博客:
https://blog.csdn.net/yijianqingyu/article/details/79746551
https://www.jianshu.com/p/4a9a52c62bcc

# 3.3 HistoryService 流程系统历史服务

管理流程实例结束后的历史数据
构建历史数据的查询对象
根据流程实例id删除流程历史数据
历史数据实体
HistoricProcessInstance 历史流程实例实体类(学习博客:https://blog.csdn.net/yijianqingyu/article/details/80311179 )
HistoricTaskInstance 用户任务实例的信息
HistoricActivityInstance 单个活动节点执行的信息
HistoricVariableInstance 流程或任务的变量值实体
HistoricDetail 历史流程活动任务详细信息
备注:历史数据实体与运行时的数据实体的API大同小异
学习博客:https://blog.csdn.net/mchgogo/article/details/79126404
构建历史查询对象
create{历史数据实体}Query();
createNative{历史数据实体}Query();
createProcessInstanceHistoryLogQuery(processInstanceId);
备注:各历史查询对象API大同小异
删除历史操作

historyService.deleteHistoricProcessInstance(processInstanceId);
historyService.deleteHistoricTaskInstance(processInstanceId);
1
2

学习博客:https://www.jianshu.com/p/0b6ecf500e9d

# 3.4 TaskService 任务管理服务

# 3.4.1 对用户任务UserTask的管理和流程的控制

Task对象的创建和删除
查询Task,驱动Task节点完成执行
Task相关参数变量variable设置

# 3.4.2 设置用户任务的权限信息(设置候选人等)

候选用户candidateUser和候选组candidateGroup
指定拥有人Owner和办理人Assignee
通过claim设置办理人(签收 )

# 3.4.3 针对用户任务添加任务附件,任务评论和事件记录

任务附件Attachment创建与查询
任务评论Comment创建与查询
事件记录Event创建与查询

# 3.4.5 学习博客

https://www.jianshu.com/p/dfad80be1dbf
https://blog.csdn.net/syq8023/article/details/89852339

# 3.5 IdentityService 用户管理服务

管理用户
管理用户组
用户与用户组的关系(MemberShip)
学习博客:https://www.jianshu.com/p/4150818b924e

# 3.6 FormService 表单管理服务

解析流程定义中表单项的配置
提交表单的方式驱动用户节点流转
获取自定义外部表单key
学习博客:https://www.jianshu.com/p/66e336554a06

# 3.7 managementService 工作管理服务

Job任务管理
数据库相关通用操作
执行流程引擎命令(Command)
学习博客:https://www.jianshu.com/p/a1c132f729b9

# 4.flowable的使用

# 4.0 学习示例

https://gitee.com/lwj/flowable.git flowable-base分支
https://www.cnblogs.com/liuwenjun/category/1296599.html
将本地jar包导入maven仓库:

PS E:\JVM\MavenRepository\com\dragon\tools>mvn install:install-file -D file=tools-1.0-SNAPSHOT.jar -D groupId=com.dragon -D artifactId=tools -D version=1.0-SNAPSHOT -D packaging=jar
1

# 4.1 部署流程定义(BPMN文件),获取流程定义文件对象

	// resouce:BPMN文件路径,inputStream:该文件的字节流
	DeploymentBuilder deploymentBuilder = repositoryService.createDeployment().addInputStream(resource, inputStream);
	// 根据参数设置流程部署构建器,parameter :部署参数,一个Map<String, Object>
	deploymentBuilder.category(parameter.get("flowType")).name(parameter.get("flowName")).key(parameter.get("flowKey")).tenantId(parameter.get("flowTenantId"));
	// 并获取流程定义部署对象 
	Deployment deployment = deploymentBuilder.deploy();
	String deploymentId = deployment.getId();
	ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
	// 流程定义ID
	String processDefinitionId = processDefinition.getId();
	// 流程定义Key
	String processDefinitionKey = processDefinition.getKey();

# 4.2 挂起与恢复流程定义,挂起后发起流程实例就会抛出异常

	// 挂起
	repositoryService.suspendProcessDefinitionById(processDefinitionId);
	repositoryService.suspendProcessDefinitionByKey(processDefinitionKey);
	// 恢复
	repositoryService.activateProcessDefinitionById(processDefinitionId);
	repositoryService.activateProcessDefinitionByKey(processDefinitionKey);

# 4.3 启动流程实例,并获取流程实例对象

	// variables:流程变量,Map<String, Object>类型
	ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId, variables);
	ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, variables);
	// 将流程实例与发起人绑定
	identityService.setAuthenticatedUserId(userId);

# 4.4 对流程实例的操作

# 4.4.1 processInstance

	// 流程实例ID
		String processInstanceId = processInstance.getId();
		// 判断流程是否结束
		processInstance.isEnded();
		// 判断流程是否挂起
		processInstance.isSuspended();
		// 获取流程的发起人ID
		String startUserId = processInstance.getStartUserId();

# 4.4.2 runtimeService

		// 该流程的执行对象查询
		List<Execution> executionList = runtimeService.createExecutionQuery().processInstanceId(processInstanceId).list();
		Execution execution = runtimeService.createExecutionQuery().processInstanceId(processInstanceId).singleResult();
		// 该流程实例下的所有活动实例
		List<Execution> executions = runtimeService.createExecutionQuery().parentId(processInstanceId).list();
		// 更改多个活动实例的状态节点为指定节点 activityId ,比如结束节点终止流程
		runtimeService.createChangeActivityStateBuilder().moveExecutionsToSingleActivityId(executionIds, activityId).changeState();
		// 挂起流程实例
		runtimeService.suspendProcessInstanceById(processInstanceId);
		// 恢复挂起的流程实例
		runtimeService.activateProcessInstanceById(processInstanceId);
		// 删除一个正在流转的流程 deleteReason:删除原因
		HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId);
		// 获取该流程实例下的任务数量
		long count = query.count();
		// 任务数量大于1,则流程已经启动了,不能撤回
		if (count > 1) {
			throw new FlowException(ResultEnum.EX_INSTANCE_BEGIN);
		}
		runtimeService.deleteProcessInstance(processInstanceId, deleteReason);
		// 获取流程实例的查询对象
		ProcessInstanceQuery instanceQuery = runtimeService.createProcessInstanceQuery();
		// 与某个用户相关的
		instanceQuery.involvedUser(userId);
		// 某个用户开启的
		instanceQuery.startedBy(userId);
		// 或者查询条件 .or().endOr() ==> (xx or  xx or ... ... or xx),等于包裹内容的两括号
		instanceQuery.or().endOr();
		// 挂起的流程
		instanceQuery.suspended();
		// 在某个时间点之后开始
		instanceQuery.startedAfter(Date date);
		// 在某个时间点之前开始
		instanceQuery.startedBefore(Date date);
		// 获取正在流转的一个指定的流程实例
		instanceQuery.processInstanceId(processInstanceId);
		// 单个的流程实例
		ProcessInstance processInstance = instanceQuery.singleResult();
		// 多个流程实例 begin : 从第几个开始 ; max : 展示多少个
		List<ProcessInstance> processInstances = instanceQuery.list();
		List<ProcessInstance> processInstances = instanceQuery.listPage(int begin,int max);
		// 流程实例的数量
		long count = taskQuery.count();

# 4.4.3 historyService

		// 获取历史流程实例查询对象
		HistoricProcessInstanceQuery historicProcessInstanceQuery = 	            historyService.createHistoricProcessInstanceQuery();
		// 已完成的
		historicProcessInstanceQuery.finished();
		// 未完成的
		historicProcessInstanceQuery.unfinished();
		// 删除的
		historicProcessInstanceQuery.deleted();
		// 没有删除的
		historicProcessInstanceQuery.notDeleted();
		// 在某个时间点之后结束
		historicProcessInstanceQuery.finishedAfter(Date date);
		// 在某个时间点之前结束
		historicProcessInstanceQuery.finishedBefore(Date date);
		// 指定父流程ID的流程实例
		historicProcessInstanceQuery.superProcessInstanceId(processInstanceId)
		// 历史流程实例
		HistoricProcessInstance processInstance = historicProcessInstanceQuery.processInstanceId(processInstanceId).singleResult();
		// 删除该流程的历史记录
		historyService.deleteHistoricProcessInstance(processInstanceId);

# 4.5 任务服务的操作

# 4.5.1 获取task任务对象

		// 任务基础查询对象
		TaskQuery taskQuery = taskService.createTaskQuery();
		// 某个任务
		taskQuery.taskId(taskId);
		// 某个经办人的任务
		taskQuery.taskAssignee(userId);
		// 某个委托人的任务
		taskQuery.taskOwner(userId);
		// 某个或多个流程实例的任务
		taskQuery.processInstanceId(String processInstanceId);
		taskQuery.processInstanceIdIn(List<String> processInstanceIds);
		// 某个或多个部署实例的任务
		taskQuery.deploymentId(String deploymentId);
		taskQuery.deploymentIdIn(List<String> deploymentIds);
		// 某个活动实例的任务
		taskQuery.executionId(String executionId);
		// 按照任务创建时间倒序
		taskQuery.orderByTaskCreateTime().desc();
		// 存活的任务
		taskQuery.active();
		// 挂起的任务
		taskQuery.suspended();
		// 没有 删除原因 的任务
		taskQuery.taskWithoutDeleteReason();
		// 没有签收的任务
		taskQuery.taskUnassigned();
		// 单个的任务对象
		Task task = taskQuery.singleResult();
		// 多个任务对象 begin : 从第几个开始 ; max : 展示多少个
		List<Task> tasks = taskQuery.list();
		List<Task> tasks = taskQuery.listPage(int begin,int max);
		// 任务的数量
		long count = taskQuery.count();

# 4.5.2 变量的设值与取值

		// 任务ID
		String taskId = task.getId();
		// 设置全局变量
		taskService.setVariable(taskId,"key1","value1");
		// 设置局部变量
		taskService.setVariableLocal(taskId,"key2","value2");
		// 获取全局变量
		Map<String,Object> a = taskService.getVariables(taskId);
		// 获取局部变量
		Map<String,Object> b = taskService.getVariablesLocal(taskId);
		// 流程启动后获取变量(全局变量)
		Map<String,Object> variables = runtimeService.getVariables(processInstanceId);
		// 设置变量(全局变量)
		runtimeService.setVariable(processInstanceId,"key","value");

# 4.5.3 任务的流转

		// 任务的执行(委托人)
		taskService.resolveTask(taskId);
		taskService.complete(taskId);
		// 任务的执行(经办人) variables : 下次任务所需要的参数 localScope : 变量的存储范围(true:作用范围为当前任务,false:表示这个变量是全局的)
		// 博客:https://blog.csdn.net/u013026207/article/details/53405265
		taskService.complete(taskId);
		taskService.complete(String taskId, Map<String, Object> variables);
		taskService.complete(String taskId, Map<String, Object> variables, boolean localScope);
		// 添加和删除候选人
		taskService.addCandidateUser(taskId, userId);
		taskService.deleteCandidateUser(taskId, userId);
		// 签收
		taskService.claim(taskId, userId);
		// 委派
		taskService.delegateTask(taskId, acceptUserId);
		// 转发
		taskService.setAssignee(taskId, acceptUserId);
		// 驳回 currTaskKeys : 该任务的节点 ; activityId : 上一个节点ID
		List<String> currTaskKeys = new ArrayList<>();
		List<Task> tasks = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
		for (Task task : tasks) {
				currTaskKeys.add(task.getTaskDefinitionKey());
		}
		runtimeService.createChangeActivityStateBuilder()
					.processInstanceId(processInstanceId)
					.moveActivityIdsToSingleActivityId(currTaskKeys, activityId)
					.changeState();
		// 删除任务
		taskService.deleteTask(taskId, deleteReason);
		taskService.deleteTasks(List<String> taskIds, deleteReason);

# 4.5.4 根据流程实例ID获取流程图(流程图在服务器上的访问地址)

		// 1.获取流程实例
		ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult();
		// 2.根据流程实例ID获取该实例所有的历史轨迹对象
		List<HistoricActivityInstance> historyProcess = historyService.createHistoricActivityInstanceQuery().processInstanceId(instanceId).finished().list();
		// 所有的历史轨迹对象
		Map<String, HistoricActivityInstance> hisActivityMap = new HashMap<>(16);
		historyProcess.forEach(historicActivityInstance -> {
			if (!hisActivityMap.containsKey(historicActivityInstance.getActivityId())) {
				hisActivityMap.put(historicActivityInstance.getActivityId(), historicActivityInstance);
			}
		});
		// 流程定义ID
		String processDefinitionId;
		// 节点ID的集合
		List<String> activityIds = new ArrayList<>();
		// 3.获取高亮显示的节点ID和流程定义ID
		if (pi == null) {
			// 如果流程已经走完了,则从历史记录查询 historyService
			HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(instanceId).singleResult();
			processDefinitionId = historicProcessInstance.getProcessDefinitionId();
			// 获取该流程的结束节点高亮显示
			String endActivityId = historicProcessInstance.getEndActivityId();
			activityIds.add(endActivityId);
		} else {
			// 如果流程没有走完,则从运行记录查询 runtimeService
			processDefinitionId = pi.getProcessDefinitionId();
			activityIds = runtimeService.getActiveActivityIds(instanceId);
		}
		// 4.获取流程图
		BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
		// 5.获取流程定义的所有节点信息
		Map<String, FlowElement> activityMap = new HashMap<>(16);
		List<Process> processes = bpmnModel.getProcesses();
		for (Process process : processes) {
			Collection<FlowElement> flowElements = process.getFlowElements();
			for (FlowElement flowElement : flowElements) {
				if (flowElement != null) {
					String flowElementId = flowElement.getId();
					activityMap.put(flowElementId, flowElement);
				}
			}
		}
		// 6.获取高亮显示的连线集合
		List<String> flows = new ArrayList<>();
		// 递归获取高亮连线
		for (String activityId : activityIds) {
			this.getHighLightedFlows(activityMap, hisActivityMap, activityId, flows, activityId);				
			 // 递归方法
			 private void getHighLightedFlows(Map<String, FlowElement> flowNodeMap,Map<String, HistoricActivityInstance> hisActivityMap,String activeActivityId,List<String> highLightedFlows,String oldActivityId) {
				 // 获取有效节点的节点信息
				 FlowElement flowElement = flowNodeMap.get(activeActivityId);
				 FlowNode flowNode = (FlowNode) flowElement;
				// 获取连线信息集合
				List<SequenceFlow> incomingFlows = flowNode.getIncomingFlows();
				for (SequenceFlow sequenceFlow : incomingFlows) {
				// 获取连线ID
				String sourceRefId = sequenceFlow.getSourceRef();
				if (hisActivityMap.containsKey(sourceRefId) && !oldActivityId.equals(sourceRefId)) {
					highLightedFlows.add(sequenceFlow.getId());
					this.getHighLightedFlows(flowNodeMap, hisActivityMap, sourceRefId, highLightedFlows, oldActivityId);
				} else {
					if (hisActivityMap.containsKey(sourceRefId)) {
						highLightedFlows.add(sequenceFlow.getId());
					} 														
				    break;
				  }
				}
			}

		}
		// 获取流程引擎配置
		ProcessEngineConfiguration engConf = processEngine.getProcessEngineConfiguration();
		// 定义流程画布生成器
		ProcessDiagramGenerator processDiagramGenerator = engConf.getProcessDiagramGenerator();
		// 获取流程图字节流
		InputStream in = processDiagramGenerator.generateDiagram(bpmnModel, FlowableConstants.PNG, activityIds, flows, engConf.getActivityFontName(), engConf.getLabelFontName(), engConf.getAnnotationFontName(), engConf.getClassLoader(), 1.0, true);
		// 流程图文件名
		String fileName = instanceId.replace("-", "");
		// 将流程图保存到本地,并返回流程图在服务器上的访问地址
		try {
			// ***该方法为本文4.5.6的方法***,应单独封装为一个工具类中的方法
			return FileUtil.writeFile(in, filePath, fileName, FlowableConstants.PNG);
		} catch (IOException e) {
			return null;
		}

# 4.5.5 根据流程定义ID获取流程图(流程图在服务器的访问路径)

		// 获取流程图
		BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
		// 获取流程引擎配置
		ProcessEngineConfiguration engConf = processEngine.getProcessEngineConfiguration();
		// 定义流程画布生成器
		ProcessDiagramGenerator processDiagramGenerator = engConf.getProcessDiagramGenerator();
		InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel,FlowableConstants.PNG,engConf.getActivityFontName(),engConf.getLabelFontName(),engConf.getAnnotationFontName(),engConf.getClassLoader(),1.0,true);
		// 流程图文件名
		String fileName = bpmnModel.getTargetNamespace();
		if (fileName == null || "".equals(fileName)) {
			fileName = processDefinitionId.substring(0, processDefinitionId.indexOf(":")).replace("-", "");
		}
		// 将流程图保存到本地
		try {
			// ***该方法为本文4.5.6的方法***,应单独封装为一个工具类中的方法
			return FileUtil.writeFile(inputStream, filePath, fileName, FlowableConstants.PNG);
		} catch (IOException e) {
			return null;
		}

# 4.5.6 保存文件到服务器,并返回保存文件在服务器的路径

/**
	* 保存文件并返回保存文件的路径
	*
	* @param inputStream 数据流
	* @param path        保存路径
	* @param fileName    文件名
	* @param fileType    文件类型
	* @return
	*/
	public static String writeFile(InputStream inputStream, String path, String fileName, String fileType) throws IOException {
		OutputStream out = null;
		// 按照文件类型分目录存放
		String folderPath = path + "/" + fileType + "/";
		File file = new File(folderPath);
		// 判断目录是否存在
		if (!file.exists()) {
			file.mkdirs();
		}
		// 完整文件名
		String fileNames = fileName + "." + fileType;
		// 文件存放路径
		String filePath = folderPath + fileNames;
		File image = new File(filePath);
		image.createNewFile();
		byte[] bytes = new byte[1024];
		int length = 0;
		try {
			out = new FileOutputStream(image);
			while ((length = inputStream.read(bytes)) != -1) {
				out.write(bytes, 0, length);
			}
			return fileType + "/" + fileNames;
		} finally {
			if (inputStream != null) {
				inputStream.close();
			}
			if (out != null) {
				out.close();
			}
		}
	}

# 5.flowable使用时的数据库变化

# 5.1 流程模型

开始节点 ----> 审批人甲 ----> 审批人乙 ----> 结束节点

# 5.2 部署

act_re_deployment:会有一条部署记录,记录这次部署的基本信息
act_ge_bytearray:有两条记录,记录的是本次上传的bpmn文件和对应的图片文件,每条记录都有act_re_deployment表的外键关联
act_re_procdef:有一条记录,记录的是该bpmn文件包含的基本信息,包含act_re_deployment表外键

# 5.3 发起申请,启动流程

act_ru_execution:插入一条记录,记录这个流程定义的执行实例,其中id和proc_inst_id相同都是流程执行实例id,也就是本次执行这个流程定义的id,包含流程定义的id外键
act_ru_task:插入一条记录,记录的是第一个任务的信息,也就是开始执行第一个任务。包括act_ru_execution表中的execution_id外键和proc_inst_id外键,也就是本次执行实例id
act_hi_procinst:插入一条记录,记录的是本次执行实例的历史记录
act_hi_taskinst:插入一条记录,记录的是本次任务的历史记录

# 5.4 审批人甲批准

act_ru_variable:插入变量信息,包含本次流程执行实例的两个id外键,但不包括任务的id,因为setVariable方法设置的是全局变量,也就是整个流程都会有效的变量
act_ru_task:表中审批人甲的记录被删除,新插入审批人乙的任务记录
act_ru_execution:活动记录并没有删除,而是将正在执行的任务变成审批人乙
act_hi_var_inst:插入流程实例的历史记录
act_hi_taskinst:插入任务的历史记录

# 5.5 审批人乙批准(流程结束)

act_ru_task:该流程实例任务实例记录全被清空
act_ru_execution:该流程实例活动实例记录全被清空
act_ru_variable:该流程实例的参数记录全被清空
act_hi_actinst:记录该流程实例所有历史活动信息 start+甲+乙+end

#flowable
上次更新: 2022/01/13, 16:11:59
集合

← 集合

最近更新
01
Centos7安装caddy 、xui
02-21
02
docker安装samba
09-04
03
docker安装openvpn
07-17
更多文章>
Theme by Vdoing | Copyright © 2021-2025 京ICP备2021033341号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式