spring-activiti动态指定审批人及其设计思想

近期刚开始接触spring-activiti工作流,并运用于实际项目中,此处记录相关思想可做以后参考。

1. 统一服务执行入口,spring-activiti的ExecutionListener为多实例:

   spring-activiti中写监听器,我们可以统一一个监听器入口,并准备springUtils可以实现获取spring的bean,将流程的执行逻辑转发到服务bean中执行。

package net.mshome.twisted.tmall.process;


import lombok.extern.slf4j.Slf4j;
import net.mshome.twisted.tmall.util.SpringUtils;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
import org.activiti.engine.delegate.Expression;
import org.apache.commons.lang3.StringUtils;

@Slf4j
public class ProcessExecutionListener implements ExecutionListener {

    /**
     * 流程注入的流程配置的服务类,即spring的bean名
     */
    private Expression servceName;

    /**
     * 流程注入的参数:推荐采用json格式传递参数
     */
    private Expression param;

    /**
     * 传递的param参数
     */
    private String paramString;

    /**
     * 具体的业务逻辑执行类,也是spring的bean
     */
    private ProcessExecutionService processExecutionService;


    @Override
    public void notify(DelegateExecution delegateExecution) {
        init();
        this.processExecutionService.execute(delegateExecution, paramString);
    }

    private void init() {
        if (servceName == null || StringUtils.isBlank(servceName.getExpressionText())) {
            throw new ActivitiException("serviceName is required");
        }
        String serviceName = servceName.getExpressionText();

        if (param == null || StringUtils.isBlank(param.getExpressionText())) {
            log.warn("{} executed without any param provided", serviceName);
        }

        this.paramString = param == null ? null : param.getExpressionText();

        Object service = SpringUtils.getApplicationContext().getBean(serviceName);
        if (service instanceof ProcessExecutionService) {
            processExecutionService = (ProcessExecutionService) service;
        } else {
            throw new ActivitiException(serviceName + " is not a implementation of " + ProcessExecutionService.class.getSimpleName());
        }
    }
}

 2. 和spring bean关联的参数传递接口,流程服务service bean需实现此接口

package net.mshome.twisted.tmall.process;

import org.activiti.engine.delegate.DelegateExecution;

public interface ProcessExecutionService  {

    void execute(DelegateExecution delegateExecution, String param);

}

3. 获取bean的类

package net.mshome.twisted.tmall.util;


import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringUtils.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
}

4. 具体查询审批人服务

package net.mshome.twisted.tmall.process.service;

import net.mshome.twisted.tmall.process.ProcessExecutionService;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.delegate.DelegateExecution;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
@Transactional
public class ProcessTaskAssignService implements ProcessExecutionService {

    @Override
    public void execute(DelegateExecution delegateExecution, String param) {

        // 获取下一步节点,并判断是否是userTask类型

        FlowElement currentFlowElement = delegateExecution.getCurrentFlowElement();
        if (!(currentFlowElement instanceof SequenceFlow)) return;
        SequenceFlow sequenceFlow = (SequenceFlow) currentFlowElement;
        FlowElement targetNode = sequenceFlow.getTargetFlowElement();
        if (!(targetNode instanceof UserTask)) return;
        UserTask userTask = (UserTask) targetNode;

        // 实际情况需判断是否是会签节点,即多人审批节点
        boolean isMultiInstanceNode = userTask.getLoopCharacteristics() != null;

        // 获取配置的表达式
        String assignExpression = userTask.getAssignee();
        // fixme 去除el表达式的格式,设值,此处作为演示,没有去除
        delegateExecution.setVariable(assignExpression, "zhangsan"); // 实际情况可根据配置的人或者角色查询出用户,然后设值

        // 获取配置的表达式
        String assigneeListExpression = userTask.getLoopCharacteristics().getInputDataItem();
        List userList = new ArrayList<>();
        // fixme 去除el表达式的格式,设值,此处作为演示,没有去除
        delegateExecution.setVariable(assigneeListExpression, userList);


    }
}

5.  动态指定下一步的审批人,可以在连接到userTask类型的节点线上也就是sequeceFlow上增加执行服务,取线上约定固定格式的审批人表达式如 assigneeList,设置参数。如 { "userList" : [], "roleList":[] } ,如需要根据业务查询审批人,自行写服务。

番外篇:

1. 流程开始时,可写服务将流程相关参数和流程状态更新进业务表,还可以将流程需要的业务参数放入,比如整个表单对象放入流程。以达到可配置el表达式决定流程的走向效果或者其他作用。

2. 流程执行时可配置服务类,将下一步的节点名写入业务表,如下一步是分支,则可在前一步,传入参数param当作下一步的节点名。

你可能感兴趣的:(spring)