activiti6 第二部分:流程图设计及部署

1 项目没有使用activiti示例中的流程图配置,需自己设计并完成流程配置功能

(1)前端使用gooflow插件画图,后端保存流程图相关信息

     流程图相关类及其关系

(2)添加流程点,线,流程定义的增删改查功能

2 部署流程

这一步是流程配置中最重要的一部分,因为需要把流程图中配置的内容准换成activiti中BpmnModel相应的内容,比如一个用户任务类型的流程点对应着一个用户任务;

具体步骤为:

  1. 添加开始事件,addStartEvent
  2. 添加结束事件,addEndEvent
  3. 添加用户任务,addUserTask
  4. 添加节点之间的线,addSeqFlows

注意:

添加用户任务时,需根据流程点配置的候选人和候选角色配置表达式;

当用户任务为会签任务时,需将给该对象的MultiInstanceLoopCharacteristics属性赋值,表示该对象可以处理串行和并行任务,当sequential为false时为并行任务。同时,如果用户任务为会签任务需要在该任务处添加一个“排他网关”(排他网关只会选择一条满足条件的执行)(并行网关:先将任务分成多个任务,多个任务完成后聚合成一个任务后流转,如下图)

同时,用户任务可以添加监听;

具体代码如下

package activiti.service;

import activiti.service.provider.ProviderManager;
import activiti.service.provider.TaskEventEnum;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import flowchart.model.ProcessDefine;
import flowchart.model.ProcessPoint;
import flowchart.model.ProcessPointType;
import flowchart.model.SeqFlow;
import flowchart.service.ProcessDefineService;
import flowchart.service.ProcessPointService;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import util.ConvertUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;

import static flowchart.Constants.*;
import static org.activiti.editor.constants.ModelDataJsonConstants.MODEL_NAME;
import static org.activiti.editor.constants.ModelDataJsonConstants.MODEL_REVISION;
import static util.ConvertUtil.addPrefix;

@Service
@Transactional
public class ActivitiBuilder {
    @Autowired
    ProcessDefineService processDefineService;
    @Autowired
    ProcessPointService processPointService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ProviderManager providerManager;

    public boolean deploy2Activiti(String processDefineId) throws Exception {
        ProcessDefine processDefine = processDefineService.findOne(processDefineId);
        if(processDefine.isEnabled()) {
            List<ProcessPoint> points = processPointService.findByProcess_IdOrderBySortIndexAsc(processDefineId);
            BpmnModel bpmnModel = new BpmnModel();
            Process process = new Process();
            process.setName(processDefine.getName());
            process.setId(processDefine.getId());

            addFlowNodes(bpmnModel, process, points);
            bpmnModel.addProcess(process);

            String processName = null;
            if (StringUtils.isNotEmpty(bpmnModel.getMainProcess().getName())) {
                processName = bpmnModel.getMainProcess().getName();
            } else {
                processName = bpmnModel.getMainProcess().getId();
            }

            Model modelData = repositoryService.newModel();
            ObjectNode modelObjectNode = new ObjectMapper().createObjectNode();
            modelObjectNode.put(MODEL_NAME, processName);
            modelObjectNode.put(MODEL_REVISION, 1);
            modelData.setMetaInfo(modelObjectNode.toString());
            modelData.setName(processName);

            repositoryService.saveModel(modelData);

            BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
            ObjectNode editorNode = jsonConverter.convertToJson(bpmnModel);

            repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8"));

            deployModelerModel(modelData, editorNode);
            return true;
        }

        return false;
    }

    /**
     * 增加流程节点
     * @param bpmnModel
     * @param process
     * @param points
     */
    private void addFlowNodes(BpmnModel bpmnModel,Process process,List<ProcessPoint> points){
        for (ProcessPoint point : points) {
            //添加开始节点
            if(point.getProcessPointType().equals(ProcessPointType.START_EVENT)){
                addStartEvent(bpmnModel,process,point);
            } else if(point.getProcessPointType().equals(ProcessPointType.END_EVENT)){
                //添加结束节点
                addEndEvent(bpmnModel,process,point);
            } else {
                addUserTask(bpmnModel,process,point);
            }
        }
        for (ProcessPoint point : points) {
            addSequenceFlows(bpmnModel,process,point);
        }
    }

    /**
     * 添加顺序流
     * @param bpmnModel
     * @param process
     * @param point
     */
    private void addSequenceFlows(BpmnModel bpmnModel,Process process,ProcessPoint point ){
//        int startX=0,startY=50;
        String sourceId = point.getId();

        if(point.getProcessPointType().equals(ProcessPointType.START_EVENT)){
            sourceId = START_EVENT_ID;
        }

        if(point.getProcessPointType().equals(ProcessPointType.SIGN_TASK)) {
           String  targetId = GATEWAY_ID_PREFIX + sourceId; //会签任务自动生成一个排他网关
            addSequenceFlow(bpmnModel, process,
                    addPrefix(targetId, SEQ_ID_PREFIX),false,
                    sourceId,
                    targetId,
                    "","",point);
            sourceId=targetId;
        }

        List<SeqFlow> seqflows=point.getOutSeqFlows();
        for (SeqFlow seqflow : seqflows) {
            String  targetId;
            if(seqflow.getTargetPoint().getProcessPointType().equals(ProcessPointType.END_EVENT)){
                targetId = END_EVENT_ID;
            } else {
                targetId = seqflow.getTargetPoint().getId();
            }
            addSequenceFlow(bpmnModel,process,
                    seqflow.getId(),
                    seqflow.isPrimalExpression(),
                    sourceId,
                    targetId,
                    seqflow.getSeqFlowCondition(),seqflow.getVoter(),point);
        }
    }

    private void addSequenceFlow(BpmnModel bpmnModel, Process process,String sequenceFlowId,boolean isPrimalExpression,
                                 String sourceRefId,String targetRefId,String condition,String voterName,ProcessPoint point ) {

        FlowNode sourceRef= (FlowNode) process.getFlowElement(sourceRefId);
        FlowNode targetRef=  (FlowNode) process.getFlowElement(targetRefId);

        SequenceFlow sequenceFlow=new SequenceFlow();
        sequenceFlow.setId(sequenceFlowId);
        sequenceFlow.setName(sourceRef.getName()+"--"+targetRef.getName());
        sequenceFlow.setSourceRef(sourceRefId);
        sequenceFlow.setTargetRef(targetRefId);

        if(isPrimalExpression){
            sequenceFlow.setConditionExpression(condition);
        }else {
            if(point.getProcessPointType().equals(ProcessPointType.SIGN_TASK)){
                sequenceFlow.setConditionExpression(buildMutiInstanceTaskSequenceFlowCondition(condition,voterName,sequenceFlow,point));
            } else {
                sequenceFlow.setConditionExpression(buildSequenceFlowCondition(condition,voterName,sequenceFlow,point));
            }
        }

        sourceRef.getOutgoingFlows().add(sequenceFlow);
        targetRef.getIncomingFlows().add(sequenceFlow);

        List<GraphicInfo> graphicInfoList=new ArrayList<>();
        graphicInfoList.add(bpmnModel.getLocationMap().get(sourceRefId));
        graphicInfoList.add(bpmnModel.getLocationMap().get(targetRefId));

        bpmnModel.addFlowGraphicInfoList(sequenceFlow.getId(),graphicInfoList);
        process.addFlowElement(sequenceFlow);
    }

    private void addStartEvent(BpmnModel bpmnModel,Process process,ProcessPoint processPoint){
        GraphicInfo graphicInfo;
        StartEvent startEvent=new StartEvent();
        startEvent.setId(START_EVENT_ID);
        startEvent.setName("开始");
        startEvent.setOutgoingFlows(new ArrayList<SequenceFlow>());
        process.addFlowElement(startEvent);


        graphicInfo= new GraphicInfo();
        graphicInfo.setElement(startEvent);
        graphicInfo.setX(processPoint.getLeftPosition());
        graphicInfo.setY(processPoint.getTopPosition());
        graphicInfo.setHeight(processPoint.getHeight());
        graphicInfo.setWidth(processPoint.getWidth());
        bpmnModel.addGraphicInfo(startEvent.getId(),graphicInfo);
    }

    private void addEndEvent(BpmnModel bpmnModel,Process process,ProcessPoint processPoint){
        GraphicInfo graphicInfo;
        EndEvent endEvent=new EndEvent();
        endEvent.setId(END_EVENT_ID);
        endEvent.setName("结束");
        endEvent.setIncomingFlows(new ArrayList<SequenceFlow>());
        process.addFlowElement(endEvent);

        graphicInfo= new GraphicInfo();
        graphicInfo.setElement(endEvent);
        graphicInfo.setX(processPoint.getLeftPosition());
        graphicInfo.setY(processPoint.getTopPosition());
        graphicInfo.setHeight(processPoint.getHeight());
        graphicInfo.setWidth(processPoint.getWidth());
        bpmnModel.addGraphicInfo(endEvent.getId(),graphicInfo);
    }

    private void addUserTask(BpmnModel bpmnModel,Process process,ProcessPoint point){
        UserTask userTask=new UserTask();

        userTask.setId(point.getId());
        userTask.setName(point.getName());
        userTask.setIncomingFlows(new ArrayList<>());
        userTask.setOutgoingFlows(new ArrayList<>());
        userTask.setDocumentation("${businessKey}");
        if(point.getProcessPointType().equals(ProcessPointType.USER_TASK)){
            if(point.isManualAssign()){
                userTask.setAssignee(buildManualAssigneeExpression(point));
            }
            if(point.getCandidateUsers() != null && !"".equals(point.getCandidateUsers())){
                userTask.setCandidateUsers(Collections.singletonList(buildCandidatesUsersExpression(point)));
            }
            if(point.getCandidateGroups() != null && !"".equals(point.getCandidateGroups())){
                userTask.setCandidateGroups(Collections.singletonList(buildCandidatesGroupsExpression(point)));
            }
        }

        if(point.getProcessPointType().equals(ProcessPointType.SIGN_TASK)){
            MultiInstanceLoopCharacteristics miInfo= new MultiInstanceLoopCharacteristics();
            miInfo.setSequential(false);
            miInfo.setInputDataItem("${activitiCallBackService.getMultiInstanceTaskAssignment(execution"+
                    ",'"+point.getId()+"'"+
                    ",'"+ConvertUtil.null2EmptyStr(point.getCandidateUsers()).trim()+"'"+
                    ",'"+ConvertUtil.null2EmptyStr(point.getCandidateGroups()).trim()+"'"+

                    ")}"
            );
            miInfo.setElementVariable("assign");

            userTask.setLoopCharacteristics(miInfo);
            userTask.setAssignee("${assign}");
        }

        if(point.getListeners()!=null&&!"".equals(point.getListeners())){
            Stream.of(point.getListeners().split(",")).forEach(handler->{
                TaskEventEnum taskEvent=providerManager.getTaskEventByHandler(handler);
                ActivitiListener activitiListener=new ActivitiListener();
                activitiListener.setEvent(taskEvent.name().toLowerCase());
                activitiListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_EXPRESSION);
                activitiListener.setImplementation(this.buildListenerExpression(point,handler));
                userTask.getTaskListeners().add(activitiListener);
            });
        }

        process.addFlowElement(userTask);

        GraphicInfo graphicInfo = new GraphicInfo();
        graphicInfo.setElement(userTask);
        graphicInfo.setX(point.getLeftPosition());
        graphicInfo.setY(point.getTopPosition());
        graphicInfo.setHeight(point.getHeight());
        graphicInfo.setWidth(point.getWidth());
        bpmnModel.addGraphicInfo(userTask.getId(),graphicInfo);

        if(point.getProcessPointType().equals(ProcessPointType.SIGN_TASK)) {
            ExclusiveGateway gateway = new ExclusiveGateway();
            gateway.setId(GATEWAY_ID_PREFIX+userTask.getId());
            process.addFlowElement(gateway);

            graphicInfo = new GraphicInfo();
            graphicInfo.setElement(gateway);
            graphicInfo.setX(point.getLeftPosition());
            graphicInfo.setY(point.getTopPosition());
            graphicInfo.setHeight(point.getHeight());
            graphicInfo.setWidth(point.getWidth());
            bpmnModel.addGraphicInfo(gateway.getId(),graphicInfo);
        }
    }

    /**
     * 创建流转函数,该函数负责生成
     * @param sourceCondition
     * @return
     */
    private String buildSequenceFlowCondition(String sourceCondition,String voterName,SequenceFlow sequenceFlow,ProcessPoint point){
        return "${activitiCallBackService.testFlowCondition(execution,"+
                "'"+point.getId()+"',"+
                "'"+ ConvertUtil.null2EmptyStr(sourceCondition).trim()+"',"+
                "'"+ConvertUtil.null2EmptyStr(voterName).trim()+"'"+
                ")}";
    }

    private String buildMutiInstanceTaskSequenceFlowCondition(String sourceCondition,String voterName,SequenceFlow sequenceFlow,ProcessPoint point){
        return "${activitiCallBackService.testMultiInstanceTaskFlowCondition(execution,"+
                "'"+point.getId()+"',"+
                "'"+ConvertUtil.null2EmptyStr(sourceCondition).trim()+"',"+
                "'"+ConvertUtil.null2EmptyStr(voterName).trim()+"'"+
                ")}";
    }

    private String buildManualAssigneeExpression(ProcessPoint point){
        return "${activitiCallBackService.getManualAssignAssignee(execution)}";
    }

    private String buildCandidatesUsersExpression(ProcessPoint point){
        return  "${activitiCallBackService.getTaskCandidatesUsers(execution"+
                ",'"+point.getId()+"'"+
                ",'"+ConvertUtil.null2EmptyStr(point.getCandidateUsers()).trim()+"'"+
                ")}";
    }

    private String buildCandidatesGroupsExpression(ProcessPoint point){
        return  "${activitiCallBackService.getTaskCandidateGroups(execution"+
                ",'"+point.getId()+"'"+
                ",'"+ConvertUtil.null2EmptyStr(point.getCandidateGroups()).trim()+"'"+
                ")}";
    }

    private String buildListenerExpression(ProcessPoint point,String handler){
        return "${activitiCallBackService.callTaskEventHandler(task.eventName,task,'" + point.getId() + "','" + handler + "')}";
    }

    private void deployModelerModel( Model modelData,final ObjectNode modelNode) throws Exception {
        BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);

        byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model);
        String bpmnString=null;
        // add:上面的参数,是直接把对象转成xml,再转成字节,由于他使用utf-8转的xml,所以转回来也得用utf-8

        bpmnString = new String(bpmnBytes,"utf-8");

        String processName = modelData.getName() + ".bpmn20.xml";
        repositoryService.createDeployment()
                .name(modelData.getName())
                .addString(processName,bpmnString)
                .deploy();
    }

}

猜你喜欢

转载自blog.csdn.net/u013984781/article/details/88420646