一.工作流
1.工作流(Workflow)
就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在“多个参与者”之间按照某种“预定义的规则”传递文档、信息或任务的过程自动进行,从而实现某个预期的业务目标,或者促使此目标的实现”。
通俗的说,流程就是多个人在一起合作完成某件事情的步骤,把步骤变成计算机能理解的形式就是工作流。
2.工作流框架
工作流管理联盟(WfMC,Workflow Management Coalition)给出的关于工作流管理系统的定义是:
工作流管理系统是一个软件系统,它通过执行经过计算的流程定义去支持一批专门设定的业务流程的执行。工作流管理系统被用来定义、管理、和执行工作流程。
1、定义工作流:包括具体的活动、规则等。抽取请假和报销等流程
2、执行工作流:按照流程定义的规则执行,并由多个参与者进行控制。
工作流核心:
一、定义工作流:eclipse或者myeclipse安装activiti插件
二、执行工作流:顺序、分支、聚合、并发…
工作流框架就是管理工作流框架
工作流管理系统的目标:管理工作的流程以确保工作在正确的时间被期望的人员所执行——在自动化进行的业务过程中插入人工的执行和干预。
采用工作流管理系统的优点
1、提高系统的柔性,适应业务流程的变化
2、实现更好的业务过程控制,提高顾客服务质量
3、降低系统开发和维护成本
工作流框架有:Activiti、JBPM、OSWorkflow、ActiveBPEL、YAWL等。
二.Activiti
Activiti5是由Alfresco软件在2010年5月17日发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理、工作流、服务协作等领域的一个开源的、灵活的、易扩展的可执行流程语言框架
1、Activiti基于Apache许可的开源BPM平台
2、Activiti和业界也用的多的JBPM历史渊源。
创始人Tom Baeyens是JBoss jBPM4的项目架构师,后来去Alfresco做了继承和发展了Activiti.而Jboss公司抛弃了JBPM4的设计思想,重新设计开发了JBPM5.所以原来习惯于JBPM4的大部分用户都使用Activiti
3、它特色是提供了eclipse插件,开发人员可以通过插件直接绘画出业务流程图。 并且提供了Demo,可以从里面抽取流程在线设计器。比较强大。
1.Activiti–核心–工作流引擎(ProcessEngine),这是Activiti工作的核心。负责生成流程运行时的各种实例及数据、监控和管理流程的运行。(核心对象)
2.Activiti–流程定义语言-BPMN2.0 *,业务流程建模与标注(Business Process Model and Notation,BPMN) ,描述流程的基本符号,包括这些图元如何组合成一个业务流程图(Business Process Diagram)
3.Activiti–持久化-数据库持久化
Activiti是一个强大的业务流程管理(BPM)框架,他本身需要数据库支持,它使用了Mybatis作为持久化框架,对于数据库管理系统(DBMS)支持多个。并且它的数据库表名有一定的特征。
Activiti的后台是有数据库的支持,所有的表都以ACT_开头。 第二部分是表示表的用途的两个字母标识。 用途也和服务的API对应。
4.资源库流程规则表
1)act_re_deployment 部署信息表
2)act_re_model 流程设计模型信息表
3)act_re_procdef 流程定义数据表
5.运行时数据库表
1)act_ru_execution 运行时流程执行实例表
2)act_ru_identitylink 运行时流程人员表,主要存储任务节点与参与者的相关信息
3)act_ru_task 运行时任务节点表
4)act_ru_variable 运行时流程变量数据表
6.历史数据库表
1)act_hi_actinst 历史节点表
2)act_hi_attachment 历史附件表
3)act_hi_comment 历史意见表
4)act_hi_identitylink 历史流程人员表
5)act_hi_detail 历史详情表,提供历史变量的查询
6)act_hi_procinst 历史流程实例表
7)act_hi_taskinst 历史任务实例表
8)act_hi_varinst 历史变量表
7.组织机构表
1)act_id_group 用户组信息表 JBPM_ID_MEMBERSHIP
2)act_id_info 用户扩展信息表
3)act_id_membership 用户与用户组对应信息表
4)act_id_user 用户信息表
这四张表很常见,基本的组织机构管理,关于用户认证方面建议还是自己开发一套,组件自带的功能太简单,使用中有很多需求难以满足
8.通用数据表
1)act_ge_bytearray 二进制数据表
2)act_ge_property 属性数据表存储整个流程引擎级别的数据,初始化表结构时,会默认插入三条记录。
三.Activiti准备环境
1.软件版本需求
1)JDK1.6或者更高版本
2)支持的数据库有:h2, mysql, oracle, postgres, mssql, db2等。
3)支持activiti5运行的jar包
4)开发环境为Eclipse3.7.2+或者以上版本,myeclipse为8.6版本
2.安装流程设计器(eclipse插件)
此为5.18版本(https://download.youkuaiyun.com/download/dingliang1122/10599407)
本人使用为5.16版本,暂时没有上传,有需要的私聊
将文件解压后丢入此文件夹,然后重启eclipse
如果能new出这个东西说明安装成功
勾上 可以生成图片
3.导包
进入之后copy 48个jar包
此为 h2 的支持包 ,删除
换成mysql 支持包,如果为其他 数据库择换成相应支持包
4.Test
(这里可以进行源码查看,不需要导包即可查看,需要用到反编译插件,直接丢入即可的插件,需要可以评论私聊)
public class Config_Test {
@Test
public void testConnect() throws Exception {
// 根据doc文档 ctrl+f ProcessEngineConfiguration 不用配置文件
// 配置信息
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration
.createStandaloneProcessEngineConfiguration();
// jdbc 连接信息
processEngineConfiguration.setJdbcUrl("jdbc:mysql:///activiti?createDatabaseIfNotExist=true");
processEngineConfiguration.setJdbcDriver("com.mysql.jdbc.Driver");
processEngineConfiguration.setJdbcUsername("root");
processEngineConfiguration.setJdbcPassword("123456");
// 自动创建表
processEngineConfiguration.setDatabaseSchemaUpdate("true");
// 服务核心对象 (一旦核心对象 它就会创建表结构)
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
System.out.println(processEngine);
}
}
生成表方式一:
运行时会自动在数据库中生成如下表
(不懂表意可以查看上面关于表的解释)
方式二:
注意: 这个xml配置文件名一定要是activiti.cfg.xml
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<!--数据连接信息 -->
<property name="jdbcUrl" value="jdbc:mysql:///activiti?createDatabaseIfNotExist=true" />
<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
<property name="jdbcUsername" value="root" />
<property name="jdbcPassword" value="123456" />
<!-- 自动建表 -->
<property name="databaseSchemaUpdate" value="true" />
</bean>
</beans>
方法三:
四.学习activiti的API
1.核心业务
1 绘制流程--定义(规则)流程
通过eclipese插件绘制流程,会产生两个文件:bpmn(流程定义文件),png(流程图)
2 流程定义(规则)管理--核心(ProcessDefinition)
1、部署流程
2、流程定义列表查询
3、删除流程(删除部署,流程的挂起和激活)
4、查看规则流程图
(没有修改,删除了重新部署!!)
3 流程运行时管理--核心(ProcessInstance)
1、启动流程
2、查看任务
私有任务
公共任务
3、认领任务
4、完成任务
5、查看流程状态
2.四个核心的api
// 查询部署信息列表和流程定义列表
RepositoryService getRepositoryService();
// 查询运行的实例的表
RuntimeService getRuntimeService();
// 查询任务表
TaskService getTaskService();
// 查询历史的表
HistoryService getHistoryService();
添加发布部署
@Test
public void testDeloy() throws Exception {
// 获取核心对象 服务大管家
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// RepositoryService 仓库
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
// 获取流程发布对象
DeploymentBuilder createDeployment = repositoryService.createDeployment();
// 上传资源
createDeployment.addClasspathResource("MyProcess.bpmn");
createDeployment.addClasspathResource("MyProcess.png");
createDeployment.name("xxx");
// 部署发布
Deployment deploy = createDeployment.deploy();
System.out.println(deploy);
}
@Test
public void testQueryDeloy() throws Exception {
// 获取核心对象 服务大管家
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// RepositoryService 仓库
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
// 查询对象
DeploymentQuery createDeploymentQuery = repositoryService.createDeploymentQuery();
// 设置查询条件
// createDeploymentQuery.deploymentName(name)
//createDeploymentQuery.deploymentId(deploymentId)
//createDeploymentQuery.deploymentNameLike(nameLike)
//createDeploymentQuery.listPage(firstResult, maxResults)
//createDeploymentQuery.singleResult();
List<Deployment> list = createDeploymentQuery.list();
for (Deployment deployment : list) {
System.out.println(deployment.getDeploymentTime());
}
}
// 查询流程定义信息列表
@Test
public void testQueryProcessDef() throws Exception {
// 获取核心对象 服务大管家
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// RepositoryService 仓库
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
// 获取查询对象
ProcessDefinitionQuery createProcessDefinitionQuery = repositoryService.createProcessDefinitionQuery();
// 设置查询条件
//createProcessDefinitionQuery.listPage(firstResult, maxResults)
List<ProcessDefinition> list = createProcessDefinitionQuery.list();
for (ProcessDefinition pd : list) {
System.out.println(pd);
}
}
其他代码使用
// 删除部署(物理删数-真删)
@Test
public void testdeleteDeloy() throws Exception {
// 获取核心对象 服务大管家
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// RepositoryService 仓库
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
repositoryService.deleteDeployment("2501");
System.out.println();
}
// 假删除部署 (挂起和激活)
@Test
public void testUpdateDeleteDeloy() throws Exception {
// 获取核心对象 服务大管家
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// RepositoryService 仓库
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
// 挂起
//repositoryService.suspendProcessDefinitionByKey("myProcess");
// 激活
repositoryService.activateProcessDefinitionByKey("myProcess");
}
// 显示流程图片
@Test
public void testShowPng() throws Exception {
// 获取核心对象 服务大管家
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// RepositoryService 仓库
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
// web项目输出到浏览器的输入流
// 模拟输出本地硬盘
// 获取png图片
String deploymentId="5001";
String resourceName="MyProcess.png";
// 获取输入的流对象 读的字节
InputStream resourceAsStream = repositoryService.getResourceAsStream(deploymentId, resourceName);
//模拟输出本地硬盘
IOUtils.copy(resourceAsStream, new FileOutputStream("d:/a.png"));
}
3.其他API
1 RuntimeService(重要--运行时)
流程实例和执行对象相关
是activiti的流程执行服务类。可以从这个服务类中获取很多关于流程执行相关的信息。
2 TaskService(重要--针对人工任务)
是activiti的任务服务类。可以从这个类中获取任务的信息,比如查看、办理任务等操作。
3 ProcessDefinition(流程定义【规则】对象)
流程定义类。可以从这里获得资源文件等
4 ProcessInstance(流程实例)
代表流程定义的执行实例。如范冰冰请了一天的假,她就必须发出一个流程实例的申请。一个流程实例包括了所有的运行节点。我们可以利用这个对象来了解当前流程实例的进度等信息。流程实例就表示一个流程从开始到结束的最大的流程分支,即一个流程中流程实例只有一个,流程实例是唯一的。
流程实例(ProcessInstance)的4大特点:
1、开启一个流程就会创建一个对应的流程实例
2、一个流程从始至终都有且只有1个流程实例,实例的id不会改变,唯一的
3、流程实例永远指向当前活动的节点
4、流程实例是一个特殊的Execution对象。流程实例永远是作为父亲级别的Execution。
单线流程中,执行对象就是流程实例对象。
5、并发流程中,会在分支处,生成一个Execution对象作为Root(即流程实例),会在分之下,每个活动节点创建一个新的独立Execution作为子挂在Root下。
4.Execution
Activiti用这个对象去描述流程执行的每一个节点。在没有并发的情况下,Execution就是同ProcessInstance。流程按照流程定义的规则执行一次的过程,就可以表示执行对象Execution。
总结:
- 一个流程中,执行对象可以存在多个,但是流程实例只能有一个。
- 当流程按照规则只执行一次(单线)的时候,那么流程实例就是执行对象。
五.设计流程定义文档
1 流程图
2 bpmn文件
BPMN 2.0根节点是definitions节点。 这个元素中,可以定义多个流程定义(不过我们建议每个文件只包含一个流程定义, 可以简化开发过程中的维护难度)。 一个空的流程定义看起来像下面这样。注意,definitions元素 最少也要包含xmlns 和 targetNamespace的声明。 targetNamespace可以是任意值,它用来对流程实例进行分类。
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" targetNamespace="Examples">
<!-- 流程定义部分 -->
<processid="myProcess"name="My First Process">
<startEvent id="startevent1" name="Start"></startEvent>
<endEvent id="endevent1" name="End"></endEvent>
<userTask id="usertask1" name="员工申请请假" activiti:assignee="员工"></userTask>
<userTask id="usertask2" name="部门经理审批" activiti:assignee="经理"></userTask>
<userTask id="usertask3" name="老板审批" activiti:assignee="老板"></userTask>
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
<sequenceFlow id="flow2" name="提交申请" sourceRef="usertask1"
argetRef="usertask2"></sequenceFlow>
<sequenceFlow id="flow3" name="经理审批" sourceRef="usertask2"
argetRef="usertask3"></sequenceFlow>
<sequenceFlow id="flow4" name="老板审批" sourceRef="usertask3"
argetRef="endevent1"></sequenceFlow>
</process>
<!-- BPMN绘图规范定义部分(用来描述节点图标的大小和坐标) -->
<bpmndi:BPMNDiagram id="BPMNDiagram_myProcess">
....
</bpmndi:BPMNDiagram>
</definitions>
说明:流程定义文档有两部分组成:
- bpmn文件
流程规则文件。在部署后,每次系统启动时都会被解析,把内容封装成流程定义放入项目缓存中。Activiti框架结合这个xml文件自动管理流程,流程的执行就是按照bpmn文件定义的规则执行的,bpmn文件是给计算机执行用的。 - 展示流程图的图片
在系统里需要展示流程的进展图片,图片是给用户看的。
设计一个请假流程:
修改ID,name等
办理人
2.部署流程定义
部署流程定义也可以认为是增加流程定义。
/**
* ①:获取核心对象ProcessEngine
* ②:分析需求,通过核心对象获取对应的"服务实例"
* ③:使用服务的方法做事情
* 三张表:
* 1)act_re_deployment 部署信息表:部署一次就有一条记录
2)act_re_procdef 流程定义数据表 :部署一次,就产生一个流程,有一个流程定义数据
3)act_ge_bytearray 二进制数据表:一个流程定义会有有两个2机制数据:.bpmn和png的数据
//部署一个流程定义
*/
@Test
public void deployTest() {
// 1、获取核心对象
ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
// 2、分析需求,通过核心对象获取对应的“服务实例”
RepositoryService repositoryService = processEngine.getRepositoryService();
//通过仓库服务创建一个部署builder
DeploymentBuilder builder = repositoryService.createDeployment();
//添加部署的资源文件:必须添加两个文件,png文件可以不添加,自动添加,但是自动添加后在数据库看到是乱码的、在classpath下按照名字加载
builder.addClasspathResource("MyProcess.bpmn").addClasspathResource("MyProcess.png");
// 3、使用服务的方法做事情
//部署
builder.deploy();
}
说明:
1)首先获得默认的流程引擎,在创建时会自动加载classpath下得activiti.cfg.xml
2)通过流程引擎获取了一个RepositoryService对象->仓库服务对象
3由仓库的服务对象产生一个部署对象配置对象,用来封装部署环境的相关配置。
4)可以看出这是一个链式编程,在部署配置对象中设置显示名,上传规则文件相对classpath的地址。
5)部署,也是往数据库中存储流程定义的过程。
6)这一步在数据库中将操作三张表:
a)act_re_deployment
存放流程定义的显示名和部署时间,每部署一次增加一条记录
b)act_re_procdef
存放流程定义的属性信息,部署每个新的流程定义都会在这张表中增加一条记录。
c)act_ge_bytearray
存储流程定义相关的部署信息。即流程定义文档的存放地。每部署一次就会增加两条记录,一条是关于bpmn规则文件的,一条是图片的(如果部署时只指定了bpmn一个文件,activiti会在部署时解析bpmn文件内容自动生成流程图)。两个文件不是很大,都是以二进制形式存储在数据库中。
3流程定义列表
查询流程定义的信息
@Test
public void processDefinedList(){
// 1、创建核心对象
ProcessEngine engine=ProcessEngines.getDefaultProcessEngine();
// 2、分析需求,获取对应的服务
RepositoryService repositoryService = engine.getRepositoryService();
// 3、通过服务,做查询
// a)创建对应查询对象
ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery();
// b)添加查询条件
// 各种查询条件
// definitionQuery.processDefinitionKey(processDefinitionKey)
// definitionQuery.processDefinitionKeyLike(processDefinitionKeyLike)
// definitionQuery.processDefinitionName(processDefinitionName)
// definitionQuery.processDefinitionNameLike(processDefinitionNameLike)
// 排序
// definitionQuery.orderByProcessDefinitionId().desc()
// c)执行查询
// definitionQuery.count();//查询总的条数
// definitionQuery.list();//查询所有的流程定义
// definitionQuery.singleResult();//查询唯一记录
// definitionQuery.listPage(firstResult, maxResults);//分页查询
List<ProcessDefinition> list = definitionQuery.list();
// 4、遍历,展示结果
for (ProcessDefinition pd : list) {
System.out.println("id-->"+pd.getId());
System.out.println("name-->"+pd.getName());
System.out.println("key-->"+pd.getKey());
System.out.println("version-->"+pd.getVersion());
System.out.println("resourceName-->"+pd.getResourceName());
System.out.println("DeploymentId-->"+pd.getDeploymentId());
System.out.println("DiagramResourceName-->"+pd.getDiagramResourceName());
System.out.println("category-->"+pd.getCategory());
System.out.println("Description-->"+pd.getDescription());
}
}
说明:
1) 因为流程定义的信息存放在仓库中,所以应该获取RepositoryService。
2) 创建流程定义查询对象,可以在ProcessDefinitionQuery上设置查询过滤参数
3) 调用ProcessDefinitionQuery对象的list方法,执行查询,获得符合条件的流程定义列表
4) 注意流程定义对象结果和bpmn文件关系:
a) Key和Name的值为:bpmn文件process节点的id和name的属性值
b) key属性被用来区别不同的流程定义。
c) 带有特定key的流程定义第一次部署时,version为1。之后每次部署都会在当前最高版本号上加1
d) Id的值的生成规则为:{processDefinitionKey}:{processDefinitionVersion}:{generated-id}, 这里的generated-id是一个自动生成的唯一的数字
e) 重复部署一次,deploymentId的值以一定的形式变化
f) 流程定义(ProcessDefinition)在数据库中没有相应的表对应,只是从act_ge_bytearray表中取出相应的bpmn和png图片,并进行解析。
4.删除流程定义
删除部署到activiti中的流程定义。
/**
* 删除流程定义(删除部署,就删除了流程定义)-->使用流程挂起和激活来实现流程的删除
*/
@Test
public void delProcess() {
// 获取核心对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、分析需求,通过核心对象获取对应的“服务实例”
RepositoryService repositoryService = processEngine.getRepositoryService();
//流程部署的id:act_re_deployment表可以得到
String deploymentId = "1";
// 使用服务的方法做事情:删除一个部署,就删除一个流程定义
repositoryService.deleteDeployment(deploymentId);
// 不需要实际删除,做一个挂起和激活的操作:让流程定义挂起,暂时不可用
String processDefinitionKey = "myProcess";
// repositoryService.suspendProcessDefinitionByKey(processDefinitionKey);
// 激活挂起的流程定义:激活流程定义,重新可用
//repositoryService.activateProcessDefinitionByKey(processDefinitionKey);
}
5.(查看规则流程图)获取流程定义文档的资源
查询出流程定义文档。主要查的是图片,用于显示流程用。
新方法
//查看规则流程图
@Test
public void viewProcessDiagram() throws Exception{
//获取核心对象
ProcessEngine engine= ProcessEngines.getDefaultProcessEngine();
//分析需求,通过核心对象获取对应的"服务实例"
RepositoryService repositoryService = engine.getRepositoryService();
//使用服务方法做事情
String deploymentId="5001";
String resourceName="MyProcess.png";
//通过流的方式获取,以后在做项目的时候直接复制到response中就可以输出了
InputStream resourceAsStream = repositoryService.getResourceAsStream(deploymentId, resourceName);
IOUtils.copy(resourceAsStream, new FileOutputStream(new File("c://9.png")));
}
说明:
1)deploymentId为流程部署ID
2)resourceName为act_ge_bytearray表中NAME_列的值
3)使用repositoryService的getDeploymentResourceNames方法可以获取指定部署下得所有文件的名称
4)使用repositoryService的getResourceAsStream方法传入部署ID和文件名称可以获取部署下指定名称文件的输入流
5)最后的有关IO流的操作,使用FileUtils工具的copyInputStreamToFile方法完成流程流程到文件的拷贝
六. 流程实例管理–运行时
1、启动流程
2、查看任务
私有任务
公共任务
3、认领任务
4、办理任务
5、查看流程状态
1.启动流程实例
在完成了流程定义部署后,就要启动流程实例了。
/*** 启动流程实例
* 两张表会产生数据变化:
* act_ru_execution 运行时流程执行对象表 1 流程中执行当前节点就会有一个指向对象
* act_ru_task 运行时任务节点表 如果当前节点是人工任务几点,会同时产生一个task任务,来对执行对象做补充
*/
@Test
public void startProcessInstance() {
//①获取核心对象
ProcessEngine engine=ProcessEngines.getDefaultProcessEngine();
//②分析需求,通过核心对象获取对应的"服务实例":启动实例,启动后就运行了,使用运行服务
RuntimeService runtimeService = engine.getRuntimeService();
//③使用服务方法作事情
//如果有多次部署,流程定义的key是一样的,启动最新一个版本的
String processDefinitionKey="commonTaskId";
//启动流程实例
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey);
System.out.println("instanceId:"+processInstance.getId());
System.out.println("instanceIName:"+processInstance.getName());
}
说明:
操作数据库的act_ru_execution表,如果是用户任务节点,同时也会在act_ru_task添加一条记录
2.查询任务
在activiti任务中,主要分为两大类:
1.确切指定了办理者的任务,这个任务将成为指定者的私有任务
2.无法指定具体的某一个人来办理的任务,可以把任务分配给几个人或者一到 多个小组,让这个范围内的用户可以选择性(如有空余时间时)来办理这类任务。
查询指定用户的代办任务
对指定用户的未完成的个人任务执行查询。
//任务查看//私有任务
@Test
public void viewPersonTask(){
// 创建核心对象
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
// 需求分析,通过核心对象获取对应的"服务实例"
TaskService taskService = engine.getTaskService();
// 调用服务的方法,做事情
// 任务的查询:
// 创建查询对象
TaskQuery taskQuery = taskService.createTaskQuery();
// 设置查询条件:查询冰冰的任务
String assignee = "冰冰";
taskQuery.taskAssignee(assignee);
// 执行查询
// taskQuery.count();//任务数量统计
// taskQuery.singleResult();//唯一任务
// taskQuery.listPage(firstResult, maxResults);//分页
List<Task> list = taskQuery.list();// 查询所有的任务
for (Task task : list) {
System.out.println("taskId="+task.getId());
System.out.println("taskName="+task.getName());
System.out.println("taskAssignee="+task.getAssignee());
}
}
说明:
1)因为是任务查询,所以从processEngine中应该得到TaskService
2)使用TaskService获取到任务查询对象TaskQuery
3)为查询对象添加查询过滤条件,使用taskAssignee指定任务的候选者(即查询指定用户的代办任务),添加分页排序等过滤条件
4)调用list方法执行查询,返回办理者为指定用户的任务列表
5)任务ID、名称、办理人、创建时间可以从act_ru_task表中查到。
6)Execution与ProcessInstance见5.6章节的介绍。在这种情况下,ProcessInstance相当于Execution
7)如果assignee属性为部门经理,结果为空。因为现在流程只到了”填写请假申请”阶段,后面的任务还没有执行,即在数据库中没有部门经理可以办理的任务,所以查询不到。
8)一个Task节点和Execution节点是1对1的情况,在task对象中使用Execution_来标示他们之间的关系
9)任务ID在数据库表act_ru_task中对应“ID_”列
查询指定用户的可接任务(公共任务)
对指定用户的可接取的公共任务执行查询。
//查看任务:公共任务
@Test
public void commandTask(){
//创建核心对象
ProcessEngine engine=ProcessEngines.getDefaultProcessEngine();
//分析需求,通过核心对象获取对应"服务实例"
TaskService taskService = engine.getTaskService();
//调用服务方法做事情
TaskQuery taskQuery = taskService.createTaskQuery();
String candidateUser="大牛";
taskQuery.taskCandidateUser(candidateUser);
List<Task> list = taskQuery.list();
System.out.println(candidateUser+"的公有任务:");
for (Task task : list) {
System.out.println("taskId="+task.getId());
System.out.println("taskName="+task.getName());
}
}
说明:
1.前面步骤类似,查询任务首先使用TaskService创建TaskQuery对象
2.在查询对象上,添加taskCandidateUser过滤条件,代表过滤任务候 选者为自己的任务
3.调用list方法返回指定用户的可接任务列表
4.所有公共任务的assignee属性为空
3.认领任务(针对公共任务)
通常一个任务为公共任务任务都有一个以上的候选者,用户想要办理它应该先进行认领任务操作,即把自己变成任务的拥有者。
/**
* 任务认领:对于公有任务,可以认领。一旦认领后,自己就不再有这个任务
*/
@Test
public void claimTask(){
ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
String taskId="2504";
String userId="大牛";
taskService.claim(taskId, userId);
}
说明:
1.任务相关操作,首先得到taskService
2.确定被认领的任务ID和认领人ID
3.调用taskService的claim(认领)方法,把公共任务变成指定用户的私有任务
4.办理任务
指定任务ID,完成该任务。
//办理任务
@Test
public void completeProcess(){
//流程执行
ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
//流程启动后,办理是人在办理,使用taskService
TaskService taskService = processEngine.getTaskService();
//表:act_ru_task
String taskId="2504";
taskService.complete(taskId);
}
说明:
1)是办理任务,所以从ProcessEngine得到的是TaskService。
2)当执行完这段代码,再以员工的身份去执行查询的时候,会发现这个时候已经没有数据了。
3)对于执行完的任务,activiti将从act_ru_task表中删除该任务,下一个任务会被插入进来。
4)以”部门经理”的身份进行查询,可以查到结果。因为流程执行到部门经理审批这个节点了。
5)再执行办理任务代码,执行完以后以”部门经理”身份进行查询,没有结果。
6)重复第3和4步直到流程执行完。
5.验证流程已经结束
在流程执行的过程中,创建的流程实例ID在整个过程中都不会变,当流程结束后,流程实例将会被删除。
//查看流程实例状态
@Test
public void checkProceeEnd(){
ProcessEngine engine=ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = engine.getRuntimeService();
//创建流程查询对象
ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery();
String processInstanceId="2501";
//设置查询条件
query.processInstanceId(processInstanceId);
//查询
ProcessInstance singleResult = query.singleResult();
if(singleResult==null){
System.out.println("processInstanceId="+processInstanceId+"流程已经结束");
}else{
System.out.println("processInstanceId="+processInstanceId+"流程还在运行中");
}
}
说明:
1)因为是查询流程实例,所以先获取runtimeService
2)创建流程历史查询对象,设置实例ID过滤参数
3)由于一个流程实例ID只对应一个实例,使用singleResult执行查询返回一个唯一的结果,如果结果数量大于1,则抛出异常
4)判断指定ID的实例是否存在,如果结果为空,则代表流程结束,实例已被删除
历史是一个组件,它可以捕获发生在进程执行中的信息并永久的保存,与运行时数据不同的是,当流程实例运行完成之后它还会存在于数据库中。
在流程引擎配置对象中可以设置历史记录规则:
由于数据库中保存着历史信息以及正在运行的流程实例信息,在实际项目中对已完成任务的查看频率远不及对代办和可接任务的查看,所以在activiti采用分开管理,把正在运行的交给runtimeService管理,而历史数据交给HistoryService来管理。
对已成为历史的数据主要进行查询操作,我们主要关心两种类型的历史数据:
HistoricProcessInstance 包含当前和已经结束的流程实例信息。
HistoricActivityInstance 包含一个活动(流程上的节点)的执行信息 。
七.查看历史流程实例
1.查看用户按照某个流程规则执行了多少次流程。
/**
* 流程定义执行多少次:
* 流程定义id:LeaveFlow:2:10004
流程开始时间:2017-09-24 23:22:49
流程结束时间:2017-09-24 23:25:33
流程定义id:LeaveFlow:1:4
流程开始时间:2017-09-24 22:37:48
流程结束时间:2017-09-24 22:38:44
*/
@Test
public void processDefinitionHistoryTest() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
HistoryService historyService = processEngine.getHistoryService();
HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery();
String processDefinitionKey="LeaveFlow";
List<HistoricProcessInstance> list =
processInstanceQuery.processDefinitionKey(processDefinitionKey)//通过流程定义的key过滤
.finished()//查询已经完成的
.list();
for (HistoricProcessInstance hp : list) {
System.out.println("流程定义id:"+hp.getProcessDefinitionId());
System.out.println("流程开始时间:"+getDateStr(hp.getStartTime()));
System.out.println("流程结束时间:"+getDateStr(hp.getEndTime()));
}
}
说明:
1.通常查询历史流程实例都需要指定一个过滤条件,指定 processDefinitionId查看具体某一次部署所开启的流程或者指定 processDefinitionKey查看某个规则下不限版本的所有流程
2.可以选择性添加finished方法控制是否查询未完成的流程实例。在流 程开启时,activiti同时在act_ru_execution表和act_hi_procinst表中 创建了一条记录,在流程完成之前act_hi_procinst表中实例的结束时间 为空
2.查看历史流程活动
查看某次流程的执行执行经历。
/**
* 活动实历史:
* 活动id:2502
活动开始时间:2017-09-24 22:37:48
活动结束时间:2017-09-24 22:37:48
活动名字:Start
=================================
活动id:2503
活动开始时间:2017-09-24 22:37:48
活动结束时间:2017-09-24 22:37:57
活动名字:员工请假
=================================
活动id:5001
活动开始时间:2017-09-24 22:37:57
活动结束时间:2017-09-24 22:38:44
活动名字:助理审批
=================================
活动id:7501
活动开始时间:2017-09-24 22:38:44
活动结束时间:2017-09-24 22:38:44
活动名字:End
=================================
*/
@Test
public void activityInstanceTest() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
HistoryService historyService = processEngine.getHistoryService();
HistoricActivityInstanceQuery activityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
String processInstanceId="12501";
List<HistoricActivityInstance> list =
activityInstanceQuery.processInstanceId(processInstanceId)//流程实例id过滤
.list();
for (HistoricActivityInstance ha : list) {
System.out.println("活动id:"+ha.getId());
System.out.println("活动开始时间:"+getDateStr(ha.getStartTime()));
System.out.println("活动结束时间:"+getDateStr(ha.getEndTime()));
System.out.println("活动名字:"+ha.getActivityName());
System.out.println("=================================");
}
}
private String getDateStr(Date date){
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return simpleDateFormat.format(date);
}
说明:
1.通常查询历史流程活动都需要指定一个过滤条件,指定processInstanceId查看具体某一次流程执行过程中所经历的步奏
为什么要单独提出历史:
操作比较多少正在执行,已经执行操作比较少,采用分而治之的思想把正在执行的和历史分开管理提高效率。
历史的内容
HistoricProcessInstance 包含流程实例信息。
HistoricActivityInstance 包含一个活动(流程上的节点)的执行信息 。
怎么查询?-单独使用一个服务操作它 historyServcie