Activiti工作流笔记

Activiti

介绍

processEngine是Activiti的工作核心,负责生成流程运动时的各种实例与数据。

一共涉及23张表,所有表都已ACT_开头。

ACT_RE_*:repository,包含流程定义和流程静态资源。

ACT_RU_*:runtime,运行时的表,包含实例、任务、变量、异步任务等运行时的数据。流程结束后会删除。

ACT_ID_*:identity,包含身份信息。

ACT_HI_*:history,包含历史数据,历史流程实例。

ACT_GE_*:通用数据,如资源文件。

起步

1.使用代码创建表:

                ProcessEngineConfiguration configuration = ProcessEngineConfiguration
				.createStandaloneProcessEngineConfiguration();//静态方法,相当于new单例的StandaloneProcessEngineConfiguration()
		configuration.setJdbcDriver("com.mysql.jdbc.Driver");
		configuration.setJdbcUrl("jdbc:mysql://localhost:3306/activiti_demo?useUnicode=true&characterEncoding=utf8");
		configuration.setJdbcUsername("xxx");
		configuration.setJdbcPassword("xxx");

		/*
		    public static final String DB_SCHEMA_UPDATE_FALSE = "false";不能自动创建表
			public static final String DB_SCHEMA_UPDATE_CREATE_DROP = "create-drop";先删除后建表
			public static final String DB_SCHEMA_UPDATE_TRUE = "true";自动创建表
		*/
		configuration.setDatabaseSchemaUpdate(configuration.DB_SCHEMA_UPDATE_TRUE);
		ProcessEngine processEngine = configuration.buildProcessEngine();// 创建表

2.配置文件创建表:

ProcessEngineConfiguration resource = ProcessEngineConfiguration
				.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
		ProcessEngine buildProcessEngine = resource.buildProcessEngine();

service

  1. RepositoryService    // 管理流程定义查询
  2. RuntimeService    // 执行管理,包括启动、推进、删除流程实例
  3. TaskService    // 任务管理
  4. HistoryService    // 历史管理
  5. IdentityService    // 组织机构管理
  6. FormService    // 一个可选服务,任务表单管理
  7. ManagerService


初体验

部署流程定义

// 1.得到流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();    // 默认加载classpath下activiti.cfg.xml文件

// 2.调用管理与部署的service
RepositoryService repositoryService = processEngine.getRepositoryService();    // 流程定义与部署对象相关的service

// 3.创建一个部署对象
repositoryService.createDeployment().name("helloword")
// 4.加载资源文件
.addClasspathResource("diagrams/helloword.bpmn")    // 加载bpmn文件
.addClasspathResource("diagrams/helloword.png")     // 加载png文件
// 部署
.deploy();

启动流程实例

流程引擎相同。

// 利用流程引擎得到servic
processEngine.getRuntimeService()
// 启动
.startProcessInstanceByKey(processDefinitionKey);    // 会返回ProcessInstance对象
注:使用流程定义的key启动,key对应的是.bpmn文件的id值。使用key启动可以自动的找到最新版本的流程实例进行启动(如果,同一个流程启动两次,那么版本就会叠加)。

查询个人任务

流程引擎相同。

// 利用流程引擎得到service
processEngine.getTaskService()
// 创建任务查询对象
.createTaskQuery()
// 指定查询条件
.taskAssignee("张三")    // 根据代办人查询
// 返回结果集
.list();    // 需用list接收


RepositoryService

部署时用的四张表

act_re_deployment:部署对象表

act_re_procdef:流程定义表

act_ge_bytearray:资源文件表

act_ge_property:主键生成策略表

说明:

  1. 先获取流程引擎对象:在创建时会自动加载classpath下的activit.cfg.xml
  2. 首先获取默认的流程引擎,通过流程引擎获取一个repositoryservice对象(仓库对象)
  3. 由仓库的服务对象产生一个部署对象配置对象,用来封装部署操作的相关配置
  4. 这是一个链式的操作,在部署对象配置对象在部署中设置显示名,上传流程定义规则文件
  5. 向数据库存放流程定义的规则信息
  6. 这一步在数据库中操作四张表
注:存储流程定义的部署信息,即流程定义文档存放地会一次增加两条记录一条是.bpmn结尾的文件(如果在部署时只指定了一个bpmn文件,则activiti会在部署时解析bpmn文件生成png图片进行存储),一个是png的文件,都是以二进制的方式存储在数据库中。

zip部署方式实例

        /**
	 * zip部署
	 */
	public void deployProcessDefinition() {
		InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("diagrams/helloword.zip");
		ZipInputStream zipInputStream = new ZipInputStream(resourceAsStream);
		
		Deployment deployment = processEngine.getRepositoryService()
		.createDeployment()
		.name("请假流程demo")
		.addZipInputStream(zipInputStream)
		.deploy();// 部署
		
		System.out.println("部署ID:"+deployment.getId());
		System.out.println("部署名称:"+deployment.getName());
	}

删除流程定义

// 实例流程引擎获取service,然后删除
processEngine.getRepositoryService().deleteDeployment("15001", true);

注:带有true是级联删除。反之只能删除没有启动的流程。

查看流程图

        /**
	 * 获取资源文件
	 * @throws IOException
	 */
	@Test
	public void viewPic() throws IOException {
		List list = processEngine.getRepositoryService()
		.getDeploymentResourceNames("1");// 根据id来获取名称,得到一个集合
		
		// 得到png文件的名称
		String resourceName = "";
		for (String name : list) {
			if(name.indexOf(".png")>0) {
				resourceName = name;
			}
		}
		
		// 获取数据流
		InputStream inputStream = processEngine.getRepositoryService()
		.getResourceAsStream("1", resourceName);
		
		// 利用org.apache.commons.io.FileUtils来完成写入
		FileUtils.copyInputStreamToFile(inputStream, new File("D:"+File.separator+resourceName));
	}

最新的流程实例小案例

问:查看最新的流程实例

思路:先查询出所有的流程实例,根据版本asc排序(最高版本就会在最底下)。把流程定义装进map中,key值设置为流程定义的key,value为流程定义对象(因为map有这个特性,会过替换掉key相同的,故只留下了最新的版本)。最后value转成list就行了。

代码实现如下:

        /**
	 * 查询最新的流程定义
	 */
	public void findLastVersionProcessDefinition() {
		
		List lists = processEngine.getRepositoryService()
		.createProcessDefinitionQuery()
		.orderByProcessDefinitionVersion()
		.asc()
		.list();
		
		Map map = new LinkedHashMap<>();
		if(lists.size()>0) {
			for (ProcessDefinition list : lists) {
				map.put(list.getKey(), list);
			}
		}
		
		List pdlist = new ArrayList<>(map.values());
		
		for (ProcessDefinition list : pdlist) {
			System.out.println("流程定义的ID:"+list.getId());
			System.out.println("流程定义的名称:"+list.getName());
			System.out.println("流程定义的key:"+list.getKey());
			System.out.println("流程定义的version:"+list.getVersion());
		}
	}


RuntimeService

ru表示正在执行的表

act_ru_axcution正在执行的对象表

结论:

1.如果是单例流程(没有分值的聚合),那么流程实例ID(ID_),和对象ID相同(reoc_inst_id_).

2.一个流程实例只有一个,执行对象可以有多个(存在分支和聚合的情况下)

具体的启动操作参见前面的初体验部分

查询参看taskservice部分


TaskService

关于的四张表:

act_hi_procinst:流程实例历史表

act_ru_task:正在执行的任务表(只有带节点是user_task的时候,该表中存在数据)

act_hi_taskinst:任务历史表

act_hi_actinst:所有活动的节点

查询

        /**
	 * 查询个人任务
	 */
	public void findMyPersonTask() {
		
		List list = processEngine.getTaskService() // 得到对应的service
		.createTaskQuery() // 创建任务查询对象
		.taskAssignee("张三")  // 根据代办人条件查询,相当于sql中的where
		.orderByTaskCreateTime()  // 设置排序条件,可以设置多个
		.asc() // 排序
		.list(); // 返回的结果集,有list()、count()、singleResult()等
		
	}

完成任务

processEngine.getTaskService()
		.complete("42502"); // 根据id来完成

说明:

  1. 因为是任务查询,所以用taskservice
  2. 获取任务查询对象createTaskQuery
  3. 为查询添加过滤条件,使用taskAssignee,同时添加其他过滤条件
  4. 调用list方法实行查询结果,返回结果集
  5. ID、名称、办理人、创建时间、从act_ru_task表中查到


流程变量

作用于一个流程实例。

设置变量的场景:

  1. getRuntimeService()的service中setVariable、setVariables...
  2. .getTaskService()的service中的setVariable、setVariables...
  3. 启动时设置:.startProcessInstanceByKey(processDefiniftion,variables)
  4. 完成任务时.eomplete(taskid,variables)

涉及的表:

act_ru_variable:正在执行的变量

act_hi_variable:你是流程变量表

获取变量同设置

代码演示:

        /**
	 * 设置流程变量
	 */
	public void setVariables() {
		TaskService taskService = processEngine.getTaskService();
		// 设置任务ID
		String taskid = "37504";
		taskService.setVariableLocal(taskid, "请假天数", 3);
		taskService.setVariable(taskid, "请假日期", new Date());
		taskService.setVariable(taskid, "请假原因", "回家探亲");
	}

        /**
	 * 获取流程变量
	 */
	public void getVariables() {
		TaskService taskService = processEngine.getTaskService();
		// 设置任务ID
		String taskid = "42502";
		
		Integer days = (Integer) taskService.getVariable(taskid, "请假天数");
		Object date = taskService.getVariable(taskid, "请假日期");
		String yuanyin = (String) taskService.getVariable(taskid, "请假原因");

               System.out.println("请假天数:"+days+"===请假日期:"+date+"===请假原因:"+yuanyin);
	}

注:

.setVariable和.setVariableLocal的区别:

第二个是与该节点试行绑定,到下一个就看不到。反之就是不绑定。

使用javabean设置流程变量

需要序列化。会存到act_ge_bytearray(资源表)

代码演示:

javabean:

public class Person implements Serializable{

	/**
	 * javabean
	 */
	private static final long serialVersionUID = 1L; // 设置版本号
	
	public Person() {
		
	}
	
	public Person(String id, String name) {
		this.id = id;
		this.name = name;
	}

	private String id;
	private String name;
	private String sex;
	
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}
设置变量:
        /**
	 * 设置流程变量
	 */
	public void setVariables() {
		TaskService taskService = processEngine.getTaskService();
		// 设置任务ID
		String taskid = "37504";
		
		taskService.setVariable(taskid, "人员信息", new Person(UUID.randomUUID().toString(),"张狗子"));
		
	}
取流程变量:
        /**
	 * 获取流程变量
	 */
	public void getVariables() {
		TaskService taskService = processEngine.getTaskService();
		// 设置任务ID
		String taskid = "42502";
		
		Person person = (Person) taskService.getVariable(taskid, "人员信息");
		System.out.println("ID:"+person.getId()+"===name:"+person.getName());
	}

遇到的问题:

一旦序列化,javabean不能发生改变。

解决:可在javabean中设置版本号。也就是:

private static final long serialVersionUID = 1L; // 设置版本号


历史记录

总结:

查询的套路

  1. 获取对应的service
  2. 创建查询对象
  3. 设置where条件
  4. 排序等
  5. 返回结果

实例演示:

        /**
	 * 流程实例查询
	 */
	public void findHistoryProcessInstance() {
		processEngine.getHistoryService()
		.createHistoricProcessInstanceQuery()
		.processInstanceId("")
		.list();
	}

常见的查询对象:

.createHistoricProcessInstanceQuery() // 历史流程实例查询
.createHistoricActivitiInstanceQuery() // 历史活动实例查询
.createHistoricTaskInstanceQuery() // 历史任务实例查询
.createHistoricVariableInstanceQuery() // 历史变量实例查询


连线:

添加判断

在MainConfig中codition添加判断,使用${}或者#{}

所以在完成任务时需要加上流程变量。

代码实例:

Activiti工作流笔记_第1张图片

processEngine.getTaskService().complete(taskId, variables);


排他网关

解释:所有条件都不符合的时候走一个分支

Activiti工作流笔记_第2张图片


个人任务分配

1.Assignee设置变量:

办理人使用流程变量${__}或者#{__},启动时:

processEngine.getRuntimeService()
		.startProcessInstanceByKey(key,设置变量);

2.使用类的方式

2.1类实现TaskListener接口

2.2重写notify方法

2.3设置值。delegateTask.setAssignee("xxx");

2.4在Listeners找到并选中该类。

3.还有一个就是直接写死

最后启动即可成功。


组任务

1.直接指定

在main config下的Candidate users 直接指定。

查询组任务:

processEngine.getTaskService()
		.createTaskQuery()
		.taskCandidateUser("xxx");	// 组任务查询正在执行的任务办理人

查询正在执行的任务办理人:

processEngine.getTaskService()
		.getIdentityLinksForTask(taskid)

将组任务分配给个人任务:

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

将个人任务退回为组任务:

思路:

把Assignee置为空。

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

向组任务添加或删除成员:

processEngine.getTaskService()
		.addCandidateUser(taskId, userId);	// 添加
		.deleteCandidateUser(taskId, userId);	// 删除

2.使用流程变量

map.put("变量","添加组")

3.使用类

雷同个人任务分配。

总结:

存放表在act_ru_identitylink、act_hi_identitylink

个人任务与组任务的区别:

个人任务的type为participant(参与者),但组任务为candidate(候选者)

你可能感兴趣的:(Activiti)