activiti6超详细教程
1.activiti6表说明
ACT_RE_ *:RE代表repository。具有此前缀的表包含静态信息,例如流程定义和流程资源(图像,规则等)。
ACT_RU_ *:RU代表runtime。这些是运行时表,其中包含流程实例,用户任务,变量,作业等的运行时数据。Activiti仅在流程实例执行期间存储运行时数据,并在流程实例结束时删除记录。这样可以使运行时表较小而又快速。
ACT_ID_ *:ID代表identity。这些表包含身份信息,例如用户,组等。
ACT_HI_ *:HI代表history。这些表包含历史数据,例如过去的流程实例,变量,任务等。
ACT_GE_ *:general数据,用于各种用例中。
2.获取流程引擎
Activiti流程引擎通过名为的XML文件进行配置activiti.cfg.xml。请注意,如果您使用的是Spring风格的流程引擎构建,则此方法不适用。
获得的最简单方法ProcessEngine是使用org.activiti.engine.ProcessEngines类:
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine()
3.创建数据库
为数据库创建数据库表的最简单方法是:
将激活引擎jar添加到您的类路径中
添加合适的数据库驱动程序
将Activiti配置文件(activiti.cfg.xml)添加到您的类路径中,指向您的数据库(请参阅数据库配置部分)
执行DbSchemaCreate类的main方法
但是,通常只有数据库管理员才能在数据库上执行DDL语句。在生产系统上,这也是最明智的选择。可以在Activiti下载页面或database子目录中的Activiti分发文件夹内找到SQL DDL语句。脚本也位于引擎jar(activiti-engine-x.jar)的org / activiti / db / create包中(drop文件夹包含drop语句)。SQL文件的格式为
activiti。{db}。{create | drop}。{type} .sql
4.Process Engine API和服务
引擎API是与Activiti交互的最常见方式。中心起点是ProcessEngine
,可以按照配置部分中所述的多种方式创建 。从ProcessEngine,您可以获取包含工作流/ BPM方法的各种服务。ProcessEngine和服务对象是线程安全的。因此,您可以为整个服务器保留对其中之一的引用。
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//运行时service
RuntimeService runtimeService = processEngine.getRuntimeService();
//资源service
RepositoryService repositoryService = processEngine.getRepositoryService();
//任务service
TaskService taskService = processEngine.getTaskService();
ManagementService managementService = processEngine.getManagementService();
IdentityService identityService = processEngine.getIdentityService();
//历史service
HistoryService historyService = processEngine.getHistoryService();
FormService formService = processEngine.getFormService();
DynamicBpmnService dynamicBpmnService = processEngine.getDynamicBpmnService();
ProcessEngines.getDefaultProcessEngine()
会在首次调用时初始化并构建一个流程引擎,此后始终返回相同的流程引擎。可以使用ProcessEngines.init()
和正确创建和关闭所有流程引擎ProcessEngines.destroy()
。
ProcessEngines类将扫描所有activiti.cfg.xml
和activiti-context.xml
文件。对于所有activiti.cfg.xml
文件,将以典型的Activiti方式构建流程引擎:ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(inputStream).buildProcessEngine()
。对于所有activiti-context.xml
文件,将以Spring方式构建流程引擎:首先创建Spring应用程序上下文,然后从该应用程序上下文中获取流程引擎。
所有服务都是无状态的。这意味着您可以轻松地在群集中的多个节点上运行Activiti,每个节点都访问同一数据库,而不必担心哪台计算机实际执行了先前的调用。无论在何处执行,对任何服务的任何调用都是幂等的。
当使用Activiti引擎时,RepositoryService可能是第一个需要的服务。这项服务提供运营管理和操纵deployments
和process definitions
。此处无需赘述,流程定义是BPMN 2.0流程的Java对应项。它代表了流程中每个步骤的结构和行为。A deployment
是Activiti引擎中包装的单位。一个部署可以包含多个BPMN 2.0 xml文件和任何其他资源。一个部署中包含的内容的选择取决于开发人员。它的范围从单个流程BPMN 2.0 xml文件到整个流程包和相关资源(例如,部署hr-processes)可能包含与hr进程相关的所有内容)。在RepositoryService
允许deploy
这样的包。部署部署意味着将其上载到引擎,在这里将检查并解析所有进程,然后再将它们存储在数据库中。从那时起,系统便知道该部署,并且现在可以启动该部署中包括的任何过程。
此外,这项服务还可以
查询引擎已知的部署和流程定义。
挂起并激活整个部署或特定过程定义。挂起表示无法对其进行进一步的操作,而激活是相反的操作。
检索各种资源,例如部署中包含的文件或引擎自动生成的流程图。
检索流程定义的POJO版本,该版本可用于使用Java而不是xml自省流程。
尽管与RepositoryService
静态信息(即不变的数据,或至少不变的数据)有关,但RuntimeService却相反。它处理启动流程定义的新流程实例。如上所述,a process definition
定义了过程中不同步骤的结构和行为。流程实例是这种流程定义的一种执行。对于每个流程定义,通常会同时运行许多实例。这RuntimeService
也是用于检索和存储的服务process variables
。这是特定于给定流程实例的数据,并且可以由流程中的各种构造使用(例如,专用网关通常使用流程变量来确定选择哪个路径来继续该流程)。的Runtimeservice
还允许查询流程实例和执行。执行代表'token'
了BPMN 2.0 的概念。基本上,执行是指向流程实例当前所在位置的指针。最后,RuntimeService
只要流程实例正在等待外部触发器并且需要继续流程,就使用。一个流程实例可以具有各种,wait states
并且该服务包含各种操作,以向该实例发出信号,表示已接收到外部触发器,并且该流程实例可以继续。
需要由系统的实际人类用户执行的任务是BPM引擎(如Activiti)的核心。任务周围的所有内容都分组在TaskService中,例如
查询分配给用户或组的任务
创建新的独立任务。这些是与流程实例无关的任务。
操纵任务分配给哪个用户或该任务涉及某种用户。
声明并完成任务。声明意味着某人决定担任该任务的受让人,这意味着该用户将完成任务。完成就是完成任务的工作。通常,这是一种形式的填充。
该IdentityService是非常简单的。它允许对群组和用户进行管理(创建,更新,删除,查询等)。重要的是要了解Activiti实际上在运行时不对用户进行任何检查。例如,可以将任务分配给任何用户,但是引擎不会验证系统是否知道该用户。这是因为Activiti引擎也可以与LDAP,Active Directory等服务结合使用。
该FormService是一个可选的服务。这意味着Activiti无需它即可完美使用,而不会牺牲任何功能。该服务介绍了启动表单和任务表单的概念。一开始的形式是流程实例启动前显示给用户的一种形式,而任务的形式是当一个用户要填写一份表格的形式显示出来。Activiti允许在BPMN 2.0流程定义中定义这些形式。该服务以一种简单的方式公开此数据。但是,这又是可选的,因为表单不需要嵌入流程定义中。
该HistoryService暴露在Activiti的引擎收集的所有历史数据。在执行流程时,引擎可以保存很多数据(这是可配置的),例如流程实例的启动时间,谁执行了哪些任务,完成任务所花的时间,每个流程实例遵循的路径等。该服务主要公开查询功能以访问此数据。
该ManagementService编码使用Activiti的自定义应用程序时,通常是没有必要的。它允许检索有关数据库表和表元数据的信息。此外,它公开了作业的查询功能和管理操作。作业在Activiti中用于各种用途,例如计时器,异步继续,延迟的挂起/激活等。稍后,将更详细地讨论这些主题。
的DynamicBpmnService可以用来改变流程定义的一部分,而无需重新部署。例如,您可以在流程定义中更改用户任务的受让人定义,或更改服务任务的类名。
5.部署Activiti流程
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.createDeployment().addClasspathResource("org/activiti/test/VacationRequest.bpmn20.xml").deploy();
Log.info("Number of process definitions: " + repositoryService.createProcessDefinitionQuery().count());
6.启动流程实例
将流程定义部署到Activiti引擎后,我们可以从中启动新流程实例。对于每个流程定义,通常都有许多流程实例。流程定义是蓝图,而流程实例是其运行时执行。
与进程的运行时状态相关的所有内容都可以在RuntimeService中找到。有多种启动新流程实例的方法。在以下代码段中,我们使用在流程定义xml中定义的键来启动流程实例。我们还在流程实例启动时提供了一些流程变量,因为第一个用户任务的描述将在其表达式中使用它们。通常使用过程变量,因为它们为特定过程定义的过程实例赋予了含义。通常,流程变量使流程实例彼此不同。
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("employeeName", "Kermit");
variables.put("numberOfDays", new Integer(4));
variables.put("vacationMotivation", "I'm really tired!");
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("vacationRequest", variables);
// Verify that we started a new process instance
Log.info("Number of process instances: " + runtimeService.createProcessInstanceQuery().count());
7.完成任务
该过程开始时,第一步将是用户任务。这是系统用户必须执行的步骤。通常,此类用户将拥有一个任务收件箱,其中列出了该用户需要完成的所有任务。以下代码段显示了如何执行这种查询:
// Fetch all tasks for the management group
TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("management").list();
for (Task task : tasks) {Log.info("Task available: " + task.getName());
}
要继续该流程实例,我们需要完成此任务。对于Activiti引擎,这意味着您需要complete
执行任务。以下片段显示了如何完成此操作:
Task task = tasks.get(0);
Map<String, Object> taskVariables = new HashMap<String, Object>();
taskVariables.put("vacationApproved", "false");
taskVariables.put("managerMotivation", "We have a tight deadline!");
taskService.complete(task.getId(), taskVariables);
8.暂停和激活流程
可以暂停流程定义。流程定义被挂起时,无法创建新的流程实例(将引发异常)。可以通过以下方式暂停流程定义
RepositoryService
:
repositoryService.suspendProcessDefinitionByKey("vacationRequest");
try {runtimeService.startProcessInstanceByKey("vacationRequest");
} catch (ActivitiException e) {e.printStackTrace();
}
要重新激活流程定义,只需调用其中一种repositoryService.activateProcessDefinitionXXX
方法。
也可以挂起流程实例。暂停后,该过程将无法继续执行(例如,完成任务会引发异常),并且不会执行任何作业(例如计时器)。可以通过调用runtimeService.suspendProcessInstance
方法来挂起流程实例。通过调用runtimeService.activateProcessInstanceXXX
方法来再次激活流程实例。
9.查询API
有两种从引擎查询数据的方式:查询API和本机查询。查询API允许使用流利的API编写完全类型安全的查询。您可以向查询中添加各种条件(所有条件都作为逻辑AND一起应用),也可以仅添加一个顺序。以下代码显示了一个示例:
List<Task> tasks = taskService.createTaskQuery().taskAssignee("kermit").processVariableValueEquals("orderId", "0815").orderByDueDate().asc().list();
有时您需要更强大的查询,例如使用OR运算符的查询或无法使用Query API表示的限制。对于这些情况,我们引入了本机查询,使您可以编写自己的SQL查询。返回类型由您使用的Query对象定义,数据被映射到正确的对象中,例如Task,ProcessInstance,Execution等。由于查询将在数据库中触发,因此您必须使用数据库中定义的表名和列名。这需要有关内部数据结构的一些知识,建议谨慎使用本机查询。可以通过API检索表名,以使依赖性尽可能小。
List<Task> tasks = taskService.createNativeTaskQuery().sql("SELECT count(*) FROM " + managementService.getTableName(Task.class) + " T WHERE T.NAME_ = #{taskName}").parameter("taskName", "gonzoTask").list();
long count = taskService.createNativeTaskQuery().sql("SELECT count(*) FROM " + managementService.getTableName(Task.class) + " T1, "+ managementService.getTableName(VariableInstanceEntity.class) + " V1 WHERE V1.TASK_ID_ = T1.ID_").count();
10.流程变量
每个流程实例都需要并使用数据来执行其存在的步骤。在Activiti中,此数据称为变量,它们存储在数据库中。变量可以在表达式中使用(例如,在独占网关中选择正确的传出序列流),在调用外部服务时在Java服务任务中(例如,提供输入或存储服务调用的结果)等。
流程实例可以具有变量(称为流程变量),但是执行(可以是指向流程活动位置的特定指针)也可以具有用户任务。流程实例可以具有任意数量的变量。每个变量都存储在ACT_RU_VARIABLE数据库表的一行中。
任何startProcessInstanceXXX方法都具有可选参数,以在创建和启动流程实例时提供变量。例如,从RuntimeService:
ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables);
可以在流程执行期间添加变量。例如(RuntimeService):
void setVariable(String executionId, String variableName, Object value);
void setVariableLocal(String executionId, String variableName, Object value);
void setVariables(String executionId, Map<String, ? extends Object> variables);
void setVariablesLocal(String executionId, Map<String, ? extends Object> variables);
请注意,可以为给定执行将变量设置为本地(请记住,流程实例由执行树组成)。该变量仅在该执行中可见,而在执行树中不可见。如果不应将数据传播到流程实例级别,或者该变量在流程实例中的某个路径具有新值(例如,使用并行路径时),则这很有用。
也可以再次获取变量,如下所示。请注意,TaskService上存在类似的方法。这意味着任务,如执行,可以有局部变量是活着只是为了任务的持续时间。
Map<String, Object> getVariables(String executionId);
Map<String, Object> getVariablesLocal(String executionId);
Map<String, Object> getVariables(String executionId, Collection<String> variableNames);
Map<String, Object> getVariablesLocal(String executionId, Collection<String> variableNames);
Object getVariable(String executionId, String variableName);
<T> T getVariable(String executionId, String variableName, Class<T> variableClass);
变量通常用于Java委托,表达式,执行或任务侦听器,脚本等中。在这些构造中,当前执行或任务对象可用,并且可用于变量设置和/或检索。最简单的方法是:
execution.getVariables();
execution.getVariables(Collection<String> variableNames);
execution.getVariable(String variableName);
execution.setVariables(Map<String, object> variables);
execution.setVariable(String variableName, Object value);
请注意,上述所有内容都可以使用带有local的变体。
由于历史(和向后兼容的原因)的原因,在进行上述任何调用时,实际上都会从数据库中获取所有变量。这意味着,如果您有10个变量,并且仅通过getVariable(“ myVariable”)获得一个变量,则将在后台获取其他9 个变量并将其缓存。这还不错,因为后续调用不会再次打入数据库。例如,当您的流程定义具有三个顺序的服务任务(并因此有一个数据库事务)时,使用一个调用来获取第一个服务任务中的所有变量可能比分别获取每个服务任务中所需的变量更好。请注意,这适用于既用于获取和设置变量。
当然,当使用很多变量时,或者只是想对数据库查询和流量进行严格控制时,这是不合适的。自Activiti 5.17以来,引入了新方法以通过对此进行更严格的控制,方法是添加具有可选参数的新方法,该参数告诉引擎是否需要在后台获取和缓存所有变量:
Map<String, Object> getVariables(Collection<String> variableNames, boolean fetchAllVariables);
Object getVariable(String variableName, boolean fetchAllVariables);
void setVariable(String variableName, Object value, boolean fetchAllVariables);
当对参数fetchAllVariables使用true时,行为将完全如上所述:在获取或设置变量时,将提取并缓存所有其他变量。
但是,当使用false作为值时,将使用特定的查询,并且不会获取或缓存其他变量。仅此处讨论的变量的值将被缓存以备后用。
11.节点跳转
流程节点跳转操作类 如下:
package com.broadtext.ycadp.activiti.service.impl;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.impl.history.HistoryManager;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntityManager;
import org.activiti.engine.impl.util.ProcessDefinitionUtil;
/*** @ClassName JumpAnyWhereCmd* @Description 流程节点跳转操作类* @Author ZP* @Date 2019/12/10 9:46* @Version 1.0*/
public class JumpAnyWhereCmd implements Command {
private String taskId;
private String targetNodeId;
public JumpAnyWhereCmd(String taskId, String targetNodeId) {this.taskId = taskId;this.targetNodeId = targetNodeId;}
@Overridepublic Object execute(CommandContext commandContext) {
//获取任务实例管理类TaskEntityManager taskEntityManager = commandContext.getTaskEntityManager();//获取当前任务实例TaskEntity currentTask = taskEntityManager.findById(taskId);
//获取当前节点的执行实例ExecutionEntity execution = currentTask.getExecution();String executionId = execution.getId();
//获取流程定义idString processDefinitionId = execution.getProcessDefinitionId();//获取目标节点Process process = ProcessDefinitionUtil.getProcess(processDefinitionId);FlowElement flowElement = process.getFlowElement(targetNodeId);
//获取历史管理HistoryManager historyManager = commandContext.getHistoryManager();
//通知当前活动结束(更新act_hi_actinst)historyManager.recordActivityEnd(execution,"jump to initiator");//通知任务节点结束(更新act_hi_taskinst)historyManager.recordTaskEnd(taskId,"jump to initiator");//删除正在执行的当前任务taskEntityManager.delete(taskId);
//此时设置执行实例的当前活动节点为目标节点execution.setCurrentFlowElement(flowElement);
//向operations中压入继续流程的操作类commandContext.getAgenda().planContinueProcessOperation(execution);
return null;}
}
触发节点跳转(进入controller调用service service找到impl实现类进行触发)
Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();if(task==null) {throw new ServiceException("流程未启动或已执行完成,无法撤回");}//判断当前节点是否已审批 已审批无法撤回List<HistoricActivityInstance> histList= historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list();boolean flag=true;for(HistoricActivityInstance hai:histList){//排除开始节点if(!StringUtils.equals(hai.getActivityType(),"startEvent")){//只要审批过 都会有结束时间if(hai.getEndTime() != null){flag=false;break;}}}if(!flag){throw new ServiceException("流程节点已审批无法撤回!");}//节点跳转processEngine.getManagementService().executeCommand(new JumpAnyWhereCmd(task.getId(),nodeId));
activiti6超详细教程相关推荐
- 手把手从零开始搭建k8s集群超详细教程
本教程根据B站课程云原生Java架构师的第一课K8s+Docker+KubeSphere+DevOps同步所做笔记教程 k8s集群搭建超详细教程 1. 基本环境搭建 1. 创建私有网络 2. 创建服务 ...
- 安装64位Oracle 10g超详细教程
安装64位Oracle 10g超详细教程 1. 安装准备阶段 1.1 安装Oracle环境 经过上一篇博文的过程,已经完成了对Linux系统的安装,本例使用X-Manager来实现与Linux系统的连 ...
- mysql超详细教程_MySQL8.0.23安装超详细教程
前言 最近在做一个人脸识别的项目,需要用数据库保存学生信息与前段交互. MySQL的优点 1.mysql性能卓越,服务稳定,很少出现异常宕机. 2.mysql开放源代码且无版权制约,自主性及使用成本低 ...
- WebRTC VideoEngine超详细教程(三)——集成X264编码和ffmpeg解码
转自:http://blog.csdn.net/nonmarking/article/details/47958395 本系列目前共三篇文章,后续还会更新 WebRTC VideoEngine超详细教 ...
- 二进制安装部署 4 kubernetes集群---超详细教程
二进制安装部署kubernetes集群---超详细教程 前言:本篇博客是博主踩过无数坑,反复查阅资料,一步步搭建完成后整理的个人心得,分享给大家~~~ 本文所需的安装包,都上传在我的网盘中,需要的可以 ...
- 【超详细教程】使用Windows Live Writer 2012和Office Word 2013 发布文章到博客园全面总结...
[超详细教程]使用Windows Live Writer 2012和Office Word 2013 发布文章到博客园全面总结 原文 http://www.cnblogs.com/liuxianan/ ...
- mysql 8.0.22_最新版MySQL 8.0.22下载安装超详细教程(Windows 64位)
前言 前几天下载安装了最新版的MySQL 8.0.22,遇到了不少问题,参考了一些方法,最终得以解决.今天将自己的安装过程记录下来,希望对各位有所帮助. 一.MySQL 8.0.22官网下载 点击进入 ...
- post修改服务器数据源,postgresql安装及配置超详细教程
1. 安装 根据业务需求选择版本,官网下载 初始化数据库 执行完初始化任务之后,postgresql 会自动创建和生成两个用户和一个数据库: linux 系统用户 postgres:管理数据库的系统用 ...
- 微服务Springcloud超详细教程+实战(二)
微服务Springcloud超详细教程+实战(二) -------------------------------------- 远程调用方式 无论是微服务还是分布式服务(都是SOA,都是面向服务编程 ...
- rtl8811au黑苹果10.15_荣耀MagicBook I5黑苹果折腾记(超详细教程与排坑)
本文主要介绍如何安装Win10 + Mac OS双系统,以及安装过程中可能遇到的一些坑. 本人的机型是:MagicBook I5-8250U MX150独显 8GB+256GB (VLT-W50),更 ...
最新文章
- 研究项目: JBoss架构分析
- nyoj-491--幸运三角形--简单深搜枚举(TLE)
- 程序代码初学者_初学者:如何使用热键在Windows中启动任何程序
- C++ MFC string转Cstring为什么会乱码
- 什么叫做石英表_石英表 是什么意思??
- C语言中利用switch语句和 if--else 语句输出,,闰年或平年,及每月对应的天数。
- URL加载系统之三:NSURLConnection
- getCacheDir()和getFilesDir()方法区别
- 《How to Use the TimeDistributed Layer for Long Short-Term Memory Networks in Python》学习笔记
- docker nginx 命令。
- 计算机系统结构自考知识点总结,自考《计算机系统结构》问答题总结(3)
- YoC RTOS 实战:FOTA系统升级
- 再谈iOS视频播放器旋转视图开发
- 网盘资源搜索神器,只有你想不到没有你搜不到的,老司机必备!
- 《QTreeView中嵌入QPushButton实现命令操作》:系列教程之八(第8小节)
- ALFA机器视觉深度学习外观缺陷检测系统软件机器视觉
- 有道云笔记分享_有道云笔记的使用分享
- 虚幻4引擎开发的手游_虚幻引擎 4 手游《绝地求生:刺激战场》 开发经验分享...
- HTML-图文排版如何以代码实现
- 这一次,卡98%问题终于解决了