因工作需要,本人現在在學習Flowable工作流。此處將自己學習和測試通過的demo展示給大家,希望對同為初學者的你有所幫助。
對於什么是工作流,flowable和activiti的區別,各位可自行百度,此處不再贅述。
直接上demo:
1、環境搭建:jdk1.8+maven+eclipse
創建標准的maven項目,項目框架截圖如下:
2、添加相關依賴:pom.xml
<!-- https://mvnrepository.com/artifact/org.flowable/flowable-engine -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-engine</artifactId>
<version>6.5.0</version>
</dependency>
<dependency>
<artifactId>junit</artifactId>
<groupId>junit</groupId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.10</version>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
<!-- 使用h2數據庫,方便測試-->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.197</version>
</dependency>
3、使用flowable插件創建mywork.bpmn文件(因篇幅問題,只貼關鍵代碼),flowable插件安裝請自行百度
mywork.png如下:
mywork.bpmn:
<process id="mywork" name="二級審批流程" isExecutable="true"> <startEvent id="startEvent" name="開始"></startEvent> <userTask id="userDev" name="申請審批流程"> <extensionElements> <activiti:formProperty id="message" name="申請信息" type="string" required="true"></activiti:formProperty> <activiti:formProperty id="name" name="申請人" type="string" required="true"></activiti:formProperty> <activiti:formProperty id="submitTime" name="提交時間" type="date" datePattern="yyyy-MM-dd" required="true"></activiti:formProperty> <activiti:formProperty id="submitType" name="確認申請" type="string" required="true"></activiti:formProperty> </extensionElements> </userTask> <sequenceFlow id="flow1" sourceRef="startEvent" targetRef="userDev"></sequenceFlow> <exclusiveGateway id="Dev_exclusivegateway" name="確認提交"></exclusiveGateway> <sequenceFlow id="flow2" sourceRef="userDev" targetRef="Dev_exclusivegateway"></sequenceFlow> <userTask id="userTL" name="主管審批"> <extensionElements> <activiti:formProperty id="TLApprove" name="主管審批結果" type="string" required="true"></activiti:formProperty> <activiti:formProperty id="TLMessage" name="主管備注" type="string" required="true"></activiti:formProperty> </extensionElements> </userTask> <sequenceFlow id="flow3" sourceRef="Dev_exclusivegateway" targetRef="userTL"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${submitType == "y" || submitType =="Y"}]]></conditionExpression> </sequenceFlow> <endEvent id="endEvent" name="結束"></endEvent> <exclusiveGateway id="TL_exclusivegateway" name="主管審批結果"></exclusiveGateway> <sequenceFlow id="flow8" sourceRef="userTL" targetRef="TL_exclusivegateway"></sequenceFlow> <userTask id="userHR" name="人事審批"> <extensionElements> <activiti:formProperty id="HRApprove" name="人事審批結果" type="string" required="true"></activiti:formProperty> <activiti:formProperty id="HRMessage" name="人事審批備注" type="string" required="true"></activiti:formProperty> </extensionElements> </userTask> <sequenceFlow id="flow9" sourceRef="TL_exclusivegateway" targetRef="userHR"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${TLApprove == "y" || TLApprove =="Y"}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow11" sourceRef="TL_exclusivegateway" targetRef="userDev"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${TLApprove == "N" || TLApprove =="n"}]]></conditionExpression> </sequenceFlow> <exclusiveGateway id="HR_exclusivegateway" name="人事審批結果"></exclusiveGateway> <sequenceFlow id="flow12" sourceRef="userHR" targetRef="HR_exclusivegateway"></sequenceFlow> <endEvent id="endEvent1" name="取消"></endEvent> <sequenceFlow id="flow13" sourceRef="HR_exclusivegateway" targetRef="endEvent1"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${HRApprove == "y" || HRApprove =="Y"}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow14" sourceRef="HR_exclusivegateway" targetRef="userDev"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${HRApprove == "n" || HRApprove =="N"}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow15" sourceRef="Dev_exclusivegateway" targetRef="endEvent1"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${submitType == "n" || submitType =="N"}]]></conditionExpression> </sequenceFlow> </process>
4、創建主運行類:DemoMain.java
package com.lx.activiti.helloworld; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Scanner; import org.flowable.engine.FormService; import org.flowable.engine.ProcessEngine; import org.flowable.engine.ProcessEngineConfiguration; import org.flowable.engine.RepositoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.form.FormProperty; import org.flowable.engine.form.TaskFormData; import org.flowable.engine.impl.form.DateFormType; import org.flowable.engine.impl.form.StringFormType; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Maps; /** * 啟動類 * @author * */ public class DemoMain { private static final Logger logger = LoggerFactory.getLogger(DemoMain.class); public static void main(String[] args) throws ParseException { logger.info("啟動程序"); //抽取各步驟作為方法調用 //1. 創建流程引擎 ProcessEngine processEngine = getProcessEngine(); //2. 部署流程文件 ProcessDefinition processDefinition = getDeployment(processEngine); //3. 啟動運行流程 ProcessInstance processInstance =getProcessInstance(processEngine, processDefinition); //4. 處理流程任務 //控制台輸入 Scanner scanner = new Scanner(System.in); //判斷,當流程實例不為空,且流程沒有結束時 while (processInstance!=null && !processInstance.isEnded()) { //獲取任務服務組件 TaskService taskService = processEngine.getTaskService(); //創建任務查詢,將結果放入list集合中 List<Task> list = taskService.createTaskQuery().list(); logger.info("待處理任務數量: [{}]",list.size()); //遍歷list集合 for (Task task : list) { logger.info("待處理任務: [{}]",task.getName()); //獲取表單服務組件 FormService formService = processEngine.getFormService(); //獲取表單內容的集合formProperties TaskFormData taskFormData = formService.getTaskFormData(task.getId()); List<FormProperty> formProperties = taskFormData.getFormProperties(); HashMap<String, Object> variables = Maps.newHashMap(); String line = null; //遍歷formProperties for (FormProperty property : formProperties) { //判斷,如果表單中定義的是字符串類型變量,則按該格式輸入 if (StringFormType.class.isInstance(property.getType())) { logger.info("請輸入 {} ?",property.getName()); line = scanner.nextLine(); variables.put(property.getId(), line); //判斷,如果表單中定義的是日期類型變量,按日期格式輸入 }else if(DateFormType.class.isInstance(property.getType())) { logger.info("請輸入 {} ? 格式 (yyyy-MM-dd)",property.getName()); line = scanner.nextLine(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date date = dateFormat.parse(line); variables.put(property.getId(), date); }else { logger.info("類型暫不支持 {} ",property.getType()); } logger.info("你輸入的是[{}]",line); } taskService.complete(task.getId(),variables); processInstance = processEngine.getRuntimeService() .createProcessInstanceQuery() .processInstanceId(processInstance.getId()) .singleResult(); } } logger.info("結束程序"); } /** * 3. 獲取流程實例:ProcessInstance,啟動運行流程 * @param processEngine * @param processDefinition * @return ProcessInstance */ public static ProcessInstance getProcessInstance(ProcessEngine processEngine, ProcessDefinition processDefinition) { //獲取運行服務 RuntimeService runtimeService = processEngine.getRuntimeService(); //傳入流程定義文件id,調用startProcessInstanceById(),獲取流程實例 ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId()); //獲取流程部定義文件的key值 logger.info("啟動流程[ {}]",processInstance.getProcessDefinitionKey()); return processInstance; } /** * 2 . 獲取流程定義文件:ProcessDefinition , 部署流程 * @param processEngine * @return ProcessDefinition */ public static ProcessDefinition getDeployment(ProcessEngine processEngine) { //通過引擎獲取倉儲服務 RepositoryService repositoryService = processEngine.getRepositoryService(); //通過倉儲服務鏈式調用,部署流程 Deployment deploy = repositoryService.createDeployment()//得到流程部署 .addClasspathResource("diagrams/mywork.bpmn")//加載資源 .deploy();//部署流程 String deployId = deploy.getId(); //獲取流程定義文件:processDefinition ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()//創建流程定義文件查詢 .deploymentId(deployId)//傳入流程部署ID .singleResult();//根據查詢條件;到數據庫中查詢唯一的數據記錄,如果沒有,則為空,如果有多條,則拋出異常 logger.info("流程定義文件: [ {}] ,流程id: [{}]",processDefinition.getName(),processDefinition.getId()); return processDefinition; } /** * 1. 創建流程引擎 * @return ProcessEngine */ public static ProcessEngine getProcessEngine() { //獲取流程配置文件 ProcessEngineConfiguration cfg = ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration(); //通過流程文件創建引擎 ProcessEngine processEngine = cfg.buildProcessEngine(); String name = processEngine.getName(); String version = processEngine.VERSION; logger.info("流程引擎名稱{},版本 [{}]}", name, version); return processEngine; } }
5、運行該類,截取部分測試結果如下圖: