Activiti工作流介绍及使用


工作流及Activiti介绍gitee 示例

工作流及Activiti介绍

  • 工作流(Workflow),就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在多个参与者之间按照某种预定义的规则传递文档、信息或任务的过程自动进行,从而实现某个预期的业务目标,或者促使此目标的实现”。
  • 工作流管理系统(Workflow Management System, WfMS)是一个软件系统,它完成工作量的定义和管理,并按照在系统中预先定义好的工作流规则进行工作流实例的执行。工作流管理系统不是企业的业务系统,而是为企业的业务系统的运行提供了一个软件的支撑环境。
  • 工作流管理联盟(WfMC,Workflow Management Coalition)给出的关于工作流管理系统的定义是:工作流管理系统是一个软件系统,它通过执行经过计算的流程定义去支持一批专门设定的业务流程。工作流管理系统被用来定义、管理、和执行工作流程。

activiti官网:https://www.activiti.org

官网教程: https://www.activiti.org/userguide/

一、srpingboot 整合 activiti

1. 在maven中引入依赖
  • pom.xml
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter</artifactId>
            <version>7.1.0.M2</version>
        </dependency>
2. 配置activiti相关属性
  • appliction.yml
spring:
  # activiti工作流配置
  activiti:
    db-history-used: true
    check-process-definitions: false  #自动检查、部署流程定义文件
    database-schema-update: true #自动更新数据库结构
    history-level: full #保存历史数据级别设置为full最高级别,便于历史数据的追溯
    process-definition-location-prefix: classpath:/processes/ #流程定义文件存放目录
    process-definition-location-suffixes: #流程文件格式
      - .bpmn20.xml
      - .bpmn

二、activiti的介绍

1. 使用idea插件绘制activiti流程图

BPMN 业务流程建模与标注(Business Process Model and Notation,BPMN) ,描述流程的基本符号,包括这些图元如何组合成一个业务流程图(Business Process Diagram)

流程定义文档有两部分组成:bpmn文件是给计算机执行用的,图片是给用户看的。

1.1 安装插件 Activiti BPMN visualizer

File ——> Setting ——> Plugins 搜索 Activiti BPMN visualizer 安装
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cK3rw6jT-1687161026325)(img/activiti-bpmn-visualizer.png)]

设置bpmn文件后缀: File ——> Setting ——> Tools ——> Activiti BPMN plugin confg,在Supported extensions(comma-separated):添加bpmn20.xml,bpmn
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OcLp5CHt-1687161026326)(img/activiti-tool-setting.png)]

1.2 绘制bpmn流程图
  • 1)创建bpmn文件
    右键 ——> New ——> New Activiti 6.0x BPMN 2.0 file
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dx3xawtD-1687161026327)(img/bpmn-add-file.png)]
  • 2) 查看bpmn图
    在bpmn文件里 右键 ——> View BPMN(Activiti) Diagram
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rOvs7AEj-1687161026327)(img/bpmn-view.png)]
  • 3) 绘制bpmn图
    在图形界面 ——> 右键,可添加需要的组件
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tGJdOsLD-1687161026327)(img/bpmn-edit.png)]

2. 数据库表

Activiti的后台是有数据库的支持,所有的表都以ACT_开头。 第二部分是表示表的用途的两个字母标识。 用途也和服务的API对应。

  • ACT_RE_*: 'RE’表示repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。

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

  • ACT_ID_*: 'ID’表示identity。 这些表包含身份信息,比如用户,组等等。

  • ACT_HI_*: 'HI’表示history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。

  • ACT_GE_*: 通用数据, 用于不同场景下,如存放资源文件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q7wkMMoB-1687161026329)(img/activiti-table.png)]

2.1 资源库流程规则表
  • act_re_deployment 部署信息表
    • 存放流程定义的显示名和部署时间,每部署一次增加一条记录
  • act_re_model 流程设计模型部署表
  • act_re_procdef 流程定义数据表
    • 部署每个新的流程定义都会在这张表中增加一条记录。
    • 注意:当流程定义的key相同的情况下,使用的是版本升级
2.2:运行时数据库表
  • act_ru_execution 运行时流程执行实例表
    • 正在执行的信息
  • act_ru_identitylink 运行时流程人员表
    • 主要存储任务节点与参与者的相关信息
  • act_ru_task 运行时任务节点表
  • act_ru_variable 运行时流程变量数据表
2.3:历史数据库表
  • act_hi_actinst 历史节点表
    • 存放历史所有完成的活动
  • act_hi_attachment 历史附件表
  • act_hi_comment 历史意见表
  • act_hi_identitylink 历史流程人员表
  • act_hi_detail 历史详情表,提供历史变量的查询
  • act_hi_procinst 历史流程实例表
    • 已经执行完的历史流程实例信息
  • act_hi_taskinst 历史任务实例表
  • act_hi_varinst 历史变量表
2.4:组织机构表
  • act_id_group 用户组信息表
  • act_id_info 用户扩展信息表
  • act_id_membership 用户与用户组对应信息表
  • act_id_user 用户信息表

这四张表很常见,基本的组织机构管理,关于用户认证方面建议还是自己开发一套,组件自带的功能太简单,使用中有很多需求难以满足

2.5:通用数据表
  • act_ge_bytearray 二进制数据表
    • 即流程定义文档的存放地。
    • 每部署一次就会增加两条记录,一条是关于bpmn规则文件的,一条是图片的(如果部署时只指定了bpmn一个文件,activiti会在部署时解析bpmn文件内容自动生成流程图)
  • act_ge_property 属性数据表存储整个流程引擎级别的数据,初始化表结构时,会默认插入三条记录
    • 主键生成策略表

3. 核心API介绍

工作流引擎ProcessEngine对象,这是Activiti工作的核心。负责生成流程运行时的各种实例及数据、监控和管理流程的运行。

3.1 ProcessEngine 流程引擎

说明:在Activiti中最核心的类,其他的类都是由他而来。

各个Service作用
RepositoryService管理流程定义
RuntimeService执行管理,包括启动、推进、删除流程实例等操作
TaskService任务管理
HistoryService历史管理(执行完的数据的管理)
IdentityService组织机构管理
FormService一个可选服务,任务表单管理
ManagerService引擎管理
  • 创建代码
    void contextLoads() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        DynamicBpmnService dynamicBpmnService = processEngine.getDynamicBpmnService();
        HistoryService historyService = processEngine.getHistoryService();
        ProcessEngineConfiguration processEngineConfiguration = processEngine.getProcessEngineConfiguration();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        TaskService taskService = processEngine.getTaskService();
   }
3.2:RepositoryService

是Activiti的仓库服务类。所谓的仓库指流程定义文档的两个文件:bpmn文件和流程图片。

3.2.1 部署(Deployment)流程
    @Test
    void deploy(){
        // 获取仓库服务,从类路径下完成部署
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("processes/test.bpmn20.xml") // 添加定义的规则文件
                .addClasspathResource("processes/test.png") // 添加定义的规则图片
                .name("提交请假流程")  // 部署规则的别名
                .key("test-flow")
                .deploy();
        System.out.println("流程部署id:" + deployment.getId());
        System.out.println("流程部署名称:" + deployment.getName());
        System.out.println("key:"+deployment.getKey());
    }

3.2.2 查看流程定义 (ProcessDefinition)

解析.bpmn后得到的流程定义规则的信息,工作流系统就是按照流程定义的规则执行的。流程定义的Id是【key:版本:生成ID】

  • Id的值的生成规则为:{processDefinitionKey}:{processDefinitionVersion}:{generated-id}, 这里的generated-id是一个自动生成的唯一的数字
    @Test
    public void queryProcessDefinition() throws Exception {//获取仓库服务对象,使用版本的升序排列,查询列表
        List<ProcessDefinition> processDefinitionList = processEngine.getRepositoryService().createProcessDefinitionQuery()
                //添加查询条件
//                .processDefinitionId("")
//                .processDefinitionName("提交请假流程")
//                .processDefinitionKey("test-flow")
                //排序
                .orderByProcessDefinitionVersion().asc()
                //查询的结果集
                .list();
        
        // 遍历集合,查看内容
        for (ProcessDefinition pd : processDefinitionList) {
            System.out.println("id:"+pd.getId());
            System.out.println("name:"+pd.getName());
            System.out.println("key:"+pd.getKey());
            System.out.println("version:"+pd.getVersion());
            System.out.println(""+pd.getResourceName());
            System.out.println("------------------------------");
        }
    }
3.2.3.查询最新版流程定义
    @Test
    public void queryLatestProcessDefinition() throws Exception {//获取仓库服务对象,使用版本的升序排列,查询列表
        List<ProcessDefinition> processDefinitionList = processEngine.getRepositoryService().createProcessDefinitionQuery()
                //添加查询条件
                //排序
                .orderByProcessDefinitionVersion().asc()
                //查询的结果集
                .list();
        // 过滤最新版本
        LinkedHashMap<String, ProcessDefinition> map = new LinkedHashMap<>();
        for (ProcessDefinition pd: processDefinitionList) {
            map.put(pd.getKey(),pd);
        }

        // 遍历集合,查看内容
        for (ProcessDefinition pd : map.values()) {
            System.out.println("id:"+pd.getId());
            System.out.println("name:"+pd.getName());
            System.out.println("key:"+pd.getKey());
            System.out.println("version:"+pd.getVersion());
            System.out.println("DeploymentId:"+pd.getDeploymentId());
            System.out.println("ResourceName:"+pd.getResourceName());
            System.out.println("------------------------------");
        }
    }
3.2.4.删除流程定义
    @Test
    void deleteDeployment(){
        String id = "a1063f67-0b59-11ee-9a36-38d57a012850";
        RepositoryService repositoryService = processEngine.getRepositoryService();
        repositoryService.deleteDeployment(id);
    }
3.3:RuntimeService

是activiti的流程执行服务类。可以从这个服务类中获取很多关于流程执行相关的信息。

  • ProcessInstance 流程实例

    • 一个流程实例包括了所有的运行节点。可以通过这个对象来了解当前流程实例的进度等信息。
    • 流程实例就表示一个流程从开始到结束的最大的流程分支,即一个流程中流程实例只有一个。
  • Execution 执行对象

    • 描述流程执行的每一个节点。在没有并发的情况下,Execution就是同ProcessInstance。
    • 流程按照流程定义的规则执行一次的过程,就可以表示执行对象Execution。
  • 对应的表:

    • act_ru_execution: 正在执行的信息
    • act_hi_procinst:已经执行完的历史流程实例信息
    • act_hi_actinst:存放历史所有完成的活动

注: 一个流程中,执行对象可以存在多个,但是流程实例只能有一个。

3.3.1 开启流程
    @Test
    public void startProcess(){
        //获得流程执行服务类对象
        RuntimeService runServ = processEngine.getRuntimeService();
        //启动流程
        ProcessInstance pi = runServ.startProcessInstanceByKey("test");

        System.out.println(pi.getId()+","+pi.getActivityId()+","+pi.getProcessDefinitionId()+","+pi.getProcessDefinitionKey()
                +","+pi.getProcessDefinitionName()+","+pi.getBusinessKey()+","+pi.getName()+","+pi.getDeploymentId());
    }

代码里的key——》“test” 是bpmn文件里process的id
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DaeCQRkd-1687161026330)(img/bpmn-process-id.png)]

3.3.2 查询流程实例
    @Test
    public void queryProcess() {
        String processInstanceId = "90d7a464-0c12-11ee-81f2-38d57a012850";
        //获得流程执行服务类对象
        ProcessInstance pi = processEngine.getRuntimeService()
                .createProcessInstanceQuery() // 流程实例查询
                .processInstanceId(processInstanceId)
                .singleResult(); // 唯一结果

        if (pi == null) {
            System.out.println("流程已结束!");
        } else {
            System.out.println("流程定义key:" + pi.getProcessDefinitionKey());
            System.out.println("流程定义名称:" + pi.getProcessDefinitionName());
            System.out.println("name:" + pi.getName());
            System.out.println("当前流程在" + pi.getActivityId());
            System.out.println("业务id:" + pi.getBusinessKey());
            System.out.println("DeploymentId:" + pi.getDeploymentId());
        }
    }
3.3.3 流程挂起、激活

ac_ru_excutionac_ru_task 表中 suspetion_state字段: 1-激活;2-挂起

    /**
     * 流程挂起
     */
    @Test
    public void suspend(){
        String processInstanceId = "90d7a464-0c12-11ee-81f2-38d57a012850";
        processEngine.getRuntimeService().suspendProcessInstanceById(processInstanceId);
        System.out.println("暂停/挂起成功");
    }

    /**
     * 流程激活
     */
    @Test
    public void active(){
        String processInstanceId = "90d7a464-0c12-11ee-81f2-38d57a012850";
        processEngine.getRuntimeService().activateProcessInstanceById(processInstanceId);
        System.out.println("激活成功");
    }
3.4:TaskService

是activiti的任务服务类。可以从这个类中获取任务的信息。

Task任务:执行到某任务环节时生成的任务信息。对应的表:

  • act_ru_task:正在执行的任务信息
  • act_hi_taskinst:已经执行完的历史任务信息
3.4.1 查看待办任务
    /**
     * 查看代办任务
     */
    @Test
    public void getTodoTask() {
        //获取一个TaskService对象
        TaskService taskService = processEngine.getTaskService();
        //查询代办业务
        List<Task> list = taskService.createTaskQuery() //查询任务
                .taskAssignee("小红") // 查询待办个人任务
//                .taskCandidateOrAssigned("lisi")  // 查询所有待办任务(个人、组任务)
//                .taskCandidateUser("小红")// 查询待办组任务
                .processDefinitionKey("test") //processDefinitionKey:查询流程
                .list();
        //分页:List<Task> list = taskService.createTaskQuery().taskAssignee("小红").processDefinitionKey("test").listPage(i,j);
        for (Task task : list) {
            System.out.println("任务名称:" + task.getName());
            System.out.println("任务执行人:" + task.getAssignee());
            System.out.println("任务ID:" + task.getId());
            System.out.println("流程实例ID:" + task.getProcessInstanceId());
        }
    }
3.4.2 查看任务办理人列表
    /**
     * 查询正在执行的任务办理人表
     */
    @Test
    public void findRunPersonTask() {
        //任务ID
        String taskId = "5805";
        List<IdentityLink> list = processEngine.getTaskService()
                .getIdentityLinksForTask(taskId);
        if (list != null && list.size() > 0) {
            for (IdentityLink identityLink : list) {
                System.out.println(identityLink.getTaskId() + "   " + identityLink.getType() + "  " + identityLink.getUserId());
                System.out.println("---------------------IdentityLink-----------------------");
                System.out.println("ProcessInstanceId:"+identityLink.getProcessInstanceId() + "   taskId:"+identityLink.getTaskId() );
                System.out.println( "identityLinkType:" + identityLink.getType() + "   UserId:" + identityLink.getUserId());
            }
        }
    }
3.4.3 完成当前流程节点任务
    /**
     * 任务处理:完成这一节点任务。当所有任务处理完毕,对应当前流程实例信息删除,但是可以在历史中查看到该信息
     */
    @Test
    public void completeTask() {
        //获取一个TaskService对象
        TaskService taskService = processEngine.getTaskService();
        //任务处理,传任务id
        taskService.complete("1ae429da-0be9-11ee-9e49-38d57a012850");

    }
3.4.4 流程转办
    /**
     * 流程转办
     */
    @Test
    public void transferAssignee() {
        //获取一个TaskService对象
        TaskService taskService = processEngine.getTaskService();
        //任务转办
        taskService.setAssignee("1ae429da-0be9-11ee-9e49-38d57a012850","xiaoli");

    }
3.4.5 直接中止(结束)流程
/**
     * 结束任务
     * @param taskId    当前任务ID
     */
    public void endTask(String taskId) {

        TaskService taskService = processEngine.getTaskService();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //  当前任务
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();

        BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(task.getProcessDefinitionId());
        List<EndEvent> endEventList = bpmnModel.getMainProcess().findFlowElementsOfType(EndEvent.class);
        FlowNode endFlowNode = endEventList.get(0);
        FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(task.getTaskDefinitionKey());

        //  临时保存当前活动的原始方向
        List originalSequenceFlowList = new ArrayList<>();
        originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows());
        //  清理活动方向
        currentFlowNode.getOutgoingFlows().clear();

        //  建立新方向
        SequenceFlow newSequenceFlow = new SequenceFlow();
        newSequenceFlow.setId("newSequenceFlowId");
        newSequenceFlow.setSourceFlowElement(currentFlowNode);
        newSequenceFlow.setTargetFlowElement(endFlowNode);
        List newSequenceFlowList = new ArrayList<>();
        newSequenceFlowList.add(newSequenceFlow);
        //  当前节点指向新的方向
        currentFlowNode.setOutgoingFlows(newSequenceFlowList);

        //  完成当前任务
        taskService.complete(task.getId());

        //  可以不用恢复原始方向,不影响其它的流程
//        currentFlowNode.setOutgoingFlows(originalSequenceFlowList);
    }
3.5:HistoryService

是activiti的查询历史信息的类。在一个流程执行完成后,这个对象为我们提供查询历史信息。

  • act_hi_taskinst: 各个任务节点,没有事件节点,事件节点指的是 开始节点,结束节点等;
  • act_hi_procinst: 流程实例对象,记住,一个流程实例对象里面有很多的任务节点;
  • act_hi_actinst: 不仅仅存的用户节点,而且还存的事件节点;
3.5.1 HistoricProcessInstance 历史流程实例

查询所有的流程实例信息

    /**
     * 查询历史流程实例  HistoricProcessInstance
     */
    @Test
    public void findHistoryProcessInstance(){
//        String processInstanceId="8769f060-0be4-11ee-a0d2-38d57a012850";
        List<HistoricProcessInstance> list = processEngine.getHistoryService()      //与历史数据(历史表)相关的Service
                .createHistoricProcessInstanceQuery()  //创建历史流程实例查询
//                .processInstanceId(processInstanceId)  //使用流程实例ID查询
                .orderByProcessInstanceStartTime().asc()
                .list();
        for (HistoricProcessInstance instance: list) {
            System.out.println("---------------- HistoricProcessInstance -------------------");
            System.out.println("instanceId:"+instance.getId());
            System.out.println("ProcessDefinitionId:"+instance.getProcessDefinitionId());
            System.out.println("StartTime:"+instance.getStartTime());
            System.out.println("EndTime:"+instance.getEndTime());
            System.out.println("DurationInMillis:"+instance.getDurationInMillis());
        }

    }
3.5.2 HistoricActivityInstance 流程节点活动实例

查询每个流程实例processInstance经历的所有活动,即走过的审批节点历程。包括任务执行人、网关、开始事件和结束事件等。

    /**
     * 查看历史活动(包括开始节点和结束节点)
     */
    @Test
    public void getHistory() {
        //获取HistoryService接口
        HistoryService historyService = processEngine.getHistoryService();
        //获取历史任务列表
        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId("eb0ec508-0b65-11ee-9f99-38d57a012850") //获取指定流程实例的任务
                .orderByHistoricActivityInstanceStartTime().desc() // 按开始时间排序
                .list();
        for (HistoricActivityInstance ai : list) {
            System.out.println("任务节点ID:"+ai.getActivityId());
            System.out.println("任务节点名称:"+ai.getActivityName());
            System.out.println("流程定义ID信息:"+ai.getProcessDefinitionId());
            System.out.println("流程实例ID信息:"+ai.getProcessInstanceId());
            System.out.println("==============================");
        }
    }
3.5.3 HistoricTaskInstance 历史任务实例

查询历史任务

    // 根据发布编号查询已经完成的历史任务记录
    @Test
    public void queryHisByDeployId() {
        String deployId ="5b0a5c4c-0b62-11ee-91ec-38d57a012850";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        HistoryService hisServ = engine.getHistoryService(); // 历史信息服务
        List<HistoricProcessInstance> instanceList=hisServ.createHistoricProcessInstanceQuery() // 历史流程实例查询
                .deploymentId(deployId)
                .list();
        HistoricTaskInstanceQuery hisTaskInstanceQuery = hisServ.createHistoricTaskInstanceQuery(); // 历史任务实例查询
        for(HistoricProcessInstance processInstance:instanceList){
            System.out.println("流程实例id:"+processInstance.getId());
            List<HistoricTaskInstance> theTaskList = hisTaskInstanceQuery
                    .processInstanceId(processInstance.getId())
                    .orderByTaskCreateTime().asc()
                    .list();
            for (HistoricTaskInstance taskInstance : theTaskList) {
                if(taskInstance.getEndTime()!=null){
                    System.out.println("任务id:" + taskInstance.getId());
                    System.out.println("办理人:" + taskInstance.getAssignee());
                    System.out.println("任务名称:" + taskInstance.getName());
                    System.out.println("开始时间:" + sdf.format(taskInstance.getStartTime()) + ",结束时间:"
                            + sdf.format(taskInstance.getEndTime()) + ",耗时(秒钟):" + taskInstance.getDurationInMillis() / 1000);
                }
            }
            System.out.println("=========华丽的分割线====================");
        }
    }
3.5.4 HistoricVariableInstance 历史流程变量
    /**
     * 查询历史流程变量 HistoricVariableInstance
     */
    @Test
    public void findHistoryProcessVariables(){
        String processInstanceId = "8769f060-0be4-11ee-a0d2-38d57a012850";
        List<HistoricVariableInstance> list = processEngine.getHistoryService()
                .createHistoricVariableInstanceQuery()
                .processInstanceId(processInstanceId)
                .list();
        if(list!=null && list.size()>0){
            for (HistoricVariableInstance hti : list) {
                System.out.println("------------------------- HistoricVariableInstance ---------------------------");
                System.out.println(hti.getId()+" ProcessInstanceId:"+hti.getProcessInstanceId()+" taskId:"+hti.getTaskId());
                System.out.println(hti.getVariableName()+": "+ hti.getValue()+" type:"+hti.getVariableTypeName());
            }
        }
    }
3.5.5 HistoricIdentityLink 历史参与者
    /**
     * 查询历史任务的办理人表
     */
    @Test
    public void findHistoryPersonTask() {
        //流程实例ID
        String processInstanceId = "8769f060-0be4-11ee-a0d2-38d57a012850";
        List<HistoricIdentityLink> list = processEngine.getHistoryService()
                .getHistoricIdentityLinksForProcessInstance(processInstanceId);
        if (list != null && list.size() > 0) {
            for (HistoricIdentityLink identityLink : list) {
                System.out.println("---------------------HistoricIdentityLink-----------------------");
                System.out.println("ProcessInstanceId:"+identityLink.getProcessInstanceId() + "   taskId:"+identityLink.getTaskId() );
                System.out.println( "identityLinkType:" + identityLink.getType() + "   UserId:" + identityLink.getUserId());
            }
        }

    }

4. 流程变量

4.1 流程变量

流程变量:在流程执行或者任务执行的过程中,用于设置和获取变量,使用流程变量在流程传递的过程中传递业务参数。

  • 对应的表:
    • act_ru_variable:正在执行的流程变量表
    • act_hi_varinst:流程变量历史表
  • setVariablesetVariableLocal的区别:
    • setVariable:节点通用变量,流程变量名称相同的时候,后一次的值替换前一次的值。
    • setVariableLocal:针对当前活动的节点设置流程变量。例如act_hi_varinst 表的数据:不同的任务节点,即使流程变量名称相同,存放的值也是不同的。

注:Javabean类型设置获取流程变量,除了需要这个javabean实现了Serializable接口外,还要求流程变量对象的属性不能发生变化,否则抛出异常。解决方案,固定序列化ID

4.1.1 启动流程时设置
    @Test
    public void startProcess(){
        //获得流程执行服务类对象
        RuntimeService runServ = processEngine.getRuntimeService();
        //启动流程的时候【动态设置每个步骤的执行人】,map的key值需要与Leave.bpmn中对应
        Map<String, Object> variables=new HashMap<String, Object>();
        variables.put("user1", "张三");
        variables.put("user2", "李四");
        //启动流程得到流程实例,对应act_ru_execution表
        ProcessInstance pi= runServ.startProcessInstanceByKey("test","aaa", variables);

        System.out.println(pi.getId()+","+pi.getActivityId()+","+pi.getProcessDefinitionId()+","+pi.getProcessDefinitionKey()
                +","+pi.getProcessDefinitionName()+","+pi.getBusinessKey()+","+pi.getName()+","+pi.getDeploymentId());
    }
4.1.2 通过RuntimeService设置和获取变量

taskId为空的变量

    /**
     * 设置和获取流程变量
     */
    @Test
    void processVariable(){
        String processInstanceId ="90d7a464-0c12-11ee-81f2-38d57a012850";
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 设置变量
        runtimeService.setVariable(processInstanceId,"action","请假申请");
        // 获取变量
        System.out.println(runtimeService.getVariable(processInstanceId,"action"));
    }
4.1.3 通过TaskService设置和获取变量

taskId为当前节点的变量

    /**
     * 设置任务节点变量
     */
    @Test
    void setTaskVariable(){
        String processInstanceId ="90d7a464-0c12-11ee-81f2-38d57a012850";
        TaskService taskService = processEngine.getTaskService();
        List<Task> list = taskService.createTaskQuery().processInstanceId(processInstanceId)
                .list();
        for (Task task : list) {
            System.out.println("任务名称:" + task.getName());
            System.out.println("任务执行人:" + task.getAssignee());
            System.out.println("任务ID:" + task.getId());
            Map<String, Object> variables=new HashMap<String, Object>();
            variables.put("msg", "请假理由4");
            variables.put("user1", "王二4");
            taskService.setVariables(task.getId(),variables);
            taskService.setVariable(task.getId(),"var","setVariable4");
            taskService.setVariableLocal(task.getId(),"var2","VariableLocal4");
            System.out.println(taskService.getVariablesLocal(task.getId()));
            //多次对同一个流程变量赋值时,流程变量的值不会更新,即后面的赋值永远是不生效的
//            taskService.complete(task.getId(),variables);
        }
    }

    /**
     * 获取任务节点变量
     */
    @Test
    void getTaskVariable(){
        String processInstanceId ="90d7a464-0c12-11ee-81f2-38d57a012850";
        TaskService taskService = processEngine.getTaskService();
        List<Task> list = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .list();
        for (Task task : list) {
            System.out.println("任务名称:" + task.getName());
            System.out.println("任务执行人:" + task.getAssignee());
            System.out.println("任务ID:" + task.getId());
            System.out.println("Variables:"+taskService.getVariables(task.getId()));
            System.out.println("VariableLocal"+taskService.getVariablesLocal(task.getId()));
        }
        System.out.println("processVariables:"+processEngine.getRuntimeService().getVariables(processInstanceId));
    }
4.2 流程分支
4.2.1 连线流程(SequenceFlow)

一个活动中可以指定一个或多个SequenceFlow(Start中有一个,End中没有)。

  • 开始活动中有一个SequenceFlow 。
  • 结束活动中没有SequenceFlow 。
  • 其他活动中有1条或多条SequenceFlow

如果有多个,则需要使用流程变量设置codition的名称。${}中间的内容要使用boolean类型的表达式,用来判断应该执行的连线。

4.2.2 排它网关(X)

最上面的分支是默认分支,可以不设置条件

  • 一个排他网关对应一个以上的顺序流
  • 由排他网关流出的顺序流都有个conditionExpression元素,在内部维护返回boolean类型的决策结果。
  • 决策网关只会返回一条结果。当流程执行到排他网关时,流程引擎会自动检索网关出口,从上到下检索如果发现第一条决策结果为true或者没有设置条件的(默认为成立),则流出。
  • 如果没有任何一个出口符合条件,则抛出异常

使用流程变量,设置连线的条件,并按照连线的条件执行工作流,如果没有条件符合的条件,则以默认的连线离开。

4.2.3 并行网关(parallelGateWay) (+)
  • 说明:
    • 一个流程中流程实例只有1个,执行对象有多个
    • 并行网关的功能是基于进入和外出的顺序流的:
  • 分支(fork): 并行后的所有外出顺序流,为每个顺序流都创建一个并发分支。
  • 汇聚(join): 所有到达并行网关,在此等待的进入分支, 直到所有进入顺序流的分支都到达以后, 流程就会通过汇聚网关。
    • 并行网关的进入和外出都是使用相同节点标识
    • 如果同一个并行网关有多个进入和多个外出顺序流, 它就同时具有分支和汇聚功能。 这时,网关会先汇聚所有进入的顺序流,然后再切分成多个并行分支。
    • 并行网关不会解析条件。 即使顺序流中定义了条件,也会被忽略。
4.3 用户任务、组任务、监听器

个人任务和组任务存放办理人对应的表:

  • act_ru_identitylink表存放任务的办理人,包括个人任务和组任务,表示正在执行的任务
  • act_hi_identitylink表存放任务的办理人,包括个人任务和组任务,表示历史任务

区别在于:如果是个人任务TYPE的类型表示participant(参与者)

如果是组任务TYPE的类型表示candidate(候选者)和participant(参与者)

4.3.1 个人任务

1 )三种分配方式:

  • 方式一:直接指定办理人。在taskProcess.bpmn中直接写 assignee=“小红"
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aiRgCIMx-1687161026331)(img/bpmn-assignee.png)]
  • 方式二:使用流程变量指定办理人。在taskProcess.bpmn中写 assignee=“#{userID}”,变量的值要是String的。
  • 方式三:使用监听器类,实现TaskListener接口.
    • delegateTask.setAssignee(assignee);// 指定个人任务的办理人
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ersPkQrc-1687161026332)(img/bpmn-listener.png)]
      2 )使用任务ID和办理人重新指定办理人: processEngine.getTaskService().setAssignee(taskId, userId);
4.3.2 组任务

1 )三种分配方式:

  • 方式一:直接指定办理人。在taskProcess.bpmn中直接写 candidate-users=“小A,小B,小C,小D"
  • 方式二:使用流程变量指定。在taskProcess.bpmn中写 candidate-users =“#{userIDs}”,变量的值要是String的。
            //使用流程变量指定办理人
            Map<String, Object> variables = new HashMap<String, Object>();
            variables.put("userIDs", "大大,小小,中中");
  • 方式三:使用监听器类,实现TaskListener接口,在类中定义:
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;

public class TestTaskListener implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {
        String userId1="xiaoHong";
        String userId2="xiaoMing";
        // 指定个人任务的办理人
//        delegateTask.setAssignee(userId1);
        //添加组任务的用户
        delegateTask.addCandidateUser(userId1);
        delegateTask.addCandidateUser(userId2);
    }
}

2 )组任务分配给个人任务(认领任务):

 processEngine.getTaskService().claim(taskId, userId);

3 )个人任务分配给组任务:

 processEngine.getTaskService().setAssignee(taskId, null);

4 )向组任务添加人员:

 processEngine.getTaskService().addCandidateUser(taskId, userId);

5)向组任务删除人员:

 processEngine.getTaskService().deleteCandidateUser(taskId, userId);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值