springboot2.0整合工作流activiti6.0,以及與業務整合時的一些坑
1、首先,要在springboot工程的pom檔案中引入相關jar包
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring</artifactId>
<version>6.0.0</version>
</dependency>
2、新增配置檔案,注入activiti的service
@Configuration public class ActivitiConfiguration { @Autowired private DataSource dataSource; @Autowired private PlatformTransactionManager platformTransactionManager; @Bean public SpringProcessEngineConfiguration springProcessEngineConfiguration(){ SpringProcessEngineConfiguration spec = new SpringProcessEngineConfiguration(); spec.setDataSource(dataSource); spec.setTransactionManager(platformTransactionManager); spec.setDatabaseSchemaUpdate("true"); Resource[] resources = null; // 啟動自動部署流程 try { resources = new PathMatchingResourcePatternResolver().getResources("classpath*:bpmn/*.bpmn"); } catch (IOException e) { e.printStackTrace(); } spec.setDeploymentResources(resources); return spec; } @Bean public ProcessEngineFactoryBean processEngine(){ ProcessEngineFactoryBean processEngineFactoryBean = new ProcessEngineFactoryBean(); processEngineFactoryBean.setProcessEngineConfiguration(springProcessEngineConfiguration()); return processEngineFactoryBean; } @Bean public RepositoryService repositoryService() throws Exception{ return processEngine().getObject().getRepositoryService(); } @Bean public RuntimeService runtimeService() throws Exception{ return processEngine().getObject().getRuntimeService(); } @Bean public TaskService taskService() throws Exception{ return processEngine().getObject().getTaskService(); } @Bean public HistoryService historyService() throws Exception{ return processEngine().getObject().getHistoryService(); } }
3、與業務進行整合。
這裡我使用activiti變數儲存流程資訊,在流程執行中使用流程監聽器去修改業務表。為了簡單,業務表和activiti的表在一個數據庫內,這樣就不會涉及分散式事務的問題了,直接使用spring的事務管理器就可以控制事務的提交,回滾了。
3.1 畫流程圖
3.2設定流程資訊
3.3設定任務監聽器
這裡有不同的設定方式,我這裡用的是expression,這樣就不用實現activiti的JavaDelegate介面了,而且同一個類中
可以實現很多方法,就像下面的apply方法就是自定義的一個方法。(Java Class和Delegate expression都需要實現
接口才行)。
注意配置中的Event事件,這裡可以選擇監聽器觸發的時機,任務監聽器有craete,assignment,complete,all四
種。 連線監聽器有take,還有其他監聽器請自行探索。
上面的apply方法中,我們可以看到有兩個引數,其中execution是屬於activiti內建的引數,java程式碼中只需要使用 DelegateExecution接收即可,從中我們可以獲取流程相關的一些資訊,而task是我自定義的一個引數,如果要想在
監聽器中監聽,我們需要在流程變數中設定名為task的引數,變數分為全域性的流程變數,區域性的任務變數,和瞬時
變數,因為我這裡 task變數不需要存庫,只是想在監聽器中獲取一下,所以這裡我儲存的是瞬時變數。
注意點:因為在流程啟動的時候我沒有直接設定臨時變數的地方,所以我是在啟動流程例項的時候觸發了一個監聽器,
然後在監聽器中設定了的瞬時變數。
4、啟動流程,並執行稽核流程
4.1 啟動流程
// 這裡的myProcess就是我們上面流程中設定的Id,businessKey是業務key,可以用來和
// 業務進行繫結
runtimeService.startProcessInstanceByKey("myProcess", "businessKey");
4.2執行稽核流程
// 通過業務key查詢出對應的任務
Task task = taskService.createTaskQuery()
.processInstanceBusinessKey("businessKey").singleResult();
// 將相關資訊放入工作流區域性變數,和任務進行繫結
Map<String, Object> localVariable = new HashMap<>(2);
localVariable.put("user", "username");
localVariable.put("time" ,"2018-12-09");
taskService.setVariablesLocal(task.getId(), localVariable);
// 設定臨時變數
Map<String, Object> variable = new HashMap<>(1);
variable.put("result", "pass");
// 完成任務並設定瞬時變數(這裡還可以通過taskService直接設定瞬時變數)
taskService.complete(task.getId(),null,variable);
4.3完成任務會觸發我們的任務監聽器(設定event為complete)
@Transactional(rollbackFor = Exception.class)
public void apply(DelegateExecution execution,Task task){
// 這裡可以對我們的業務表進行操作,保證業務表和工作流中的狀態是匹配的
}
以上,許可權是在業務表中進行控制的,所以的工作流執行的過程中,我沒有給任務指定任何處理人(工作流不指定
任務處理人也可以一直往下執行),在我的業務方法中,就相當於一直呼叫next方法,流程就會按照正常流程一直
往下執行,直到結束。 如果是需要駁回等流程,那就需要單獨處理判斷了。
如果需要設定處理人,只需要在任務的屬性中進行配置即可,如下圖:
總結:使用工作流有兩種方式
1、任務處理許可權還是在業務表中進行控制,通過業務key查詢任務並完成任務,工作流只是起一個流轉以及
儲存流程歷史資訊的作用,對於業務來說,只要通過業務key找到流程任務,然後執行下一步即可,駁回等
操作需要自己處理判斷,然後完成任務後,自動觸發作流的監聽器去修改業務的具體資料。
2、任務處理許可權由工作流控制,我們在工作流中指定任務的處理人(處理人可以動態指定),然後通過處理人查
詢任務並完成任務,然後自動觸發作流的監聽器去修改業務的具體資料。
注意事項:1、如果想要在監聽器中繫結任務變數,需要在任務監聽器中進行設定任務變數,千萬不要在任務之後的連
線監聽器中設定任務變數,因為在一個事務中,上一個任務屬於還沒有完成,所以還能設定。但是!!!這樣
設定會導致任務變數儲存到act_ru_variable中,正常應該儲存到act_hi_varinst中。不然設定的時候雖然不會報
錯,但是到最後結束流程的時候,你就會發現結束不了了,因為外來鍵原因,act_ru_variable中存在任務變數沒有
刪除,匯出結束任務時,任務資訊不能刪除,然後報錯!!!
2、瞬時變數的設定問題,啟動流程的時候,沒有直接設定瞬時變數的地方,所以我找到了在啟動時觸發監聽器
設定。但是,流程如果執行到了最後,後面沒有使用者任務節點了,這時候,就不能設定瞬時變量了,不然activiti
會轉換型別異常,它會將瞬時變數轉為全域性變數型別,這時就會報錯,轉換異常!!!