Activiti中的流程歷史保存流程發起人的方法
源自:http://my.oschina.net/liyuj/blog/380777
Activiti中流程的歷史信息保存在ACT_HI_ACTINST表中,流程歷史信息保存在ACT_HI_PROCINST表中,我們可以通過API或者直接寫SQL進行查詢,但是這裏面並沒有流程發起人的信息,流程發起人信息有的時候還是非常必要的,比如查詢某人發起的流程或者做相關的統計等。
鑑於ACT_HI_ACTINST中保存了流程的活動歷史信息,我們還是想在這個表上做文章,但是這個表中並沒有發起人等相關的字段,這時候,我們發現,當一個流程剛發起時,ACT_TYPE_爲startEvent,這時ASSIGNEE_爲空,如果我們能借用這個字段,保存申請人,查詢起來代碼還是比較優雅的,雖然這個字段本身的含義不是申請人。
另外,ACT_HI_PROCINST表中還有一個START_USER_ID_字段,但是默認爲空。通過上述兩種保存流程發起人的方式,在不同的場景中都能夠通過簡單的方式查詢到流程的發起人信息。
下一步,就是研究Activiti的代碼了,看看能不能找到相應的擴展點,解決這個問題。
經過研究,找到了擴展點,開發起來還是比較方便的,下面進行詳細描述,注意,本文的開發基於Activiti5.15.1版本,大體掃了下代碼,更新的5.17版本應該也兼容,但未經過測試。
對於流程發起時保存ACT_HI_ACTINST表和ACT_HI_PROCINST表的代碼,在DefaultHistoryManager類的recordProcessInstanceStart方法中,所以我們只要想辦法繼承這個類,然後覆寫這個方法即可,而DefaultHistoryManager的創建,是在DefaultHistoryManagerSessionFactory中,而DefaultHistoryManagerSessionFactory的初始化,是在ProcessEngineConfigurationImpl中的initSessionFactories方法,找到這裏,思路已經非常清晰了,需要寫的代碼沒有多少。
另外,還需要注意一點,Activiti中有一個線程局部變量,保存着線程上下文有關的用戶信息,爲Authentication中的authenticatedUserIdThreadLocal,並且該類提供相關的API進行賦值和取值,因此我們需要在流程發起之前設置該局部變量。
一、擴展ProcessEngineConfigurationImpl,如果使用Spring集成的話,繼承SpringProcessEngineConfiguration類,覆寫initSessionFactories方法,在該方法中調用addSessionFactory方法添加新的自定義DefaultHistoryManagerSessionFactory;
二、擴展DefaultHistoryManagerSessionFactory,覆寫openSession方法,在該方法中創建新的DefaultHistoryManager;
三、擴展DefaultHistoryManager,覆寫recordProcessInstanceStart方法,在該方法中爲assign字段賦值即可,至於當前的流程發起人獲取方法,可以調用Authentication的API獲取;
具體代碼如下所示:
1
2
3
4
5
6
7
8
9
10
|
import org.activiti.spring.SpringProcessEngineConfiguration; public class ProcessEngineConfiguration extends SpringProcessEngineConfiguration { @Override protected void initSessionFactories() { super .initSessionFactories(); super .addSessionFactory( new ProcessHistoryManagerSessionFactory()); } } |
1
2
3
4
5
6
7
8
9
10
|
import org.activiti.engine.impl.interceptor.Session; import org.activiti.engine.impl.persistence.DefaultHistoryManagerSessionFactory; public class ProcessHistoryManagerSessionFactory extends DefaultHistoryManagerSessionFactory { @Override public Session openSession() { return new ProcessHistoryManager(); } } |
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
|
public class ProcessHistoryManager extends DefaultHistoryManager { @Override public void recordProcessInstanceStart(ExecutionEntity processInstance) { if (isHistoryLevelAtLeast(HistoryLevel.ACTIVITY)) { HistoricProcessInstanceEntity historicProcessInstance = new HistoricProcessInstanceEntity(processInstance); getDbSqlSession().insert(historicProcessInstance); IdGenerator idGenerator = Context.getProcessEngineConfiguration().getIdGenerator(); String processDefinitionId = processInstance.getProcessDefinitionId(); String processInstanceId = processInstance.getProcessInstanceId(); String executionId = processInstance.getId(); HistoricActivityInstanceEntity historicActivityInstance = new HistoricActivityInstanceEntity(); historicActivityInstance.setId(idGenerator.getNextId()); historicActivityInstance.setProcessDefinitionId(processDefinitionId); historicActivityInstance.setProcessInstanceId(processInstanceId); historicActivityInstance.setExecutionId(executionId); historicActivityInstance.setActivityId(processInstance.getActivityId()); historicActivityInstance.setActivityName((String) processInstance.getActivity().getProperty( "name" )); historicActivityInstance.setActivityType((String) processInstance.getActivity().getProperty( "type" )); Date now = Context.getProcessEngineConfiguration().getClock().getCurrentTime(); historicActivityInstance.setStartTime(now); if (processInstance.getTenantId() != null ) { historicActivityInstance.setTenantId(processInstance.getTenantId()); } //通過Authentication.getAuthenticatedUserId()獲取當前線程綁定的用戶ID。 historicActivityInstance.setAssignee(Authentication.getAuthenticatedUserId()); getDbSqlSession().insert(historicActivityInstance); } } } |
Activiti在HistoricProcessInstanceEntity的構造器中已經通過Authentication獲取了線程綁定用戶ID。因此,我們只需要在調用runtimeService的startProcessInstance的相關方法之前賦值即可,賦值方法有兩種:
1
2
|
identityService.setAuthenticatedUserId(); //調用官方的開放API; Authentication.setAuthenticatedUserId(); //直接調用底層實現;
|