天天看點

一個使用示例,五個操作步驟!從此輕松掌握項目中工作流的開發建立流程釋出流程啟動一個流程執行個體完成任務挂起或激活一個流程

建立流程

  • 要想操作Activiti引擎,需要通過org.activiti.engine.ProcessEngine執行個體暴露的服務.就可以操作一個org.activiti.engine.ProcessEngine
  • 建立一個請假申請的工作業務流程:
一個使用示例,五個操作步驟!從此輕松掌握項目中工作流的開發建立流程釋出流程啟動一個流程執行個體完成任務挂起或激活一個流程

釋出流程

  • 任何與“靜态”資源有關的資料(比如流程定義)都可以通過RepositoryService通路,從概念上講,所有靜态資料都是Activiti的資源内容
  • 在src/test/resources/org/activiti/test目錄下建立一個新的xml檔案 VacationRequest.bpmn20.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<definitions id="definitions"
             targetNamespace="http://activiti.org/bpmn20"
             xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:activiti="http://activiti.org/bpmn">

  <process id="vacationRequest" name="Vacation request">

    <startEvent id="request" activiti:initiator="employeeName">
      <extensionElements>
        <activiti:formProperty id="numberOfDays" name="Number of days" type="long" value="1" required="true"/>
        <activiti:formProperty id="startDate" name="First day of holiday (dd-MM-yyy)" datePattern="dd-MM-yyyy hh:mm" type="date" required="true" />
        <activiti:formProperty id="vacationMotivation" name="Motivation" type="string" />
      </extensionElements>
    </startEvent>
    <sequenceFlow id="flow1" sourceRef="request" targetRef="handleRequest" />

    <userTask id="handleRequest" name="Handle vacation request" >
      <documentation>
        ${employeeName} would like to take ${numberOfDays} day(s) of vacation (Motivation: ${vacationMotivation}).
      </documentation>
      <extensionElements>
         <activiti:formProperty id="vacationApproved" name="Do you approve this vacation" type="enum" required="true">
          <activiti:value id="true" name="Approve" />
          <activiti:value id="false" name="Reject" />
        </activiti:formProperty>
        <activiti:formProperty id="managerMotivation" name="Motivation" type="string" />
      </extensionElements>
      <potentialOwner>
        <resourceAssignmentExpression>
          <formalExpression>management</formalExpression>
        </resourceAssignmentExpression>
      </potentialOwner>
    </userTask>
    <sequenceFlow id="flow2" sourceRef="handleRequest" targetRef="requestApprovedDecision" />

    <exclusiveGateway id="requestApprovedDecision" name="Request approved?" />
    <sequenceFlow id="flow3" sourceRef="requestApprovedDecision" targetRef="sendApprovalMail">
      <conditionExpression xsi:type="tFormalExpression">${vacationApproved == 'true'}</conditionExpression>
    </sequenceFlow>

    <task id="sendApprovalMail" name="Send confirmation e-mail" />
    <sequenceFlow id="flow4" sourceRef="sendApprovalMail" targetRef="theEnd1" />
    <endEvent id="theEnd1" />

    <sequenceFlow id="flow5" sourceRef="requestApprovedDecision" targetRef="adjustVacationRequestTask">
      <conditionExpression xsi:type="tFormalExpression">${vacationApproved == 'false'}</conditionExpression>
    </sequenceFlow>

    <userTask id="adjustVacationRequestTask" name="Adjust vacation request">
      <documentation>
        Your manager has disapproved your vacation request for ${numberOfDays} days.
        Reason: ${managerMotivation}
      </documentation>
      <extensionElements>
        <activiti:formProperty id="numberOfDays" name="Number of days" value="${numberOfDays}" type="long" required="true"/>
        <activiti:formProperty id="startDate" name="First day of holiday (dd-MM-yyy)" value="${startDate}" datePattern="dd-MM-yyyy hh:mm" type="date" required="true" />
        <activiti:formProperty id="vacationMotivation" name="Motivation" value="${vacationMotivation}" type="string" />
        <activiti:formProperty id="resendRequest" name="Resend vacation request to manager?" type="enum" required="true">
          <activiti:value id="true" name="Yes" />
          <activiti:value id="false" name="No" />
        </activiti:formProperty>
      </extensionElements>
      <humanPerformer>
        <resourceAssignmentExpression>
          <formalExpression>${employeeName}</formalExpression>
        </resourceAssignmentExpression>
      </humanPerformer>
    </userTask>
    <sequenceFlow id="flow6" sourceRef="adjustVacationRequestTask" targetRef="resendRequestDecision" />

    <exclusiveGateway id="resendRequestDecision" name="Resend request?" />
    <sequenceFlow id="flow7" sourceRef="resendRequestDecision" targetRef="handleRequest">
      <conditionExpression xsi:type="tFormalExpression">${resendRequest == 'true'}</conditionExpression>
    </sequenceFlow>

     <sequenceFlow id="flow8" sourceRef="resendRequestDecision" targetRef="theEnd2">
      <conditionExpression xsi:type="tFormalExpression">${resendRequest == 'false'}</conditionExpression>
    </sequenceFlow>
    <endEvent id="theEnd2" />

  </process>

</definitions>           
  • 為了讓Activiti引擎知道這個流程,我們必須先進行[釋出],釋出意味着引擎會把BPMN 2.0 xml解析成可以執行的東西,釋出包中的所有流程定義都會添加到資料庫中.這樣,當引擎重新開機時,它依然可以獲得[已釋出]的流程:
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.createDeployment()
  .addClasspathResource("org/activiti/test/VacationRequest.bpmn20.xml")
  .deploy();

Log.info("Number of process definitions: " + repositoryService.createProcessDefinitionQuery().count());           

啟動一個流程執行個體

  • 把流程定義釋出到Activiti引擎後,可以基于它發起新流程執行個體.
  • 對每個流程定義,都可以有很多流程執行個體.流程定義是"藍圖",流程執行個體是它的一個運作的執行
  • 所有與流程運作狀态相關的東西都可以通過RuntimeService獲得.有很多方法可以啟動一個新流程執行個體.
    • 可以在流程執行個體啟動時添加一些流程變量, 因為第一個使用者任務的表達式需要這些變量.流程變量經常會被用到,因為它們賦予來自同一個流程定義的不同流程執行個體的特别含義
    • 流程變量是區分流程執行個體的關鍵
    • 下面使用定義在流程定義xml 中的key來啟動流程執行個體:
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("employeeName", "Kermit");
variables.put("numberOfDays", new Integer(4));
variables.put("vacationMotivation", "I'm really tired!");

RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("vacationRequest", variables);

// Verify that we started a new process instance
Log.info("Number of process instances: " + runtimeService.createProcessInstanceQuery().count());           

完成任務

  • 流程啟動後,第一步就是使用者任務.這是必須由系統使用者處理的一個環節.
  • 使用者會有一個"任務清單",展示了所有必須由整個使用者處理的任務.下面是對應的查詢:
// Fetch all tasks for the management group
TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("management").list();
for (Task task : tasks) {
  Log.info("Task available: " + task.getName());
}           
  • 為了讓流程執行個體繼續運作,我們需要完成整個任務.對Activiti來說,就是需要complete任務:
Task task = tasks.get(0);

Map<String, Object> taskVariables = new HashMap<String, Object>();
taskVariables.put("vacationApproved", "false");
taskVariables.put("managerMotivation", "We have a tight deadline!");
taskService.complete(task.getId(), taskVariables);           
  • 然後流程執行個體就會進入到下一個環節
  • 下一環節允許員工通過表單調整原始的請假申請.員工可以重新送出請假申請,這會使流程重新進入到第一個任務

挂起或激活一個流程

  • 可以挂起一個流程定義,當挂起流程定義時,就不能建立新流程了,會抛出一個異常.可以通過RepositoryService挂起一個流程:
repositoryService.suspendProcessDefinitionByKey("vacationRequest");
try {
  runtimeService.startProcessInstanceByKey("vacationRequest");
} catch (ActivitiException e) {
  e.printStackTrace();
}           
  • 要想重新激活一個流程定義,可以調用repositoryService.activateProcessDefinitionXXX方法
  • 也可以挂起一個流程執行個體:
    • 挂起時,流程不能繼續執行:比如,完成任務會抛出異常,異步操作(比如定時器)也不會執行.挂起流程執行個體可以調用runtimeService.suspendProcessInstance方法
    • 激活流程執行個體可以調用runtimeService.activateProcessInstanceXXX方法