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();
//直接调用底层实现;
|