前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >工作流引擎之activiti-modeler在线流程设计器流程节点校验

工作流引擎之activiti-modeler在线流程设计器流程节点校验

作者头像
lyb-geek
发布2018-12-24 15:52:26
7K0
发布2018-12-24 15:52:26
举报
文章被收录于专栏:Linyb极客之路Linyb极客之路

前言

Activiti Modeler是一款基于angular的web流程在线设计器,主要用于保存BPMN规范相关的对象,例如将模型转换为相应的流程图对象。该组件可以方便业务人员进行在线工作流程图设计。 Activiti Modeler它本身是不提供流程节点合法性校验,而为了保证流程能够顺利走通,因此我们需要进行流程节点校验。

流程节点校验的方式

1、前端保存前校验,通过扩展流程设计器的校验功能 2、后端保存校验,主要通过异常导致事务回滚机制进行校验

由于项目其前端框架主要用iview,项目组缺乏有angular.js开发经验的伙伴,又因为工期原因,没法空出多余时间进行angular研究,因此后面采用的后端保存校验的方式,本文主要介绍以后端保存校验

需要校验流程节点的哪些环节

其实就是校验流程节点的完整性

1、流程节点是否存在开始节点、步骤节点、结束节点 2、流程节点是否有设置节点名称 3、流程节点与节点之间是否有设置流程连接线 4、当流程节点出口存在多个分支时,是否有出口规则条件判断 5、。。。

后端校验的方式

1、通过activiti自带的API进行校验

核心代码片段

代码语言:javascript
复制
List<ValidationError> validationErrorList = repositoryService.validateProcess(bpmnModel);

上面的校验方式,其自带的文案可能过于技术性,可能会给业务人员带来一定的阅读困难,因此项目组采用下面的校验方式

2、通过校验FlowElement合法性

核心代码

代码语言:javascript
复制
/**
     * 流程校验,因流程判断比较复杂,取巧借用事务回滚机制,如果校验失败,则回滚
     * @param bpmnModel
     * @param handlerPersonMap 流程办理人map
     */
    private void validateFlowModel(BpmnModel bpmnModel,Map<String, List<String>> handlerPersonMap) {

        if(bpmnModel != null){
            Collection<FlowElement> flowElements = bpmnModel.getMainProcess().getFlowElements();
            List<StartEvent> startEvents = new ArrayList<>();
            List<UserTask> userTasks = new ArrayList<>();
            List<EndEvent> endEvents = new ArrayList<>();
            List<SequenceFlow> sequenceFlows = new ArrayList<>();
            StringBuilder nodeError = new StringBuilder();
            boolean isFoundNodeNameNotSet = false;
            for (FlowElement e : flowElements) {
                if (e instanceof StartEvent) {
                    StartEvent startEvent = (StartEvent)e;
                    startEvents.add(startEvent);
                } else if (e instanceof SequenceFlow) {
                    SequenceFlow sequenceFlow = (SequenceFlow)e;
                    sequenceFlows.add(sequenceFlow);
                } else if (e instanceof UserTask) {
                    UserTask userTask = (UserTask) e;
                    userTasks.add(userTask);
                    if(StringUtil.isBlank(userTask.getName())){
                        isFoundNodeNameNotSet = true;
                    }
                } else if (e instanceof EndEvent) {
                    EndEvent endEvent = (EndEvent) e;
                    endEvents.add(endEvent);
                }
            }

            if(CollectionUtils.isEmpty(startEvents)){
                nodeError.append(Constants.PRCOESS_STARTEVENT_NOT_FOUND).append(Constants.SEMICOLON).append(Constants.HTML_NEWLINE);
            }

            if(CollectionUtils.isEmpty(userTasks)){
                nodeError.append(Constants.PRCOESS_USERTASK_NOT_FOUND).append(Constants.SEMICOLON).append(Constants.HTML_NEWLINE);
            }

            if (CollectionUtils.isEmpty(endEvents)){
                nodeError.append(Constants.PRCOESS_ENDEVENT_NOT_FOUND).append(Constants.SEMICOLON).append(Constants.HTML_NEWLINE);
            }

            if(StringUtil.isNotBlank(nodeError.toString())){
                throw new MuseException(ErrorCode.PROCESS_SAVE_FAIL,nodeError.toString());
            }

            if(isFoundNodeNameNotSet){
                throw new MuseException(ErrorCode.PROCESS_SAVE_FAIL,Constants.PRCOESS_NODE_NAME_NOT_SET);
            }


            if(!CollectionUtils.isEmpty(sequenceFlows)){
                for(SequenceFlow sequenceFlow : sequenceFlows){
                    if(StringUtil.isBlank(sequenceFlow.getSourceRef()) && StringUtil.isBlank(sequenceFlow.getTargetRef())){
                        nodeError.append(Constants.PRCOESS_SEQUENCEFLOW_RELATE_NODE_NOT_FOUND).append(Constants.SEMICOLON).append(Constants.HTML_NEWLINE);
                        break;
                    }
                }
            }


            StringBuilder handlerPersonNotFound = new StringBuilder();

            for(StartEvent startEvent : startEvents){
                List<SequenceFlow> outGoingFlows = startEvent.getOutgoingFlows();
                if(CollectionUtils.isEmpty(outGoingFlows)){
                   nodeError.append("[").append(startEvent.getName()).append("]").append(Constants.PRCOESS_OUTGOING_FLOWS_NOT_FOUND).append(Constants.SEMICOLON).append(Constants.HTML_NEWLINE);
                }
                //节点之间连线校验
                validateSequenceFlows(nodeError, startEvent.getName(), outGoingFlows,SequenceFlowType.TARGET);

                List<String> handlerPersonList = handlerPersonMap.get(startEvent.getId());
                if(CollectionUtils.isEmpty(handlerPersonList)){
                    handlerPersonNotFound.append("[").append(startEvent.getName()).append("]").append(Constants.PRCOESS_HANDLER_PERSON_NOT_FOUND).append(Constants.SEMICOLON).append(Constants.HTML_NEWLINE);
                }

            }


            for(UserTask userTask : userTasks){
                List<SequenceFlow> incomingFlows = userTask.getIncomingFlows();
                if(CollectionUtils.isEmpty(incomingFlows)){
                    nodeError.append("[").append(StringUtil.isBlank(userTask.getName())? Constants.PRCOESS_WIHTOUT_NAME : userTask.getName()).append("]").append(Constants.PRCOESS_INCOMING_FLOWS_NOT_FOUND).append(Constants.SEMICOLON).append(Constants.HTML_NEWLINE);
                }
                //节点之间连线校验
                validateSequenceFlows(nodeError,StringUtil.isBlank(userTask.getName())? Constants.PRCOESS_WIHTOUT_NAME : userTask.getName(),incomingFlows,SequenceFlowType.SOURCE);

                List<SequenceFlow> outGoingFlows = userTask.getOutgoingFlows();
                if(CollectionUtils.isEmpty(outGoingFlows)){
                    nodeError.append("[").append(StringUtil.isBlank(userTask.getName())? Constants.PRCOESS_WIHTOUT_NAME : userTask.getName()).append("]").append(Constants.PRCOESS_OUTGOING_FLOWS_NOT_FOUND).append(Constants.SEMICOLON).append(Constants.HTML_NEWLINE);
                }
                //节点之间连线校验
                validateSequenceFlows(nodeError, StringUtil.isBlank(userTask.getName())? Constants.PRCOESS_WIHTOUT_NAME : userTask.getName(), outGoingFlows,SequenceFlowType.TARGET);

                List<String> handlerPersonList = handlerPersonMap.get(userTask.getId());
                if(CollectionUtils.isEmpty(handlerPersonList)){
                    handlerPersonNotFound.append("[").append(userTask.getName()).append("]").append(Constants.PRCOESS_HANDLER_PERSON_NOT_FOUND).append(Constants.SEMICOLON).append(Constants.HTML_NEWLINE);
                }

            }

            for(EndEvent endEvent : endEvents){
                List<SequenceFlow> incomingFlows = endEvent.getIncomingFlows();
                if(CollectionUtils.isEmpty(incomingFlows)){
                    nodeError.append("[").append(StringUtil.isBlank(endEvent.getName()) ? Constants.ACT_TYPE_END_CN : endEvent.getName()).append("]").append(Constants.PRCOESS_INCOMING_FLOWS_NOT_FOUND).append(Constants.SEMICOLON).append(Constants.HTML_NEWLINE);
                }
                //节点之间连线校验
                validateSequenceFlows(nodeError,StringUtil.isBlank(endEvent.getName()) ? Constants.ACT_TYPE_END_CN : endEvent.getName(),incomingFlows,SequenceFlowType.SOURCE);
            }

            if(StringUtil.isNotBlank(handlerPersonNotFound.toString())){
                nodeError.append(handlerPersonNotFound.toString());
            }



            if(StringUtil.isNotBlank(nodeError.toString())){
                throw new MuseException(ErrorCode.PROCESS_SAVE_FAIL,nodeError.toString());
            }



        }
    }

    /**
     * 节点之间连接线校验
     * @param nodeError
     * @param nodeName
     * @param sequenceFlows
     */
    private void validateSequenceFlows(StringBuilder nodeError, String nodeName, List<SequenceFlow> sequenceFlows,SequenceFlowType sequenceFlowType) {
        if(CollectionUtils.isEmpty(sequenceFlows)){
            return;
        }
        String tip = null;
        String seqRef = null;
        int  conditionCount = sequenceFlows.size();
        for(SequenceFlow sequenceFlow : sequenceFlows){
            switch (sequenceFlowType){
                case SOURCE:
                    seqRef = sequenceFlow.getSourceRef();
                    tip = Constants.PRCOESS_INCOMING_FLOWS_NOT_FOUND;
                    break;
                case TARGET:
                    seqRef = sequenceFlow.getTargetRef();
                    tip = Constants.PRCOESS_OUTGOING_FLOWS_NOT_FOUND;
                    break;
                    default:
                        break;
            }

            if(StringUtil.isBlank(seqRef)){
                nodeError.append("[").append(nodeName).append("]").append(tip).append(Constants.SEMICOLON).append(Constants.HTML_NEWLINE);
                break;
            }

            //存在多个分支时,则进行出口条件校验
            if(sequenceFlows.size() > 1){
               String conditionExpression = sequenceFlow.getConditionExpression();
               if(StringUtil.isBlank(conditionExpression)){
                   conditionCount = conditionCount - 1;
               }

            }

        }

        if(conditionCount == 0){
            nodeError.append("[").append(nodeName).append("]").append(Constants.PRCOESS_EXPORT_RULE_NOT_FOUND).append(Constants.SEMICOLON).append(Constants.HTML_NEWLINE);
        }
    }

效果图展示

其他

项目组有用iview的伙伴们,且要实现modal弹窗的拖拽、遮罩层的禁用的需求的话,如果你们项目是采用iview3.x版本以上,则modal加上draggable=true,和mask=false这两个属性就可以实现效果。如果目前采用的是iview2.x版本,这个版本没有这两个属性,可以通过引入jquery-ui.min.js,调用该js提供的 draggable()实现拖拽

附录

view2.x 版本实现modal弹窗拖拽和遮罩层禁用的方法如下

代码语言:javascript
复制
draggableWithDisAbledMask:function(){
            $("div.ivu-modal").draggable();
            $("div.ivu-modal-mask").remove();
            $("div.ivu-modal-content").css("background","#F7F7F7");
            setTimeout(function(){
                $(".ivu-modal-wrap").removeClass("ivu-modal-wrap");
            }, 1500);
        }
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-12-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linyb极客之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 流程节点校验的方式
  • 需要校验流程节点的哪些环节
  • 后端校验的方式
  • 效果图展示
  • 其他
  • 附录
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档