Activiti入门学习demo

jopen 9年前

本文提供activiti入门学习的demo,包括流程文件和调用代码。

一、新建工程,导入相应的jar包,建议用maven做jar包的依赖管理。maven依赖部分代码如下:

 <dependencies>      <dependency>        <groupId>junit</groupId>        <artifactId>junit</artifactId>        <version>4.11</version>        <scope>test</scope>      </dependency>      <!--activiti的核心jar包,其相关依赖jar包会一并导入-->      <dependency>        <groupId>org.activiti</groupId>        <artifactId>activiti-engine</artifactId>        <version>5.18.0</version>      </dependency>      <!--h2内存数据库的jar包,本文的例子用的是h2数据库,基于内存模式,方便测试-->      <dependency>        <groupId>com.h2database</groupId>        <artifactId>h2</artifactId>        <version>1.3.176</version>      </dependency>    </dependencies>

二、流程文件,测试中用到的两个流程文件,放到合适的目录下,一般是resources目录下,至于如何生成流程文件,请参照相关资料:

  1. MyProcess.bpmn20.xml

 <?xml version="1.0" encoding="UTF-8"?>  <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">    <process id="myProcess" name="My process" isExecutable="true">      <startEvent id="startevent1" name="Start"></startEvent>      <userTask id="usertask1" name="User Task"></userTask>      <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>      <endEvent id="endevent1" name="End"></endEvent>      <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="endevent1"></sequenceFlow>    </process>  </definitions>

这是一个最简单的流程,流程图如下:

Activiti入门学习demo

2. pool.bpmn

<?xml version="1.0" encoding="UTF-8"?>  <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">    <collaboration id="Collaboration">      <participant id="pool1" name="请假流程" processRef="process_pool1"></participant>    </collaboration>    <process id="process_pool1" name="process_pool1" isExecutable="true">      <laneSet id="laneSet_process_pool1">        <lane id="lane1" name="员工">          <flowNodeRef>startevent1</flowNodeRef>          <flowNodeRef>usertask1</flowNodeRef>          <flowNodeRef>usertask4</flowNodeRef>          <flowNodeRef>endevent1</flowNodeRef>          <flowNodeRef>exclusivegateway3</flowNodeRef>        </lane>        <lane id="lane2" name="领导">          <flowNodeRef>usertask2</flowNodeRef>          <flowNodeRef>exclusivegateway1</flowNodeRef>        </lane>        <lane id="lane3" name="人事">          <flowNodeRef>usertask3</flowNodeRef>          <flowNodeRef>exclusivegateway2</flowNodeRef>        </lane>      </laneSet>      <startEvent id="startevent1" name="Start" activiti:initiator="applyUserId">        <extensionElements>          <activiti:formProperty id="startDate" name="请假开始日期" type="date" datePattern="yyyy-MM-dd" required="true"></activiti:formProperty>          <activiti:formProperty id="endDate" name="请假结束日期" type="date" datePattern="yyyy-MM-dd" required="true"></activiti:formProperty>          <activiti:formProperty id="reason" name="请假原因" type="string" required="true"></activiti:formProperty>        </extensionElements>      </startEvent>      <userTask id="usertask1" name="调整申请" activiti:assignee="${applyUserId}">        <extensionElements>          <activiti:formProperty id="startDate" name="请假开始日期" type="date" value="${startDate}" datePattern="yyyy-MM-dd" required="true"></activiti:formProperty>          <activiti:formProperty id="endDate" name="请假结束日期" type="date" value="${endDate}" datePattern="yyyy-MM-dd" required="true"></activiti:formProperty>          <activiti:formProperty id="reason" name="请假原因" type="string" value="${reason}" required="true"></activiti:formProperty>          <activiti:formProperty id="reApply" name="重新申请" type="enum" required="true">            <activiti:value id="true" name="重新申请"></activiti:value>            <activiti:value id="false" name="取消申请"></activiti:value>          </activiti:formProperty>        </extensionElements>      </userTask>      <sequenceFlow id="flow2" name="提交申请" sourceRef="startevent1" targetRef="usertask2"></sequenceFlow>      <userTask id="usertask2" name="领导审批" activiti:candidateGroups="deptLeader">        <extensionElements>          <activiti:formProperty id="startDate" name="请假开始日期" type="date" value="${startDate}" datePattern="yyyy-MM-dd" writable="false"></activiti:formProperty>          <activiti:formProperty id="endDate" name="请假结束日期" type="date" value="${endDate}" datePattern="yyyy-MM-dd" writable="false"></activiti:formProperty>          <activiti:formProperty id="reason" name="请假原因" type="string" value="${reason}" writable="false"></activiti:formProperty>          <activiti:formProperty id="deptLeaderApprove" name="审批意见" type="enum" required="true">            <activiti:value id="true" name="同意"></activiti:value>            <activiti:value id="false" name="拒绝"></activiti:value>          </activiti:formProperty>        </extensionElements>      </userTask>      <exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway>      <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="exclusivegateway1"></sequenceFlow>      <sequenceFlow id="flow4" name="同意" sourceRef="exclusivegateway1" targetRef="usertask3">        <conditionExpression xsi:type="tFormalExpression"><![CDATA[${deptLeaderApprove=='true'}]]></conditionExpression>      </sequenceFlow>      <userTask id="usertask3" name="人事审批" activiti:candidateGroups="hr">        <extensionElements>          <activiti:formProperty id="startDate" name="请假开始日期" type="date" value="${startDate}" datePattern="yyyy-MM-dd" writable="false"></activiti:formProperty>          <activiti:formProperty id="endDate" name="请假结束日期" type="date" value="${endDate}" datePattern="yyyy-MM-dd" writable="false"></activiti:formProperty>          <activiti:formProperty id="reason" name="请假原因" type="string" value="${reason}" writable="false"></activiti:formProperty>          <activiti:formProperty id="hrApprove" name="审批意见" type="enum" required="true">            <activiti:value id="true" name="同意"></activiti:value>            <activiti:value id="false" name="拒绝"></activiti:value>          </activiti:formProperty>        </extensionElements>      </userTask>      <sequenceFlow id="flow6" name="不同意" sourceRef="exclusivegateway1" targetRef="usertask1">        <conditionExpression xsi:type="tFormalExpression"><![CDATA[${deptLeaderApprove=='false'}]]></conditionExpression>      </sequenceFlow>      <exclusiveGateway id="exclusivegateway2" name="Exclusive Gateway"></exclusiveGateway>      <sequenceFlow id="flow7" sourceRef="usertask3" targetRef="exclusivegateway2"></sequenceFlow>      <sequenceFlow id="flow8" name="同意" sourceRef="exclusivegateway2" targetRef="usertask4">        <conditionExpression xsi:type="tFormalExpression"><![CDATA[${hrApprove=='true'}]]></conditionExpression>      </sequenceFlow>      <userTask id="usertask4" name="销假" activiti:assignee="${applyUserId}">        <extensionElements>          <activiti:formProperty id="startDate" name="请假开始日期" type="date" value="${startDate}" datePattern="yyyy-MM-dd" writable="false"></activiti:formProperty>          <activiti:formProperty id="endDate" name="请假结束日期" type="date" value="${endDate}" datePattern="yyyy-MM-dd" writable="false"></activiti:formProperty>          <activiti:formProperty id="reason" name="请假原因" type="string" value="${reason}" writable="false"></activiti:formProperty>          <activiti:formProperty id="reportBackDate" name="销假日期" type="date" default="${endDate}" datePattern="yyyy-MM-dd" required="true"></activiti:formProperty>        </extensionElements>      </userTask>      <sequenceFlow id="flow9" name="不同意" sourceRef="exclusivegateway2" targetRef="usertask1">        <conditionExpression xsi:type="tFormalExpression"><![CDATA[${hrApprove=='false'}]]></conditionExpression>      </sequenceFlow>      <endEvent id="endevent1" name="End"></endEvent>      <sequenceFlow id="flow10" sourceRef="usertask4" targetRef="endevent1">        <extensionElements>          <activiti:executionListener event="take" expression="${execution.setVariable('result','OK')}"></activiti:executionListener>        </extensionElements>      </sequenceFlow>      <sequenceFlow id="flow11" name="继续提交申请" sourceRef="exclusivegateway3" targetRef="usertask2">        <conditionExpression xsi:type="tFormalExpression"><![CDATA[${reApply=='true'}]]></conditionExpression>      </sequenceFlow>      <sequenceFlow id="flow12" name="取消申请" sourceRef="exclusivegateway3" targetRef="endevent1">        <extensionElements>          <activiti:executionListener event="take" expression="${execution.setVariable('result','canceled')}"></activiti:executionListener>        </extensionElements>        <conditionExpression xsi:type="tFormalExpression"><![CDATA[${reApply=='false'}]]></conditionExpression>      </sequenceFlow>      <exclusiveGateway id="exclusivegateway3" name="Exclusive Gateway"></exclusiveGateway>      <sequenceFlow id="flow13" sourceRef="usertask1" targetRef="exclusivegateway3"></sequenceFlow>    </process>  </definitions>

这是一个请假流程,流程图如下:

Activiti入门学习demo

三、用于测试的java代码,采用junit方式运行:

 package com.wangtl.activiti;  import java.io.File;  import java.io.FileInputStream;  import java.io.InputStream;  import java.text.SimpleDateFormat;  import java.util.Calendar;  import java.util.HashMap;  import java.util.List;  import java.util.Map;  import org.activiti.engine.FormService;  import org.activiti.engine.HistoryService;  import org.activiti.engine.IdentityService;  import org.activiti.engine.ProcessEngine;  import org.activiti.engine.ProcessEngineConfiguration;  import org.activiti.engine.RepositoryService;  import org.activiti.engine.RuntimeService;  import org.activiti.engine.TaskService;  import org.activiti.engine.history.HistoricDetail;  import org.activiti.engine.history.HistoricFormProperty;  import org.activiti.engine.history.HistoricProcessInstance;  import org.activiti.engine.history.HistoricVariableInstance;  import org.activiti.engine.history.HistoricVariableUpdate;  import org.activiti.engine.repository.Deployment;  import org.activiti.engine.repository.ProcessDefinition;  import org.activiti.engine.runtime.ProcessInstance;  import org.activiti.engine.task.Task;  import org.junit.Test;  public class VerySimpleLeaveProcessTest {      @Test   public  void testProcessDefinition() throws Exception{    // 创建 Activiti流程引擎    ProcessEngine processEngine=        ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration()        .buildProcessEngine();      // 取得 Activiti 服务     RepositoryService repositoryService=processEngine.getRepositoryService();    // 部署流程定义    Deployment deploy=repositoryService.createDeployment().addClasspathResource("MyProcess.bpmn20.xml").deploy();        ProcessDefinition processDefinition=repositoryService.createProcessDefinitionQuery().deploymentId(deploy.getId())      .singleResult();    System.out.println(processDefinition.getKey());    // 启动流程实例    RuntimeService runtimeService=processEngine.getRuntimeService();    ProcessInstance processInstance=runtimeService.startProcessInstanceByKey(processDefinition.getKey());    System.out.println("pid="+processInstance.getId()+",pdid="+      processInstance.getProcessDefinitionId());   }      @Test   public void testStartProcess() throws Exception{    // 1.创建 Activiti流程引擎(此处使用的是h2数据库,并启用的是内存模式,即数据保存在内存中,程序运行完数据就丢失)    ProcessEngine processEngine=        ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration()        .buildProcessEngine();        // 2.部署流程定义    //取得 Activiti 服务     RepositoryService repositoryService=processEngine.getRepositoryService();    //获得流程定义的相关数据    String fileName="E:/workspace/activiti-demo/src/main/resources/MyProcess.bpmn20.xml";    File f =new File(fileName);    InputStream fileInputStream = new FileInputStream(f);    //创建Deployment,同时部署流程定义    repositoryService.createDeployment()     .addInputStream(fileName, fileInputStream)     .deploy();    //查看定义的流程(非必须,只是验证流程定义是否部署成功)    ProcessDefinition processDefinition=repositoryService.createProcessDefinitionQuery()      .singleResult();    System.out.println("流程定义文件的key为:"+processDefinition.getKey());    // 3.启动流程实例    RuntimeService runtimeService=processEngine.getRuntimeService();    ProcessInstance processInstance=runtimeService.startProcessInstanceByKey(processDefinition.getKey());    System.out.println("流程实例的id="+processInstance.getId()+",流程实例的definitionId="+      processInstance.getProcessDefinitionId());        //4.取得当前任务    //获得任务服务    TaskService taskService=processEngine.getTaskService();    //取得当前任务(由于流程定义中没有指明任务指派给谁,所以这里不用申明任务由谁获得)    Task task=taskService.createTaskQuery().singleResult();    System.out.println("当前任务的名称是:"+task.getName());    //5.认领任务(由于流程定义中没有指明任务指派给谁,任何人都可以认领该任务,如这里的“leaderUser”)    taskService.claim(task.getId(), "leaderUser");    //查看"leaderUser"现在是否能够获取到该任务(非必须)    task=taskService.createTaskQuery().taskAssignee("leaderUser").singleResult();    System.out.println("认领任务的人是:"+task.getAssignee());    //6.完成任务    taskService.complete(task.getId());        //以下是验证任务是否完成,通过重新查找任务(为空),查询历史记录(有),说明之前的任务完成了(非必须)    task=taskService.createTaskQuery().singleResult();    System.out.println("当前的任务是:"+task);    HistoryService historyService=processEngine.getHistoryService();    long count=historyService.createHistoricProcessInstanceQuery().finished().count();    System.out.println("已完成的任务数是:"+count);   }            @Test   public void testStartProcess2() throws Exception{    // 1.创建 Activiti流程引擎(此处使用的是h2数据库,并启用的是内存模式,即数据保存在内存中,程序运行完数据就丢失)    ProcessEngine processEngine=        ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration()  //      .setHistory("full")        .buildProcessEngine();        // 2.部署流程定义    //取得 Activiti 服务     RepositoryService repositoryService=processEngine.getRepositoryService();    //获得流程定义的相关数据    String fileName="E:/workspace/activiti-demo/src/main/resources/pool.bpmn";    File f =new File(fileName);    InputStream fileInputStream = new FileInputStream(f);    //创建Deployment,同时部署流程定义    repositoryService.createDeployment()     .addInputStream(fileName, fileInputStream)     .deploy();    //查看定义的流程(非必须,只是验证流程定义是否部署成功)    ProcessDefinition processDefinition=repositoryService.createProcessDefinitionQuery()      .processDefinitionKey("process_pool1")      .singleResult();    System.out.println("流程定义文件的key为:"+processDefinition.getKey());        //设置当前用户    String currentUserId="hen";    IdentityService identityService=processEngine.getIdentityService();    identityService.setAuthenticatedUserId(currentUserId);        //设置表单变量    SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");    Map<String,String> variables =new HashMap<String,String>();    Calendar ca=Calendar.getInstance();    String startDate = sdf.format(ca.getTime());    ca.add(Calendar.DAY_OF_MONTH, 2);    String endDate=sdf.format(ca.getTime());    variables.put("startDate", startDate);    variables.put("endDate", endDate);    variables.put("reason", "年假");        // 3.当前用户启动流程实例(类似RuntimeService,只是这里带上了表单数据)    FormService formService=processEngine.getFormService();    ProcessInstance processInstance=      formService.submitStartFormData(processDefinition.getId(), variables);    System.out.println("流程实例的id="+processInstance.getId()+",流程实例的definitionId="+      processInstance.getProcessDefinitionId());        //取得deptLeader的任务    TaskService taskService=processEngine.getTaskService();    Task leaderTask=taskService.createTaskQuery().taskCandidateGroup("deptLeader").singleResult();    System.out.println("当前任务的名称是:"+leaderTask.getName());    //审批当前任务(类似于TaskService的complete)    variables=new HashMap<String,String>();    variables.put("deptLeaderApprove", "true");    formService.submitTaskFormData(leaderTask.getId(), variables);        //取得hr的任务    Task hrTask=taskService.createTaskQuery().taskCandidateGroup("hr").singleResult();    System.out.println("当前任务的名称是:"+hrTask.getName());    //审批当前任务(类似于TaskService的complete)    variables=new HashMap<String,String>();    variables.put("hrApprove", "true");    formService.submitTaskFormData(hrTask.getId(), variables);        //取得用户的销假任务    Task reportBackTask=taskService.createTaskQuery().taskAssignee(currentUserId).singleResult();    //提交任务    variables=new HashMap<String,String>();    variables.put("reportBackDate", endDate);    formService.submitTaskFormData(reportBackTask.getId(),variables);        //以下是验证流程是否结束(非必须)    HistoryService historyService=processEngine.getHistoryService();    HistoricProcessInstance historicProcessInstance=historyService      .createHistoricProcessInstanceQuery().finished().singleResult();    System.out.println("已执行的流程id:"+historicProcessInstance.getId());    Map<String,Object> historyVariables=packageVariables(historyService,processInstance);    System.out.println(historyVariables.get("result"));       }      private Map<String,Object> packageVariables(HistoryService historyService,ProcessInstance processInstance){        Map<String,Object> historyVariables=new HashMap<String,Object>();        //在保存表单字段的同时会复制一份经过类型转换的值,并以字段的ID为变量名保存到数据库中,当然前提是要设置引擎的“history”属性为“full”级别    /*List<HistoricDetail> list=    historyService.createHistoricDetailQuery().processInstanceId(processInstance.getId()).list();    System.out.println("历史记录数"+list.size());    for(HistoricDetail historicDetail:list){     if(historicDetail instanceof HistoricFormProperty){      HistoricFormProperty field=(HistoricFormProperty) historicDetail;      historyVariables.put(field.getPropertyId(), field.getPropertyValue());      System.out.println("form field: taskId="+field.getTaskId()+", "        +field.getPropertyId()+"="+field.getPropertyValue());     }else if(historicDetail instanceof HistoricVariableUpdate){      HistoricVariableUpdate variable=(HistoricVariableUpdate) historicDetail;      historyVariables.put(variable.getVariableName(),variable.getValue());      System.out.println("variable: "+variable.getVariableName()+"="+variable.getValue());     }    }*/            /* 查询所有保存的变量:5.11版本之后,从表act_hi_varinst*/    List<HistoricVariableInstance> list =       historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId()).list();    for (HistoricVariableInstance variable : list)     {      historyVariables.put(variable.getVariableName(),variable.getValue());     System.out.println("variable: " + variable.getVariableName() + " = " + variable.getValue());        }            /* 只读取表单变量:从表act_hi_detail*/    /*List<HistoricDetail> formProperties =       historyService.createHistoricDetailQuery().processInstanceId(processInstance.getId())      .formProperties().list();    for (HistoricDetail historicDetail : formProperties) {       HistoricFormProperty field = (HistoricFormProperty) historicDetail;       historyVariables.put(field.getPropertyId(), field.getPropertyValue());     System.out.println("field id: " + field.getPropertyId() + ", value: " + field.getPropertyValue());    } */      return historyVariables;   }  }
来自:http://my.oschina.net/wangrikui/blog/506338