项目地址:activiti-workflow,欢迎star。
在流程审批中,在某一个节点需要抄送某人,被抄送人看查看流程,不需要审批。这里是通过对activit扩展,自定义BPMN标签,追加了抄送属性。
对普通用户节点设置抄送属性,继承UserTask
/**
* @description: 自定义用户节点
* @author lhj
* @param
* @return
* @date 2020-6-11 10:50
*/
public class CustomUserTask extends UserTask {
//抄送用户
protected List<String> candidateNotifyUsers = new ArrayList();
public List<String> getCandidateNotifyUsers() {
return candidateNotifyUsers;
}
public void setCandidateNotifyUsers(List<String> candidateNotifyUsers) {
this.candidateNotifyUsers = candidateNotifyUsers;
}
public CustomUserTask clone() {
CustomUserTask clone = new CustomUserTask();
clone.setValues(this);
return clone;
}
public void setValues(CustomUserTask otherElement) {
super.setValues(otherElement);
this.setCandidateNotifyUsers(otherElement.getCandidateNotifyUsers());
}
}
解析BPMN的xml和json是设置该属性
if (StringUtils.isNotEmpty(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_CANDIDATE_NOTIFY_USERS))) {
String expression = xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_CANDIDATE_NOTIFY_USERS);
userTask.getCandidateNotifyUsers().addAll(parseDelimitedList(expression));
}
task.setCandidateNotifyUsers(getValueAsList(CANDIDATE_NOTIFY_USERS, assignmentDefNode));
bpmn文件格式
<userTask id="sid-254390AD-30E7-4390-8B97-E2A395C4A15C" name="主管审批" activiti:assignee="lisi" activiti:candidateNotifyUsers="wangwu,zhangsan">
<extensionElements>
<modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
</extensionElements>
</userTask>
在流程流转过程中将抄送人落地,存入数据库,处理逻辑主要在UserTaskActivityBehavior,通过继承实现
//保存抄送人
if (candidateNotifyUsers != null && !candidateNotifyUsers.isEmpty()) {
for (String notify : candidateNotifyUsers) {
Expression userIdExpr = expressionManager.createExpression(notify);
Object value = userIdExpr.getValue(execution);
if (value instanceof String) {
List<String> userIds = extractCandidates((String) value);
for (String userId : userIds) {
Context.getCommandContext().getIdentityLinkEntityManager().addUserIdentityLink(task, userId, ProcessConstants.NOTIFY);
}
} else if (value instanceof Collection) {
Iterator userIdSet = ((Collection) value).iterator();
while (userIdSet.hasNext()) {
Context.getCommandContext().getIdentityLinkEntityManager().addUserIdentityLink(task, (String)userIdSet.next(), ProcessConstants.NOTIFY);
}
throw new ActivitiException("Expression did not resolve to a string or collection of strings");
}
}
}
到此,抄送定义和数据保存都已实现,剩下就是如何查询数据,这就要看具体业务需要是怎么样的。这里做简单实现,根据待办一起查询抄送。通过activiti提供的扩展Mybatis实现。
/**
* 查询待审批任务
* @param taskUnFinishQuery 查询条件
* @return
*/
@Override
public PageBean<ProcessTaskResult> queryUnFinishTask(TaskUnFinishQuery taskUnFinishQuery){
PageUtil<ProcessTaskResult, TaskUnFinishQuery> pageUtil = new PageUtil<>();
Long count = managementService.executeCustomSql(new AbstractCustomSqlExecution<CustomActivitiDatabaseMapper, Long>(CustomActivitiDatabaseMapper.class) {
@Override
public Long execute(CustomActivitiDatabaseMapper customActivitiDatabaseMapper) {
return customActivitiDatabaseMapper.selectUnFinishTaskCount(taskUnFinishQuery);
}
});
//没有查询到,就直接返回空
if(count <= 0){
return pageUtil.buildPage(Collections.emptyList(), taskUnFinishQuery, 0);
}
List<ProcessTaskResult> list = managementService.executeCustomSql(new AbstractCustomSqlExecution<CustomActivitiDatabaseMapper, List<ProcessTaskResult>>(CustomActivitiDatabaseMapper.class) {
@Override
public List<ProcessTaskResult> execute(CustomActivitiDatabaseMapper customActivitiDatabaseMapper) {
return customActivitiDatabaseMapper.selectUnFinishTask(taskUnFinishQuery);
}
});
return pageUtil.buildPage(list,taskUnFinishQuery,count);
}
还有额外处理,抄送可能是针对整个流程,但并不是某个节点。因此在存抄送人时,不但存taskId,还保存了processInstanceId实例ID
@Override
public IdentityLinkEntity addIdentityLink(TaskEntity taskEntity, String userId, String groupId, String type) {
IdentityLinkEntity identityLinkEntity = (IdentityLinkEntity)this.identityLinkDataManager.create();
taskEntity.getIdentityLinks().add(identityLinkEntity);
identityLinkEntity.setTask(taskEntity);
identityLinkEntity.setUserId(userId);
identityLinkEntity.setGroupId(groupId);
if (ProcessConstants.NOTIFY.equals(type)) {
identityLinkEntity.setProcessInstanceId(taskEntity.getProcessInstanceId());
}
identityLinkEntity.setType(type);
this.insert(identityLinkEntity);
if (userId != null && taskEntity.getProcessInstanceId() != null) {
this.involveUser(taskEntity.getProcessInstance(), userId, "participant");
}
return identityLinkEntity;
}
这里给出一种实现思路,只供参考。具体代码可到github项目中查看。
关于扩展BPMN遇到的问题,参考