Activity workflow study notes

1. Activiti database support

Table Name effect
act_re_* "re" means repository. These tables contain process definitions and process static resources (pictures, rules, etc.)
act_ru_* "ru" means runtime. These runtime tables contain running data such as process instances, tasks, variables, and asynchronous tasks. Activiti only saves these data during the execution of the process instance, and deletes these records at the end of the process.
act_hi_* "hi" means history. These tables contain historical data such as historical process instances, variables, tasks, etc.
act_ge_* "ge" means general. General data, used in different scenarios, such as storing resource files.

Two, table structure operation

Repository Process Rules Table

Table Name effect
act_re_deployment Deployment Information Sheet
act_re_model Process Design Model Deployment Table
act_re_procdef Process Definition Data Sheet

runtime database table

Table Name effect
act_ru_execution Runtime process execution instance table
act_ru_identitylink Runtime process personnel table, which mainly stores information about task nodes and participants
act_ru_task Runtime task node table
act_ru_variable Runtime Process Variable Data Table

History database table

Table Name effect
act_hi_actinst History node table
act_hi_attachment History Attachment Sheet
act_hi_comment Historical Comment Form
act_hi_identitylink Historical process personnel list
act_hi_detail Historical details table, providing query of historical variables
act_hi_procinst Historical Process Instance Table
act_hi_taskinst Historical Task Instance Table
act_hi_varinst Historical variable table

Organizational Structure Table (removed in version 7.0)

Table Name effect
act_id_group User Group Information Form
act_id_info User Extension Information Form
act_id_membership User and user group correspondence information table
act_id_user User Information Form

Note: These four tables are very common. For basic organizational management, it is recommended to develop a set by yourself for user authentication. The functions that come with the components are too simple, and there are many requirements that are difficult to meet during use.

General Data Sheet

act_ge_bytearray binary data table

The act_ge_property attribute data table stores data at the entire process engine level. When initializing the table structure, three records will be inserted by default

activiti.cfg.xml (configuration file)

Activiti core configuration file, which configures the basic parameters of the process engine creation tool and the parameters of the database connection pool.

Define the database configuration parameters:

parameter name effect
jdbcUrl The JDBC URL of the database
jdbcDriver Drivers for different database types
jdbcUsername The username to connect to the database
jdbcPassword Password to connect to the database

The database connection configured based on JDBC parameters will use the default MyBatis connection pool. The following parameters can be used to configure the connection pool (from MyBatis parameters):

jdbcMaxActiveConnections: The maximum number of connections in the connection pool being used. The default is 10.

jdbcMaxIdleConnections: The maximum number of idle connections in the connection pool.

jdbcMaxCheckoutTime: The maximum time for the connection to be taken out. If the time is exceeded, it will be forcibly recycled. Defaults to 20000 (20 seconds).

dbcMaxWaitTime: This is an underlying configuration that allows the connection pool to print a log and retry to obtain a connection when it cannot obtain a connection for a long time. (to avoid silent operation failures due to misconfiguration). Defaults to 20000 (20 seconds).

Example database configuration:

javax.sql.DataSource can also be used. (e.g. Apache Commons' DBCP):

3. Core API

ProcessEngine

Description: The core class in Activiti, other classes come from him

The role of each Service interface (this is the interface of version 7.0)

interface effect
RepositoryService Management Process Definition
RuntimeService Execution management, including operations such as starting, advancing, and deleting process instances
TaskService task management
HistoryService History management (management of executed data)
ManagerService Engine Management

RepositoryService

是Activiti的仓库服务类。所谓的仓库指流程定义文档的两个文件:bpmn文件和流程图片。

产生方式

可以产生DeploymentBuilder,用来定义流程部署的相关参数

删除流程定义

RuntimeService

是activiti的流程执行服务类。可以从这个服务类中获取很多关于流程执行相关的信息。

TaskService

是activiti的任务服务类。可以从这个类中获取任务的信息。

HistoryService

是activiti的查询历史信息的类。在一个流程执行完成后,这个对象为我们提供查询历史信息。

ProcessDefinition

流程定义类。可以从这里获得资源文件等。

ProcessInstance

代表流程定义的执行实例。如范冰冰请了一天的假,她就必须发出一个流程实例的申请。一个流程实例包括了所有的运行节点。我们可以利用这个对象来了解当前流程实例的进度等信息。流程实例就表示一个流程从开始到结束的最大的流程分支,即一个流程中流程实例只有一个

Execution

​ Activiti用这个对象去描述流程执行的每一个节点。在没有并发的情况下,Execution就是同ProcessInstance。流程按照流程定义的规则执行一次的过程,就可以表示执行对象Execution。

​ 如图为ProcessInstance的源代码:

​ 从源代码中可以看出ProcessInstance就是Execution。但在现实意义上有所区别:

在单线流程中,如上图的贷款流程,ProcessInstance与Execution是一致的。
​
​ 这个例子有一个特点:wire money(汇钱)和archive(存档)是并发执行的。 这个时候,总线路代表ProcessInstance,而分线路中每个活动代表Execution。

总结:

一个流程中,执行对象可以存在多个,但是流程实例只能有一个。

当流程按照规则只执行一次的时候,那么流程实例就是执行对象。

四、一些注意知识点

查看流程定义

查询流程定义的信息

结果:

再部署一次运行结果为:

可以看到流程定义的key值相同的情况下,版本是从1开始逐次升级的

流程定义的Id是【key:版本:生成ID】

​ 说明:

  1. 流程定义和部署对象相关的Service都是RepositoryService。

  2. 创建流程定义查询对象,可以在ProcessDefinitionQuery上设置查询的相关参数

  3. 调用ProcessDefinitionQuery对象的list方法,执行查询,获得符合条件的流程定义列表

  4. 由运行结果可以看出:

Key和Name的值为:bpmn文件process节点的id和name的属性值

5) key属性被用来区别不同的流程定义。

  1. 带有特定key的流程定义第一次部署时,version为1。之后每次部署都会在当前最高版本号上加1

  2. Id的值的生成规则为:{processDefinitionKey}:{processDefinitionVersion}:{generated-id}, 这里的generated-id是一个自动生成的唯一的数字

  3. 重复部署一次,deploymentId的值以一定的形式变化,规则act_ge_property表生成

流程变量

流程变量在整个工作流中扮演很重要的作用。例如:请假流程中有请假天数、请假原因等一些参数都为流程变量的范围。流程变量的作用域范围是只对应一个流程实例。也就是说各个流程实例的流程变量是不相互影响的。流程实例结束完成以后流程变量还保存在数据库中(存放到流程变量的历史表中)。

​ 例如:

即:

活动

排他网关(ExclusiveGateWay)

流程图
12.2:部署流程定义+启动流程实例
12.3:查询我的个人任务
12.4:完成我的个人任务
说明:

  1. 一个排他网关对应一个以上的顺序流

  2. 由排他网关流出的顺序流都有个conditionExpression元素,在内部维护返回boolean类型的决策结果。

  3. 决策网关只会返回一条结果。当流程执行到排他网关时,流程引擎会自动检索网关出口,从上到下检索如果发现第一条决策结果为true或者没有设置条件的(默认为成立),则流出。

  4. 如果没有任何一个出口符合条件,则抛出异常

  5. 使用流程变量,设置连线的条件,并按照连线的条件执行工作流,如果没有条件符合的条件,则以默认的连线离开。例如:
    则执行连线:
    如果使用流程变量设置
    则执行连线:

并行网关(ParallelGateWay)

流程图
部署流程定义+启动流程实例
查询我的个人任务
完成我的个人任务
说明:

1) 一个流程中流程实例只有1个,执行对象有多个

2) 并行网关的功能是基于进入和外出的顺序流的:

分支(fork): 并行后的所有外出顺序流,为每个顺序流都创建一个并发分支。

汇聚(join): 所有到达并行网关,在此等待的进入分支, 直到所有进入顺序流的分支都到达以后, 流程就会通过汇聚网关。

3) 并行网关的进入和外出都是使用相同节点标识

4) 如果同一个并行网关有多个进入和多个外出顺序流, 它就同时具有分支和汇聚功能。 这时,网关会先汇聚所有进入的顺序流,然后再切分成多个并行分支。

5) 并行网关不会解析条件。 即使顺序流中定义了条件,也会被忽略。

并行网关不需要是“平衡的”(比如, 对应并行网关的进入和外出节点数目不一定相等)。如图中标示是合法的:

用户任务(userTask,即用户操作的任务)

个人任务

流程图

分配个人任务方式一(直接指定办理人)

1:流程图中任务节点的配置
2:测试代码:

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

	//部署流程定义,启动流程实例
	@Test
	public void testTask() throws Exception {
    
    
		// 1 发布流程
		InputStream inputStreamBpmn = this.getClass().getResourceAsStream("taskProcess.bpmn");
		InputStream inputStreamPng = this.getClass().getResourceAsStream("taskProcess.png");

		processEngine.getRepositoryService()//
						.createDeployment()//
						.addInputStream("userTask.bpmn", inputStreamBpmn)
						.addInputStream("userTask.png", inputStreamPng)
						.deploy();		
    	// 2 启动流程
		//启动流程实例的同时,设置流程变量
		ProcessInstance pi = processEngine.getRuntimeService()
						.startProcessInstanceByKey("taskProcess");
		System.out.println("pid:" + pi.getId());
	}

	//查询我的个人任务列表
	@Test
	public void findMyTaskList(){
    
    
		String userId = "张三丰";
		List<Task> list = processEngine.getTaskService()
		        .createTaskQuery()
		        .taskAssignee(userId)//指定个人任务查询
		        .list();
		for(Task task:list ){
    
    
			System.out.println("id="+task.getId());
			System.out.println("name="+task.getName());
			System.out.println("assinee="+task.getAssignee());
			System.out.println("createTime="+task.getCreateTime());
			System.out.println("executionId="+task.getExecutionId());
		}
	}

	//完成任务
	@Test
	public void completeTask(){
    
    
		String taskId = "3209";
		processEngine.getTaskService()
					.complete(taskId);
		System.out.println("完成任务");
	}

说明:

1) 张三丰是个人任务的办理人

2) 但是这样分配任务的办理人不够灵活,因为项目开发中任务的办理人不要放置XML文件中。

分配个人任务方式二(使用流程变量)

1:流程图中任务节点的配置
2:测试代码

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

	//部署流程定义,启动流程实例
	@Test
	public void testTask() throws Exception {
    
    
		// 1 发布流程
		InputStream inputStreamBpmn = this.getClass().getResourceAsStream("taskProcess.bpmn");
		InputStream inputStreamPng = this.getClass().getResourceAsStream("taskProcess.png");

		processEngine.getRepositoryService()//
						.createDeployment()//
						.addInputStream("userTask.bpmn", inputStreamBpmn)
						.addInputStream("userTask.png", inputStreamPng)
						.deploy();		
    	// 2 启动流程
		//启动流程实例的同时,设置流程变量
		Map<String, Object> variables = new HashMap<String, Object>();
		variables.put("userID", "张翠三");
		ProcessInstance pi = processEngine.getRuntimeService()
						.startProcessInstanceByKey("taskProcess",variables);
		System.out.println("pid:" + pi.getId());
	}
	
	//查询我的个人任务列表
	@Test
	public void findMyTaskList(){
    
    
		String userId = "张翠三";
		List<Task> list = processEngine.getTaskService()
		        .createTaskQuery()
		        .taskAssignee(userId)//指定个人任务查询
		        .list();
		for(Task task:list ){
    
    
			System.out.println("id="+task.getId());
			System.out.println("name="+task.getName());
			System.out.println("assinee="+task.getAssignee());
			System.out.println("createTime="+task.getCreateTime());
			System.out.println("executionId="+task.getExecutionId());
		}
	}
	
	//完成任务
	@Test
	public void completeTask(){
    
    
		String taskId = "3209";
		processEngine.getTaskService()
					.complete(taskId);
		System.out.println("完成任务");
	}

说明:

1) 张翠山是个人任务的办理人

2) 在开发中,可以在页面中指定下一个任务的办理人,通过流程变量设置下一个任务的办理人

分配个人任务方式三(使用类)

1:流程图中任务节点的配置

此时流程图的XML文件,如图:
2:TaskListenerImpl类,用来设置任务的办理人

public class TaskListenerImpl implements TaskListener {
    
    
	
   	/**指定个人任务和组任务的办理人*/
	@Override
	public void notify(DelegateTask delegateTask) {
    
    
		String assignee = "张无忌";
		//指定个人任务
		delegateTask.setAssignee(assignee);
	}
}

3:测试代码

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

	//部署流程定义,启动流程实例
	@Test
	public void testTask() throws Exception {
    
    
		// 1 发布流程
		InputStream inputStreamBpmn = this.getClass().getResourceAsStream("taskProcess.bpmn");
		InputStream inputStreamPng = this.getClass().getResourceAsStream("taskProcess.png");

		processEngine.getRepositoryService()//
						.createDeployment()//
						.addInputStream("userTask.bpmn", inputStreamBpmn)
						.addInputStream("userTask.png", inputStreamPng)
						.deploy();		
    	// 2 启动流程
		ProcessInstance pi = processEngine.getRuntimeService()
						.startProcessInstanceByKey("taskProcess",variables);
		System.out.println("pid:" + pi.getId());
	}
	
	//查询我的个人任务列表
	@Test
	public void findMyTaskList(){
    
    
		String userId = "张无忌";
		List<Task> list = processEngine.getTaskService()
		        .createTaskQuery()
		        .taskAssignee(userId)//指定个人任务查询
		        .list();
		for(Task task:list ){
    
    
			System.out.println("id="+task.getId());
			System.out.println("name="+task.getName());
			System.out.println("assinee="+task.getAssignee());
			System.out.println("createTime="+task.getCreateTime());
			System.out.println("executionId="+task.getExecutionId());
		}
	}
	
	//完成任务
	@Test
	public void completeTask(){
    
    
		String taskId = "3408";
		processEngine.getTaskService()
					.complete(taskId);
		System.out.println("完成任务");
	}
	
	//可以分配个人任务从一个人到另一个人(认领任务)
	@Test
	public void setAssigneeTask(){
    
    
		//任务ID
		String taskId = "3408";
		//指定认领的办理者
		String userId = "周芷若";
		processEngine.getTaskService()//
					.setAssignee(taskId, userId);
    }

说明:

1) 在类中使用delegateTask.setAssignee(assignee);的方式分配个人任务的办理人,此时张无忌是下一个任务的办理人

2) 通过processEngine.getTaskService().setAssignee(taskId, userId);将个人任务从一个人分配给另一个人,此时张无忌不再是下一个任务的办理人,而换成了周芷若

3) 在开发中,可以将每一个任务的办理人规定好,例如张三的领导是李四,李四的领导是王五,这样张三提交任务,就可以查询出张三的领导是李四,通过类的方式设置下一个任务的办理人

总结

个人任务及三种分配方式

1:在taskProcess.bpmn中直接写 assignee=“张三丰"

2:在taskProcess.bpmn中写 assignee=“#{userID}”,变量的值要是String的。

​ 使用流程变量指定办理人

3,使用TaskListener接口,要使类实现该接口,在类中定义:

delegateTask.setAssignee(assignee);// 指定个人任务的办理人

使用任务ID和办理人重新指定办理人:

processEngine.getTaskService()
         .setAssignee(taskId, userId);

组任务

流程图

分配组任务方式一(直接指定办理人)

1:流程图中任务节点的配置
2:测试代码:

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

	//部署流程定义,启动流程实例
	@Test
	public void testTask() throws Exception {
    
    
		// 1 发布流程
		InputStream inputStreamBpmn = this.getClass().getResourceAsStream("taskProcess.bpmn");
		InputStream inputStreamPng = this.getClass().getResourceAsStream("taskProcess.png");

		processEngine.getRepositoryService()//
						.createDeployment()//
						.addInputStream("userTask.bpmn", inputStreamBpmn)
						.addInputStream("userTask.png", inputStreamPng)
						.deploy();		
    	// 2 启动流程
		//启动流程实例的同时,设置流程变量
		ProcessInstance pi = processEngine.getRuntimeService()
						.startProcessInstanceByKey("taskProcess",variables);
		System.out.println("pid:" + pi.getId());
	}

	//3 查询我的个人任务列表
	@Test
	public void findMyTaskList(){
    
    
		String userId = "小A";
		List<Task> list = processEngine.getTaskService()
		        .createTaskQuery()
		        .taskAssignee(userId)//指定个人任务查询
		        .list();
		for(Task task:list ){
    
    
			System.out.println("id="+task.getId());
			System.out.println("name="+task.getName());
			System.out.println("assinee="+task.getAssignee());
			System.out.println("createTime="+task.getCreateTime());
			System.out.println("executionId="+task.getExecutionId());
		}
	}

	//4 查询组任务列表
 	@Test
 	public void findGroupList(){
    
    
		String userId = "小A";
		List<Task> list = processEngine.getTaskService()
 		        .createTaskQuery()
 		        .taskCandidateUser(userId)//指定组任务查询
 		        .list();
 		for(Task task:list ){
    
    
 			System.out.println("id="+task.getId());
 			System.out.println("name="+task.getName());
 			System.out.println("assinee="+task.getAssignee());
 			System.out.println("createTime ="+task.getCreateTime());
 			System.out.println("executionId="+task.getExecutionId());
 			System.out.println("##################################");
 		}
	}

	//5 查询组任务成员列表
	@Test
	public void findGroupUser(){
    
    
		String taskId = "3709";
		List<IdentityLink> list = processEngine.getTaskService()
		        .getIdentityLinksForTask(taskId);
    	//List<IdentityLink> list = processEngine.getRuntimeService()
		//				.getIdentityLinksForProcessInstance(instanceId);
		for(IdentityLink identityLink:list ){
    
    
			System.out.println("userId="+identityLink.getUserId());
			System.out.println("taskId="+identityLink.getTaskId());
			System.out.println("piId="+identityLink.getProcessInstanceId());
			System.out.println("######################");
		}
	}

	//6 查询组任务成员历史列表
	@Test
	public void findGroupHisUser(){
    
    
		String taskId = "3709";
		List<HistoricIdentityLink> list = processEngine.getHistoryService()
						.getHistoricIdentityLinksForTask(taskId);
    	// List<HistoricIdentityLink> list = processEngine.getHistoryService()
        	// .getHistoricIdentityLinksForProcessInstance(processInstanceId);

		for(HistoricIdentityLink identityLink:list ){
    
    
			System.out.println("userId="+identityLink.getUserId());
			System.out.println("taskId="+identityLink.getTaskId());
			System.out.println("piId="+identityLink.getProcessInstanceId());
			System.out.println("######################");
		}
	}	
	
	//完成任务
	@Test
	public void completeTask(){
    
    
		String taskId = "3709";
		processEngine.getTaskService()
					.complete(taskId);
		System.out.println("完成任务");
	}

 

   /**将组任务分配给个人任务,拾取任务*/
	//由1个人去完成任务
	@Test
	public void claim(){
    
    
		//任务ID
		String taskId = "5908";
		//分配的办理人
		String userId = "小B";
		processEngine.getTaskService()
					.claim(taskId, userId);
	}

说明:

1) 小A,小B,小C,小D是组任务的办理人

2) 但是这样分配组任务的办理人不够灵活,因为项目开发中任务的办理人不要放置XML文件中。

3) act_ru_identitylink表存放任务的办理人,包括个人任务和组任务,表示正在执行的任务

4) act_hi_identitylink表存放任务的办理人,包括个人任务和组任务,表示历史任务

区别在于:如果是个人任务TYPE的类型表示participant(参与者)

​ 如果是组任务TYPE的类型表示candidate(候选者)和participant(参与者)

分配个人任务方式二(使用流程变量)

1:流程图中任务节点的配置
2:测试代码

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

	//部署流程定义,启动流程实例
	@Test
	public void testTask() throws Exception {
    
    
		// 1 发布流程
		InputStream inputStreamBpmn = this.getClass().getResourceAsStream("taskProcess.bpmn");
		InputStream inputStreamPng = this.getClass().getResourceAsStream("taskProcess.png");

		processEngine.getRepositoryService()//
						.createDeployment()//
						.addInputStream("userTask.bpmn", inputStreamBpmn)
						.addInputStream("userTask.png", inputStreamPng)
						.deploy();		
    	// 2 启动流程
		//启动流程实例的同时,设置流程变量,用来指定组任务的办理人
		Map<String, Object> variables = new HashMap<String, Object>();
		variables.put("userIDs", "大大,小小,中中");
		ProcessInstance pi = processEngine.getRuntimeService()
						.startProcessInstanceByKey("taskProcess",variables);
		System.out.println("pid:" + pi.getId());
	}

	//3 查询我的个人任务列表
	@Test
	public void findMyTaskList(){
    
    
		String userId = "大大";
		List<Task> list = processEngine.getTaskService()
		        .createTaskQuery()
		        .taskAssignee(userId)//指定个人任务查询
		        .list();
		for(Task task:list ){
    
    
			System.out.println("id="+task.getId());
			System.out.println("name="+task.getName());
			System.out.println("assinee="+task.getAssignee());
			System.out.println("createTime="+task.getCreateTime());
			System.out.println("executionId="+task.getExecutionId());
		}
	}

	//4 查询组任务列表
 	@Test
 	public void findGroupList(){
    
    
		String userId = "大大";
		List<Task> list = processEngine.getTaskService()
 		        .createTaskQuery()
 		        .taskCandidateUser(userId)//指定组任务查询
 		        .list();
 		for(Task task:list ){
    
    
 			System.out.println("id="+task.getId());
 			System.out.println("name="+task.getName());
 			System.out.println("assinee="+task.getAssignee());
 			System.out.println("createTime ="+task.getCreateTime());
 			System.out.println("executionId="+task.getExecutionId());
 			System.out.println("##################################");
 		}
	}

	//5 查询组任务成员列表
	@Test
	public void findGroupUser(){
    
    
		String taskId = "3709";
		List<IdentityLink> list = processEngine.getTaskService()
		        .getIdentityLinksForTask(taskId);
    	//List<IdentityLink> list = processEngine.getRuntimeService()
		//				.getIdentityLinksForProcessInstance(instanceId);
		for(IdentityLink identityLink:list ){
    
    
			System.out.println("userId="+identityLink.getUserId());
			System.out.println("taskId="+identityLink.getTaskId());
			System.out.println("piId="+identityLink.getProcessInstanceId());
			System.out.println("######################");
		}
	}

	//6 查询组任务成员历史列表
	@Test
	public void findGroupHisUser(){
    
    
		String taskId = "3709";
		List<HistoricIdentityLink> list = processEngine.getHistoryService()
						.getHistoricIdentityLinksForTask(taskId);
    	// List<HistoricIdentityLink> list = processEngine.getHistoryService()
        	// .getHistoricIdentityLinksForProcessInstance(processInstanceId);

		for(HistoricIdentityLink identityLink:list ){
    
    
			System.out.println("userId="+identityLink.getUserId());
			System.out.println("taskId="+identityLink.getTaskId());
			System.out.println("piId="+identityLink.getProcessInstanceId());
			System.out.println("######################");
		}
	}	
	
	//完成任务
	@Test
	public void completeTask(){
    
    
		String taskId = "3709";
		processEngine.getTaskService()
					.complete(taskId);
		System.out.println("完成任务");
	}

 

   /**将组任务分配给个人任务,拾取任务*/
	//由1个人去完成任务
	@Test
	public void claim(){
    
    
		//任务ID
		String taskId = "5908";
		//分配的办理人
		String userId = "小B";
		processEngine.getTaskService()
					.claim(taskId, userId);
	}

说明:

1) 大大,中中,小小是组任务的办理人

2) 在开发中,可以在页面中指定下一个组任务的办理人,通过流程变量设置下一个任务的办理人

分配个人任务方式三(使用类)

1:流程图中任务节点的配置

此时流程图的XML文件,如图:
2:TaskListenerImpl类,用来设置任务的办理人

public class TaskListenerImpl implements TaskListener {
    
    

	/**指定个人任务和组任务的办理人*/
	@Override
	public void notify(DelegateTask delegateTask) {
    
    
		String userId1 = "孙悟空";
		String userId2 = "猪八戒";
		//指定组任务
		delegateTask.addCandidateUser(userId1);
		delegateTask.addCandidateUser(userId2);
	}
}

3:测试代码

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

	//部署流程定义,启动流程实例
	@Test
	public void testTask() throws Exception {
    
    
		// 1 发布流程
		InputStream inputStreamBpmn = this.getClass().getResourceAsStream("taskProcess.bpmn");
		InputStream inputStreamPng = this.getClass().getResourceAsStream("taskProcess.png");

		processEngine.getRepositoryService()//
						.createDeployment()//
						.addInputStream("userTask.bpmn", inputStreamBpmn)
						.addInputStream("userTask.png", inputStreamPng)
						.deploy();		
    	// 2 启动流程
		ProcessInstance pi = processEngine.getRuntimeService()
						.startProcessInstanceByKey("taskProcess",variables);
		System.out.println("pid:" + pi.getId());
	}

	//3 查询我的个人任务列表
	@Test
	public void findMyTaskList(){
    
    
		String userId = "孙悟空";
		List<Task> list = processEngine.getTaskService()
		        .createTaskQuery()
		        .taskAssignee(userId)//指定个人任务查询
		        .list();
		for(Task task:list ){
    
    
			System.out.println("id="+task.getId());
			System.out.println("name="+task.getName());
			System.out.println("assinee="+task.getAssignee());
			System.out.println("createTime="+task.getCreateTime());
			System.out.println("executionId="+task.getExecutionId());
		}
	}

	//4 查询组任务列表
 	@Test
 	public void findGroupList(){
    
    
		String userId = "孙悟空";
		List<Task> list = processEngine.getTaskService()
 		        .createTaskQuery()
 		        .taskCandidateUser(userId)//指定组任务查询
 		        .list();
 		for(Task task:list ){
    
    
 			System.out.println("id="+task.getId());
 			System.out.println("name="+task.getName());
 			System.out.println("assinee="+task.getAssignee());
 			System.out.println("createTime ="+task.getCreateTime());
 			System.out.println("executionId="+task.getExecutionId());
 			System.out.println("##################################");
 		}
	}

	//5 查询组任务成员列表
	@Test
	public void findGroupUser(){
    
    
		String taskId = "4008";
		List<IdentityLink> list = processEngine.getTaskService()
		        .getIdentityLinksForTask(taskId);
		for(IdentityLink identityLink:list ){
    
    
			System.out.println("userId="+identityLink.getUserId());
			System.out.println("taskId="+identityLink.getTaskId());
			System.out.println("piId="+identityLink.getProcessInstanceId());
			System.out.println("######################");
		}
	}

	//6 查询组任务成员历史列表
	@Test
	public void findGroupHisUser(){
    
    
		String taskId = "4008";
		List<HistoricIdentityLink> list = processEngine.getHistoryService()
						.getHistoricIdentityLinksForTask(taskId);
		for(HistoricIdentityLink identityLink:list ){
    
    
			System.out.println("userId="+identityLink.getUserId());
			System.out.println("taskId="+identityLink.getTaskId());
			System.out.println("piId="+identityLink.getProcessInstanceId());
			System.out.println("######################");
		}
	}	
	
	//完成任务
	@Test
	public void completeTask(){
    
    
		String taskId = "4008";
		processEngine.getTaskService()
					.complete(taskId);
		System.out.println("完成任务");
	}

   //将组任务分配给个人任务(认领任务)
	@Test
	public void claim(){
    
    
		//任务ID
		String taskId = "4008";
		//个人任务的办理人
		String userId = "如来";
		processEngine.getTaskService()
					.claim(taskId, userId);
	}

	//可以分配个人任务回退到组任务,(前提之前是个组任务)
	@Test
	public void setAssigneeTask(){
    
    
		//任务ID
		String taskId = "4008";
		processEngine.getTaskService()
					.setAssignee(taskId, null);
	}

	//向组任务中添加成员
	@Test
	public void addUser(){
    
    
		String taskId = "4008";
		String userId = "沙和尚";
		processEngine.getTaskService().addCandidateUser(taskId, userId);
	}

	//向组任务中删除成员
	@Test
	public void removeUser(){
    
    
		String taskId = "4008";
		String userId = "沙和尚";
		processEngine.getTaskService().deleteCandidateUser(taskId, userId);
	}

说明:

1) 在类中使用delegateTask.addCandidateUser (userId);的方式分配组任务的办理人,此时孙悟空和猪八戒是下一个任务的办理人。

2) 通过processEngine.getTaskService().claim (taskId, userId);将组任务分配给个人任务,也叫认领任务,即指定某个人去办理这个任务,此时由如来去办理任务。

注意:认领任务的时候,可以是组任务成员中的人,也可以不是组任务成员的人,此时通过Type的类型为participant来指定任务的办理人

3) addCandidateUser()即向组任务添加成员,deleteCandidateUser()即删除组任务的成员。

在开发中,可以将每一个任务的办理人规定好,例如张三的领导是李四和王五,这样张三提交任务,由李四或者王五去查询组任务,可以看到对应张三的申请,李四或王五再通过认领任务(claim)的方式,由某个人去完成这个任务。

总结

组任务及三种分配方式:

1:在taskProcess.bpmn中直接写 candidate-users=“小A,小B,小C,小D"

2:在taskProcess.bpmn中写 candidate-users =“#{userIDs}”,变量的值要是String的。


使用流程变量指定办理人

Map<String, Object> variables = new HashMap<String, Object>();
variables.put("userIDs", "大大,小小,中中");

3,使用TaskListener接口,使用类实现该接口,在类中定义:

添加组任务的用户

delegateTask.addCandidateUser(userId1);
delegateTask.addCandidateUser(userId2);

组任务分配给个人任务(认领任务):

processEngine.getTaskService().claim(taskId, userId);

个人任务分配给组任务:

processEngine.getTaskService(). setAssignee(taskId, null);

向组任务添加人员:

processEngine.getTaskService().addCandidateUser(taskId, userId);

向组任务删除人员:

processEngine.getTaskService().deleteCandidateUser(taskId, userId);

个人任务和组任务存放办理人对应的表:

act_ru_identitylink表存放任务的办理人,包括个人任务和组任务,表示正在执行的任务

act_hi_identitylink表存放任务的办理人,包括个人任务和组任务,表示历史任务

区别在于:如果是个人任务TYPE的类型表示participant(参与者)

​ 如果是组任务TYPE的类型表示candidate(候选者)和participant(参与者)

工作流定义的角色组(了解)

流程图

流程图中任务节点的配置:
分配任务负责的组

使用 candidate groups属性指定 任务负责组

代码:

<userTask id="usertask1" name="审批" **activiti:candidateGroups="部门经理">
</userTask>   

其中部门经理表示一个用户组的角色

测试代码

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

	//部署流程定义,启动流程实例
	@Test
	public void testTask() throws Exception {
    
    
		// 1 发布流程
		InputStream inputStreamBpmn = this.getClass().getResourceAsStream("taskProcess.bpmn");
		InputStream inputStreamPng = this.getClass().getResourceAsStream("taskProcess.png");

		processEngine.getRepositoryService()//
						.createDeployment()//
						.addInputStream("userTask.bpmn", inputStreamBpmn)
						.addInputStream("userTask.png", inputStreamPng)
						.deploy();		
		/**在部署流程定义和启动流程实例的中间,设置组任务的办理人,向Activity表中存放组和用户的信息**/
		IdentityService identityService = processEngine.getIdentityService();//认证:保存组和用户信息
		identityService.saveGroup(new GroupEntity("部门经理"));//建立组
		identityService.saveGroup(new*GroupEntity("总经理"));//建立组
		identityService.saveUser(new UserEntity("小张"));//建立用户
		identityService.saveUser(new UserEntity("小李"));//建立用户
		identityService.saveUser(new UserEntity("小王"));//建立用户
		identityService.createMembership("小张", "部门经理");//建立组和用户关系
		identityService.createMembership("小李", "部门经理");//建立组和用户关系
		identityService.createMembership("小王", "总经理");//建立组和用户关系
		
        // 2 启动流程
		ProcessInstance pi = processEngine.getRuntimeService()
						.startProcessInstanceByKey("taskProcess",variables);
		System.out.println("pid:" + pi.getId());
	}

	//3 查询我的个人任务列表
	@Test
	public void findMyTaskList(){
    
    
		String userId = "唐僧";
		List<Task> list = processEngine.getTaskService()
		        .createTaskQuery()
		        .taskAssignee(userId)//指定个人任务查询
		        .list();
		for(Task task:list ){
    
    
			System.out.println("id="+task.getId());
			System.out.println("name="+task.getName());
			System.out.println("assinee="+task.getAssignee());
			System.out.println("createTime="+task.getCreateTime());
			System.out.println("executionId="+task.getExecutionId());
		}
	}

	//4 查询组任务列表
 	@Test
 	public void findGroupList(){
    
    
		String userId = "小李";//小张,小李可以查询结果,小王不可以,因为他不是部门经理
		List<Task> list = processEngine.getTaskService()
 		        .createTaskQuery()
 		        .taskCandidateUser(userId)//指定组任务查询
 		        .list();
 		for(Task task:list ){
    
    
 			System.out.println("id="+task.getId());
 			System.out.println("name="+task.getName());
 			System.out.println("assinee="+task.getAssignee());
 			System.out.println("createTime ="+task.getCreateTime());
 			System.out.println("executionId="+task.getExecutionId());
 			System.out.println("##################################");
 		}
	}

	//5 查询组任务成员列表
	@Test
	public void findGroupUser(){
    
    
		String taskId = "4408";
		List<IdentityLink> list = processEngine.getTaskService()
		        .getIdentityLinksForTask(taskId);
		for(IdentityLink identityLink:list ){
    
    
			System.out.println("userId="+identityLink.getUserId());
			System.out.println("taskId="+identityLink.getTaskId());
			System.out.println("piId="+identityLink.getProcessInstanceId());
			System.out.println("######################");
		}
	}

	//完成任务
	@Test
	public void completeTask(){
    
    
		String taskId = "5108";
		processEngine.getTaskService()
					.complete(taskId);
		System.out.println("完成任务");
	}
分配任务负责的组(IdentityService)
/**在部署流程定义和启动流程实例的中间,设置组任务的办理人,向Activity表中存放组和用户的信息**/
	IdentityService identityService = processEngine.getIdentityService();//认证:保存组和用户信息
	identityService.saveGroup(new GroupEntity("部门经理"));//建立组
	identityService.saveGroup(new*GroupEntity("总经理"));//建立组
	identityService.saveUser(new UserEntity("小张"));//建立用户
	identityService.saveUser(new UserEntity("小李"));//建立用户
	identityService.saveUser(new UserEntity("小王"));//建立用户
	identityService.createMembership("小张", "部门经理");//建立组和用户关系
	identityService.createMembership("小李", "部门经理");//建立组和用户关系
	identityService.createMembership("小王", "总经理");//建立组和用户关系

表结构介绍

act_id_group:角色组表

act_id_user:用户表

act_id_membership:用户角色表

指定组任务的办理人,查询组任务

String userId = "小李";//小张,小李可以查询结果,小王不可以,因为他不是部门经理
		List<Task> list = processEngine.getTaskService()
 		        .createTaskQuery()
 		        .taskCandidateUser(userId)//指定组任务查询
 		        .list();

五、总结

Deployment 部署对象

1、一次部署的多个文件的信息。对于不需要的流程可以删除和修改。

2、对应的表:

表名 作用
act_re_deployment 部署对象表
act_re_procdef 流程定义表
act_ge_bytearray 资源文件表
act_ge_property 主键生成策略表

ProcessDefinition 流程定义

1、解析.bpmn后得到的流程定义规则的信息,工作流系统就是按照流程定义的规则执行的。

Execution 执行对象

按流程定义的规则执行一次的过程.

对应的表:

表名 作用
act_ru_execution 正在执行的信息
act_hi_procinst 已经执行完的历史流程实例信息
act_hi_actinst 存放历史所有完成的活动

ProcessInstance 流程实例

特指流程从开始到结束的那个最大的执行分支,一个执行的流程中,流程实例只有1个。

注意

(1)如果是单例流程,执行对象ID就是流程实例ID

(2)如果一个流程有分支和聚合,那么执行对象ID和流程实例ID就不相同

(3)一个流程中,流程实例只有1个,执行对象可以存在多个。

Task 任务

执行到某任务环节时生成的任务信息。

对应的表:

表名 作用
act_ru_task 正在执行的任务信息
act_hi_taskinst 已经执行完的历史任务信息

流程变量

在流程执行或者任务执行的过程中,用于设置和获取变量,使用流程变量在流程传递的过程中传递业务参数。

对应的表:

表名 作用
act_ru_variable 正在执行的流程变量表
act_hi_varinst 流程变量历史表

扩展知识:setVariable和setVariableLocal的区别

setVariable:设置流程变量的时候,流程变量名称相同的时候,后一次的值替换前一次的值,而且可以看到TASK_ID的字段不会存放任务ID的值

setVariableLocal:

1:设置流程变量的时候,针对当前活动的节点设置流程变量,如果一个流程中存在2个活动节点(可理解为同时有两份请假申请需要处理),对每个活动节点都设置流程变量,即使流程变量的名称相同,后一次的版本的值也不会替换前一次版本的值,它会使用不同的任务ID作为标识,存放2个流程变量值,而且可以看到TASK_ID的字段会存放任务ID的值

例如act_hi_varinst 表的数据:不同的任务节点,即使流程变量名称相同,存放的值也是不同的。

如图:
2:还有,使用setVariableLocal说明流程变量绑定了当前的任务,当流程继续执行时,下个任务获取不到这个流程变量(因为正在执行的流程变量中没有这个数据),所有查询正在执行的任务时不能查询到我们需要的数据,此时需要查询历史的流程变量。

连线

1、一个活动中可以指定一个或多个SequenceFlow(Start中有一个,End中没有)。

* 开始活动中有一个SequenceFlow 。

* 结束活动中没有SequenceFlow 。

* 其他活动中有1条或多条SequenceFlow

2、如果只有一个,则可以不使用流程变量设置codition的名称;
如果有多个,则需要使用流程变量设置codition的名称。message表示流程变量的名称,‘不重要’表示流程变量的值,${}中间的内容要使用boolean类型的表达式,用来判断应该执行的连线。

六、一些有用的参考文章

activiti_小李子ING的博客-CSDN博客

userTask中MultiInstanceLoopCharacteristics设置collection_程序猿劝退狮的博客-CSDN博客

Activiti会签_Uself_的博客-CSDN博客_activiti会签

springboot整合activity6_Activiti之多用户任务分配(无废话版)--------------------------------------------(十五)_hunheidaode的博客-CSDN博客

activiti工作流5.22.0 多人会审功能实现_烫烫烫口的博客-CSDN博客_activiti5.22 加签

Activiti多人会签,1/3的人同意则审批通过的实现_狡猾的bug的博客-CSDN博客
参考代码项目
heartlhj/activiti-workflow: activiti工作流 (github.com)

Guess you like

Origin blog.csdn.net/weixin_51306597/article/details/125583963