Activiti7工作流引擎:基础篇 常用操作

Posted vbirdbest

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Activiti7工作流引擎:基础篇 常用操作相关的知识,希望对你有一定的参考价值。

人最可贵之处在于看透生活的本质后,依然热爱生活。

1. 获取工作流引擎

// 方式一:
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

// 方式二:可以自定义配置文件的名字和ProcessEngineConfiguration对应的bean id值
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml", processEngineConfiguration);
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();

2. 部署

@Test
public void testAddBpmnModel() 
    BpmnModel bpmnModel = repositoryService.getBpmnModel("helloworld:1:3");
    UserTask userTask = (UserTask)bpmnModel.getFlowElement("_4");
    userTask.setAssignee("hrbp");
    userTask.setName("HRBP审批");

    // insert ACT_RE_DEPLOYMENT
    // insert ACT_RE_PROCDEF
    // insert ACT_GE_BYTEARRAY
    repositoryService.createDeployment()
            .addBpmnModel("bpmn/helloworld.bpmn", bpmnModel)
            .deploy();

2. 压缩包方式部署

压缩包方式部署可以将多个.bpmn文件和.png文件打成一个.zip文件,然后一次性部署压缩包中的所有资源,个人感觉用处不大,打成压缩包不便于浏览.bpmn文件。

@Test
public void deployProcessByZip() 
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 定义zip输入流
    InputStream inputStream = this.getClass().getClassLoader()
            .getResourceAsStream("bpmn/process.zip");
    ZipInputStream zipInputStream = new ZipInputStream(inputStream);
    RepositoryService repositoryService = processEngine.getRepositoryService();
    // 流程部署
    Deployment deployment = repositoryService.createDeployment()
            .addZipInputStream(zipInputStream)
            .deploy();
    System.out.println("流程部署id:" + deployment.getId());
    System.out.println("流程部署名称:" + deployment.getName());

3. 删除部署

删除部署会删除和此次部署相关的所有数据,包括资源表ACT_RE_PROCDEF和ACT_GE_BYTEARRAY。一般情况下很少删除。

/**
* 如果有未完成的流程实例删除不了会抛异常
* ACT_RE_PROCDEF
* ACT_GE_BYTEARRAY
* ACT_RE_DEPLOYMENT
* ACT_RU_IDENTITYLINK
*/
@Test
public void deleteDeployment() 
    String deploymentId = "1";
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    processEngine.getRepositoryService()
            .deleteDeployment(deploymentId);


/**
* 级联删除:删除所有和此次相关的数据,包括未完成的流程实例
* ACT_RE_DEPLOYMENT
* ACT_RE_PROCDEF
* ACT_GE_BYTEARRAY
* ACT_RU_EXECUTION
* ACT_RU_TASK
* ACT_RU_IDENTITYLINK
* ACT_RU_VARIABLE
* ACT_HI_COMMENT
* ACT_HI_PROCINST
* ACT_HI_TASKINST
* ACT_HI_IDENTITYLINK
* ACT_HI_ACTINST
* ACT_HI_VARINST
*/
@Test
public void deleteDeployment() 
    String deploymentId = "1";
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // true:表示级联删除
    processEngine.getRepositoryService()
            .deleteDeployment(deploymentId, true);

4. 查询流程定义

@Test
public void testQueryProcessDefinition() 
	/**
	*select 
	*	distinct RES.*
	* FROM ACT_RE_PROCDEF RES
	* WHERE RES.KEY_ = 'helloworld-var' 
	* order by RES.ID_ asc
	* LIMIT 2147483647 OFFSET 0;
	*/
    List<ProcessDefinition> list = ProcessEngines.getDefaultProcessEngine()
            .getRepositoryService()
            .createProcessDefinitionQuery()
            .processDefinitionKey("helloworld-var")
            .list();

5. 获取.bpmn、.png文件

public void  saveBpmnFile() throws IOException 
    //        1、得到引擎
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    //        2、获取repositoryService
    RepositoryService repositoryService = processEngine.getRepositoryService();
    //        3、得到查询器:ProcessDefinitionQuery,设置查询条件,得到想要的流程定义
    ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
            .processDefinitionKey("helloworld-var")
            .singleResult();
    //        4、通过流程定义信息,得到部署ID
    String deploymentId = processDefinition.getDeploymentId();
    //        5、通过repositoryService的方法,实现读取图片信息和bpmn信息
    //        png图片的流
    InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());
    //        bpmn文件的流
    InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getResourceName());
    //        6、构造OutputStream流
    File file_png = new File("d:/helloworld-var.png");
    File file_bpmn = new File("d:/helloworld-var.bpmn");
    FileOutputStream bpmnOut = new FileOutputStream(file_bpmn);
    FileOutputStream pngOut = new FileOutputStream(file_png);
    //        7、输入流,输出流的转换
    IOUtils.copy(pngInput,pngOut);
    IOUtils.copy(bpmnInput,bpmnOut);
    //        8、关闭流
    pngOut.close();
    bpmnOut.close();
    pngInput.close();
    bpmnInput.close();

6. 查询流程元素FlowElement

根据流程定义Id查询ACT_RE_PROCDEF.DEPLOYMENT_ID_,进而查询ACT_GE_BYTEARRAY.BYTES_,然后解析.bpmn文件,封装成Model对象。

@Test
public void testQueryFlowElement()
    BpmnModel bpmnModel = repositoryService.getBpmnModel("helloworld:1:3");
    // Process就是.bpmn文件中的<process>节点
    Process process = bpmnModel.getProcesses().get(0);
    Collection<FlowElement> flowElements = process.getFlowElements();
    for (FlowElement flowElement : flowElements) 
        if (flowElement instanceof UserTask) 
            UserTask userTask = (UserTask)flowElement;
            System.out.println(userTask);
        
    

    // 直接根据Id属性获取UserTask
    UserTask userTask = (UserTask)bpmnModel.getFlowElement("_4");
    System.out.println(userTask);

7. 获取指定节点的下一个节点

/**
 * 获取指定节点的下一个节点
 * 排它网关:获取所有分支
 */
@Test
public void getNextNode() 
    BpmnModel bpmnModel = repositoryService.getBpmnModel("leaveProcess:1:3");
    UserTask userTask = (UserTask) bpmnModel.getFlowElement("pmApprove");
    // 获取该节点出去的SequenceFlow
    List<SequenceFlow> outgoingFlows = userTask.getOutgoingFlows();
    for (SequenceFlow sequenceFlow : outgoingFlows) 
        FlowElement flowElement = bpmnModel.getFlowElement(sequenceFlow.getTargetRef());
        if (flowElement instanceof ExclusiveGateway) 
            ExclusiveGateway exclusiveGateway = (ExclusiveGateway) flowElement;
            List<SequenceFlow> gatewayOutgoingFlows = exclusiveGateway.getOutgoingFlows();
            for (SequenceFlow gatewaySequenceFlow : gatewayOutgoingFlows) 
                FlowElement flowElementItem = bpmnModel.getFlowElement(gatewaySequenceFlow.getTargetRef());
                System.out.println(flowElementItem.getId() + "-" + flowElementItem.getName());
            
         else 
            System.out.println(flowElement.getId() + "-" + flowElement.getName());
        
    

8. 查询正在进行的任务

@Test
public void testQueryRuTask() 
	// 查询哪个工作流下的哪个负责人的待办任务
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    List<Task> list = processEngine.getTaskService()
            .createTaskQuery()
            .processDefinitionKey("helloworld-var")
            .taskAssignee("zhangsan")
            .list();
    // [Task[id=2508, name=请假申请]]
    System.out.println(list);

select 
	distinct RES.*
FROM ACT_RU_TASK RES
INNER JOIN ACT_RE_PROCDEF D ON RES.PROC_DEF_ID_ = D.ID_
WHERE RES.ASSIGNEE_ = 'zhangsan' and D.KEY_ = 'helloworld-var' 
order by RES.ID_ asc
LIMIT 2147483647 OFFSET 0;

9. 查询历史流程实例

@Test
public void testQueryHistoryProcessInstance() 
    ProcessEngines.getDefaultProcessEngine()
            .getHistoryService()
            .createHistoricProcessInstanceQuery()
            .processInstanceId("2501")
            .list();

select 
	distinct RES.* , 
	DEF.KEY_ as PROC_DEF_KEY_, 
	DEF.NAME_ as PROC_DEF_NAME_, 
	DEF.VERSION_ as PROC_DEF_VERSION_, 
	DEF.DEPLOYMENT_ID_ as DEPLOYMENT_ID_
FROM ACT_HI_PROCINST RES 
left outer join ACT_RE_PROCDEF DEF ON RES.PROC_DEF_ID_ = DEF.ID_
WHERE RES.PROC_INST_ID_ = '2501' 
order by RES.ID_ asc
LIMIT 2147483647 
OFFSET 0;

10. 查询历史活动

@Test
public void queryHistoryActivity() 
	//    select
	//      RES.*
	//    FROM ACT_HI_ACTINST RES
	//    WHERE RES.PROC_DEF_ID_ = 'helloworld-var:1:4'
	//    order by RES.ID_ asc
	//    LIMIT 2147483647 OFFSET 0;
    List<HistoricActivityInstance> activityInstanceList = ProcessEngines.getDefaultProcessEngine()
            .getHistoryService()
            .createHistoricActivityInstanceQuery()
            .processDefinitionId("helloworld-var:1:4")
            .list();

11. 挂起和激活流程实例

有时候在特殊的时间内会需要暂停流程的发起,比如月底不允许发起新的请假审批,因为财务要计算工资了等情况就需要将发起申请请求暂停掉,此时可以将流程定义挂起。

有时候我们只会暂停某一个流程实例,比如张三是否要出差现在还不能确定,先暂停他的出差申请,等过几天确定了再继续走流程,这就是挂起单个流程实例。

流程实例挂起相当于暂停了,不允许被继续执行会抛异常(ActivitiException: Cannot complete supended task),也不允许启动新的实例。主要是设置数据库字段挂起状态字段 SUSPENSION_STATE_ 挂起状态 2:挂起,1:激活。

挂起流程定义就是挂起该流程下的所有流程实例。

@Test
public void testSuspendProcessDefinition() 
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    RepositoryService repositoryService = processEngine.getRepositoryService();
    ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
            .processDefinitionKey("helloworld-var")
            .singleResult();
    if (processDefinition.isSuspended()) 
        repositoryService.activateProcessDefinitionById(processDefinition.getId());
     else 
        repositoryService.suspendProcessDefinitionById(processDefinition.getId());
    

update ACT_RE_PROCDEF 
set 
	REV_ = 2, 
	SUSPENSION_STATE_ = 2
WHERE ID_ = 'helloworld-var:1:4' and REV_ = 1;

挂起单个流程实例:分别设置ACT_RU_TASKACT_RU_EXECUTION的SUSPENSION_STATE_ = 2

@Test
public void testSuspendedProcessInstance() 
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    RuntimeService runtimeService = processEngine.getRuntimeService();
    ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
            .processInstanceId("2501")
            .singleResult();
    boolean suspended = processInstance.isSuspended();
    if (suspended) 
        runtimeService.activateProcessInstanceById(processInstance.getId());
     else 
        runtimeService.suspendProcessInstanceById(processInstance.getId());
    

-- ACT_RU_TASK.SUSPENSION_STATE_ = 2
update ACT_RU_TASK 
SET 
	SUSPENSION_STATE_ = 2, 
WHERE ID_= '2508' and REV_ = 1;

-- ACT_RU_EXECUTION.SUSPENSION_STATE_ = 2
-- 流程实例
update ACT_RU_EXECUTION 
set 
	SUSPENSION_STATE_ = 2
WHERE ID_ = '2501' and REV_ = 1;

-- 该流程实例下的其它执行流
update ACT_RU_EXECUTION 
set 
	SUSPENSION_STATE_ = 2
WHERE ID_ = '2505' and REV_ = 1;

12. 候选人CandidateUsers

候选人就是不指定任务节点的负责人,而是在实际审批的过程中由候选人自己将任务的负责人设置为自己或者候选人中的其他人,然后再由负责人去完成审批。

经理审批不指定Assignee复制人了,而是指定候选人列表。

@Test
public void startProcessInstance() 
    String businessKey = "666";

    Map<String, Object> variables = new HashMap<>();
    variables.put("creator", "zhangsan");
    // 指定候选人列表
    variables.put("pmCandidateUsers", "狗经理,猪经理");

    ProcessInstance processInstance = ProcessEngines.getDefaultProcessEngine()
            .getRuntimeService()
            .startProcessInstanceByKey("candidateUsers", businessKey, variables);


@Test
public void completeTask() 
    TaskService taskService = ProcessEngines.getDefaultProcessEngine().getTaskService();
    Task task = taskService
            .createTaskQuery()
            .processDefinitionKey("candidateUsers")
            .taskAssignee("zhangsan")
            .singleResult();
    taskService.complete(task.getId());

当发起人zhangsan完成自己的审批后到底下一个任务节点经理审批时,此时的ASSIGNEE_字段是空的。

/**
* 猪经理拾取任务,即将任务负责人设置为猪经理
*/
@Test
public void testTaskClaim() 
   String currentUserId = "猪经理";
   TaskService taskService = ProcessEngines.getDefaultProcessEngine().getTaskService();
   Task task = taskService.createTaskQuery()
           .processDefinitionKey("candidateUsers")
           .taskCandidateUser(currentUserId)
           .singleResult();
   // update ACT_RU_TASK SET ASSIGNEE_ = '猪经理' WHERE ID_= '5002' and REV_ = 1;
   // update ACT_HI_ACTINST set ASSIGNEE_ = '猪经理' WHERE ID_ = '5001';
   // update ACT_HI_TASKINST set ASSIGNEE_ = '猪经理'  WHERE ID_= '5002' and REV_ = 1;;
   taskService.claim(task.getId(), currentUserId);


// 如果当前任务的负责人是自己,而自己却不想审批,可以直接将任务负责人设置为null或者交接给其他候选人
@Test
public void testSetAssignee() 
    TaskService taskService = ProcessEngines.getDefaultProcessEngine().getTaskService();
    Task task = taskService
            .createTaskQuery()
            .processDefinitionKey("candidateUsers")
            .taskAssignee("猪经理")
            .singleResult();
    taskService.setAssignee(task.getId(), 以上是关于Activiti7工作流引擎:基础篇 常用操作的主要内容,如果未能解决你的问题,请参考以下文章

Activiti7工作流引擎:基础篇 基本查询

Activiti7工作流引擎:基础篇 Annotation

Activiti7工作流引擎:基础篇 Annotation

Activiti7工作流引擎:基础篇 Hello World

Activiti7工作流引擎:基础篇 网关Gateway

Activiti7工作流引擎:基础篇 流程变量