实际工作中,待办事项一般是通过用户ID进行查询的,这样比较简单、方便。在Activiti中,当绘制流程的人工任务节点时,为了便于日后维护,也为了更符合实际的场景,通常不会直接指定受理人,而是指定候选组,也就是通常说的角色。而很多时候,这个角色只有一个用户,但是在Activiti的实现中,这里面需要一个中间环节,就是签收,这个签收的过程,显得不够智能,用户会很自然的觉得多此一举,多了一步没必要的操作,那么能不能把这个环节省掉呢?本文将提供解决这个问题的方法。
这个问题,只能研究下Activiti的源代码了,如果能找到扩展点,那这个问题就好办了,经过研究,发现并不难,工作量也不大,下面进行详细说明(本文前提是Activiti与Spring集成,其他环境请自行举一反三)。
一、自定义DefaultActivityBehaviorFactory,自定义该类的目的是创建自定义的UserTaskActivityBehavior,自定义的DefaultActivityBehaviorFactory需要通过set方法注入到SpringProcessEngineConfiguration中;
二、自定义UserTaskActivityBehavior,通过扩展handleAssignments方法,对于受理人、候选人和候选组进行处理。这里面需要注意的是,至于如何确定一个候选组只有一个用户,如何获取这个唯一的用户,开发者需要自行确定,下面的样例代码仅供参考。
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
import org.activiti.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFactory;
import org.activiti.engine.impl.task.TaskDefinition;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class ProcessActivityBehaviorFactory extends DefaultActivityBehaviorFactory implements ApplicationContextAware{
private ApplicationContext applicationContext;
@Override
public UserTaskActivityBehavior createUserTaskActivityBehavior(
UserTask userTask, TaskDefinition taskDefinition) {
ProcessUserTaskActivityBehavior taskActivityBehavior = (ProcessUserTaskActivityBehavior)applicationContext.getBean("taskActivityBehavior");
taskActivityBehavior.setTaskDefinition(taskDefinition);
return taskActivityBehavior;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.ActivitiIllegalArgumentException;
import org.activiti.engine.TaskService;
import org.activiti.engine.delegate.Expression;
import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.pvm.delegate.ActivityExecution;
import org.activiti.engine.impl.task.TaskDefinition;
import org.springframework.beans.factory.annotation.Autowired;
public class ProcessUserTaskActivityBehavior extends UserTaskActivityBehavior {
@Autowired
private TaskService taskService;
public ProcessUserTaskActivityBehavior() {
super(null);
}
public void setTaskDefinition(TaskDefinition taskDefinition){
super.taskDefinition = taskDefinition;
}
public ProcessUserTaskActivityBehavior(TaskDefinition taskDefinition) {
super(taskDefinition);
}
@Override
protected void handleAssignments(TaskEntity task,ActivityExecution execution) {
String assignee = null;
List<String> candidateUserId = null,candidateGroupId = null;
if (taskDefinition.getAssigneeExpression() != null) {
assignee = (String) taskDefinition.getAssigneeExpression().getValue(execution);
task.setAssignee(assignee,true,false);
}
if (taskDefinition.getOwnerExpression() != null) {
task.setOwner((String) taskDefinition.getOwnerExpression().getValue(execution));
}
if (!taskDefinition.getCandidateGroupIdExpressions().isEmpty()) {
for (Expression groupIdExpr : taskDefinition.getCandidateGroupIdExpressions()) {
Object value = groupIdExpr.getValue(execution);
if (value instanceof String) {
candidateGroupId = extractCandidates((String) value);
task.addCandidateGroups(candidateGroupId);
} else if (value instanceof Collection) {
task.addCandidateGroups((Collection) value);
} else {
throw new ActivitiIllegalArgumentException("Expression did not resolve to a string or collection of strings");
}
}
}
if (!taskDefinition.getCandidateUserIdExpressions().isEmpty()) {
for (Expression userIdExpr : taskDefinition.getCandidateUserIdExpressions()) {
Object value = userIdExpr.getValue(execution);
if (value instanceof String) {
candidateUserId = extractCandidates((String) value);
task.addCandidateUsers(candidateUserId);
} else if (value instanceof Collection) {
task.addCandidateUsers((Collection) value);
} else {
throw new ActivitiException("Expression did not resolve to a string or collection of strings");
}
}
}
if (assignee == null && candidateUserId == null && candidateGroupId.size() ==1){
String groupId = candidateGroupId.get(0);
//下面的代码开发者自行确定处理方法
String sql = "SELECT USER_ID FROM SYS_ROLE_USER WHERE ROLE_ID = '" + groupId + "' AND ROLE_TYPE = '3'";
CoreTemplate coreTemplate = CoreContextContainer.getContext().getCoreTemplate();
List data = coreTemplate.find(sql,null,true);
if (data.size() == 1){
String userId = (String)((Map)data.get(0)).get("user_id");
taskService.claim(task.getId(),userId);//符合条件的自动签收
}
}
}
}
下面是对应的Spring配置文件,这里面特别需要注意的是,taskActivityBehavior不能是单例的,相应的scope值为prototype。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<bean id="processEngineConfiguration" class="com.process.ProcessEngineConfiguration">
<property name="activityBehaviorFactory" ref="activityBehaviorFactory"/>
</bean>
<bean id="activityBehaviorFactory" class="com.process.ProcessActivityBehaviorFactory"/>
<bean id="taskActivityBehavior" class="com.process.ProcessUserTaskActivityBehavior" scope="prototype"/>
</beans>
以上代码在Activiti5.15.1版本中测试通过。