一 Flowable介绍

  1. BPMN

    1. 一个软件协议,此协议用于约定了流程框架的开发规范。比如说,我们去绘制流程图的图标的规范。

    2. 基于这个规范,很方便地学习基于此规范的其它的流程框架。

  2. flowable是一个服务平台

    1. 等一系列功能

      1. BPMN

      2. DMN决策表(树)

      3. CMMN Case管理引擎

      4. 用户管理

      5. 微服务API

    2. 功能比acitviti更加强大。如果有activiti的基础,那么可以很容易地学习与使用flowable。

    3. 如果会使用开源版本的flowable,那么商业版的flowable就无缝衔接了。

二 Flowable类关系图

  1. ProcessEnginConfiguration:配置类,用于配置流程引擎

    1. JtaProcessEngineConfiguration
    2. MultiSchemaMultiTenantProcessEngineConfiguration
    3. ProcessEngineConfigurationImpl
    4. StandaloneInMemProcessEngineConfiguration:基于内存的
    5. StandaloneProcessEngineConfiguration:单体的
  2. ProcessEngin:流程引擎对象接口
    1. 作用:

      1. 同activiti一样,它是操作flowable流程的核心对象,类似于JDBC中的Connnection对象,或者说类似于做mybatis操作时的SqlSessionFactory对象。
      2. 在编码时,主要用于获取多个XxxService服务,如下图源码:
    2. 特点:
      1. 在一个程序中可以有多个流程引擎对象ProcessEngin,而且可以给这些对象取名。
    3. 获取方式:
      1. 第一步:获取配置流程引擎对象的配置类:ProcessEnginConfiguration
      2. 第二步:获取流程引擎对象:ProcessEngin
    4. 配置文件使用方式:
      1. 方式1:默认配置文件是resources目录下的flowable.cfg.xml

        1. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
      2. 方式2:加载自定义名称的配置文件:
        1. @Test
              public void test2() throws Exception{
                  ProcessEngineConfiguration configuration = ProcessEngineConfiguration
                          .createProcessEngineConfigurationFromResource("flowable.cfg.xml");
                  ProcessEngine processEngine = configuration.buildProcessEngine();
                  System.out.println("processEngine = " + processEngine);
              }
  3. ProcessEngineConfigurationImpl:抽象类
    1. 配置对象,是ProcessEngine的配置对象的默认实现。这是因为有如下代码来创建ProcessEngine:

      public abstract class ProcessEngineConfigurationImpl extends ProcessEngineConfiguration implements ScriptingEngineAwareEngineConfiguration {public ProcessEngine buildProcessEngine() {// this表示绑定当前对象,即绑定ProcessEngineConfigurationImplthis.init();ProcessEngineImpl processEngine = new ProcessEngineImpl(this);this.postProcessEngineInitialisation();return processEngine;}
      }
    2. this.init()初始化了很多东西,使用了模板模式(设计模式)
      this.initConfigurators();
      this.configuratorsBeforeInit();
      this.initProcessDiagramGenerator();
      this.initHistoryLevel();
      this.initFunctionDelegates();
      this.initDelegateInterceptor();
      this.initExpressionManager();
      this.initAgendaFactory();
      if (this.usingRelationalDatabase) {this.initDataSource();  //如何关联数据为的?this.initDbSchemaManagers();
      }this.initHelpers();
      this.initVariableTypes();
      this.initBeans();
      this.initFormEngines();
      this.initFormTypes();
      this.initScriptingEngines();
      this.initClock();
      this.initBusinessCalendarManager();
      this.initCommandContextFactory();
      this.initTransactionContextFactory();
      this.initCommandExecutors();
      this.initServices();
      this.initIdGenerator();
      this.initWsdlImporterFactory();
      this.initBehaviorFactory();
      this.initListenerFactory();
      this.initBpmnParser();
      this.initProcessDefinitionCache();
      this.initProcessDefinitionInfoCache();
      this.initAppResourceCache();
      this.initKnowledgeBaseCache();
      this.initJobHandlers();
      this.initHistoryJobHandlers();
      this.initTransactionFactory();
      if (this.usingRelationalDatabase) {this.initSqlSessionFactory(); //初始化SqlSessionFactory
      }this.initSessionFactories();
      this.initDataManagers(); //初始化好多个管理器
      this.initEntityManagers();
      this.initCandidateManager();
      this.initHistoryManager();
      this.initDynamicStateManager();
      this.initJpa();
      this.initDeployers();
      this.initEventHandlers();
      this.initFailedJobCommandFactory();
      this.initEventDispatcher();
      this.initProcessValidator();
      this.initFormFieldHandler();
      this.initDatabaseEventLogging();
      this.initFlowable5CompatibilityHandler();
      this.initVariableServiceConfiguration();
      this.initIdentityLinkServiceConfiguration();
      this.initTaskServiceConfiguration();
      this.initJobServiceConfiguration();
      this.initAsyncExecutor();
      this.initAsyncHistoryExecutor();
      this.configuratorsAfterInit();
      this.afterInitTaskServiceConfiguration();
  4. RepositoryService:资源(流程定义、流程部署等)管理服务
  5. RuntimeService:流程运行时服务
  6. TaskService:流程任务处理服务
  7. ManagementService:Activiti的引擎管理类,提供了对Flowable 流程引擎的管理和维护功能,这些功能不在工作流驱动的应用程序中使用,主要用于 Flowable 系统的日常维护。
  8. HistoryService:流程历史信息

-------------------------------------------------------------------------------------------------------------------------------

  1. 规则:

    1. XxxService,在flowable中用来专门处理流程的各种操作。
  2. 关系:
    1. ProcessEngin 与 RepositoryService、RuntimeService、TaskService、ManagementService、HistoryService
              ProcessEngin相当于公司的老板,RepositoryService、RuntimeService、TaskService、ManagementService、HistoryService这几个相当于公司下各个部门(从事、财务、开发、运维)的主管。XxxService,在flowable中用来专门处理流程的各种操作。老板要做什么事情,都会去找相关的部门的主管说一下,主管会全权负责完成。

三 Flowable基础表结构(30张)

  1. 基础表

    1. 建表语句:jar源码包:
    2. 建表时机:
      1. 当我们去获取ProcessEngine对象的时候,flowable会在数据库中创建这5个类型的表(ACT_RE、ACT_RU、ACT_HI、ACT_GE、ACT_ID)。
      2. 随着业务复杂度的提高,后面去做业务处理或使用flowable UI的时候,还会创建一些其它前缀的数据表。
    3. 分类:
      1. ACT_RE :'RE'表示 repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。

      2. ACT_RU:'RU'表示 runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Flowable只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。

      3. ACT_HI:'HI'表示 history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。

      4. ACT_GE: GE 表示 general。 通用数据, 用于不同场景下

      5. ACT_ID: ’ID’表示identity(组织机构)。这些表包含标识的信息,如用户,用户组,等等。

  2. 基础表结构
    1. 一般数据表

      1. ACT_GE_BYTEARRAY:数据源表,保存通用的流程定义和流程资源
        1. 保存流程部署的相关信息,比如保存着流程定义xml文件                    
      2. ACT_GE_PROPERTY:系统相关属性                                       
    2. 流程历史记录表                                                                            
      1. ACT_HI_ACTINST:历史的流程实例                                  
      2. ACT_HI_ATTACHMENT:历史的流程附件                                  
      3. ACT_HI_COMMENT:历史的说明性信息                                   
      4. ACT_HI_DETAIL:历史的流程运行中的细节信息                         
      5. ACT_HI_IDENTITYLINK:历史的流程运行过程中用户关系                       
      6. ACT_HI_PROCINST:历史的流程实例 【PRO是process流程的简写】               
      7. ACT_HI_TASKINST:历史的任务实例 【TASK是task任务】                      
      8. ACT_HI_VARINST:历史的流程运行中的变量信息【VAR是valiable流程变量的简写】                 
    3. 流程定义表                                                                          
      1. ACT_RE_DEPLOYMENT:部署单元信息 。每部署一个流程,就会在此表产生一条记录。                                  
      2. ACT_RE_MODEL :模型信息                                           
      3. ACT_RE_PROCDEF:流程定义表,保存已部署的流程定义【PROC是process流程的简写,而DEF是definition定义的简写】                                   
    4. 运行实例表                                                                              
      1. ACT_RU_EVENT_SUBSCR:跟执事件相关,运行时事件                                    
      2. ACT_RU_EXECUTION:跟执行器相关,运行时流程执行实例                             
      3. ACT_RU_IDENTITYLINK:跟用户相关,运行时用户关系信息,存储任务节点与参与者的相关信息 
      4. ACT_RU_JOB:运行时作业                                         
      5. ACT_RU_TASK:任务表,运行时任务                                         
      6. ACT_RU_VARIABLE:运行时变量表,即流程变量的信息,即提交参数(表单数据)到流程                              
    5. 用户用户组表                                                                            
      1. ACT_ID_BYTEARRAY:相关的一些资源,二进制数据表                                     
      2. ACT_ID_GROUP:用户组信息表                                       
      3. ACT_ID_INFO:用户详细信息详情表                                     
      4. ACT_ID_MEMBERSHIP :人与组关系表                                       
      5. ACT_ID_PRIV:权限表                                             
      6. ACT_ID_PRIV_MAPPING:用户或组权限关系表                                 
      7. ACT_ID_PROPERTY:属性表                                             
      8. ACT_ID_TOKEN:跟认证相关,记录用户的token信息                                
      9. ACT_ID_USER:用户表 
  3. 规则:
    1. 成功部署并一个请假流程以后,会在表:
      ACT_GE_BYTEARRAY、
      ACT_RE_DEPLOYMENT、
      ACT_RE_PROCDEF
      中创建一条新的记录,用于保存请假流程相关的信息。
    2. 删除已经部署的请假流程以后,会把表:
      ACT_GE_BYTEARRAY、
      ACT_RE_DEPLOYMENT、
      ACT_RE_PROCDEF
      中对应的一条记录删除去。
    3. 启动一个流程以后:
      1. ACT_RU_VARIABLE会保存流程变量的信息。
      2. ACT_RU_TASK会保存第一步的任务,如请假条会流转到总经理审批(Approve or reject request)这一步任务,总经理要决策操作:是审批通过 或者 是拒绝。
      3. ACT_RU_EXECUTION会保存成功启动的流程的相关信息。
    4. 每走一步任务:
      1. ACT_RU_TASK:中的记录的审批者都会变成下一个要审批的人
    5. 最完所有任务:
      1. ACT_RU_TASK:与此流程相关的一条记录会被删除掉。
  4. 关系:

四 Flowable基础:基于BPMN 2.0

  1. 官方手册:Flowable BPMN 用户手册 (v 6.3.0) (tkjohn.github.io)
  2. 流程设计
    1. eclipse Designer
    2. flowable UI
  3. 基本应用、简单案例:不去结合流程设计,完成一个流程的完整的工作走向(流程)
    1. 流程部署
    2. 流程实例创建
    3. 启动流程
    4. 查询任务
    5. 处理任务
  4. 简单案例演示详细步骤
    1. 第一步:创建流程引擎对象ProcessEngine

      1. 第1步:创建maven项目
      2. 第2步:引入依赖
        1. flowable-engine 6.3.0
        2. mysql-connector-java 8.0.21
        3. junit 4.13.2
      3. 第3步:测试类(src/test/java/com.bobo.flowable.test/Test01.java)
        1. 配置流程引擎对象的配置类:ProcessEnginConfiguration
        2. 获取流程引擎对象:ProcessEngin
        3. 新建30张表:
          package com.bobo.flowable.test;import org.flowable.engine.ProcessEngine;
          import org.flowable.engine.ProcessEngineConfiguration;
          import org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration;public class Test01 {/*** 获取流程引擎对象*/public static void testProcessEngine(){//  获取流程引擎配置类对象:ProcessEngineConfigurationProcessEngineConfiguration configuration = new StandaloneProcessEngineConfiguration();//  配置数据库连接信息configuration.setJdbcUrl("jdbc:mysql://10.203.5.185:3306/fLearn?serverTimezone=UTC&nullCatalogMeansCurrent=true").setJdbcUsername("root").setJdbcPassword("MySQL#567890").setJdbcDriver("com.mysql.cj.jdbc.Driver")//  如果数据库中的表结构不存在就新建.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);//  通过ProcessEngineConfiguration构建我们需要的流程引擎对象ProcessEngineProcessEngine ProcessEngine = configuration.buildProcessEngine();System.out.println("ProcessEngine:"+ProcessEngine);}public static void main(String[] args) {testProcessEngine();}
          }
          
      4. 第4步:加入日志功能
        1. 第a步:引入依赖

          1. slf4j-api
          2. slf4j-log4j12
        2. 第b步:Log4j需要一个配置文件。在src/main/resources文件夹下添加log4j.properties文件,并写入下列内容:

          log4j.rootLogger=DEBUG, CA

          log4j.appender.CA=org.apache.log4j.ConsoleAppender
          log4j.appender.CA.layout=org.apache.log4j.PatternLayout
          log4j.appender.CA.layout.ConversionPattern= %d{hh:mm:ss,SSS} [%t] %-5p %c %x - %m%n

        3. 第c步:重新运行单元测试方法

        4. 第d步:在控制台中看到多了很多日志。如果之前没有创建对应的表结构(30张),那么就会看到创建这30张表的建表语句。

    2. 第二步:部署流程定义
                     ps:创建流程,一般第1步:通过流程设计器绘制流程图。但为了把流程操作的完整流程演示出来,在此先不用流程设计器,而是使用一个写好的xml格式的流程文件(官网案例)

      1. 流程图:请假流程

        1. 第1步:部署一个流程
        2. 第2步:发起一个流程
          1. 提供的参数:姓名、请假天数、请假理由、请假开始和结束时间等
        3. 第3步:管理员进行决策:同意 或者 拒绝
        4. 第4步:网关
          1. 第a步:如果管理员同意了,继续走下一步审批(如:人事审批等,直至审批环节走完、结束)。
          2. 第b步:如果管理员拒绝了,触发事件,发一封拒绝的邮件。
      2. 部署流程
        1. 概述:这里部署流程,是基于BPMN 2.0的格式来部署的。这就要求去创建一个xml格式的流程文件,在这个xml格式的流程文件中定义了请假流程的整个过程
        2. 详细步骤
          1. 第1步:将下面的XML保存在src/main/resources文件夹下名为holiday-request.bpmn20.xml的文件中。(注:其中后缀“.bpmn20.xml”是固定不变的,而前缀“holiday-request”是流程名称。)

            1. <definitions>中定义了一些约束在里面。
            2. <process>是一个流程
                id:唯一标识(主键)
                name:流程名称。可修改。

              1. <startEvent id="startEvent"/>:编号是"startEvent"
              2. <sequenceFlow>:顺序流
                sourceRef="startEvent":顺序流的来源是"startEvent"。targetRef="approveTask":目标的引用是"approveTask(同意的任务)"。

                1. <conditionExpression>:条件表达式
                  xsi:type="tFormalExpression":去到哪个表达式

                  1. <![CDATA[]]>:表达式写在里面

                    1. ${!approved}:条件表达式,包含参数运算
              3. <userTask>:用户的任务
                id="approveTask(同意的任务)"
                name="Approve or reject request":同意或者拒绝
              4. 排他网关<exclusiveGateway id="decision"/>
              5. <serviceTask id="sendRejectionMail" name="Send out rejection email"
                                  flowable:class="org.flowable.SendRejectionMail"/>
                flowable:class="org.flowable.SendRejectionMail"用来处理发送拒绝请假邮件的操作。
              6. <endEvent id="approveEnd"/>:某个分支的流程终止的节点。
            3. 总结:
              1. 第a步:<startEvent id="startEvent"/>表示开始
              2. 第b步:走到:用户任务<userTask id="approveTask(同意的任务)" name="Approve or reject request(同意或者拒绝)"/>
              3. 第c步:走到:排他网关<exclusiveGateway id="decision"/>
                1. 条件:<sequenceFlow sourceRef="decision" targetRef="externalSystemCall">
                              <conditionExpression xsi:type="tFormalExpression">
                                  <![CDATA[
                            ${approved}
                          ]]>
                              </conditionExpression>
                          </sequenceFlow>

                  1. 排他网关的第1个流程,分支1是targetRef="externalSystemCall"
                  2. 排他网关的第2个流程,分支2是targetRef="sendRejectionMail"
                    1. 人事
              4. 第d步:人事处理请假的2个分支,如扣钱   和   发邮件处理拒绝请假:<serviceTask id="Xxx" name="Xxx"/>
              5. 第e步:人事处理请假的2个分支都走完终止流程:<endEvent id="Xxx"/>
          2. 第2步:使用代码实现流程部署
            package com.bobo.flowable.test;import org.flowable.engine.ProcessEngine;
            import org.flowable.engine.ProcessEngineConfiguration;
            import org.flowable.engine.RepositoryService;
            import org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration;
            import org.flowable.engine.repository.Deployment;
            import org.junit.Before;
            import org.junit.Test;public class Test01 {ProcessEngineConfiguration configuration = null;/*** 初始化流程引擎配置对象*/@Beforepublic void before(){//  获取流程引擎配置类对象:ProcessEngineConfigurationconfiguration = new StandaloneProcessEngineConfiguration();//  配置数据库连接信息configuration.setJdbcUrl("jdbc:mysql://10.203.5.185:3306/fLearn?serverTimezone=UTC&nullCatalogMeansCurrent=true").setJdbcUsername("root").setJdbcPassword("MySQL#567890").setJdbcDriver("com.mysql.cj.jdbc.Driver")//  如果数据库中的表结构不存在就新建.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);}/*** 部署流程*/@Testpublic void testProcessEngine(){//  创建流程引擎对象:通过ProcessEngineConfiguration构建我们需要的流程引擎对象ProcessEngineProcessEngine processEngine = configuration.buildProcessEngine();//  创建RepositoryService对象//  类似地还有:RepositoryService、RuntimeService、TaskService、ManagementService、HistoryService,都是flowable提供的关于流程操作的核心服务类(service))RepositoryService repositoryService = processEngine.getRepositoryService();//  创建流程部署对象Deployment://    (1)添加流程部署文件//    (2)设置部署流程的名称//    (3)执行部署操作Deployment deployment = repositoryService.createDeployment().addClasspathResource("holiday-request.bpmn20.xml").name("请假流程").deploy();System.out.println("deployment.getId() = " + deployment.getId());System.out.println("deployment.getName() = " + deployment.getName());}}
            
          3. 第3步:运行测试方法

          4. 第4步:验证

            1. 方式1:日志打印出流程id与名称:

            2. 方式2:查看数据库表

    3. 第三步:操作CRUD流程

      1. 查看完成部署的流程定义的信息:// 获取流程定义对象
                ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                        .deploymentId("2501")
                        .singleResult();

      2. 删除完成部署的流程实例:

            // 删除完成部署的流程实例// 删除部署的流程// (1)第一个参数是id。如果部署的流程启动了就不允许删除了// (2)第二个参数是级联删除,如果为true,那么删除流程的同时启动了相关的任务也一并会被删除外repositoryService.deleteDeployment("1");
    4. 第四步:启动流程实例
      1. 概述:经过上面的3个步骤,请假流程已经成功部署了。张三和李四都要请假,因此他们都需要发起一个流程。
                  张三和李四请假时,要填写请假表单(请假的相关信息,如请假人、请假时长、请假理由等),然后把请假表单数据提交给审批人。
      2. 详细步骤
        1. 代码实现:

          // 启动流程实例
          // (1)第一个参数是流程定义的id(主键)
          // (2)第二个参数是提交的表单数据
          ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holidayRequest", variables);// 输出相关的流程实例信息
          System.out.println("流程定义的ID:" + processInstance.getProcessDefinitionId());
          System.out.println("流程实例的ID:" + processInstance.getId());
          System.out.println("当前活动的ID:" + processInstance.getActivityId());
        2. 控制台打印:
          流程定义的ID:holidayRequest:1:3
          流程实例的ID:2501
          当前活跃的ID:null
    5. 第五步:查看任务
      1. 第1步:修改配置文件,指定每一步任务的一个审批人 或者 一个审批小组。

        上面员工发起了一个请假流程,接下来就会流转到总经理这儿来处理,之前我们没有指定候选人经理这的处理人,我们可以加一个:
                 此时,如果任务流转到总经理(lisi)这里,那么lisi登录进来就可以看到zhansan请假的审批在这里,等待审批。

      2. 第2步:删除旧的流程:repositoryService.deleteDeployment("1",true);

        1. 验证:查看数据库表

      3. 第3步:重新启部署流程:Deployment deployment = repositoryService.createDeployment()// 创建Deployment对象
                        .addClasspathResource("holiday-request.bpmn20.xml") // 添加流程部署文件
                        .name("请假流程") // 设置部署流程的名称
                        .deploy(); // 执行部署操作

        deployment.getId() = 5001        //流程编号
        deployment.getName() = 请假流程  //流程名称

      4. 第4步:重启启动流程实例(张三请假)

      5. 第5步:代码实现,任务查看。即在实际开发中,张三的司令登录进来后会在前端页面看到流转到他的流程审批任务。

        List<Task> list = taskService.createTaskQuery().processDefinitionKey("holidayRequestNew") //指定查询的流程编号.taskAssignee("张三的司令")//查询这个任务的处理人(流转到).list(); 
      6. 第6步:验证:
        task.getProcessDefinitionId() = holidayRequest:1:5003
        task.getId() = 10008
        task.getAssignee() = 张三的司令
        task.getName() = 同意或者拒绝请假
        task.getProcessDefinitionId() = holidayRequest:1:5003
        task.getId() = 7508
        task.getAssignee() = 张三的司令
        task.getName() = 同意或者拒绝请假

    6. 第六步:(审批人)处理任务(流转到)
          不管是放行还是拒绝请假,流程任务都会流转到排他网关。网关要对任务做一个操作,即根据总经理的处理(放行或拒绝),网关要做出路由

      1. 第1步:配置文件

        在此处我们直接解决掉这个请假,然后会走发送拒绝邮件的流程,这块我们需要用到JavaDelegate来触发。

      2. 第2步:添加Java委托类

        package org.flowable;import org.flowable.engine.delegate.DelegateExecution;
        import org.flowable.engine.delegate.JavaDelegate;
        public class SendRejectionMail implements JavaDelegate {/*** 这是一个Flowable中的触发器* @param delegateExecution*/@Overridepublic void execute(DelegateExecution delegateExecution) {//  触发执行的逻辑,按照我们在流程中的定义,应该给被拒绝的员工发送邮件//  扩展:短信、邮件、订单回退、删除订单等System.out.println("请假被拒绝,,,安心工作吧");}
        }
        
      3. 第3步:单元测试,完成任务

          @Testpublic void testCompleteTask(){// 获取流程引擎对象ProcessEngine processEngine = configuration.buildProcessEngine();TaskService taskService = processEngine.getTaskService();Task task = taskService.createTaskQuery().processDefinitionKey("holidayRequest2").taskAssignee("张司令").singleResult();// 添加流程变量Map<String,Object> variables = new HashMap<String,Object>();variables.put("approved",false); // 拒绝请假// 完成任务taskService.complete(task.getId(),variables);}
      4. 第4步: 验证,查询数据库

    7. 第七步:查看历史信息

      1. 代码实现:

        /*** 查看历史*/
        @Test
        public void testQueryHistory(){// 获取流程引擎对象ProcessEngine processEngine = configuration.buildProcessEngine();HistoryService historyService = processEngine.getHistoryService();List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery().processDefinitionId("holidayRequest2:1:2503") //从数据库表ACT_RE_PROCDEF中获取定义id.finished() //查询的历史记录的状态是已经完成.orderByHistoricActivityInstanceEndTime().asc()//结束时间排序.list();for (HistoricActivityInstance historicActivityInstance : list) {System.out.println(historicActivityInstance.getActivityId() + " took "+ historicActivityInstance.getDurationInMillis() + " milliseconds");}
        }

五 Flowable流程设计器

1 纲:Eclipse Designer插件

2 Flowable UI应用

  1. 概述:flowable提供了flowable UI,是一个前端web应用

    1. 格式:war包
    2. 操作:部署
    3. 功能:绘制流程、演示、测试
  2. 使用详细步骤
    1. 部署flowable UI

      1. 第一步:官网下载:flowable-6.7.2.zip
      2. 第二步:解压,flowable-6.7.2\wars
        1. flowable-rest.war:
        2. flowable-ui.war:
        3. 注:6.4.0会把4个模块(Flowable IDM、Flowable Modeler 、Flowable Task 、Flowable Admin )分别做成1个war包,即一共4个war包。而在6.4.0以后,会把4个模块合并,并形成2个war包而已,这样更友好。
      3. 第三步:tomcat
        1. 第1步:把flowable-rest.war、flowable-ui.war放到tomcat的webapps目录中
        2. 第2步:启动tomcat服务器,startup.bat
          1. tomcat服务器会自动帮我们解压缩flowable-rest.war、flowable-ui.war
          2. 注:如果出现乱码问题的话,那么修改logging.propertie文件末尾加入java.util.logging.ConsoleHandler.encoding = GBK
      4. 第四步:浏览器中访问 http://localhost:8080/flowable-ui, 默认的账号密码是 admin/test
        1. 四个模块:任务应用程序、建模器应用程序、管理员应用程式、身份管理应用程序
        2. 注:你们第一次访问时,FirstApplication功能模块是没有的。为什么老师的页面上会有呢?这是因为,老师之前操作的时候创建了一个应用(FirstApplication)在里面。
    2. 身份管理应用程序:用户(组)的创建与权限控制
      1. 创建用户组
      2. 创建用户
      3. 权限控制
        1. 访问权限:用户可以访问哪些应用(功能)
    3. 建模器应用程序:主要用于绘制流程图
      1. 用户任务(选中)

        1. 表单引用:就是请假流程时,要把表单参数(如请假时间、请假理由、请假时长等信息)。
        2. Variable aggregations (Multi-instance):流程变量
        3. 分配用户:分配处理这个任务的用户(组)
    4. 部署流程
      1. 第一步:导出成bpmn文件

        1. 注:<bpmndi:BPMNDiagram id="BPMNDiagram_MyHolidayUI">标签中包含的是流程图所对应的元数据信息,有了元数据信息flowable要以把流程变成可视化的图片展示给我们看。
      2. 第二步:然后就是正常的操作流程了
    5. 演示应用程序:模拟演示的程序,可以帮助我们直观地看到流程流转的整个过程。
      1. 第一步:创建演示应用程序
      2. 第二步:指定关联的流程的流程图,并保存
      3. 第三步:发布演示应用程序(注:相当于我们部署并启动了一个应用)
      4. 第四步:在“任务应用程序”中,启动流程
      5. 第五步:在“任务应用程序”中,一个个任务走完流程
        1. 注:切换用户登录,进行审批(点击完成)

六 流程部署原理

  1. 环境:

    1. Eclipse
    2. 1个.bar中包含两个bpmn文件,即将一次部署两个流程
  2. 效果:
    1. 流程部署表:act_re_deployment

      1. 只会有1条部署的记录,此记录不关联相关的流程文件
    2. 流程定义表:act_re_procdef
      1. .bar会被解压出2个bpmn文件,在act_re_procdef分别生成1条流程定义文件记录,即2条记录。
    3. 流程部署资源文件表:act_ge_bytearray
      1. 每个流程会在此表中产生2条记录,即此次部署会在这张表中产生4条记录。2条记录分别记录了2个流程的流程文件,另外2条记录分别记录了2个流程的流程图文件。
  3. 总结:
    1. act_re_deployment和act_re_procdef、act_ge_bytearray是一对多的关系

      1. act_re_deployment的id,在act_re_procdef、act_ge_bytearray中都存在外键

七 流程启动的原理

  1. ACT_RU_Xxx是流程在运行过程中会涉及到的
  2. 流程启动操作涉及的表:
    1. ACT_RU_EXECUTION 运行时流程执行实例

      1. BUSINESS_KEY_:绑定的业务主键,如订单号

      2. PARENT_ID_:空代表流程实例的第一个任务

      3. ROOT_PROC_INST_ID_:当前流程实例根节点的编号

      4. Xxx_COUNT_:统计信息

      5. 注意事项:

        1. 同一个流程会有多条数据,每条数据用ROOT_PROC_INST_ID_进行关联

    2. ACT_RU_IDENTITYLINK 运行时用户关系信息

    3. ACT_RU_TASK 运行时任务表:记录当前流程实例所处的流程节点信息,比如现在到张三审批了;张三审批完,又记录现在是李四审批了。

      1. ASSIGNEE_:指派谁去处理

      2. FORM_KEY_:在flowable中是可以绑定表单的,FORM_KEY_就是用于记录绑定的表单

    4. ACT_RU_VARIABLE 运行时变量信息表

    5. ACT_HI_ACTINST 历史的流程实例

    6. ACT_HI_PROCINST 历史的流程定义信息
    7. ACT_HI_TASKINST 历史的任务实例信息
    8. ACT_HI_VARINST 历史的流程运行中的变量信息

八 流程挂起(暂停)与激活原理

  1. 挂起(暂停)

    1. 状态描述:act_re_procdef的SUSPENSION_STATE_,2代表挂起、1代表激活。
  2. 激活
    1. 状态描述:act_re_procdef的SUSPENSION_STATE_,2代表挂起、1代表激活。
  3. 注意事项:
    1. 挂起的流程,先激活,才能重新启动。

九 处理流程的原理ACT_RU_EXECUTION 运行时流程执行实例

    1. 处理流程过程中不会变
  1. ACT_RU_IDENTITYLINK 运行时用户关系信息,IDENTITYLINK中会记录每次流程操作的信息

    1. 每对流程做一次处理,ACT_RU_IDENTITYLINK 就会多1条记录

  2. ACT_RU_TASK 运行时任务表,记录了当前流程实例所运行的节点。

    1. 审批完成进入下一个环节,ACT_RU_TASK 会删除1条记录(旧任务),新增1条新记录(新任务)。

  3. ACT_RU_VARIABLE 运行时变量表:Map集合

    1. 如果之前没有绑定流程变量,那么就多1条记录,是处理流程时绑定的流程变量。

    2. 如果之前有绑定过流程变量,那么就把这条数据中的数据更新为最新数据。

十 完成(结束)一个流程

首先我们会发现

  1. ACT_RU_EXECUTION 运行时流程执行实例

  2. ACT_RU_IDENTITYLINK 运行时用户关系信息

  3. ACT_RU_TASK 运行时任务表

  4. ACT_RU_VARIABLE 运行时变量表

这四张表中对应的数据都没有了,也就是这个流程已经不是运行中的流程了。然后在对应的历史表中我们可以看到相关的信息:

  1. ACT_HI_ACTINST 历史的流程实例

  2. ACT_HI_ATTACHMENT 历史的流程附件

  3. ACT_HI_COMMENT 历史的说明性信息

  4. ACT_HI_DETAIL 历史的流程运行中的细节信息

  5. ACT_HI_IDENTITYLINK 历史的流程运行过程中用户关系

  6. ACT_HI_PROCINST 历史的流程实例

  7. ACT_HI_TASKINST 历史的任务实例

  8. ACT_HI_VARINST 历史的流程运行中的变量信息

在我们上面的处理流程的过程中设计到的历史表有

十一 任务分配和流程变量

  1. 任务分配(变更、赋值)

    1. 硬件编码分配:
    2. 表达式分配
      1. 值表达式1:${myVar}

        1. eclipse + UEL-value:
        2. idea + flowable ui+ UEL-value::选择“固定值”,并在“”分配处写上UEL-value表达式
        3. 验证:
          1. 第一步:绘制流程图
          2. 第二步:部署流程
          3. 第三步:启动流程实例
            1. 第1步:给每一个任务(节点)的“用户”变量赋值:
            2. 第2步:启动成功
            3. 第3步:打开表ACT _RU_ VARIABLE:
            4. 第4步:同时在Task表中,可以看到流程当前的分配人是张三,说明UEL表达式被解析了:

          4. 第四步:处理流程(任务1)

            1. Task表,处理人变成“李四”

      2. 值表达式2:${myBean.myProperty}

        1. 首先,和spring(springboot)整合。

        2. 其次,从spring容器中获取相应的bean对象。

        3. 最后,通过bean对象获取属性值。

      3. 方法表达式:
        1. 首先,和spring(springboot)整合。
        2. 其次,从spring容器中获取相应的bean对象。

        3. 最后,通过bean对象调用方法获取值。

    3. 监听器分配
      1. 原理

        1. 监听器可以捕获我们的很多行为和事件
      2. 监听类型
        1. create:任务创建后触发
        2. assignment:任务分配后触发
        3. Delete:任务完成后触发
        4. All:所有事件(行为)都触发
      3. eclipse + 监听器:
      4. idea + flowable UI + 监听器:
        1. 第一步:创建监听器类:

          /*** 自定义的监听器*/
          public class MyTaskListener implements TaskListener {/*** 监听器触发的方法* @param delegateTask*/@Overridepublic void notify(DelegateTask delegateTask) {System.out.println("MyTaskListener监听器触发了,触发的事件是:" + delegateTask.getName());//  满足触发条件的事件,那么我们就来设置assigneeif("提交请假".equals(delegateTask.getName()) &&"create".equals(delegateTask.getEventName())){// 指定任务的负责人delegateTask.setAssignee("小明");}else {delegateTask.setAssignee("小张");}}
          }
        2. 第二步:给任务配置监听器:
        3. 第三步:部署流程
        4. 第四步:启动流程
        5. 第五步:验证
          1. 查看日志:
          2. task表:
        6. 第六步:小明去处理任务
          1. 查看日志:事件是,审批
          2. task表:成变小李
      5. 总结
        1. 可以给多个节点(任务)指定同一个监听器,也可以分别指定监听器
  2. 流程变量
    1. 如下图所示:

      1. 流程定义:即绘制流程图
      2. 流程实例ProcessInstance:首先,部署流程定义。其次,才能启动流程创建出一个流程实例。如,张三发起一个请假流程。又如,李四也发起一个请假流程。
      3. 流程定义与流程实例的关系:
        1. 1个流程定义可以产生多个流程实例。
      4. 流程任务Task:比如,请假流程:张三发起一个请假流程,所以有一个节点需要张三处理,即张三有一个任务Task。当张三提交请假流程完成,流程到下一个节点李四时,即李四有一个任务Task。总结,在一个流程实例中有多少个节点,就对应有多少个任务Task。
      5. 流程实例与任务Task的关系:
        1. 1个流程实例中有很多个任务Task。
      6. 执行实例与流程实例的关系:
        1. 当我们去定义1个流程实例的时候,act_ru_execution表:

          1. 上图第3行表示,我们有一个流程定义。
          2. 当你创建一个流程实例,那么对应地在act_ru_execution表中就会有2条信息。1条是我们流程定义的信息,与之对应的是1条执行实例的信息。
          3. 简单业务的流程中:流程实例和执行实例是1对1的关系。
          4. 复杂业务的流程中(如有主流程和子流程,如嵌入流程,如包含流程):流程实例和执行实例是1对多的关系。
    2. 如何指定流程变量?
      1. 表达式
    3. 分类
      1. 全局变量:

        1. 作用域:流程实例的创建到结束,所有节点(任务Task)都是可见的。
        2. 生命周期:流程实例的创建到结束。
        3. 特点:
          1. 不能重名,重名会覆盖。
      2. 局部变量:
        1. 作用域:

          1. 任务和执行实例,即仅仅是针对一个任务和一个执行实例范围内。范围没有流程实例大, 称为 local 变量。
          2. 只在单个task(节点 或 任务)中生效
        2. 特点:
          1. 在不同任务或执行实例中,作用域是互不影响的,变量名可以相同。
          2. Local 变量名也可以和 global 变量名相同,没有影响。
  3. 案例演示
    1. 员工出差申请单流程图:

      1. 上图有4个用户任务:

        1. 用户任务1:创建出差申请单
        2. 用户任务2:部门经理审批(根据出差天数走不同的任务)
        3. 用户任务3:总经理审批
        4. 用户任务4:财务审批
    2. 开发步骤
      1. 第一步:绘制流程图,保存,导出,放到idea中

        1. UEL-VALUE表达式分配用户:${user1}、${user2}、${user3}、${user4}
        2. 点击“线条”,设置“流条件”:num>3,num<3
      2. 第二步:部署流程
      3. 第三步:启动流程,创建流程实例
        1. 对UEL-VALUE中的数据做一个赋值,即分配用户,${user1}、${user2}、${user3}、${user4}
      4. 第四步:验证
        1. ACT_RU_VARIABLE表数据,对于每一个流程变量都会对应表中的一条记录。如下图:
        2. tack表:
      5. 第五步:张三处理任务
        1. 新增(也可更新)全局变量——请假天数,这个流程变量的设置num=2
      6. 第六步:验证
        1. valibale表:多了全局变量(绑定了流程实例)num=2
      7. 第七步:设置局部变量
        1. 第1步:编码

          /***  演示:局部变量* 根据Task编号来更新流程变量* 比如,原先我申请出差2天,但由于疫情原因只能多请3天,就是说要出差5天。但流程已经在跑了,通过此方法可以在审批完成之前把出差天数更新了。*/
          @Test
          public void updateVariableLocal(){//  获取流程引擎对象ProcessEngine processEngine = configuration.buildProcessEngine();TaskService taskService = processEngine.getTaskService();Task task = taskService.createTaskQuery().processDefinitionId("40001").taskAssignee("李四").singleResult();//  获取所有的流程变量Map<String, Object> processVariables = task.getProcessVariables();//  新增/更新numprocessVariables.put("num",5);//  设置局部变量taskService.setVariablesLocal(task.getId(),processVariables);
          }
        2. 第2步:验证
          1. Variable表:

            1. 全局变量绑定的是流程实例
            2. 局部变量绑定的是执行实例,还绑定了任务
        3. 第3步:再次设置(修改)局部变量(执行上面的方法,把数值调整为6)
        4. 第4步:验证
          1. Variable表:版本号递增,局部变量修改为6
      8. 第八步:再次设置(修改)全局变量
        1. 代码:

          //  再次设置(更新)全局变量
          @Test
          public void updateVariable(){//  获取流程引擎对象ProcessEngine processEngine = configuration.buildProcessEngine();TaskService taskService = processEngine.getTaskService();Task task = taskService.createTaskQuery().processDefinitionId("40001").taskAssignee("李四").singleResult();//  获取所有的流程变量//  在局部变量和全局变量都有(名称相同)的情况下,这儿取出来的是局部变量Map<String, Object> processVariables = task.getProcessVariables();//  新增/更新numprocessVariables.put("num",7);//  设置全局变量
              taskService.setVariables(task.getId(),processVariables);
          }
        2. 第2步:验证
          1. Variable表:为什么还是修改的是局部变量?因为在局部变量和全局变量都有(名称相同)的情况下,这儿取出来的是局部变量
      9. 第九步:处理任务(情况:全局变量和局部变量名称都是num,而数值分别是1和6)
        1. 编码:
        2. 结果
          1. 走的是全局变量num=2的审批,因为局部变量num=6在绑定的任务外(即进入下一个任务后)是失效的。
          2. 因为局部变量失效,所以在Variable表中会被删除掉。但要以在历史信息表act_hi_varinst表中查询到局部变量的信息。
      10. 第十步:网关处理原理

十二 候选人

  1. 候选人与分配用户的区别

    1. 分配用户指的是给某个任务Task指派处理人。
    2. 候选人指的是,公司所有人(如张三、李四、王五)或仅限于某个部门有权去办理出差申请审批业务。
  2. 候选人与处理人的区别
    1. 候选人不是真实的task处理人(assignee_),如下图所示:

      1. 环境:

        1. 有一个任务Task。
        2. 任务Task有一个指派人Assignee,指派人Assignee用于处理任务。
        3. 有3个候选人,张三、李四、王五。
      2. 指派人Assignee:
        1. 指派人Assignee要在候选人(3个)中去做一个选择,选择一个人出来处理任务Task。
  3. 案例演示
    1. 第一步:环境搭建

      1. 第1步:绘制请假流程图

        1. 第a步:设置候选人${candidate1}、${candidate2}、${candidate3}
      2. 第2步:流程部署
      3. 第3步:创建(启动)流程实例
        1. variables.put("candidate1","候选1") ;
          variables.put("candidate2","候选2");
          variables.put("candidate3","候选3") ;
      4. 第4步:验证
        1. act_ru_variable表:
        2. act_ru_task表:
          1. assignee_字段没有数据,说明当前任务task并没有指派对应的处理人。为什么会这样呢?这是因为我们现在呢,有多个候选人。
          2. 注意:候选人不是真实的task处理人(assignee_)。
        3. act_ru_identitylink表:
    2. 第二步:查询候选人可拾取任务列表
      1. 第1步:场景分析

        1. 现在task表的assignee_字段为空,即此任务task没有指派处理人。
        2. 但有3个候选人。
        3. 实际开发过程中,所有的候选人登录系统以后,都可以看到一个可以“拾取”的任务,即可以把任务拉过来并进行处理的任务。
      2. 第2步:查询当前登录人可“拾取"的任务列表:
        /*** 根据登录的用户查询对应的可以拾取的任务**/@Testpublic void queryTaskCandidate(){// 获取流程引擎对象ProcessEngine processEngine = configuration.buildProcessEngine();TaskService taskService = processEngine.getTaskService();List<Task> list = taskService.createTaskQuery().processInstanceId("50001")//.processDefinitionId("houXuanRen:1:47504").taskCandidateUser("候选1").list();for (Task task : list) {System.out.println("task.getId() = " + task.getId());System.out.println("task.getName() = " + task.getName());}}

    3. 第三步:候选人对任务的拾取、归还、交接、完成等操作

      1. 拾取

        1. 编码:

              /*** 拾取任务*    一个候选人拾取了这个任务之后其他的用户就没有办法拾取这个任务了*    所以如果一个用户拾取了任务之后又不想处理了,那么可以退还*/@Testpublic void claimTaskCandidate(){// 获取流程引擎对象ProcessEngine processEngine = configuration.buildProcessEngine();TaskService taskService = processEngine.getTaskService();Task task = taskService.createTaskQuery().processInstanceId("50001")//.processDefinitionId("houXuanRen:1:47504").taskCandidateUser("候选1").singleResult();if(task != null){// 拾取对应的任务taskService.claim(task.getId(),"候选1");System.out.println("任务拾取成功");}}
          
        2. 效果:

          1. act_ru_task表中assignee_字段终于不为空,而是”候选1“了:

          2. 这回我们就可以使用用户”候选1“登录系统,并且处理这个任务task了。但”候选2“登录系统,看不见这个任务task。

        3. 拾取规则:

          1. 1个任务被某个候选人拾取以后,其它的所有人都不能再去拾取(看到)这个任务了。

          2. 1个候选人拾取了这个任务之后 ,其他的用户就没有办法拾取(看到)这个任务了。

          3. 如果1个用户拾取了任务之后,又不想处理了,那么可以归还。

      2. 归还

        1. 编码:

          /*** 退还任务*    一个候选人拾取了这个任务之后其他的用户就没有办法拾取这个任务了*    所以如果一个用户拾取了任务之后又不想处理了,那么可以退还*/@Testpublic void unclaimTaskCandidate(){// 获取流程引擎对象ProcessEngine processEngine = configuration.buildProcessEngine();TaskService taskService = processEngine.getTaskService();Task task = taskService.createTaskQuery().processInstanceId("50001")//.processDefinitionId("houXuanRen:1:47504").taskAssignee("候选1").singleResult();if(task != null){// 归还对应的任务taskService.unclaim(task.getId());System.out.println("归还拾取成功");}}
        2. 效果:

          1. act_ru_task表中assignee_字段又变成空了:

          2. 这回我们就可以使用用户”候选1、候选2、候选3......“登录系统,都能看见任务,并都有机会拾取。

        3. 归还规则:

          1. 拾取以后,是可以归还的

      3. 交接(其中一个候选人必须先拾取任务,这样他才会有交换的权限)

        1. 编码:

          /*** 任务的交接:*    如果我获取了任务,但是不想执行,那么我可以把这个任务交接给其他的用户*/@Testpublic void taskCandidate(){// 获取流程引擎对象ProcessEngine processEngine = configuration.buildProcessEngine();TaskService taskService = processEngine.getTaskService();Task task = taskService.createTaskQuery().processInstanceId("50001")//.processDefinitionId("houXuanRen:1:47504").taskAssignee("候选1").singleResult();if(task != null){// 任务的交接taskService.setAssignee(task.getId(),"候选2");System.out.println("任务交接给了'候选2'");}}
        2. 效果:

          1. act_ru_task表中assignee_字段,从”候选1“变成了”候选2“。

          2. 候选2可以登录系统,并处理这个任务了。

        3. 交换规则:先拾取,才有权交接出去

      4. 完全任务

        1. 编码:

          /*** 完成任务*/@Testpublic void completeTaskHouXuan(){// 获取流程引擎对象ProcessEngine processEngine = configuration.buildProcessEngine();TaskService taskService = processEngine.getTaskService();Task task = taskService.createTaskQuery().processInstanceId("50001")//.processDefinitionId("houXuanRen:1:47504").taskAssignee("候选2").singleResult();if(task != null){// 完成任务taskService.complete(task.getId());System.out.println("完成Task");}}
        2. 效果:

          1. 任务流转到下一个审批环节了

          2. act_ru_task表中assignee_字段,从”候选2“变成了”ww“

十二 候选人组

  1. 应用场景

    1. 当某个任务Task候选人比较多的情况下,我们可以做一个分组处理
  2. 方式1:在UI界面中的操作
    1. 第一步:中,创建多个用户:
    2. 第二步:在UI界面中,创建组:
    3. 第三步:在UI界面中,把用户分配到这个组中(即把用户跟组做一个关联):
    4. 第四步:在UI界面中,编辑流程图,把某个任务Task的“分配用户”指定为一个组
    5. 注:act_id_user和系统用户表T_USER表如何同步?只需要在T_USER表中创建用户的时候,同步到act_id_user表中即可。
  3. 方式2:编码
    1. 第一步:管理用户和组

      1. 第1步:用户管理

        1. 第a步:创建多个用户
        2. 第b步:act_id_user表中此用户可见:
        3. 注:act_id_user和系统用户表T_USER表如何同步?只需要在T_USER表中创建用户的时候,同步到act_id_user表中即可。
      2. 第2步:Group管理
        1. 第a步:创建1个或多个用户组。
        2. 第b步:act_id_group表中此组可见:
      3. 第3步:把用户分配到组
        1. 第a步:将用户分配给对应的Group。
        2. 第b步:查看n对n关系表(用户与组关联关系表)act_id_membership:
    2. 第二步:候选人组应用,即把任务Task分配到某个组的所有成员(用户)
      1. 第1步:在UI界面中,创建流程图

        1. 第a步:创建流程图
        2. 第b步:给任务Task分配用户组:
        3. 第c步:保存,并导出为.xml文件
      2. 第2步:在idea中,流程的部署运行
        1. 第a步:流程部署
        2. 第b步:启动流程,即创建一个流程实例
          1. 首先,查询所有的组
          2. 其次,遍历所有组,找到合适的一个组
          3. 接着,给流程定义中的UEL表达式赋值:
            variables.put("group1",group.getId()); // 给流程定义中的UEL表达式赋值
          4. 最后,启动流程
        3. 第c步:验证
          1. act_ru_variable:多了group1的流程变量
          2. act_ru_task:多一个任务task:
            1. 注意:这里ASSIGNEE_为空,即没有处理人。为什么呢?因为这里分配的不是指定的一个候选人,我们分配的是一个组。
          3. ​​​​​​​act_ru_identitylink:任务与候选组的关系
      3. 第3步:任务的查询、拾取、处理
        1. 第a步:根据登录的用户查询对应的可以拾取的任务
        2. 第b步:拾取任务
          1. task表变了:注意:一个候选人拾取了这个任务之后其他的用户就没有办法拾取这个任务了。所以如果一个用户拾取了任务之后又不想处理了,那么可以退还。
            
        3. 第c步:退还任务
        4. 第d步:交接任务
        5. 第d步:处理任务
          1. task表变了:

​​​​​​​​​​​​​​​​​​​​​​​​​​​​十三 网关

  1. 概述

    1. 作用:通过网关来控制流程(审批)的方向,绘制复杂流程。
  2. 排他网关:多条分支只会走其中的一条分支
    1. 案例演示:

      1. 第一步:UI,绘制流程图:

        1. 第1步:任务”创建请假单“简单点,固定候选人”zhangsan“。
        2. 第2步:排他网关
          1. 名称:判断出差申请的天数
        3. 第3步:流条件(连线条件)1:${num<3}。
        4. 第4步:流条件(连线条件)2:${num>3}。
        5. 第5步:任务”部门经理审批“简单点,固定候选人”lisi“。
        6. 第6步:任务”总经理审批“简单点,固定候选人”wangwu“。
        7. 第7步:任务”人事审批“简单点,固定候选人”zhaoliu“。
        8. 第8步:保存,下载,idea
      2. 第二步:idea,编码
        1. 第1步:部署流程

          1. act_re_procdef:获取流程id,后面通过流程id启动流程
        2. 第2步:创建(启动)流程实例
          1. 第a步:设置流程变量num=2

            1. act_ru_variable:有流程变量num=2
            2. act_ru_task:处理人“zhangsan”
        3. 第3步:处理任务
          1. act_ru_task:因为num<3所以走“部门经理审批”
    2. 对比:
      1. 没有设置网关的情况下,如果出现条件都不满足的情况,整个流程就异常结束了。
      2. 设置了网关,如果出现条件都不满足的情况时,任务没有完成,还是原来的任务,我们可以重置流程变量。
      3. 设置了网关,如果有多个条件满足时,流程会走编号较小  或  最先设置的那条路,它会自己去选择。
  3. 并行网关
    1. 概述

      1. 应用场景:多个用户同时去审批。比如开发人员请假,同时要“项目经理”和“技术经理”同时审批完成了,你才能休假。
      2. 众多分支里面每个都走。
    2. 案例演示:
      1. 第一步:UI,绘制流程图:

        1. 第1步:任务Task,创建请假单,固定给zhangsan
        2. 第2步:分支 —— 开始(入口)并行网关
        3. 第3步:任务Task,技术经理审批,固定给lisi
        4. 第4步:任务Task,项目经理审批,固定给wangwu
        5. 第5步:汇聚 —— 结束(出口)并行网关
        6. 第6步:排他网关
          1. 第a步:流条件(连线条件)1:${num>3}。
          2. 第b步:流条件(连线条件)2:${num<3}。
        7. 第7步:任务Task,总经理审批,固定给zhaoliu
        8. 第8步:结束
        9. 第9步:保存,下载,idea
      2. 第二步:idea,编码
        1. 第1步:部署流程

          1. act_re_procdef:获取流程定义ID,qj-BingXing:1:27504
        2. 第2步:创建(启动)流程实例
          1. act_ru_task:创建请假申请  zhangsan
          2. act_ru_variable:num=4
          3. act_ru_execution:可获取执行实例id
        3. 第3步:处理任务“创建请假申请”,zhangsan
          1. act_ru_task:产生并行的两条任务Task。当我们执行了“创建请假单”后,到并行网关的位置的时候,在ACT_RU_TASK表中就有两条记录,即两条并行的任务Task我们要去处理。
          2. act_ru_execution:有3条执行实例:
            1. 注意:1个任务可以包含多个流程实例。
            2. 从上图可以看出,1个任务里面有两个执行实例。也就是说,在ACT_RU_EXECUTION中会同时有三条记录,一个任务对应的有两个执行实例。
        4. 第4步:处理任务“技术经理审批”,lisi
          1. act_ru_task:lisi的任务被删除了,wangwu(项目经理审批)还在。
          2. act_ru_execution:3条执行实例都还在。
        5. 第5步:处理任务“项目经理审批”,wangwu
          1. act_ru_variable:num=4
          2. act_ru_task:wangwu(项目经理审批)的任务也删除了,因为num=4>3,所以在排他网关这里走的是总经理审批:
          3. act_ru_execution:3条执行实例都还在。
        6. 第6步:处理任务“总经理审批”,zhaoliu
        7. 第7步:流程结束
  4. 包含网关
    1. 概述

      1. 应用场景:众多分支里面,有些分支必须要去执行的,有些分支可以不去执行。比如,开发人员请假时,根据条件判断,技术经理和项目经理只会有1个去做审批,但人事经理是必须要去做审批的。
    2. 示例
      1. 第一步:UI,绘制流程图:

        1. 第1步:任务Task,创建请假单,固定给zhangsan
        2. 第2步:包容网关
          1. 第a步:流条件(连线条件)1:${num>3}。
          2. 第b步:流条件(连线条件)2:无
          3. 第a步:流条件(连线条件)3:${num<=3}。
        3. 第3步:任务Task,项目经理审批,固定给U1
        4. 第4步:任务Task,从事审批,固定给U2
        5. 第5步:任务Task,技术经理审批,固定给U3
        6. 第6步:排他网关
          1. 第a步:流条件(连线条件)1:${num>3}。
          2. 第a步:流条件(连线条件)3:${num<=3}。
        7. 第7步:任务Task,总经理审批,固定给wangzong
        8. 第8步:结束
        9. 第9步:保存,下载,idea
      2. 第二步:idea,编码
        1. 第1步:部署流程

          1. act_re_procdef:获取流程定义ID,qj-baorong:1:27504
        2. 第2步:创建(启动)流程实例
          1. act_ru_task:创建请假单  zhangsan
          2. act_ru_variable:num=4
          3. act_ru_execution:可获取执行实例id
        3. 第3步:处理任务“创建请假单”,zhangsan
          1. 第a步:包容网关

            1. 必须走,人事审批
            2. 因为num=4,所以还要走项目经理审批
            3. 条件不满足,所以不走技术经理审批
          2. act_ru_task:2条任务,”项目经理审批“和”人事审批“
          3. act_ru_execution:3条执行实例
        4. 第4步:处理任务“项目经理审批”,U1
          1. act_ru_task:只剩1条任务,人事审批
        5. 第5步:处理任务“项目经理审批”,U2
          1. act_ru_task:删除任务,从事审批
          2. 因为num=4>3,所以在排他网关这里走的是总经理审批
        6. ​​​​​​​第6步:处理任务“总经理审批”,wangzong
        7. 第7步:流程结束
  5. 事件网关
    1. 概述:

      事件网关允许根据事件判断流向。网关的每个外出顺序流都要连接到一个中间捕获事件。 当流程到达一个基于事件网关,网关会进入等待状态:会暂停执行。与此同时,会为每个外出顺序流创建相对的事件订阅。

        事件网关的外出顺序流和普通顺序流不同,这些顺序流不会真的"执行", 相反它们让流程引擎去决定执行到事件网关的流程需要订阅哪些事件。 要考虑以下条件:

      1. 事件网关必须有两条或以上外出顺序流;

      2. 事件网关后,只能使用intermediateCatchEvent类型(activiti不支持基于事件网关后连接ReceiveTask)

      3. 连接到事件网关的中间捕获事件必须只有一个入口顺序流。

    2. ps:事件网关肯定是跟相关的事件有关联的,在事件章节里再具体去学习它。

​​​​​​​​​​​​​​​​​​​​​​​​​​​​十四 flowable整合springboot

  1. 概述

    1. 可参考flowable官网的用户手册。
    2. Flowable Actuator Endpoint:flowable的健康检查、指标监测。
  2. 详细步骤
    1. 第一步:数据库(24张表)的初始化

      1. 第1创建maven、springboot、spring web项目
      2. 第2步:pom.xml中添加依赖
        1. flowable-spring-boot-starter:flowable的起步依赖
        2. mysql-connector-java:连接mysql
        3. druid:连接池
        4. junit:单元测试
      3. 第3步:application.yml配置文件
        spring:
          datasource:#数据源(库)配置
            type: com.alibaba.druid.pool.DruidDataSource
            driver-class-name: com.mysql.cj.jdbc.Driver
            url:jdbc:mysql://10.203.5.185:3306/fLearn?serverTimezone=UTC&nullCatalogMeansCurrent=true
            username: root
            password: 123456
            hikari:#下面是数据库连接池的一些配置
              minimum-idle: 5
              idle-timeout: 600000
              maximum-pool-size: 10
              auto-commit: true
              pool-name: MyHikariCP
              max-lifetime: 1800000
              connection-timeout: 30000
              connection-test-query: SELECT 1
        flowable:
          async-executor-activate: false #关闭定时任务JOB
          #  将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。
          database-schema-update: true
        server:
          port: 8082
      4. 第4步:验证
        1. 第a步:启动项目,自动创建24张表。
        2. 第b步:从容器中获取ProcessEngine对象:
          @SpringBootTest
          class FlowableSpringbootApplicationTests {   /*springboot程序在启动的时候,会自动完成流程引擎ProcessEngine processEngine的注入。ProcessEngine processEngine相关的XxxService,也会自动被注入。因此XxxService可以直接从spring容器中获取,或者通过ProcessEngine processEngine点(".")出来。*/@Autowiredprivate ProcessEngine processEngine;@Testvoid contextLoads() {System.out.println("processEngine="+processEngine);}
          }
    2. 第二步:UI,绘制流程中图
      1. 第1步:任务task,创建请假单,${us1}
      2. 第2步:任务task,总经理审批 ,${us2}
    3. 第二步:流程的部署
      1. 方案1:自动部署

        1. 第1步:在resource目录下创建processes 目录
        2. 第2步:把请假流程spingboot.bpmn20.xml文件放进processes 目录
        3. 第3步:启动项目(或者运行单元测试),记得把target目录删除
        4. 第4步:验证
          1. ACT_RE_DEPLOYMENT:有1条部署信息
          2. act_re_procdef:有1条流程实例信息
        5. 第5步:重启项目(先关闭)
          1. 不会重复部署
        6. 附:官网提出的自动部署方式:
          1. processes目录下的任何BPMN 2.0流程定义都会被自动部署。创建processes目录,并在其中创建示例流程定义(命名为one-task-process.bpmn20.xml)。

          2. cases目录下的任何CMMN 1.1事例都会被自动部署。

          3. forms目录下的任何Form定义都会被自动部署。

      2. 方案2:手动部署(建议使用)
        1. 第1步:把Xxx.bpmn20.xml文件移出processes目录
        2. 第2步:编码:
          
          @SpringBootTest
          class FlowableSpringBoot28ApplicationTests {@Autowiredprivate ProcessEngine processEngine;@Autowiredprivate RepositoryService repositoryService;@Autowiredprivate TaskService taskService;@Autowiredprivate RuntimeService runtimeService;/*** Deploy*/@Testvoid testDeploy() {//RepositoryService repositoryService = processEngine.getRepositoryService();Deployment deploy = repositoryService.createDeployment().addClasspathResource("请假流程.bpmn20.xml").name("holiday").deploy();System.out.println("deploy.getId() = " + deploy.getId());System.out.println("deploy.getName() = " + deploy.getName());}}
        3. 同理:.bar 或 .zip
    4. 第三步:启动流程
      1. 启动流程和前面介绍的就没什么差异了,通过RuntimeService来实现:

          /*** start process*/@Testvoid startFlow(){Map<String,Object> map = new HashMap();map.put("assignee0","zhangsan");map.put("assignee1","zhangsan");runtimeService.startProcessInstanceById("holiday28:2:3653a34e-ae45-11ec-969d-c03c59ad2248",map);}
    5. 第四步:完成流程
      1. 处理流程和前面介绍的也一样,通过TaskService来处理:

        /*** complete Task*/@Testvoid completeTask(){Task task = taskService.createTaskQuery().processInstanceId("fb166cd8-ae45-11ec-92c4-c03c59ad2248").taskAssignee("zhangsan").singleResult();if(task != null){taskService.complete(task.getId());System.out.println("complete ....");}}

附:官方手册:Flowable BPMN 用户手册 (v 6.3.0)

flowable,199boge,基础相关推荐

  1. Flowable工作流基础介绍

    文章目录 一:Flowable UI应用与本地部署 1.1 应用 1.2 本地的安装部署 1.2.1 安装tomcat 1.2.2 安装flowable-ui 1.2.3 修改flowable-ui. ...

  2. 一个不用写代码的案例,来看看Flowable到底给我们提供了哪些功能?

    文章目录 1. Flowable-UI 2. 安装方式 2.1 运行 war 包 2.2 docker 安装 2.3 访问 3. 身份管理(IDM) 3.1 用户管理 3.2 组管理 3.3 权限控制 ...

  3. android rxjava2 简书,RXJava2学习

    什么是RxJava 一个可观测的序列来组成异步的.基于事件的程序的库.(简单来说:它就是一个实现异步操作的库) RxJava 好在哪? RxJava 其实就是提供一套异步编程的 API,这套 API ...

  4. upp(统一流程平台)项目范围说明书

    upp(统一流程平台)已经在多家超大规模企业上线运行,本次是反向补充相关资源,并作为软考准备的练习. 1.范围描述 由于upp平台与业务平台同步进行构建,基于谁先使用,谁存在规模化使用,将由谁主导的开 ...

  5. flowable6.4 并行网关 驳回 跳转 回退 多实例加签减签

    目录 前言 flowable6.4.2 不足之处 并行网关跳转驳回BUG 多实例加签减签BUG 解决之法 说明 用法 前言 flowable 优秀的工作流流程引擎框架,前身Activity 为什么要用 ...

  6. Carson带你学Android:图文详解RxJava背压策略

    前言 Rxjava,由于其基于事件流的链式调用.逻辑简洁 & 使用简单的特点,深受各大 Android开发者的欢迎. 本文主要讲解的是RxJava中的 背压控制策略,希望你们会喜欢. Cars ...

  7. (End)从.net到java,工作流平台的延展

    2022年6月6日,我们进入了java工作流平台的第3个年头,在这三年里,平台完成了上100万次的业务审批验证,经历了从能运行-->可使用--->基本能用--->全业务能力---&g ...

  8. 【智能物流】德勤|《中国智慧物流发展报告》(全文)

    近期,德勤中国物流与交通运输团队发布专业评估报告<中国智慧物流发展报告>(下称"报告"),对国内外领先企业在智慧物流领域的新技术和相关实践案例以及新商业模式的应用进行了 ...

  9. Flowable基础二十一 Flowable springboot 集成

    Spring Boot Spring Boot是一个应用框架,按照官网的介绍,可以轻松地创建独立运行的,生产级别的,基于Spring的应用,并且可以"直接运行".坚持使用Sprin ...

最新文章

  1. 集美大学1511,1512软件工程课程作业总结
  2. python绘制正态分布曲线
  3. 【ArcGIS风暴】ArcGIS10.6图斑椭球面积计算原理与方法
  4. java基础英语---第一天
  5. 【Siddhi】Siddhi 入门案例
  6. 《玩转D语言系列》一、通过四个版本的 Hello Word 初识D语言
  7. centos 截图命令 screenshot
  8. 8天玩转并行开发——第二天 Task的使用
  9. matlab2020面板介绍
  10. 流程图常用符号及其代表含义
  11. python模拟鼠标点击和键盘输入的操作
  12. 哈工大计算机学院人才招聘,计算机学院教师赴澳大利亚进行学术访问及人才招聘...
  13. 一个软件公司需要多少前端_建一个微商城需要多少钱?
  14. python语言的特点包括哪些_Python的特点有哪些特点
  15. 基于haar+adaboost的人脸检测、深度学习的人脸识别技术应用综述
  16. 关于vue路由模式导致微信jssdk授权问题的正确解决姿势
  17. Google系统fuchsia技术总结
  18. 抖音和tiktok是什么关系?TikTok和抖音差别大吗?
  19. 微信小程序加载第三方字体
  20. 如何拍摄VR全景照片

热门文章

  1. 用Python读红楼梦之——二、词云美化
  2. 微信小程序微信账号登录
  3. java 方法 示例_Java语言环境getAvailableLocales()方法与示例
  4. 实现uniapp的app和小程序开发中能使用axios进行跨域网络请求,并支持携带cookie
  5. 自定义View之仿淘宝详情页
  6. web前端性能(一)
  7. css3动画动一次就停止,css - 在最后一帧停止CSS3动画
  8. Android 本地路径问题
  9. idea2020shezhi代码检查级别_GitLab 13.1:告警管理扩展,新代码质量工具和安全合规等...
  10. 微擎系统跟换服务器和域名,微擎修改服务器域名