• 流程建模艺术:使用Activiti设计流程


    前言

    “当今的企业和组织越来越依赖流程自动化来提高效率、降低成本并确保一致性。在这个数字化时代,Activiti和Flowable等流程引擎成为了不可或缺的工具。但是,要充分发挥它们的潜力,您需要深入了解它们的工作原理和最佳实践。本博客将带您初步了解activiti流程引擎,从基础概念到实际应用,让您在流程自动化的世界中游刃有余。”

    流程相关

    定义一个流程

    repositoryService.createDeployment().addBpmnModel(name, bpmnModel).tenantId("ceshibo").deploy()
    
    • 1

    【说明】执行上述方法会向3张表中插入数据

    1. ACT_RE_DEPLOYMENT: 存储流程部署信息,包括部署 ID、名称、时间等。
    2. ACT_GE_BYTEARRAY: 存储流程定义文件,包括 BPMN、PNG、XML 等格式的文件。
    3. ACT_RE_PROCDEF: 存储流程定义信息,包括流程定义 ID、KEY、版本号、名称、部署 ID、XML 文件名称等。

    【警告】上面的addBpmnModel(name,bpmnModel)向部署对象中添加BPMN模型,其中一定要注意,name必须是以.bpmn结尾,否则会出现ACT_RE_PROCDEF没有数据

    启动一个流程

    前提是获取到ProcessDefinition,根据ACT_RE_DEPLOYMENT的id获取

    业务表中应该含有的字段

    ID:唯一标识一条流程定义的ID。
    KEY:流程定义的标识,相当于流程定义的名称。
    NAME:流程定义的名称,用于在流程设计器中展示。
    VERSION:流程定义的版本号,用于区分不同版本的流程定义。
    DEPLOYMENT_ID:流程定义所属的部署ID。
    RESOURCE_NAME:流程定义的资源名称,即对应的BPMN文件名称。
    DIAGRAM_RESOURCE_NAME:流程定义的图形资源名称,即对应的流程图名称。
    TENANT_ID:流程定义所属的租户ID,如果没有多租户需求,可以为空。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    获取流程定义实体

    // 根据部署ID获取流程定义
      ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
      .deploymentId(deploymentId)
      .singleResult();
    
    • 1
    • 2
    • 3
    • 4
    • 根据流程id启动流程,ACT_RE_PROCDEF的id

      // 其中variables为流程变量,这里要加上businessKey,也就是业务id,因为每一个流程定义对应的是多个流程实例
      ProcessInstanceBuilder processInstanceBuilder = runtimeService.createProcessInstanceBuilder();
                  ProcessInstance processInstance = processInstanceBuilder
                          .processDefinitionId(startProcessInstanceDTO.getProcessDefinitionId())
                          .variables(processVariables)
                          .businessKey("test01")
                          .businessStatus(BUSINESS_STATUS_1)
                          .start();
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    • 根据流程定义key启动流程实例

      // 因为流程实例会存在多个版本,所以会存在相同的key,这里会取最新的一条流程实例
      ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("process_key", variables);
      
      • 1
      • 2

    启动流程后会影响的表

    1. ACT_HI_ACTINST:是一个历史记录表,记录了所有活动实例的信息,包括已经完成和正在运行中的活动实例。
    2. ACT_HI_PROCINST:历史流程实例表,里面包含流程启动时间,结束时间,持续时间等。
    3. ACT_HI_TASKINST:历史任务实例信息,流程执行过程中,任务实例没有完成,但是开始了,也会被插入到该表中
    4. ACT_HI_VARINST:流程实例的变量信息,流程变量和任务变量。对于每个发生变化的变量,都会在表中生成一条记录。一条记录对应一个变量的变化历史,包括变量名称、变量值、修改时间等信息。
    5. ACT_RU_EXECUTION:是运行时流程执行实例表,每一个正在执行中的流程实例都对应着该表中的一条数据。该表中的数据会随着流程的执行而不断发生变化,包括流程开始、流程节点完成等。一般来说,如果一个流程已经结束,对应的记录会从 ACT_RU_EXECUTION 表中删除,如果一个流程还未结束,则对应的记录会保留在表中,直到流程结束。一个流程实例在 ACT_RU_EXECUTION 表中会对应一条数据,但是如果该流程实例下有多个执行流程(例如存在子流程或并行网关等情况),则会对应多条数据
    6. ACT_RU_VARIABLE:正在执行中的流程实例中的变量信息
    7. ACT_RU_TASK:当前待办任务的运行时信息,包括任务的 ID、名称、描述、优先级、创建时间、到期时间、处理人、任务状态等信息。该表中的数据会在任务完成后被删除。

    删除一个流程

    删除流程实例分为删除运行时数据和历史数据两个方面。删除运行时数据会将该流程实例的所有运行时数据,包括任务、执行流程、事件等全部删除,同时该流程实例的历史数据也会被删除。而删除历史数据则是针对已经结束的流程实例的历史数据进行删除,包括历史任务、历史变量等。

    另外,在使用流程引擎删除流程实例时,需要注意以下几点:

    1. 如果该流程实例存在待办任务,需要先将这些任务删除或完成。
    2. 如果该流程实例已经关联了附件、评论、历史记录等信息,需要先将这些关联信息进行清理。
    3. 如果需要删除的流程实例已经产生了历史记录,需要同时删除历史记录。
    Map<String, Object> map = new HashMap<>();
    // 这一步查历史流程实例ACT_HI_PROCINST是否有符合条件的一条,这里是业务的key,返回的是单个历史流程实例
    HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery()
      .processInstanceBusinessKey(bizId).orderByProcessInstanceStartTime().desc().singleResult();
    if (processInstance == null) {
      map.put("code", 1001);
      map.put("msg", "流程未启动!");
      return map;
    }
    String processInstId = processInstance.getId();
    // 这里可以不去查运行时的流程实例,直接从上面的历史流程实例数据中查询endtime是否为null,如果不为null说明流程已经结束了,可以使用processInstance.getEndTime()来获取
    ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstId).singleResult();
    if (pi == null) {
      //该流程实例已经完成了
      historyService.deleteHistoricProcessInstance(processInstId);
    } else {
      // TODO 待办刷新,因为删除完了,不能查到,故先查询,删除后推送
      // 下面的是删除流程实例,顺序别调换
      runtimeService.deleteProcessInstance(processInstId, "");
      historyService.deleteHistoricProcessInstance(processInstId);
    }
    map.put("code", 1000);
    map.put("msg", "流程删除成功!");
    return map;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    删除流程会将上面启动流程影响的表中的数据全部删除(当前流程实例)

    方法相关

    创建流程

    Deployment deploy = repositoryService.createDeployment().addBpmnModel(bpmnName, bpmnModel).tenantId(tenantId.toString()).deploy();
    
    • 1

    【说明】返回的Deployment对应的是ACT_RE_DEPLOYMENT表

    校验流程模型是否合法

    ProcessValidatorFactory processValidatorFactory = new ProcessValidatorFactory();
    ProcessValidator processValidator = processValidatorFactory.createDefaultProcessValidator();
    List<ValidationError> validate = processValidator.validate(bpmnModel);
    
    • 1
    • 2
    • 3

    【说明】

    ProcessValidatorFactory 是 Activiti 中用于创建流程验证器的工厂类,createDefaultProcessValidator() 方法创建一个默认的流程验证器实例。然后使用流程验证器对给定的 bpmnModel 进行验证,返回一个 List,其中包含验证过程中发现的错误信息。

    验证过程可以帮助检查流程定义是否符合 BPMN 2.0 规范,例如检查是否存在未连接的节点、无效的表达式、重复的元素等。如果验证结果中存在错误信息,可以根据错误信息进行修复或调整流程定义,以确保其正确性。

    获取当前人的待办

    Task approveTask = taskService.createTaskQuery().processInstanceId(processInstanceId).taskAssignee(userId).singleResult();
    
    • 1

    【说明】

    该代码片段是使用 Activiti 的任务服务(taskService)根据给定的流程实例 ID 和用户 ID 查询待办任务(approveTask)的过程。

    具体来说,该代码执行以下操作:

    1. 使用 taskService.createTaskQuery() 创建一个任务查询对象。
    2. 使用 .processInstanceId(processInstanceId) 条件筛选,指定要查询的任务所属的流程实例 ID。
    3. 使用 .taskAssignee(userId) 条件筛选,指定要查询的任务的负责人(即指定用户 ID)。
    4. 使用 .singleResult() 方法执行查询并返回单个任务结果。

    查询候选任务

    Task candTask = taskService.createTaskQuery().processInstanceId(processInstanceId).executionId(executionIds)
      .taskCandidateUser(userId).singleResult();
    
    • 1
    • 2

    具体来说,该代码执行以下操作:

    1. 使用 taskService.createTaskQuery() 创建一个任务查询对象。
    2. 使用 .processInstanceId(processInstanceId) 条件筛选,指定要查询的任务所属的流程实例 ID。
    3. 使用 .executionId(executionIds) 条件筛选,指定要查询的任务所属的执行 ID(一般情况下可以为空,除非你要查询特定的执行任务)。
    4. 使用 .taskCandidateUser(userId) 条件筛选,指定要查询的任务的候选用户(即指定用户 ID)。
    5. 使用 .singleResult() 方法执行查询并返回单个任务结果。

    根据查询条件,该代码片段的目的是获取某个流程实例中特定候选用户可领取的任务(如果存在的话)。

    删除历史流程

    List<ProcessInstance> processInstanceList = this.runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(bizKey).list();
    if (CollUtil.isNotEmpty(processInstanceList)) {
      for (ProcessInstance pi : processInstanceList) {
        // 这里先删除运行中的再删除历史的
        this.runtimeService.deleteProcessInstance(pi.getId(), "因重复发起!");
        this.historyService.deleteHistoricProcessInstance(pi.getId());
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    具体来说,该代码执行以下操作:

    1. 使用 runtimeService.createProcessInstanceQuery() 创建一个流程实例查询对象。
    2. 使用 .processInstanceBusinessKey(bizKey) 条件筛选,指定要查询的流程实例的业务键。
    3. 使用 .list() 方法执行查询并返回流程实例列表(processInstanceList)。
    4. 如果流程实例列表不为空,则遍历每个流程实例。
    5. 对于每个流程实例,首先使用 runtimeService.deleteProcessInstance() 方法删除运行时的流程实例,参数为流程实例 ID 和删除原因。
    6. 接着使用 historyService.deleteHistoricProcessInstance() 方法删除对应的历史流程实例,参数为流程实例 ID。

    注意,上述代码片段中的 bizKey 是示例变量,你需要根据实际情况将其替换为有效的业务键。

    获取未完成的历史流程实例列表

    List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery().unfinished().list();
    
    • 1

    具体来说,该代码执行以下操作:

    1. 使用 historyService.createHistoricProcessInstanceQuery() 创建一个历史流程实例查询对象。
    2. 使用 .unfinished() 条件筛选,指定要查询的历史流程实例必须是未完成的。
    3. 使用 .list() 方法执行查询并返回符合条件的历史流程实例列表(list)。

    获取已完成的历史任务实例列表

    List<HistoricTaskInstance> hisTaskInstList = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstId)
      .finished().orderByTaskCreateTime().asc().list();
    
    • 1
    • 2

    具体来说,该代码执行以下操作:

    1. 使用 historyService.createHistoricTaskInstanceQuery() 创建一个历史任务实例查询对象。
    2. 使用 .processInstanceId(processInstId) 条件筛选,指定要查询的历史任务实例所属的流程实例ID。
    3. 使用 .finished() 条件筛选,指定要查询的历史任务实例必须是已完成的。
    4. 使用 .orderByTaskCreateTime().asc() 指定按任务创建时间升序排序。
    5. 使用 .list() 方法执行查询并返回符合条件的历史任务实例列表(hisTaskInstList)。

    根据业务id查询历史活动实例

    // 根据业务id获取历史流程实例
    HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(bizKey).orderByProcessInstanceStartTime().desc().singleResult();
    // 查询已完成的历史活动实例
    List<HistoricActivityInstance> hisActivityInstanceList = ((HistoricActivityInstanceQuery) this.historyService.createHistoricActivityInstanceQuery()
                                                              .processInstanceId(hpi.getId()).finished().orderByHistoricActivityInstanceEndTime().asc()).list();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • historyService.createHistoricProcessInstanceQuery():创建历史流程实例查询对象。
    • processInstanceQuery.processInstanceBusinessKey(bizKey):设置查询条件,通过业务ID进行查询。
    • orderByProcessInstanceStartTime().desc():按照流程实例的开始时间进行降序排序。
    • singleResult():获取单个结果,即最新的历史流程实例对象。
    • historyService.createHistoricActivityInstanceQuery():创建历史活动实例查询对象。
    • activityInstanceQuery.processInstanceId(hpi.getId()):设置查询条件,通过历史流程实例ID进行查询。
    • finished():过滤只返回已完成的历史活动实例。
    • orderByHistoricActivityInstanceEndTime().asc():按照历史活动实例的结束时间进行升序排序。
    • list():获取符合条件的历史活动实例列表。
  • 相关阅读:
    大数据从入门到精通(超详细版)之Hive的DDL操作
    Python二级题:MOOC学校名单|关键词提取和查找
    Node详细解释[带你快速入门Node](2)
    Docker:容器
    [elasticsearch]使用postman来查询数据
    TimeWise-Jira工时管理插件6.0.0发布!对比测评某知名工时插件,谁的数据处理性能更胜一筹?
    【CycleISP: Real Image Restoration via Improved Data Synthesis】ISP论文--1(个人笔记,勿喷)
    Flask 学习-41.Flask-RESTPlus 入门到放弃
    # EXCEL VBA批量获取excel标题内容并填写到当前文件中
    软件测试项目实战(包含电商、银行、app等)
  • 原文地址:https://blog.csdn.net/Mrxiao_bo/article/details/133453996