Activiti6详细教程
一、為什么選擇Activiti
activiti介紹 Activiti是由Alfresco軟件在2010年5月17日發布的業務流程管理(BPM)框架,它是覆蓋了業務流程管理,工作流,服務協作等領域的一個開源,靈活的,易擴展的可執行流程語言框架。
| 開源 | Activiti JBPM? Flowable | 開源 免費 | 開發工作量大 開發難度大 中文支持不好 | Activiti | 相對JBPM上手容易 原生支持Spring 與 Spring boot 集成較好 ? Flowable新出的,使用人數少教程資源少 |
| 商用 | 炎黃盈動 普元 慧正 天翎 宏天 | 開發工作量小 開發難度小 符合中國國情 | 閉源 價格高 | ? | ? |
二、核心7大接口、28張表
(一)7大接口
- RepositoryService:提供一系列管理流程部署和流程定義的API。
- RuntimeService:在流程運行時對流程實例進行管理與控制。
- TaskService:對流程任務進行管理,例如任務提醒、任務完成和創建任務等。
- IdentityService:提供對流程角色數據進行管理的API,這些角色數據包括用戶組、用戶及它們之間的關系。
- ManagementService:提供對流程引擎進行管理和維護的服務。
- HistoryService:對流程的歷史數據進行操作,包括查詢、刪除這些歷史數據。
- FormService:表單服務。
(二)28張表
表結構操作:?
3.3.1:資源庫流程規則表?
- 1) act_re_deployment 部署信息表?
- 2) act_re_model 流程設計模型部署表?
- 3) act_re_procdef 流程定義數據表?
3.3.2:運行時數據庫表?
- 1) act_ru_execution 運行時流程執行實例表?
- 2) act_ru_identitylink 運行時流程人員表,主要存儲任務節點與參與者的相關信息?
- 3) act_ru_task 運行時任務節點表?
- 4) act_ru_variable 運行時流程變量數據表?
3.3.3:歷史數據庫表?
- 1) act_hi_actinst 歷史節點表?
- 2) act_hi_attachment 歷史附件表?
- 3) act_ih_comment 歷史意見表?
- 4) act_hi_identitylink 歷史流程人員表?
- 5) act_hi_detail 歷史詳情表,提供歷史變量的查詢?
- 6) act_hi_procinst 歷史流程實例表?
- 7) act_hi_taskinst 歷史任務實例表?
- 8) act_hi_varinst 歷史變量表?
3.3.4:組織機構表?
- 1) act_id_group 用戶組信息表?
- 2) act_id_info 用戶擴展信息表?
- 3) act_id_membership 用戶與用戶組對應信息表?
- 4) act_id_user 用戶信息表?
這四張表很常見,基本的組織機構管理,關于用戶認證方面建議還是自己開發一套,組件自帶的功能太簡單,使用中有很多需求難以滿足?
3.3.5:通用數據表?
- 1) act_ge_bytearray 二進制數據表?
- 2) act_ge_property 屬性數據表存儲整個流程引擎級別的數據,初始化表結構時,會默認插入三條記錄,?
- 3.4:activiti.cfg.xml(activiti的配置文件)?
Activiti核心配置文件,配置流程引擎創建工具的基本參數和數據庫連接池參數。?
定義數據庫配置參數:?
- jdbcUrl: 數據庫的JDBC URL。?
- jdbcDriver: 對應不同數據庫類型的驅動。?
- jdbcUsername: 連接數據庫的用戶名。?
- jdbcPassword: 連接數據庫的密碼。?
基于JDBC參數配置的數據庫連接 會使用默認的MyBatis連接池。 下面的參數可以用來配置連接池(來自MyBatis參數):?
- jdbcMaxActiveConnections: 連接池中處于被使用狀態的連接的最大值。默認為10。?
- jdbcMaxIdleConnections: 連接池中處于空閑狀態的連接的最大值。?
- jdbcMaxCheckoutTime: 連接被取出使用的最長時間,超過時間會被強制回收。 默認為20000(20秒)。?
- jdbcMaxWaitTime: 這是一個底層配置,讓連接池可以在長時間無法獲得連接時, 打印一條日志,并重新嘗試獲取一個連接。(避免因為錯誤配置導致沉默的操作失敗)。 默認為20000(20秒)。
?
?流程部署相關表?
- act_re_deployement 部署對象表?
- act_rep_procdef ?流程定義表?
- act_ge_bytearray 資源文件表?
- act_ge_prperty ?主鍵生成策略表(對于部署對象表的主鍵ID)
?流程實例相關表
- ?act_ru_execution 正在執行的執行對象表(包含執行對象ID和流程實例ID,如果有多個線程可能流程實例ID不一樣)
- ?act_hi_procinst 流程實例歷史表
- ?act_hi_actinst 存放歷史所有完成的任務
?Task 任務相關表
- ?act_ru_task 代辦任務表 (只對應節點是UserTask的)
- ?act_hi_taskinst 代辦任務歷史表 (只對應節點是UserTask的)?
- ?act_hi_actinst ?所有節點活動歷史表 (對應流程的所有節點的活動歷史,從開始節點一直到結束節點中間的所有節點的活動都會被記錄)
流程變量表
- ?act_ru_variable 正在執行的流程變量表
- ?act_hi_variable 流程變量歷史表
?三、創建BPMN業務流程模型
1.將Activiti提供的流程設計器應用activiti-app.war部署到Tomcat的webapps目錄。
2.創建新的MySql數據庫。修改activiti-app\WEB-INF\classes\META-INF\activiti-app目錄下的activiti-app.properties配置文件,默認使用H2內存數據庫,創建的模型重啟后會丟失,改成使用MySql數據庫。
3.瀏覽器訪問http://localhost:8080/activiti-app,登錄賬戶:admin:test
4.創建一個請假審批流程圖
?
給每個用戶任務指派候選組(有權限執行當前任務的角色)
指派候選組
?
排他網關設置條件分支表達式
5.導出流程圖為.bpmn20.xml文件
導出xml文件
四、Spring Boot與Activiti 6.0整合
1.在POM文件中添加依賴
<dependency><groupId>org.activiti</groupId><artifactId>activiti-spring-boot-starter-basic</artifactId><version>6.0.0</version> </dependency>2.將導出的.bpmn20.xml文件拷貝到項目文件夾/resources/processes下
3.application.properties文件添加配置項
databaseSchemaUpdate配置項可以設置流程引擎啟動和關閉時數據庫執行的策略。 databaseSchemaUpdate有以下四個值:
- false:false為默認值,設置為該值后,Activiti在啟動時,會對比數據庫表中保存的版本,如果沒有表或者版本不匹配時,將在啟動時拋出異常。
- true:設置為該值后,Activiti會對數據庫中所有的表進行更新,如果表不存在,則Activiti會自動創建。
- create-drop:Activiti啟動時,會執行數據庫表的創建操作,在Activiti關閉時,執行數據庫表的刪除操作。
- drop-create:Activiti啟動時,執行數據庫表的刪除操作在Activiti關閉時,會執行數據庫表的創建操作。
4.啟動應用,會在數據庫里創建28張表,表創建好之后停止應用。application.properties文件修改配置項
#每次應用啟動不檢查Activiti數據表是否存在及版本號是否匹配,提升應用啟動速度 spring.activiti.database-schema-update=false5.application.properties文件增加配置項
#保存歷史數據級別設置為full最高級別,便于歷史數據的追溯 spring.activiti.history-level=full對于歷史數據,保存到何種粒度,Activiti提供了history-level屬性對其進行配置。history-level屬性有點像log4j的日志輸出級別,該屬性有以下四個值:
- none:不保存任何的歷史數據,因此,在流程執行過程中,這是最高效的。
- activity:級別高于none,保存流程實例與流程行為,其他數據不保存。
- audit:除activity級別會保存的數據外,還會保存全部的流程任務及其屬性。audit為history的默認值。
- full:保存歷史數據的最高級別,除了會保存audit級別的數據外,還會保存其他全部流程相關的細節數據,包括一些流程參數等。
6.完成以上步驟,就可以在程序中使用自動注入的方式,使用Activiti的7大接口。
@Autowired private RuntimeService runtimeService;@Autowired private TaskService taskService;@Autowired private IdentityService identityService;@Autowired private RepositoryService repositoryService;@Autowired private ProcessEngine processEngine;@Autowired private HistoryService historyService;?
5:核心API? 5.1:ProcessEngine? 說明:? 1) 在Activiti中最核心的類,其他的類都是由他而來。? 2) 產生方式:在前面看到了兩種創建ProcessEngine(流程引擎)的方式,而這里要簡化很多,調用ProcessEngines的getDefaultProceeEngine方法時會自動加載classpath下名為activiti.cfg.xml文件。? 3) 可以產生RepositoryService4) 可以產生RuntimeService5) 可以產生TaskService各個Service的作用:? RepositoryService 管理流程定義? RuntimeService 執行管理,包括啟動、推進、刪除流程實例等操作? TaskService 任務管理? HistoryService 歷史管理(執行完的數據的管理)? IdentityService 組織機構管理? FormService 一個可選服務,任務表單管理? ManagerService5.2:RepositoryService? 是Activiti的倉庫服務類。所謂的倉庫指流程定義文檔的兩個文件:bpmn文件和流程圖片。? 1) 產生方式2) 可以產生DeploymentBuilder,用來定義流程部署的相關參數3) 刪除流程定義5.3:RuntimeService? 是activiti的流程執行服務類。可以從這個服務類中獲取很多關于流程執行相關的信息。? 5.4:TaskService? 是activiti的任務服務類。可以從這個類中獲取任務的信息。? 5.5:HistoryService? 是activiti的查詢歷史信息的類。在一個流程執行完成后,這個對象為我們提供查詢歷史信息。? 5.6:ProcessDefinition? 流程定義類。可以從這里獲得資源文件等。? 5.7:ProcessInstance? 代表流程定義的執行實例。如范冰冰請了一天的假,她就必須發出一個流程實例的申請。一個流程實例包括了所有的運行節點。我們可以利用這個對象來了解當前流程實例的進度等信息。流程實例就表示一個流程從開始到結束的最大的流程分支,即一個流程中流程實例只有一個。? 5.8:Execution? Activiti用這個對象去描述流程執行的每一個節點。在沒有并發的情況下,Execution就是同ProcessInstance。流程按照流程定義的規則執行一次的過程,就可以表示執行對象Execution。??
RepositoryService:管理流程定義RuntimeService:執行管理,包括啟動、推進、刪除流程實例等操作TaskService:任務管理HistoryService:歷史管理(執行完的數據的管理)IdentityService:組織機構管理FormService:一個可選服務,任務表單管理ManagerService5.2:RepositoryService 是Activiti的倉庫服務類。所謂的倉庫指流程定義文檔的兩個文件:bpmn文件和流程圖片。1)?產生方式2)?可以產生DeploymentBuilder,用來定義流程部署的相關參數3)?刪除流程定義5.3:RuntimeService 是activiti的流程執行服務類。可以從這個服務類中獲取很多關于流程執行相關的信息。5.4:TaskService 是activiti的任務服務類。可以從這個類中獲取任務的信息。5.5:HistoryService 是activiti的查詢歷史信息的類。在一個流程執行完成后,這個對象為我們提供查詢歷史信息。5.6:ProcessDefinition 流程定義類。可以從這里獲得資源文件等。5.7:ProcessInstance 代表流程定義的執行實例。如范冰冰請了一天的假,她就必須發出一個流程實例的申請。一個流程實例包括了所有的運行節點。我們可以利用這個對象來了解當前流程實例的進度等信息。流程實例就表示一個流程從開始到結束的最大的流程分支,即一個流程中流程實例只有一個。5.8:Execution Activiti用這個對象去描述流程執行的每一個節點。在沒有并發的情況下,Execution就是同ProcessInstance。流程按照流程定義的規則執行一次的過程,就可以表示執行對象Execution。?
五、項目中的用戶、角色與Activiti中的用戶、用戶組整合
每個項目都有自己的用戶、角色表,Activiti也有自己的用戶、用戶組表。因此項目中的用戶、角色與Activiti中的用戶、用戶組要做整合。
//項目中每創建一個新用戶,對應的要創建一個Activiti用戶 //兩者的userId和userName一致 User admin=identityService.newUser("1"); admin.setLastName("admin"); identityService.saveUser(admin);//項目中每創建一個角色,對應的要創建一個Activiti用戶組 Group adminGroup=identityService.newGroup("1"); adminGroup.setName("admin"); identityService.saveGroup(adminGroup);//用戶與用戶組關系綁定 identityService.createMembership("1","1");六、請假審批流程
1.請假申請和請假審批數據庫表設計
表設計原則:流程數據和業務數據相分離。Activiti相關表只負責流程的跳轉、走向等。流程中產生的業務表單數據、審批意見、附件等存儲在開發人員定義的業務表中。流程數據和業務數據之間通過processInstanceId(流程實例ID)和業務數據主鍵相互關聯。
為什么不使用Activiti相關表來存儲表單數據和附件?
activiti參數表
Activiti為了應用的靈活性和通用性采用了縱表的方式存儲表單數據。假設一條請假申請表單數據有10個字段,那就需要10條記錄存儲原本橫表只需要一條記錄存儲的數據。采用縱表的方式會有如下問題:
會有大量的冗余數據并且數據量會急劇的增長
查詢語句復雜,查詢效率低
尤其不適合做后期的統計報表分析
activiti附件表
Activiti存儲附件使用Blob數據格式,文件存儲在數據庫里,數據庫的數據文件會變得超大,不利于數據庫備份和遷移。
請假申請表結構
請假申請表
請假審批表結構
請假審批表
2.填寫請假申請表單,啟動流程實例
填寫請假申請
//啟動流程實例,字符串"vacation"是BPMN模型文件里process元素的id ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("vacation"); //流程實例啟動后,流程會跳轉到請假申請節點 Task vacationApply = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult(); //設置請假申請任務的執行人 taskService.setAssignee(vacationApply.getId(), req.getUserId().toString());//設置流程參數:請假天數和表單ID //流程引擎會根據請假天數days>3判斷流程走向 //formId是用來將流程數據和表單數據關聯起來 Map<String, Object> args = new HashMap<>(); args.put("days", req.getDays()); args.put("formId", formId);//完成請假申請任務 taskService.complete(vacationApply.getId(), args);
3.待審批列表
?
//查出當前登錄用戶所在的用戶組 List<Group> groups = identityService.createGroupQuery().groupMember(String.valueOf(userId)).list(); List<String> groupNames = groups.stream().map(group -> group.getName()).collect(Collectors.toList());//查詢用戶組的待審批請假流程列表 List<Task> tasks = taskService.createTaskQuery().processDefinitionKey("vacation").taskCandidateGroupIn(groupNames).listPage(pageNum - 1, pageSize);//根據流程實例ID查詢請假申請表單數據 List<String> processInstanceIds = tasks.stream().map(task -> task.getProcessInstanceId()).collect(Collectors.toList()); List<VacationApplyBasicPO> vacationApplyList =?vacationRepository.getVacationApplyList(processInstanceIds);
4.請假審批功能
?
//查詢當前審批節點 Task vacationAudit = taskService.createTaskQuery().taskId(req.getTaskId()).singleResult();if (req.getAuditResult() == 1) {//審批通過//設置流程參數:審批IDMap<String, Object> args = new HashMap<>();args.put("auditId", auditId);//設置審批任務的執行人taskService.claim(vacationAudit.getId(), req.getUserId().toString());//完成審批任務taskService.complete(vacationAudit.getId(), args); } else {//審批不通過,結束流程runtimeService.deleteProcessInstance(vacationAudit.getProcessInstanceId(), auditId); }
5.查看流程圖功能
?
//controller層代碼 @RequestMapping(value = "/image", method = RequestMethod.GET) public void image(HttpServletResponse response,@RequestParam String processInstanceId) {try {InputStream is = vacationService.getDiagram(processInstanceId);if (is == null)return;response.setContentType("image/png");BufferedImage image = ImageIO.read(is);OutputStream out = response.getOutputStream();ImageIO.write(image, "png", out);is.close();out.close();} catch (Exception ex) {logger.error("查看流程圖失敗", ex);} }//service層代碼 @Override public InputStream getDiagram(String processInstanceId) {//獲得流程實例ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();String processDefinitionId = StringUtils.EMPTY;if (processInstance == null) {//查詢已經結束的流程實例HistoricProcessInstance processInstanceHistory =historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();if (processInstanceHistory == null)return null;elseprocessDefinitionId = processInstanceHistory.getProcessDefinitionId();} else {processDefinitionId = processInstance.getProcessDefinitionId();}//使用宋體String fontName = "宋體";//獲取BPMN模型對象BpmnModel model = repositoryService.getBpmnModel(processDefinitionId);//獲取流程實例當前的節點,需要高亮顯示List<String> currentActs = Collections.EMPTY_LIST;if (processInstance != null)currentActs = runtimeService.getActiveActivityIds(processInstance.getId());return processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator().generateDiagram(model, "png", currentActs, new ArrayList<String>(),fontName, fontName, fontName, null, 1.0); }
?參照教程:https://blog.csdn.net/qq877507054/article/details/60143099
?
總結
以上是生活随笔為你收集整理的Activiti6详细教程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java多个pdf文件合并一个pdf(多
- 下一篇: 多张图片合成一个pdf文件的操作方法