zoukankan      html  css  js  c++  java
  • activiti(三):关于流程实例的一些操作

    前文:activiti(二):关于流程部署和删除的一些操作

    目录:activiti 目录

    一、启动流程实例

    启动流程的方法多种,这里详细介绍启动流程的整个过程!

    1.1 操作流程实例的门面接口

    我们已知,流程的部署和流程实例数据的门面接口是:RepositoryService

    操作流程实例的门面接口是:RuntimeService。在源码中这个类上没有备注,只有些作者名称,但是我们根据方法可以分析出来,RuntimeService有哪些作用

    此接口与流程部署和定义操作的接口RepositoryService一样;
    提供了丰富的操作实例的方式,重点分为:
    1)startxxx:以start开头的启动流程实例方法。
    2)deleteProcessInstance:删除正在执行的流程
    3)getxxx:以get开头的获取流程实例(活动中或者等待中)相关信息,id列表,实例列表等等
    4)trigger:触发器形式,可以指定流程ID,和一些参数,指定流程执行。
    5)builder:获取流程实例构造器
    6)一些其他操作:流程构造器、参数的获取,修改,添加等等
    

    1.2 前置知识

    • 部署一个流程代码(随便选择一个方式部署)

           /**
           * 部署一个流程并返回部署的ID,
           * 部署表:act_re_deployment 插入一条数据,并在资源表中记录对应的资源(图片文件、bpmn文件),二进制存储。并将流程的数据插入流程数据表
           * 资源表:act_ge_bytearray 插入对应的资源数据,可能多条,看传入多少文件。
           * 流程数据表:act_re_procdef 插入流程对应的定义数据。
           * @author caodahuan
           * @date 2019/8/29
           * @return java.lang.String
           */
          private String deployProcess(){
              // 1. 获取到部署新流程的构造器
              DeploymentBuilder builder = ProcessEngines.getDefaultProcessEngine().getRepositoryService().createDeployment();
      
              // 2. 选择部署方式为:通过资源文件进行部署
              builder.addClasspathResource("apply.bpmn");
              builder.addClasspathResource("apply.png");
      
              // 3. 设置一些需要的参数(非必须)
              builder.key("key"); // 设置key,可重复但不建议重复,可用来启动流程
              builder.name("报销流程"); // 设置流程名称
              builder.category("3"); // 流程类型
      
              // 4. 部署流程
              Deployment deploy = builder.deploy();
              System.out.println(deploy.getId());
              return deploy.getId();
          }
      
    • 获取流程定义数据

          /**
           * 获取到流程定义,返回表中数据
           * 流程定义数据在表act_re_procdef表中。
           * @author caodahuan
           * @date 2019/8/29
           * @return void
           */
          private ProcessDefinition getDefinition() {
              // 1. 部署流程并返回流程ID
              String deploymentId = this.deployProcess();
      
              ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
              ProcessDefinitionQuery query = processEngine.getRepositoryService().createProcessDefinitionQuery();
              query.orderByDeploymentId();
              query.desc();
              query.deploymentId(deploymentId);
              List<ProcessDefinition> list = query.list();
      
              if (!CollectionUtils.isEmpty(list)) {
                  return list.get(0);
              }
      
              return null;
          }
      

    1.3 启动已经部署好的流程实例

    • 先定义一个获取实例操作接口的方法

          /**
           * 获取到操作流程实例的总接口
           * @author caodahuan
           * @date 2019/8/29
           * @return void
           */
          public RuntimeService getService(){
      
              // 1. 先获取流程引擎
              ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
      
              /*
               * 2. 获取操作实例的接口
               * 此接口与流程部署和定义操作的接口RepositoryService一样;
               * 提供了对丰富的操作方式,重点分为:
               * 1)startxxx:以start开头的启动流程实例方法。
               * 2)deleteProcessInstance:删除正在执行的流程
               * 3)getxxx:以get开头的获取流程实例(活动中或者等待中)相关信息,id列表,实例列表等等
               * 4)trigger:触发器形式,可以指定流程ID,和一些参数,指定流程执行。
               * 5)builder:获取流程实例构造器
               * 6)一些其他操作:流程构造器、参数的获取,修改,添加等等
               *
               */
              RuntimeService runtimeService = processEngine.getRuntimeService();
      
              return runtimeService;
          }
      
    • 方法一:根据流程定义表中的ID启动。此处ID,取流程定义数据表:act_re_procdef表中对应数据ID。

          /**
           * 启动流程实例:
           * 方法一:根据流程定义的ID;
           * 已经知道,在部署流程的时候,我们将流程的数据写到了表:act_re_prcodef
           * 通过表act_re_prcodef获取到流程,然后启动流程!
           * @author caodahuan
           * @date 2019/8/29
           * @return void
           */
          @Test
          public void startMethodOne(){
      
              // 1. 获取到操作流程数据的接口
              RuntimeService service = getService();
      
              /*
               * 2. 根据ID启动流程,返回的是启动流程后的实例
               * 部署流程后,流程数据其实存储在act_re_procdef表中。根据id启动,即根据act_re_procdef表的id启动。
               * 1)根据流程获取流程定义数据的ID
               * 2)根据ID启动流程
               */
              // 部署好的流程定义数据
              ProcessDefinition definition = this.getDefinition();
              System.out.println(definition.getId());
              /*
               * 根据流程定义数据表中的ID启动流程
               * 启动流程后:操作以下表(可以在整个过程中观察这些表,看看效果,理解更深入)
               * 1、正在执行的流程实例表:
               * act_ru_execution(正在执行的流程实例表):表示执行中的流程,会插入2条数据,一条父数据表示流程,
               * 一条子数据表示正在执行的流程进展。(完成的实例将被删除)
               * act_ru_task(正在执行的任务表):表示正在执行的任务。(完成的任务将被删除)
               * 历史表:
               * act_hi_taskinst(任务历史表):插入一条数据,通过execution_id_关联到流程执行表act_ru_execution;
               * (此表存储已经完成的和正在执行的流程节点)如果end_time有值,表示已经结束(历史);没值,表示正在执行的节点。
               * act_hi_procinst(实例历史表):插入一条数据,通过proc_def_id_关联到流程定义表act_re_procdef;
               * (此表存储已经完成的和正在执行的实例)如果end_time有值,表示已经结束(历史);没值,表示正在执行的实例。
               * act_hi_actinst(元素历史表):插入2条数据,一条startEvent数据,启动元素完成。一条userTask,正在执行元素。
               * (此表存储已经完成的和正在执行的元素)如果end_time有值,表示已经结束(历史);没值,表示正在执行的元素。
               */
              service.startProcessInstanceById(definition.getId());
          }
      
    • 方法二:根据流程定义数据的key启动:act_re_procdef表中key

          /**
           * 方法二:根据流程定义(act_re_procdef)中的KEY启动流程实例
           * 通过方法一知道了总的流程,此处就不再展示完整的获取流程。直接从表中获取KEY值。
           * @author caodahuan
           * @date 2019/8/30 
           * @return void 
           */
          @Test
          public void startMethodTwo(){
      
              // 1. 获取流程实例操作接口
              RuntimeService service = getService();
      
              // 2. 从表中已经知道了key
              ProcessInstance apply = service.startProcessInstanceByKey("apply");
          }
      
    • 方法三:通过ProcessInstanceBuilder

           /**
           * 方法三:通过ProcessInstanceBuilder来启动流程
           * @author caodahuan
           * @date 2019/9/3 
           * @return void 
           */
          @Test
          public void queryInstanceByBuilder(){
              
              // 1.操作接口
              RuntimeService service = getService();
              
              // 2.获取流程构建器(builder就是用来操作实例的构建器)
              ProcessInstanceBuilder processInstanceBuilder = service.createProcessInstanceBuilder();
              
              // 3.填充参数,通过definitionID或者definitionKey启动,但是可以设置流程参数!
              processInstanceBuilder.name("自定义builder启动");
              processInstanceBuilder.businessKey("appxx");
              processInstanceBuilder.processDefinitionId("apply:3:115004");
              
              // 4.启动流程
              ProcessInstance instance = processInstanceBuilder.start();
              System.out.println(instance.getId());
          }
      
    • 方法四:还有多种启动方法:

    1.4 查询已经启动的流程实例(ProcessInstance)

    • 方法一:根据查询条件,查询流程list

      	/**
           * 方法一:根据流程实例查询器:ProcessInstanceQuery得到list
           * 如果用过mybatis提供的Example查询接口,大概能很容易理解这种处理方式。
           * @author caodahuan
           * @date 2019/9/3
           * @return void
           */
          @Test
          public void queryInstanceList(){
              // 1. 获取到操作实例的接口
              RuntimeService service = getService();
      
              // 2. 构建一个查询器,它专用来查询实例
              ProcessInstanceQuery processInstanceQuery = service.createProcessInstanceQuery();
      
              // 3. 如果查询得到list,必须排序;
              processInstanceQuery = processInstanceQuery.processDefinitionKey("apply");
              processInstanceQuery.orderByProcessDefinitionId();
              processInstanceQuery.asc();
              List<ProcessInstance> list = processInstanceQuery.list();
      
              list.forEach(l -> System.out.println(l.getId()));
          }
      
    • 方法二:查询得到唯一记录singleResult

      	/**
           * 方法二:根据流程实例查询器:ProcessInstanceQuery得到singleResult
           * 可以通过查询list的方式,然后判断list的size == 1,再直接调用singleResult。
           * 并不是只有ID才能得到唯一数据,都可以调用singleResult,只不过,如果得到的不是唯一数据,会报异常!
           * @author caodahuan
           * @date 2019/9/3
           * @return void
           */
          @Test
          public void queryInstanceSingle(){
              // 1. 获取到操作实例的接口
              RuntimeService service = getService();
      
              // 2. 构建一个查询器,它专用来查询实例
              ProcessInstanceQuery processInstanceQuery = service.createProcessInstanceQuery();
      
              // 3. 如果查询可得到唯一条目,可使用singleResult()直接得到实例。
              // 通过多条件得到唯一数据
              processInstanceQuery = processInstanceQuery.processDefinitionKey("apply");
              processInstanceQuery.processInstanceBusinessKey("ap");
              ProcessInstance processInstance = processInstanceQuery.singleResult();
              System.out.println(processInstance.getId());
      
              // 更靠谱的是通过id得到唯一数据
              processInstanceQuery.processInstanceId("155005").singleResult();
          }	
      
    • 完成一个流程后,下列表的情况(更细节的数据变化,需要在完成每一个任务的时候观察表数据的变化才能有深入体会,依然是这几张表)

    完成任务(会在任务操作中再述)

    完成任务方法

    • 方法一:直接通过taskId来完成任务
    /**
         * 完成任务1:通过taskId来完成
         * 因为完成通过TaskService。
         * @author caodahuan
         * @date 2019/8/30
         * @return void
         */
        @Test
        public void complete(){
    
            // 1. 获取到流程引擎
            ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    
            /*
             * 2. 对于任务的操作:TaskService。
             * 操作任务表:act_ru_task,此表已经介绍过:存储正在执行的任务,一旦任务执行完,则从此表中移除。
             */
            TaskService taskService = processEngine.getTaskService();
            taskService.complete("107502");
        }
    
    
    • 方法二:在实际中通过代码获取task任务,再获取到ID

      
          /**
           * 完成任务实例:实际操作中都是通过查库来获取任务,完成任务。
           * @author caodahuan
           * @date 2019/9/2
           * @return void
           */
          @Test
          public void complete1(){
              /*
               * 启动流程
               */
              // 1. 获取到操作流程数据的接口
              RuntimeService service = getService();
      
              /*
               * 2. 根据ID启动流程,返回的是启动流程后的实例
               * 部署流程后,流程数据其实存储在act_re_procdef表中。根据id启动,即根据act_re_procdef表的id启动。
               * 1)根据流程获取流程定义数据的ID
               * 2)根据ID启动流程
               */
              // 部署好的流程定义数据(返回流程实例)
              ProcessDefinition definition = this.getDefinition();
              ProcessInstance instance = service.startProcessInstanceById(definition.getId());
      
              // 3. 获取任务操作接口
              TaskService taskService = ProcessEngines.getDefaultProcessEngine().getTaskService();
      
              // 4. 由于complete方法是通过taskId来执行,那么先获取Task详情。
              // 4.1 获取任务查询器(这个已经见过多次了)
              TaskQuery taskQuery = taskService.createTaskQuery();
      
              // 4.2 查询任务(通过流程实例来获取任务,部署流程时,已经得到了流程实例)
              Task task = taskQuery.processInstanceId(instance.getId()).singleResult();
      
              // 4.3 通过任务ID来执行任务
              taskService.complete(task.getId());
          }
      
    • 方法三:介绍其他完成任务方法

      /**
           * 其他完成任务方法
           * @author caodahuan
           * @date 2019/9/2
           * @return void
           */
          @Test
          public void completeOther(){
      
              // 1. 获取任务操作接口
              TaskService taskService = ProcessEngines.getDefaultProcessEngine().getTaskService();
      
              // 直接ID完成任务(已经描述)
              taskService.complete("112509");
      
              // 完成并设置变量:参数1=taskId,参数2=流程变量
              Map<String, Object> params = new HashMap<>();
              params.put("haha","enlo");
              taskService.complete("127503",params);
      
              // 完成并设置变量:参数1=taskId,参数2=流程变量,参数3=瞬时变量
              // 为啥不能用呢,报错:java.lang.ClassCastException,待解决!
              taskService.complete("127503",params,params);
      
              // 完成并设置变量:参数1=taskId,参数2=流程变量,参数3=是否为本地变量
              //如果为true,通过的变量将会随着本任务存亡(本任务结束,变量删除,称之为任务变量(局部)),默认为false,即为complete(String,Map)
              // 那么这时候的变量为流程变量(全局)
              taskService.complete("127503",params,false);
          }
      

      关于流程变量:(传递上下文)

      按照作用域可分为:

      • 流程变量(全局变量):整个流程都可获取到。
      • 本地变量:本任务节点可获取,下个任务节点就拿不到了。

      按照是否存库:

      • 持久变量:在act_ru_variable和act_hi_varinst中插入变量数据
      • 瞬时变量(activiti 6):只有转成持久变量才会存库
  • 相关阅读:
    kafka注册异常
    Android基于XMPP Smack Openfire下学习开发IM(五)连接断开重连
    openfire维持在线状态,监听消息
    openfire ping的smack解决方案(维持在线状态)
    openfire聊天记录插件
    openfire 发送 接受 注册 广播 好友列表 在线状态
    maven仓库中心mirrors配置多个下载中心(执行最快的镜像)
    开发openfire 消息拦截器插件PacketInterceptor
    Openfire注册流程代码分析
    linux centOS6 nexus 开启自动启动
  • 原文地址:https://www.cnblogs.com/dhcao/p/11457405.html
Copyright © 2011-2022 走看看