概述
瞭解Activiti
假如你還不知道Activiti是什麼,那麼工作流引擎對你來說一定也是新的,解決Activiti和工作流知識盲點,所以看到到這裏就對了,還有Android同學會誤以爲是“Activity”,工作流引擎Activiti和Android開發的Activity這是兩碼事兒,Activiti是一個開源的自動化業務工作流引擎,具體概念就不碎碎念介紹了,
使用工作流引擎
工作流引擎最常見用於審批流程中,現在一線互聯網公司也開始使用,並有快速推廣的趨勢,複雜繁多的業務流程如果採用if else實現那將是崩潰的,代碼不可維護,業務流程在代碼中可讀性很差,所以高人設計了業務流程模型圖示BPMN2.0,我們要做到就是把業務場景抽象爲標準流程圖,把流程圖丟到流程引擎中按流程定義約定逐步流轉,很顯然擴展性和業務可描述性會好很多,所以工作流引擎主要用於解決複雜的業務,目前經常被提起的中臺系統抽象業務爲服務,也涉及大量智能的業務流程引擎做支撐。
讓工作流引擎運行
我們快速體驗一個流程的運行過程
-
搭建流程引擎
我們在IDEA環境中使用 Spring Initializr引導我們創建一個標準工程,採用最新穩定版spring boot 2.0.2,Activiti 6.0,通過引入H2內存數據庫,方便我們快速啓動程序演示,而不用費心在創建數據庫相關工作,當程序啓動Spring boot會基於自動配置原理給我們隱式的創建一個工作流引擎對象ProcessEngine,並把RuntimeService(控制流程運行時數據流轉)等核心服務註冊到 Spring 容器中,我們只需要 依賴注入使用即可。
-
繪製流程圖
繪製流程圖建議大家通過Eclipse + Activiti插件來繪製,如果大家對流程圖元素還不瞭解,可以直接拷貝流程定義文件運行,這樣方便快速的運行我們的快速程序
-
部署流程圖
我們代碼裏面並沒有體現流程部署的過程,也得益於Spring Boot提供的自動部署功能,也是在Spring 容器啓動的過程通過 activiti-spring組件,把Class path對應的/processes目錄的流程文件自動加載部署,約定大於配置,快速演示代碼推薦大家把流程圖放到/processes 資源包下面,線上系統則不建議這樣做
-
啓動流程
啓動流程是通過流程定義文件Key創建一個流程實例的過程,類似於我們根據類名new出一個對象的原理,一個流程定義文件可以生成許許多多的流程實例
-
多用戶協助審批流程
在命令行下體驗流程審批的效果,對Java後端開發來說,更多的傾向於瞭解底層的原理,而對UI效果興趣不高,其實Activiti也跟我們提供了還不錯的activiti-app來更好的體驗流程的流轉。我們這裏在命令行下運行工作流程,可以滿足一下極客青年小小的虛榮心。
開發
創建工程
基於spring Initializr創建一個標準的maven工程,並添加相關依賴 spring boot 2.0.2最新穩定版,Activiti 6最新穩定版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
|
Spring Initializr會自動創建程序啓動入口類ActivitiDemoApplication
/src/main/java/com.imooc.activiti.demo.ActivitiDemoApplicationpackage com.imooc.activiti.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplicationpublic class ActivitiDemoApplication { public static void main(String[] args) { SpringApplication.run(ActivitiDemoApplication.class, args); } }
設計流程定義文件
剛開始設計流程定義文件推薦大家使用 Eclipse+ Activiti插件的方式, Activiti也提供了基於瀏覽器的web 流程設計器,都可以分別體驗一下,這個流程定義文件就是普通的xml,大家應該能很容易看明白這個xml文件
// src/main/resources/processes/second_approve.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" xmlns:tns="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test" id="m1528728906382" name=""> <process id="second_approve" name="二級審批流程" isExecutable="true" isClosed="false" processType="None"> <startEvent id="startEvent" name="開始"></startEvent> <userTask id="submitForm" 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="submitForm"></sequenceFlow> <exclusiveGateway id="decideSubmit" name="提交OR取消"></exclusiveGateway> <sequenceFlow id="flow2" sourceRef="submitForm" targetRef="decideSubmit"></sequenceFlow> <userTask id="tl_approve" name="主管審批"> <extensionElements> <activiti:formProperty id="tlApprove" name="主管審批結果" type="string"></activiti:formProperty> <activiti:formProperty id="tlMessage" name="主管備註" type="string" required="true"></activiti:formProperty> </extensionElements> </userTask> <sequenceFlow id="flow3" sourceRef="decideSubmit" targetRef="tl_approve"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${submitType == "y" || submitType == "Y"}]]></conditionExpression> </sequenceFlow> <exclusiveGateway id="decideTLApprove" name="主管審批校驗"></exclusiveGateway> <sequenceFlow id="flow4" sourceRef="tl_approve" targetRef="decideTLApprove"></sequenceFlow> <endEvent id="endEvent" name="結束"></endEvent> <endEvent id="endEventCancel" name="取消"></endEvent> <sequenceFlow id="flow8" sourceRef="decideSubmit" targetRef="endEventCancel"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${submitType == "n" || submitType == "N"}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow9" sourceRef="decideTLApprove" targetRef="submitForm"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${tlApprove == "n" || tlApprove == "N"}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="_2" sourceRef="decideTLApprove" targetRef="endEvent"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${tlApprove == "y" || tlApprove == "Y"}]]></conditionExpression> </sequenceFlow> </process> </definitions>
開發可以根據spring boot自動裝配的流程樣例
流程執行我們使用了CommandLineRunner,這個類的事例會在Spring boot容器啓動加載完成後直接運行
//src/main/java/com.imooc.activiti.demo.AutoConfigurationProcessDemo @Configuration @Slf4jpublic class AutoConfigurationProcessDemo { @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @Autowired private FormService formService; /** * 命令行執行 * * @return */ @Bean public CommandLineRunner commandLineRunner() { return new CommandLineRunner() { @Override public void run(String... args) throws Exception { log.info("啓動我們的程序"); //啓動運行流程 ProcessInstance processInstance = startProcessInstance("second_approve"); //處理流程任務 processTask(processInstance); log.info("結束我們的程序"); } }; } /** * 處理流程任務 * * @param processInstance * @throws ParseException */ private void processTask(ProcessInstance processInstance) throws ParseException { Scanner scanner = new Scanner(System.in); while (processInstance != null && !processInstance.isEnded()) { List<Task> list = taskService.createTaskQuery().list(); log.info("待處理任務數量 [{}]", list.size()); for (Task task : list) { log.info("待處理任務 [{}]", task.getName()); Map<String, Object> variables = buildVariablesByScanner(scanner, task); taskService.complete(task.getId(), variables); processInstance = runtimeService .createProcessInstanceQuery() .processInstanceId(processInstance.getId()) .singleResult(); } } scanner.close(); } /** * 從控制檯獲取變量 * * @param scanner * @param task * @return * @throws ParseException */ private Map<String, Object> buildVariablesByScanner(Scanner scanner, Task task) throws ParseException { TaskFormData taskFormData = formService.getTaskFormData(task.getId()); List<FormProperty> formProperties = taskFormData.getFormProperties(); return buildVariablesByScanner(scanner, formProperties); } public static Map<String, Object> buildVariablesByScanner(Scanner scanner, List<FormProperty> formProperties) throws ParseException { Map<String, Object> variables = Maps.newHashMap(); for (FormProperty property : formProperties) { String line = null; if (StringFormType.class.isInstance(property.getType())) { log.info("請輸入 {} ?", property.getName()); line = scanner.nextLine(); variables.put(property.getId(), line); } else if (DateFormType.class.isInstance(property.getType())) { log.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 { log.info("類型暫不支持 {}", property.getType()); } log.info("您輸入的內容是 [{}]", line); } return variables; } /** * 獲取流程實例 * * @param processDefinitionId * @return */ private ProcessInstance startProcessInstance(String processDefinitionId) { ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionId); log.info("啓動流程 [{}]", processInstance.getProcessDefinitionKey()); return processInstance; } }
命令行運行效果
可以看到我簡單3個文件就可以讓工作流程序運行起來,爲了讓控制檯輸出更清晰直觀,讓控制檯日誌僅僅輸出message日誌信息,忽略默認格式中日誌級別時間信息等等
//src/main/resources/application.yml logging: pattern: console: "%m%n"
我們可以直接在控制檯運行 mvn spring-boot:run,當然也可以mvn package打出一個Jar包後,運行獨立jar包
mvn spring-boot:run // 輸入正常流程審批通過 啓動我們的程序 啓動流程 [second_approve] 待處理任務數量 [1] 待處理任務 [填寫審批信息] 請輸入 申請信息 ? $辭職,世界那麼大,我想去看看 您輸入的內容是 [辭職,世界那麼大,我想去看看] 請輸入 申請人姓名 ? $Jimmy 您輸入的內容是 [Jimmy] 請輸入 提交時間 ? 格式 (yyyy-MM-dd) $2018-05-21 您輸入的內容是 [2018-05-21] 請輸入 確認申請 ? $Y 您輸入的內容是 [Y] 待處理任務數量 [1] 待處理任務 [主管審批] 請輸入 主管審批結果 ? $Y 您輸入的內容是 [Y] 請輸入 主管備註 ? $錢包那麼小,勸你別作妖 您輸入的內容是 [錢包那麼小,勸你別作妖] 結束我們的程序
總節
我們簡單演示了一下Activiti6.0工作流的使用方式,希望能幫助到大家,Activiti是非常受歡迎的工作流引擎,很多公司的工作流平臺技術選型都選了Activiti,工作流技術相對複雜一些,如果想深入瞭解工作流技術是需要下一番功夫的,正如說所Activiti工作流是一個有技術門檻的事兒,掌握有門檻的技術,提升自己的競爭力,相信大家可以做到的。
作者:JimmyNo1
鏈接:https://www.imooc.com/article/35590
來源:慕課網
本文原創發佈於慕課網 ,轉載請註明出處,謝謝合作