当前位置: 首页 > news >正文

04 完成审批任务

审批流程图

        如下图,在此流程图中,存在两个UserTask节点,第一个节点是主管审批,第二个节点是产品经理审批,两个节点中间有一个排他网关,此网关用来对主管审批的结果进行判断,如果主管审批通过,则流程走到产品经理审批节点,如果主管审批拒绝,则流程走到结束节点。

        主管审批节点通过UEL表达式${assignManager}动态赋值,产品经理审批节点通过UEL表达式${assignProductLineManager}动态赋值,网关节点通过UEL表达式${isPass}动态赋值。

完成审批任务

        以 TaskService 接口的 complete(String, Map) 方法为源码入口。

public interface TaskService {public void complete(String taskId, Map<String, Object> variables)
}

拦截器链

        TaskService 的实现类是 TaskServiceImpl,在代码中,把传入的 taskId 和变量 varriables 一起放入到了 CompleteTaskCmd 的构造函数中,用于构造一个 CompleteTaskCmd 实例,然后把这个实例放入到了 commandExecutor 执行器中。

public class TaskServiceImpl extends ServiceImpl implements TaskService {public void complete(String taskId, Map<String, Object> variables) {commandExecutor.execute(new CompleteTaskCmd(taskId, variables));}
}

        CompleteTaskCmd 实例在执行器的逻辑和 StartProcessInstanceCmd 一样,都会经过执行器内部拦截器链中的四个拦截器。最后由处于最末端的拦截器 CommandInvoker 调用 CompleteTaskCmd 实例的 execute(CommandContext) 来完成审批任务。

完成审批

        CompleteTaskCmd 的继承体系如下。

        CompleteTaskCmd 本身并没有实现 Command 接口中的 execute(CommandContext) 方法,而是由父类 NeedsActiveTaskCmd 来实现的。

public abstract class NeedsActiveTaskCmd<T> implements Command<T>, Serializable {/*** 用户调用TaskService#complete(String taskId, xxx)后,CommandInvoker会调用此类,正真的执行此命令* @param commandContext* @return*/public T execute(CommandContext commandContext) {if (taskId == null) {throw new ActivitiIllegalArgumentException("taskId is null");}// 通过 taskId 从数据库中查询 TaskEntityTaskEntity task = commandContext.getTaskEntityManager().findById(taskId);if (task == null) {throw new ActivitiObjectNotFoundException("Cannot find task with id " + taskId, Task.class);}if (task.isSuspended()) {throw new ActivitiException(getSuspendedTaskException());}// 调用子类实现的 execute(commandContext, task) 方法return execute(commandContext, task);}
}

        在父类 NeedsActiveTaskCmd execute(CommandContext) 方法中会调用 CompleteTaskCmd 实现的 execute(CommandContext, TaskEntity) 方法。在方法里,把传入的变量绑定到 task 中。紧接着调用父类 AbstractCompleteTaskCmd executeTaskComplete(CommandContext, TaskEntity, Map , boolean) 方法去完成任务的审批。

/*** 父类 NeedsActiveTaskCmd 的 execute(CommandContext commandContext) 方法会调用此方法* @param commandContext 命令上下文* @param task  任务* @return*/
protected Void execute(CommandContext commandContext, TaskEntity task) {if (variables != null) {// 绑定变量if (localScope) {task.setVariablesLocal(variables);} else if (task.getExecutionId() != null) {task.setExecutionVariables(variables);} else {task.setVariables(variables);}}if (transientVariables != null) {if (localScope) {task.setTransientVariablesLocal(transientVariables);} else {task.setTransientVariables(transientVariables);}}if(commandContext.getProcessEngineConfiguration().isCopyVariablesToLocalForTasks()){TaskVariableCopier.copyVariablesOutFromTaskLocal(task);}// 完成任务,此方法是父类 AbstractCompleteTaskCmd 的executeTaskComplete(commandContext, task, variables, localScope);return null;
}

        AbstractCompleteTaskCmd executeTaskComplete(CommandContext, TaskEntity, Map , boolean) 方法实现如下:

public abstract class AbstractCompleteTaskCmd extends NeedsActiveTaskCmd<Void> {private static final long serialVersionUID = 1L;public AbstractCompleteTaskCmd(String taskId) {super(taskId);}protected void executeTaskComplete(CommandContext commandContext, TaskEntity taskEntity, Map<String, Object> variables, boolean localScope) {// Task complete logicif (taskEntity.getDelegationState() != null && taskEntity.getDelegationState().equals(DelegationState.PENDING)) {throw new ActivitiException("A delegated task cannot be completed, but should be resolved instead.");}commandContext.getProcessEngineConfiguration().getListenerNotificationHelper().executeTaskListeners(taskEntity, TaskListener.EVENTNAME_COMPLETE);if (Authentication.getAuthenticatedUserId() != null && taskEntity.getProcessInstanceId() != null) {ExecutionEntity processInstanceEntity = commandContext.getExecutionEntityManager().findById(taskEntity.getProcessInstanceId());// 记录身份连接类型,实际就是记录 ExecutionEntity 和 User 的关联关系,信息会存储到 act_hi_identitylink 中commandContext.getIdentityLinkEntityManager().involveUser(processInstanceEntity, Authentication.getAuthenticatedUserId(), IdentityLinkType.PARTICIPANT);}ActivitiEventDispatcher eventDispatcher = Context.getProcessEngineConfiguration().getEventDispatcher();if (eventDispatcher.isEnabled()) {if (variables != null) {eventDispatcher.dispatchEvent(ActivitiEventBuilder.createEntityWithVariablesEvent(ActivitiEventType.TASK_COMPLETED, taskEntity, variables, localScope));} else {eventDispatcher.dispatchEvent(ActivitiEventBuilder.createEntityEvent(ActivitiEventType.TASK_COMPLETED, taskEntity));}}// 任务完成,删除任务commandContext.getTaskEntityManager().deleteTask(taskEntity, null, false, false);// Continue process (if not a standalone task)if (taskEntity.getExecutionId() != null) {ExecutionEntity executionEntity = commandContext.getExecutionEntityManager().findById(taskEntity.getExecutionId());// 计划触发执行操作,本质就是:当前任务已经完成,计划继续前往下一个节点。Context.getAgenda().planTriggerExecutionOperation(executionEntity);}}}

总结

        用户完成审批任务这一操作,从 Activiti 框架角度来讲,就是调用了一次 TaskService complete 方法,在这个方法内部的主要业务逻辑如下:

                1. 通过 taskId 从数据库加载 TaskEntity

                2. 给 TaskEntity 绑定变量(前提是有变量传入);

                3. 记录身份链接类型,把身份链接类型存储入库,审批完成;

                4. 删除数据库中记录的 TaskEntity

                5. 继续前往下一个节点(如果有才往下一个节点走)。

        这个逻辑上,并没有过多复杂业务,仅仅是记录当前 Task 由谁完成了,然后就前往下一个节点了。若要实现日常中常见的审批拒绝、审批驳回这些功能,需额外进行二次开发。


文章转载自:

http://fInvtkfZ.zwmjq.cn
http://eu2qeZ0Q.zwmjq.cn
http://Qs5QopGU.zwmjq.cn
http://4IWPrgXG.zwmjq.cn
http://kYxd7JYz.zwmjq.cn
http://F2mIxf9t.zwmjq.cn
http://5U5ZaHCu.zwmjq.cn
http://3z70WACE.zwmjq.cn
http://5Wf3ZD57.zwmjq.cn
http://6BXnGuy5.zwmjq.cn
http://MBOoc8hz.zwmjq.cn
http://UvLKtrdK.zwmjq.cn
http://SvD2lF48.zwmjq.cn
http://pcCMsZ2e.zwmjq.cn
http://BGLztS7O.zwmjq.cn
http://QG4kgwM3.zwmjq.cn
http://uXEnIdwW.zwmjq.cn
http://m2mQDMzP.zwmjq.cn
http://kLakSyEw.zwmjq.cn
http://CJ5GZWbi.zwmjq.cn
http://ig6hQ51x.zwmjq.cn
http://GuHydJZN.zwmjq.cn
http://L9K4tn5H.zwmjq.cn
http://AeuwfimZ.zwmjq.cn
http://kNTI54ec.zwmjq.cn
http://ckclccMn.zwmjq.cn
http://Zs8MnSgG.zwmjq.cn
http://4B5T6GHI.zwmjq.cn
http://wm5I1kJJ.zwmjq.cn
http://NgGxn47S.zwmjq.cn
http://www.dtcms.com/a/385398.html

相关文章:

  • keil出现 cmsis_compiler.h(279): error: #35: #error directive: Unknown compilr解决方法
  • CSS `:has()` 实战指南:让 CSS 拥有“if 逻辑”
  • 【开题答辩全过程】以 Java校园二手书城平台为例,包含答辩的问题和答案
  • 机器视觉在新能源汽车电池中有哪些检测应用
  • CES Asia的“五年计划”:打造与北美展比肩的科技影响力
  • 王梦迪团队推出TraceRL:迈向扩散语言模型「RL大一统」
  • 运用脚本部署lamp架构
  • Springboot项目中引入ES(一)
  • 专项智能练习(认知主义学习理论)
  • Mysql索引总结(1)
  • Spring Boot中的Binder类基本使用和工具封装
  • 数字化工厂建设:是简单组装PLM/ERP/MES/WMS等系统,还是彻底重构?
  • 带你了解STM32:OLED调试器
  • 软考中项考几门?多少分合格?
  • 1.5 调用链分层架构 - mybatis源码学习
  • 线性代数 · 矩阵 | 秩 / 行秩 / 列秩 / 计算方法
  • 期权时间价值会增长么?
  • 数据结构(陈越,何钦铭) 第十讲 排序(下)
  • Java——JVM
  • 【51单片机】【protues仿真】基于51单片机温度检测系统
  • 51单片机-使用IIC通信协议实现EEPROM模块教程
  • ISP Pipeline
  • Tomcat的安装和启动步骤以及常见问题
  • 基于 Selenium+Page Object 的电商平台自动化测试框架实践
  • 内网安全:自签名、CA机构签发与SSH、sudo最佳实践
  • 深度学习-计算机视觉-风格迁移
  • 机器学习面试题:请介绍一下你理解的集成学习算法
  • C2000基础-GPIO介绍及使用
  • 【CTF-WEB】Web基础工具的使用(burpsuit抓包并修改数值)
  • 重学前端015 --- 响应式网页设计 CSS变换