Browse Source

refactor(flow): 重构流程候选用户名解析逻辑

- 提取候选用户名解析为独立方法 getCandidateUsernamesByExecution
- 添加对 EL 表达式的完整支持,包括 ${projectBean.getCommonReportManager(execution)} 形式
- 简化 AutoSkipTaskListener 中的用户名获取逻辑
- 统一多实例分配监听器中的候选用户处理方式
- 移除重复的字符串分割和变量获取代码
- 增强表达式求值的安全性,添加执行上下文验证
feature/2026-08/0812-ccc-dev
chenchuchuan 1 week ago
parent
commit
fb35f2b406
  1. 11
      common/common-flow/src/main/java/apelet/common/flow/listener/AutoSkipTaskListener.java
  2. 8
      common/common-flow/src/main/java/apelet/common/flow/listener/MultiInstanceAssigneeListener.java
  3. 10
      common/common-flow/src/main/java/apelet/common/flow/service/FlowApiService.java
  4. 78
      common/common-flow/src/main/java/apelet/common/flow/service/impl/FlowApiServiceImpl.java
  5. 12
      common/common-flow/src/main/java/apelet/common/flow/service/impl/FlowTaskExtServiceImpl.java

11
common/common-flow/src/main/java/apelet/common/flow/listener/AutoSkipTaskListener.java

@ -135,16 +135,7 @@ public class AutoSkipTaskListener implements TaskListener { @@ -135,16 +135,7 @@ public class AutoSkipTaskListener implements TaskListener {
} else {
FlowTaskExt flowTaskExt = flowTaskExtService
.getByProcessDefinitionIdAndTaskId(t.getProcessDefinitionId(), userTask.getId());
List<String> candidateUsernames;
if (StrUtil.isBlank(flowTaskExt.getCandidateUsernames())) {
candidateUsernames = Collections.emptyList();
} else if (!StrUtil.equals(flowTaskExt.getCandidateUsernames(), "${" + FlowConstant.TASK_APPOINTED_ASSIGNEE_VAR + "}")) {
candidateUsernames = StrUtil.split(flowTaskExt.getCandidateUsernames(), ",");
} else {
String value = flowApiService
.getExecutionVariableStringWithSafe(t.getExecutionId(), FlowConstant.TASK_APPOINTED_ASSIGNEE_VAR);
candidateUsernames = value == null ? null : StrUtil.split(value, ",");
}
List<String> candidateUsernames = flowApiService.getCandidateUsernamesByExecution(flowTaskExt, t.getExecutionId());
if (candidateUsernames != null && candidateUsernames.size() == 1) {
assignedUser = candidateUsernames.get(0);
}

8
common/common-flow/src/main/java/apelet/common/flow/listener/MultiInstanceAssigneeListener.java

@ -2,6 +2,7 @@ package apelet.common.flow.listener; @@ -2,6 +2,7 @@ package apelet.common.flow.listener;
import apelet.common.core.util.ApplicationContextHolder;
import apelet.common.flow.model.FlowTaskExt;
import apelet.common.flow.service.FlowApiService;
import apelet.common.flow.service.FlowTaskExtService;
import apelet.common.flow.util.BaseFlowIdentityExtHelper;
import apelet.common.flow.util.FlowCustomExtFactory;
@ -30,6 +31,8 @@ public class MultiInstanceAssigneeListener implements ExecutionListener { @@ -30,6 +31,8 @@ public class MultiInstanceAssigneeListener implements ExecutionListener {
private final transient FlowCustomExtFactory flowCustomExtFactory = ApplicationContextHolder.getBean(FlowCustomExtFactory.class);
private final transient FlowApiService flowApiService = ApplicationContextHolder.getBean(FlowApiService.class);
@Override
public void notify(DelegateExecution execution) {
@ -44,7 +47,10 @@ public class MultiInstanceAssigneeListener implements ExecutionListener { @@ -44,7 +47,10 @@ public class MultiInstanceAssigneeListener implements ExecutionListener {
}
List<String> candidateUsernames = new ArrayList<>();
if (StrUtil.isNotBlank(flowTaskExt.getCandidateUsernames())) {
candidateUsernames.addAll(StrUtil.split(flowTaskExt.getCandidateUsernames(), ","));
List<String> configuredUsernames = flowApiService.getCandidateUsernamesByExecution(flowTaskExt, execution.getId());
if (CollUtil.isNotEmpty(configuredUsernames)) {
candidateUsernames.addAll(configuredUsernames);
}
} else {
BaseFlowIdentityExtHelper extHelper = flowCustomExtFactory.getFlowIdentityExtHelper();
if (extHelper == null) {

10
common/common-flow/src/main/java/apelet/common/flow/service/FlowApiService.java

@ -570,6 +570,16 @@ public interface FlowApiService { @@ -570,6 +570,16 @@ public interface FlowApiService {
List<String> getCandidateUsernames(FlowTaskExt flowTaskExt, String taskId);
/**
* 根据执行实例Id,获取当前任务在流程图中配置候选用户组数据。
* 配置值支持逗号分隔的登录名,以及${appointedAssignee}、${projectBean.getCommonReportManager(execution)}形式的EL表达式。
*
* @param flowTaskExt 流程任务扩展对象。
* @param executionId 执行实例Id。
* @return 候选用户组数据。
*/
List<String> getCandidateUsernamesByExecution(FlowTaskExt flowTaskExt, String executionId);
/**
* 获取当前任务在流程图中配置到的部门岗位Id集合和岗位Id集合。
*
* @param flowTaskExt 流程任务扩展对象。

78
common/common-flow/src/main/java/apelet/common/flow/service/impl/FlowApiServiceImpl.java

@ -41,6 +41,7 @@ import lombok.extern.slf4j.Slf4j; @@ -41,6 +41,7 @@ import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.common.engine.impl.de.odysseus.el.ExpressionFactoryImpl;
import org.flowable.common.engine.impl.de.odysseus.el.util.SimpleContext;
import org.flowable.common.engine.impl.identity.Authentication;
@ -52,7 +53,10 @@ import org.flowable.engine.delegate.TaskListener; @@ -52,7 +53,10 @@ import org.flowable.engine.delegate.TaskListener;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ChangeActivityStateBuilder;
import org.flowable.engine.runtime.Execution;
@ -1526,14 +1530,78 @@ public class FlowApiServiceImpl implements FlowApiService { @@ -1526,14 +1530,78 @@ public class FlowApiServiceImpl implements FlowApiService {
@Override
public List<String> getCandidateUsernames(FlowTaskExt flowTaskExt, String taskId) {
if (StrUtil.isBlank(flowTaskExt.getCandidateUsernames())) {
String configured = flowTaskExt.getCandidateUsernames();
if (StrUtil.isBlank(configured)) {
return Collections.emptyList();
}
if (!StrUtil.equals(flowTaskExt.getCandidateUsernames(), "${" + FlowConstant.TASK_APPOINTED_ASSIGNEE_VAR + "}")) {
return StrUtil.split(flowTaskExt.getCandidateUsernames(), ",");
if (StrUtil.equals(configured, "${" + FlowConstant.TASK_APPOINTED_ASSIGNEE_VAR + "}")) {
String value = getTaskVariableStringWithSafe(taskId, FlowConstant.TASK_APPOINTED_ASSIGNEE_VAR);
return value == null ? null : StrUtil.splitTrim(value, ",");
}
Object candidateUsernames = getTaskVariableStringWithSafe(taskId, FlowConstant.TASK_APPOINTED_ASSIGNEE_VAR);
return candidateUsernames == null ? null : StrUtil.split(candidateUsernames.toString(), ",");
if (!configured.startsWith("${")) {
return StrUtil.splitTrim(configured, ",");
}
Task task = this.getTaskById(taskId);
return task == null ? Collections.emptyList() : this.getCandidateUsernamesByExecution(flowTaskExt, task.getExecutionId());
}
@Override
public List<String> getCandidateUsernamesByExecution(FlowTaskExt flowTaskExt, String executionId) {
String configured = flowTaskExt.getCandidateUsernames();
if (StrUtil.isBlank(configured)) {
return Collections.emptyList();
}
if (StrUtil.equals(configured, "${" + FlowConstant.TASK_APPOINTED_ASSIGNEE_VAR + "}")) {
String value = getExecutionVariableStringWithSafe(executionId, FlowConstant.TASK_APPOINTED_ASSIGNEE_VAR);
return value == null ? null : StrUtil.splitTrim(value, ",");
}
if (!configured.startsWith("${")) {
return StrUtil.splitTrim(configured, ",");
}
// 形如${projectBean.getCommonReportManager(execution)}的EL表达式,交给引擎的表达式管理器求值。
return this.parseCandidateUsernames(this.getExpressionValue(configured, executionId));
}
private List<String> parseCandidateUsernames(Object value) {
if (value == null) {
return Collections.emptyList();
}
if (value instanceof Collection) {
List<String> candidateUsernames = new LinkedList<>();
for (Object element : (Collection<?>) value) {
if (element != null && StrUtil.isNotBlank(element.toString())) {
candidateUsernames.add(element.toString());
}
}
return candidateUsernames;
}
if (StrUtil.isBlank(value.toString())) {
return Collections.emptyList();
}
return StrUtil.splitTrim(value.toString(), ",");
}
private Object getExpressionValue(String expressionStr, String executionId) {
ProcessEngineConfigurationImpl engineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
if (engineConfiguration != null) {
return this.evaluateExpression(engineConfiguration, expressionStr, executionId);
}
// 待办详情等HTTP接口场景没有活动的命令上下文,交由引擎开启一次后再求值,保证execution关键字可正常绑定。
return managementService.executeCommand(commandContext -> this.evaluateExpression(
CommandContextUtil.getProcessEngineConfiguration(commandContext), expressionStr, executionId));
}
private Object evaluateExpression(
ProcessEngineConfigurationImpl engineConfiguration, String expressionStr, String executionId) {
ExecutionEntity execution = CommandContextUtil.getExecutionEntityManager().findById(executionId);
if (execution == null) {
log.error("Failed to getExpressionValue expression [{}], executionId [{}], execution not found.",
expressionStr, executionId);
return null;
}
// 与引擎UserTaskActivityBehavior.handleAssignments的求值方式保持一致,execution关键字可正常绑定到当前执行流对象。
Expression expression = engineConfiguration.getExpressionManager().createExpression(expressionStr);
return expression.getValue(execution);
}
@Override

12
common/common-flow/src/main/java/apelet/common/flow/service/impl/FlowTaskExtServiceImpl.java

@ -219,17 +219,7 @@ public class FlowTaskExtServiceImpl extends BaseService<FlowTaskExt, String> imp @@ -219,17 +219,7 @@ public class FlowTaskExtServiceImpl extends BaseService<FlowTaskExt, String> imp
default:
break;
}
List<String> candidateUsernames;
if (StrUtil.isBlank(flowTaskExt.getCandidateUsernames())) {
candidateUsernames = Collections.emptyList();
} else {
if (!StrUtil.equals(flowTaskExt.getCandidateUsernames(), " + FlowConstant.TASK_APPOINTED_ASSIGNEE_VAR + ")) {
candidateUsernames = StrUtil.split(flowTaskExt.getCandidateUsernames(), ",");
} else {
Object v = flowApiService.getExecutionVariableStringWithSafe(executionId, FlowConstant.TASK_APPOINTED_ASSIGNEE_VAR);
candidateUsernames = v == null ? null : StrUtil.split(v.toString(), ",");
}
}
List<String> candidateUsernames = flowApiService.getCandidateUsernamesByExecution(flowTaskExt, executionId);
if (CollUtil.isNotEmpty(candidateUsernames)) {
usernameSet.addAll(candidateUsernames);
}

Loading…
Cancel
Save