• activiti7入门教程


    一、相关概念

    1. 工作流概念

      工作流是指业务过程的部分或整体在计算机应用环境下的自动化。是对工作流程及其各操作步骤之间业务规则的抽象、概括描述。

    2. activiti介绍

      activiti是一个工作流引擎,可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言BPMN进行定义,业务流程按照预先定义的流程进行执行。实现了系统的流程由activiti进行管理,减少业务系统由于流程变更进行系统升级改造的工作流量,从而提高系统的健壮性,同时也减少了系统开发维护成本。

    3. BPM(Business Process Management)

      业务流程管理

    4. BPM软件

      通过BPM软件可以实现对业务流程的整个生命周期进行建模、自动化、管理监控和优化。

    5. BPMN(Business Process MOdel And Notation 业务流程模型和符号)

      业务流程模型和符号,是由BPMI开发的一套标准的业务流程建模符号,使用BPMN提供的符号可以创建业务流程。

    6. ProcessDefinition:流程定义

    7. ProcessInstance:流程实例

    二、使用步骤

    1. 部署activiti

      activiti是一个工作流程,业务系统访问activiti的接口,就可以方便操作流程间的相关数据,这样就可以把工作流环境和业务系统的环境集成在一起。

    2. 流程定义

      使用activiti建模工具定义业务流程,生成.bpmn文件(通过xml定义业务流程)。

    3. 流程定义部署

      使用activiti提供的api把流程定义的内容存储起来,再Activiti执行过中可以查询的内容。activiti执行把流程定内容存储在数据库中。

    4. 启动一个流程实例

      流程实例也叫ProcessInstance

      启动一个流程实例表示开始一次业务流程的执行

      比如同一个流程,张三可以启动,李四也可以启动,但是两次流程实例是互不影响的。

    5. 用户查询待办任务

      由于集成了activiti,所有的任务都可以直接通过activiti提供的api进行查询,不需要我们自己查库。

    6. 用户办理任务

      流程办理等操作,也是可以直接使用activiti提供的api即可。

    7. 流程结束

      当没有下一个需要办理的节点,说明任务就结束了。

    三、activiti配置生成表

    1. idea软件安装actiBPM插件,若idea找不到插件,可去官网下载,导入即可,可参考

      https://blog.csdn.net/weixin_40496191/article/details/125097860

    2. pom配置

      
      <dependency>
          <groupId>org.springframework.bootgroupId>
          <artifactId>spring-boot-starterartifactId>
      dependency>
      <dependency>
          <groupId>org.springframework.bootgroupId>
          <artifactId>spring-boot-starter-webartifactId>
      dependency>
      
      
      <dependency>
          <groupId>org.activitigroupId>
          <artifactId>activiti-spring-boot-starterartifactId>
          <version>7.1.0.M1version>
      dependency>
      <dependency>
          <groupId>org.activitigroupId>
          <artifactId>activiti-json-converterartifactId>
          <version>7.1.0.M1version>
      dependency>
      <dependency>
          <groupId>org.activitigroupId>
          <artifactId>activiti-image-generatorartifactId>
          <version>7.1.0.M1version>
      dependency>
      <dependency>
          <groupId>org.apache.xmlgraphicsgroupId>
          <artifactId>batik-allartifactId>
          <version>1.10version>
      dependency>
      
      
      <dependency>
          <groupId>mysqlgroupId>
          <artifactId>mysql-connector-javaartifactId>
          <scope>runtimescope>
      dependency>
      <dependency>
          <groupId>com.alibabagroupId>
          <artifactId>druidartifactId>
          <version>1.2.2version>
      dependency>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
    3. 配置文件配置activiti相关参数和数据库信息

      server:
        port: 8080
      
      spring:
        datasource:
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: root
          password: tiger
          url: jdbc:mysql://localhost:3306/activiti?useUnicode=true&characterEncoding=utf-8 &allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2b8&nullCatalogMeansCurrent=true
          type: com.alibaba.druid.pool.DruidDataSource
          servlet:
            multipart:
              max-file-size: 100MB
              max-request-size: 100MB
        activiti:
          #    false:默认,数据库表不变,但是如果版本不对或者缺失表会抛出异常(生产使用)
          #    true:表不存在,自动创建(开发使用)
          #    create_drop: 启动时创建,关闭时删除表(测试使用)
          #    drop_create: 启动时删除表,在创建表 (不需要手动关闭引擎)
          database-schema-update: true
          #监测历史表是否存在,activities7默认不开启历史表
          db-history-used: true
          #none:不保存任何历史数据,流程中这是最高效的
          #activity:只保存流程实例和流程行为
          #audit:除了activity,还保存全部的流程任务以及其属性,audit为history默认值
          #full:除了audit、还保存其他全部流程相关的细节数据,包括一些流程参数
          history-level: full
          #校验流程文件,默认校验resources下的process 文件夹的流程文件
          check-process-definitions: true
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
    4. 启动项目,即可生成相关表

      在这里插入图片描述

    5. 相关表关系

      re表:流程定义和流程相关属性

      ru表:运行时产生的数据

      hi表:历史信息

      ge表:通用信息

    在这里插入图片描述

    四、简单画一个流程

    1. 画图

      创建demo.bpmn文件,简单实现流程图,id为“myLeave“,流程名称为“员工请假审批流程”,责任人从上往下依次为worker、manager、financer。
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-84gAnIlx-1659512850380)(C:\Users\86188\AppData\Roaming\Typora\typora-user-images\image-20220718234740001.png)]

    2. 画完图后,可以将流程图导出来

      1)复制一份新的文件,以xml结尾

      2)右键显示图标

      在这里插入图片描述
      3)导出png图片
      在这里插入图片描述

    五、activiti接口基础api示例

    1. 代码创建流程

    /**
     * 部署流程
     */
    @RequestMapping("createProcesses")
    @ResponseBody
    public void createProcesses() {
        //使用获取RepositoryService进行部署
        Deployment deployment = repositoryService.createDeployment()
            .addClasspathResource("static/bpmn/demo.bpmn")//添加bpmn资源
            .addClasspathResource("static/bpmn/demo.png")//添加png资源
            .name("员工请假审批流程")
            .deploy();//部署流程
        //输出流程部署的信息
        System.out.println("流程部署id:" + deployment.getId());
        System.out.println("流程部署名称:" + deployment.getName());
    }
    
    //结果:
    //流程部署id:1fb480d0-0773-11ed-8dc3-005056c00001
    //流程部署名称:员工请假审批流程
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    执行后可以去数据库查看相关的表数据

    act_re_deployment:查看相关的流程的创建

    act_re_procdef:查看流程的定义

    act_ge_bytearray:流程文件存储

    2. 查询流程的定义

    /**
     * 查询流程的定义
     */
    @RequestMapping("searchProcess")
    @ResponseBody
    public void searchProcess() {
        String key= "myLeave";
        //获取ProcessDefinitionQuery对象,用来查询操作
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        List<ProcessDefinition> list = processDefinitionQuery.processDefinitionKey(key)
            .orderByProcessDefinitionVersion()//安装版本信息
            .desc()//倒序
            .list();
        //输出流程定义的信息
        for (ProcessDefinition processDefinition : list) {
            System.out.println("流程定义的id:" + processDefinition.getId());
            System.out.println("流程定义的name:" + processDefinition.getName());
            System.out.println("流程定义的key:" + processDefinition.getKey());
            System.out.println("流程定义的version:" + processDefinition.getVersion());
            System.out.println("流程部署的id:" + processDefinition.getDeploymentId());
            System.out.println("--------------------------------------------------");
        }
    
    }
    
    //结果
    //相同key,则自动提升版本
    //流程定义的id:myLeave:2:f6844e42-0774-11ed-96b3-005056c00001
    //流程定义的name:员工请假审批流程
    //流程定义的key:myLeave
    //流程定义的version:2
    //流程部署的id:f66888df-0774-11ed-96b3-005056c00001
    //--------------------------------------------------
    //流程定义的id:myLeave:1:fc307169-0773-11ed-9b87-005056c00001
    //流程定义的name:员工请假审批流程
    //流程定义的key:myLeave
    //流程定义的version:1
    //流程部署的id:fc1a2a46-0773-11ed-9b87-005056c00001
    //--------------------------------------------------
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    3. 删除流程

    /**
     * 删除流程
     */
    @RequestMapping("deleteProcess")
    @ResponseBody
    public void deleteProcess() {
        String id = "f66888df-0774-11ed-96b3-005056c00001";
        //设置true,择优级联删除的效果。false如果已有实例,则会删除错误
        repositoryService.deleteDeployment(id, true);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4. 获取流程里面的资源文件

    /**
     * 读取数据库中的资源文件
     */
    @RequestMapping("searchProcesslFile")
    @ResponseBody
    public void searchProcesslFile() throws IOException {
        String id = "myLeave";
        //查询器
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
            .processDefinitionKey(id)
            .singleResult();
        //获取流程部署id
        String deploymentId = processDefinition.getDeploymentId();
        //通过repositoryService对象的相关方法来获取图片信息和bpmn信息
        //png图片
        InputStream pngInput = repositoryService
            .getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());
        //bpmn 文件的流
        InputStream bpmnInput = repositoryService
            .getResourceAsStream(deploymentId, processDefinition.getResourceName());
        //文件的保存
        File filePng = new File("E:/学习/activiti/evection.png");
        File fileBpmn = new File("E:/学习/activiti/evection.bpmn");
        OutputStream pngOut = new FileOutputStream(filePng);
        OutputStream bpmnOut = new FileOutputStream(fileBpmn);
    
        //输入流和输出流的转化 
        IOUtils.copy(pngInput, pngOut);
        IOUtils.copy(bpmnInput, bpmnOut);
        pngInput.close();
        pngOut.close();
        bpmnInput.close();
        bpmnOut.close();
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    5. 创建流程实例

    /**
     * 创建流程实例
     */
    @RequestMapping("addApplication")
    @ResponseBody
    public void addApplication() {
        String businessKey = "myLeave";
        //启动一个流程实例
        //ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(businessKey);
        //启动一个流程实例,设置业务id,长度最大255,通过processInstance.getBusinessKey()获取
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(businessKey,"businessKey");
        System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例id:" + processInstance.getId());
        System.out.println("当前活动id:" + processInstance.getActivityId());
    }
    
    //结果:
    //流程定义id:myLeave:2:a07c05cb-076f-11ed-afa5-005056c00001
    //流程实例id:f6f5bf5a-0772-11ed-8dc3-005056c00001
    //当前活动id:null
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    6. 查看流程底下存在哪些实例

    /**
     * 查询流程下存在哪些实例
     * 可通过.processInstanceId等相关属性过滤
     */
    @RequestMapping("searchProcessRunInstance")
    @ResponseBody
    public void searchProcessRunInstance() {
        String key = "myLeave";
        List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().processDefinitionKey(key).list();
        //输出流程定义的信息
        for (ProcessInstance processInstance : list) {
            System.out.println("流程实例id:" + processInstance.getProcessInstanceId());
            System.out.println("所属流程定义id:" + processInstance.getProcessDefinitionId());
            System.out.println("是否完成:" + processInstance.isEnded());
            System.out.println("是否暂停:" + processInstance.isSuspended());
            System.out.println("当前活动标识:" + processInstance.getActivityId());
            System.out.println("业务关键字:" + processInstance.getBusinessKey());
            System.out.println("------------" );
        }
    
    }
    
    //结果:
    //流程实例id:906f1e33-0776-11ed-96b3-005056c00001
    //所属流程定义id:myLeave:2:f6844e42-0774-11ed-96b3-005056c00001
    //是否完成:false
    //是否暂停:false
    //当前活动标识:null
    //业务关键字:null
    //------------
    //流程实例id:fece74da-0773-11ed-9b87-005056c00001
    //所属流程定义id:myLeave:1:fc307169-0773-11ed-9b87-005056c00001
    //是否完成:false
    //是否暂停:false
    //当前活动标识:null
    //业务关键字:null
    //------------
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    7. 根据流程和负责人查询任务

    /**
     * 查询任务查询
     * 也可以不加过滤条件,查询出全部
     */
    @RequestMapping("searchTask")
    @ResponseBody
    public void searchTask() {
        String assignee = "worker";
        String key = "myLeave";
        //根据流程的key和任务负责人 查询任务
        List<Task> list = taskService.createTaskQuery()
            .processDefinitionKey(key)
            .taskAssignee(assignee)
            .list();
        //输出当前用户具有的任务
        for (Task task : list) {
            System.out.println("流程实例id:" + task.getProcessDefinitionId());
            System.out.println("任务id:" + task.getId());
            System.out.println("任务负责人:" + task.getAssignee());
            System.out.println("任务名称:" + task.getName());
        }
    
    }
    
    //结果:
    //流程实例id:myLeave:2:a07c05cb-076f-11ed-afa5-005056c00001
    //任务id:2da138fa-0772-11ed-a901-005056c00001
    //任务负责人:worker
    //任务名称:创建请假流程
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    8. 处理流程

    /**
     * 根据流程的key和任务负责人 处理任务
     */
    @RequestMapping("solveTask")
    @ResponseBody
    public void solveTask() {
        String assignee = "worker";
        String key = "myLeave";
        //根据流程的key和任务负责人 查询任务
        Task task = taskService.createTaskQuery()
            .processDefinitionKey(key)
            .taskAssignee(assignee)
            .singleResult();
        //完成任务,跳到下一个流程
        taskService.complete(task.getId());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    act_ru_execution:任务操作

    act_ru_task:目前需要处理的任务表

    9. 流程历史信息查看

    /**
     * 流程历史信息查看
     * 即时删除了流程,但是流程的历史信息还是会被保存下来,存在hi**表中
     * 也可以不加过滤条件,查询出全部
     */
    @RequestMapping("searchHistoricActivityInstance")
    @ResponseBody
    public void searchHistoricActivityInstance() {
        String id = "myLeave:1:fc307169-0773-11ed-9b87-005056c00001";
        //获取actinst表的查询对象
        HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
        //查询actinst表,根据流程id查询
        HistoricActivityInstanceQuery historicActivityInstanceQuery1 = historicActivityInstanceQuery.processDefinitionId(id);
        //查询actinst表,根据流程实例id查询
        //historicActivityInstanceQuery.processInstanceId(流程实例id);
        //排序
        historicActivityInstanceQuery1.orderByHistoricActivityInstanceStartTime().desc();
        //获取查询结果
        List<HistoricActivityInstance> list = historicActivityInstanceQuery1.list();
        //输出查询结果
        for (HistoricActivityInstance hi : list) {
            System.out.println(hi.getActivityId());
            System.out.println(hi.getActivityName());
            System.out.println(hi.getActivityType());
            System.out.println(hi.getAssignee());
            System.out.println(hi.getProcessDefinitionId());
            System.out.println(hi.getProcessInstanceId());
        }
    }
    
    //结果:
    //_4
    //部门经理审批
    //userTask
    //manager
    //myLeave:1:fc307169-0773-11ed-9b87-005056c00001
    //fece74da-0773-11ed-9b87-005056c00001
    //_3
    //创建请假流程
    //userTask
    //worker
    //myLeave:1:fc307169-0773-11ed-9b87-005056c00001
    //fece74da-0773-11ed-9b87-005056c00001
    //_2
    //StartEvent
    //startEvent
    //null
    //myLeave:1:fc307169-0773-11ed-9b87-005056c00001
    //fece74da-0773-11ed-9b87-005056c00001
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    10. 单个流程全部实例挂起

    /**
      * 全部流程实例挂起和激活
     */
    @RequestMapping("allLockOrOpenPeocess")
    @ResponseBody
    public void allLockOrOpenPeocess() {
        String id = "myLeave";
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
            .processDefinitionKey(id)
            .singleResult();
        //获取流程的状态
        boolean suspended = processDefinition.isSuspended();
        String pdId = processDefinition.getId();
        //如果激活就挂起,挂起就激活
        if (suspended) {
            //表示当前是挂起的,需要激活。
            //参数:流程定义id、是否激活、激活时间
            repositoryService.activateProcessDefinitionById(pdId, true, null);
            System.out.println("流程定义:" + pdId + ",已激活");
        } else {
            //激活状态,则需要挂起
            //参数:流程定义id、是否挂起、挂起时间
            repositoryService.suspendProcessDefinitionById(pdId, true, null);
            System.out.println("流程定义:" + pdId + ",已挂起");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    11. 单个实例挂起和激活

    /**
      * 单个流程实例挂起和激活
      */
    @RequestMapping("singleLockOrOpenPeocess")
    @ResponseBody
    public void singleLockOrOpenPeocess() {
        //task表的proc_inst_id
        String id = "dc609b81-082e-11ed-a65d-005056c00001";
        //获取实例对象
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
            .processInstanceId(id)
            .singleResult();
        //获取状态
        boolean suspended = processInstance.isSuspended();
        String pdId = processInstance.getId();
        if (suspended) {
            //表示当前是挂起的,需要激活
            runtimeService.activateProcessInstanceById(pdId);
            System.out.println("流程定义:" + pdId + ",已激活");
        } else {
            //激活状态,则需要挂起
            runtimeService.suspendProcessInstanceById(pdId);
            System.out.println("流程定义:" + pdId + ",已挂起");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    六、activiti接口进阶(变量启动)

    1. 流程变量

      Global变量:这个是流程变量的默认作用域,表示是一个完整的流程实例。Global变量名不能重复,如果重复则会被后面的覆盖。

      Local变量:Local变量只针对一个任务或者一个执行实例,变量名可相同,互不影响。

      ps1:如果设置了流程变量,就必须复制,否则将会报错导致流程结束。

      ps2:如果连线分支不设置条件,默认走sequenceFlow id(可在xml查看)小的那条线。

    2. 画分支图,并且设置流程审批人变量,依次设置为 a s s i g n e e 0 、 {assignee0}、 assignee0{assignee1}、 a s s i g n e e 2 、 {assignee2}、 assignee2{assignee3}
      在这里插入图片描述

    3. 启动流程,并且创建实例(带变量)

      /**
        * 启动流程(创建新的申请流程实例列表)
        */
      @RequestMapping("addApplication")
      @ResponseBody
      public void addApplication() {
          Map<String,Object> variables=new HashMap<>();
          Map<String ,Object>  evention=new HashMap<>();
          evention.put("num",2);
      
          variables.put("evention",evention);
          variables.put("assignee0","申请人");
          variables.put("assignee1","部门经理");
          variables.put("assignee2","总经理");
          variables.put("assignee3","财务人事");
      
          String key = "myLeave1";
          ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key,variables);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
    4. 依次调用solveTask方法,可以发现最终走的分支是num小于3的分支,即不经过总经理审批。

    5. 也可以在每次执行时,重新设置本地变量

      ps:这里需要留意,7.1.0.M1版本的activiti无法直接在complete时覆盖全局和本地变量,只能通过设置本地变量覆盖。

      /**
       * 启动流程(创建新的申请流程实例列表)
       */
      @RequestMapping("addApplication")
      @ResponseBody
      public void addApplication() {
          Map<String,Object> variables=new HashMap<>();
          Map<String ,Object>  evention=new HashMap<>();
          evention.put("num",2);
      
          variables.put("evention",evention);
          variables.put("assignee0","申请人");
          variables.put("assignee1","部门经理");
          variables.put("assignee2","总经理");
          variables.put("assignee3","财务人事");
      
          String key = "myLeave1";
          ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key,variables);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      /**
       * 根据流程的key和任务负责人 处理任务
       */
      @RequestMapping("solveTask")
      @ResponseBody
      public void solveTask() {
          String assignee = "申请人";
          String id = "myLeave1";
          //根据流程的key和任务负责人 查询任务
          Task task = taskService.createTaskQuery()
              .processDefinitionKey(id)
              .taskAssignee(assignee)
              .singleResult();
      
          //完成任务,跳到下一个流程
          Map<String,Object> variables=new HashMap<>();
          Map<String ,Object>  evention=new HashMap<>();
          evention.put("num",2);
      
          variables.put("evention",evention);
          variables.put("assignee0","申请人1");
          variables.put("assignee1","部门经理1");
          variables.put("assignee2","总经理1");
          variables.put("assignee3","财务人事1");
      
          taskService.setVariablesLocal(task.getId(),variables);
          taskService.complete(task.getId());
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      /**
       * 根据流程的key和任务负责人 处理任务
       */
      @RequestMapping("solveTaskForVariables")
      @ResponseBody
      public void solveTaskForVariables() {
          String assignee = "部门经理1";
          String id = "myLeave1";
          //根据流程的key和任务负责人 查询任务
          Task task = taskService.createTaskQuery()
              .processDefinitionKey(id)
              .taskAssignee(assignee)
              .singleResult();
          //完成任务,跳到下一个流程
          Map<String,Object> variables=new HashMap<>();
          Map<String ,Object>  evention=new HashMap<>();
          evention.put("num",2);
      
          variables.put("evention",evention);
          variables.put("assignee0","申请人2");
          variables.put("assignee1","部门经理2");
          variables.put("assignee2","总经理2");
          variables.put("assignee3","财务人事2");
      
          taskService.setVariablesLocal(task.getId(),variables);
          taskService.complete(task.getId());
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27

      然后查询当前任务

      /**
       * 根据流程的key查询存在哪些任务
       */
      @RequestMapping("searchTaskByKey")
      @ResponseBody
      public void searchTaskByKey() {
          String key = "myLeave1";
          //根据流程的key和任务负责人 查询任务
          List<Task> tasks = taskService.createTaskQuery()
              .processDefinitionKey(key)
              .list();
      
          for (Task task : tasks) {
              System.out.println(task.getId());
              System.out.println(task.getName());
              System.out.println(task.getAssignee());
              System.out.println("--------------");
          }
      }
      
      //结果
      //3c18d52e-0841-11ed-b1d5-005056c00001
      //财务部审批
      //财务人事2
      //--------------
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25

    七、activiti网关

    1. 排他网关

    1. 概念:用来在流程中实现决策。 当流程执行到这个网关,所有分支都会判断是否为true,如果为ture则执行。如果多个为true,则执行id值小的。如果没 有位true的,则抛出异常

    2. 流程图
      在这里插入图片描述

    2. 并行网关

    1. 概念:并行网关允许将流程分成多条分支,也可以把多条分支汇聚到一起。并行网关的线上面,写上条件也没有用,在并行网关的后面分支都要执行完成之后,才会走下一个任务,不然,只要有一个分支没有完成,后面的任务就不会走

    2. 流程图
      在这里插入图片描述

    3. 包含网关

    1. 概念:包含网关可以看做是排他网关和并行网关的结合体。和排他网关一样,你可以在外出顺序流上定义条件,包含网关会解析它们,不定义则默认放行。 但是主要的区别是包含网关可以选择多于一条顺序流,这和并行网关一样。这也是用的最多的网关。

    2. 流程图 在这里插入图片描述

    八、组任务流程

    1. 概念

      即任务的下一个处理人不再是一个具体的人员,而是一组候选人。候选人可以主动拾取任务,然后办理。

    2. 流程图,即再流程的第二步,经理或总经理需要拾取任务才能进行处理
      在这里插入图片描述

    3. 代码实现

      由于activiti需要整合Security框架,所以需要做好权限配置,这里是简单做了个lisi用户的配置

      package activiti.config;
      
      
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.beans.factory.annotation.Qualifier;
      import org.springframework.context.annotation.ComponentScan;
      import org.springframework.security.core.Authentication;
      import org.springframework.security.core.GrantedAuthority;
      import org.springframework.security.core.context.SecurityContextHolder;
      import org.springframework.security.core.context.SecurityContextImpl;
      import org.springframework.security.core.userdetails.UserDetails;
      import org.springframework.security.core.userdetails.UserDetailsService;
      import org.springframework.stereotype.Component;
      
      import java.util.Collection;
      
      @Component
      public class SecurityUtil {
          private Logger logger = LoggerFactory.getLogger(SecurityUtil.class);
      
          @Autowired
          @Qualifier("myUserDetailsService")
          private UserDetailsService userDetailsService;
      
          public void logInAs(String username) {
              UserDetails user = userDetailsService.loadUserByUsername(username);
      
              if (user == null) {
                  throw new IllegalStateException("User " + username + " doesn't exist, please provide a valid user");
              }
              logger.info("> Logged in as: " + username);
      
              SecurityContextHolder.setContext(
                      new SecurityContextImpl(
                              new Authentication() {
                                  @Override
                                  public Collection<? extends GrantedAuthority> getAuthorities() {
                                      return user.getAuthorities();
                                  }
      
                                  @Override
                                  public Object getCredentials() {
                                      return user.getPassword();
                                  }
      
                                  @Override
                                  public Object getDetails() {
                                      return user;
                                  }
      
                                  @Override
                                  public Object getPrincipal() {
                                      return user;
                                  }
      
                                  @Override
                                  public boolean isAuthenticated() {
                                      return true;
                                  }
      
                                  @Override
                                  public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
                                  }
      
                                  @Override
                                  public String getName() {
                                      return user.getUsername();
                                  }
                              }));
              org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      package activiti.config;
      
      
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.security.core.authority.SimpleGrantedAuthority;
      import org.springframework.security.core.userdetails.User;
      import org.springframework.security.core.userdetails.UserDetailsService;
      import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
      import org.springframework.security.crypto.password.PasswordEncoder;
      import org.springframework.security.provisioning.InMemoryUserDetailsManager;
      
      import java.util.Arrays;
      import java.util.List;
      import java.util.stream.Collectors;
      @Configuration
      public class SpringSecurityConfiguration {
          private Logger logger = LoggerFactory.getLogger(SpringSecurityConfiguration.class);
          @Bean
          public UserDetailsService myUserDetailsService() {
              InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
              //这里添加用户,后面处理流程时用到的任务负责人,需要添加在这里
              String[][] usersGroupsAndRoles = {
                      {"lisi", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
                      {"system", "password", "ROLE_ACTIVITI_USER"},
                      {"admin", "password", "ROLE_ACTIVITI_ADMIN"},
              };
      
              for (String[] user : usersGroupsAndRoles) {
                  List<String> authoritiesStrings = Arrays.asList(Arrays.copyOfRange(user, 2, user.length));
                  logger.info("> Registering new user: " + user[0] + " with the following Authorities[" + authoritiesStrings + "]");
                  inMemoryUserDetailsManager.createUser(new User(user[0], passwordEncoder().encode(user[1]),
                          authoritiesStrings.stream().map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList())));
              }
      
              return inMemoryUserDetailsManager;
          }
          @Bean
          public PasswordEncoder passwordEncoder() {
              return new BCryptPasswordEncoder();
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44

      查找并且拾取任务

      /**
       * 根据流程的key和候选人拾取任务
       * 由于是测试,所以返回单个任务。正常应该是列表展示所有候选任务,然后选择拾取。
       */
      @RequestMapping("claimTask")
      @ResponseBody
      public void claimTask() {
          String taskCandidateUser = "lisi";
          String id = "myLeave5";
          //根据流程的key和任务负责人 查询任务
          Task task = taskService.createTaskQuery()
              .processDefinitionKey(id)
              .taskCandidateUser(taskCandidateUser)
              .singleResult();
      
          if(task!=null){
              taskService.claim(task.getId(),taskCandidateUser);
          }
      }	
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19

      lisi处理任务

      /**
       * 根据流程的key和任务负责人 处理任务
       */
      @RequestMapping("solveTask")
      @ResponseBody
      public void solveTask() {
          String assignee = "lisi";
          String id = "myLeave5";
          //根据流程的key和任务负责人 查询任务
          Task task = taskService.createTaskQuery()
              .processDefinitionKey(id)
              .taskAssignee(assignee)
              .singleResult();
          //完成任务,跳到下一个流程
          taskService.complete(task.getId());
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
  • 相关阅读:
    redis数据类型
    从三个案例看数字化转型需求下存储架构的选择和应用
    Eureka注册中心
    全志V3S开发板驱动示例(linux demo驱动开发)
    【算法-动态规划】贝尔曼福特算法
    【Linux】进程控制 (万字详解)—— 进程创建 | 进程退出 | 进程等待 | 程序替换 | 实现简易shell
    基于MAX-10 FPGA 超声波测距模块HC_SR04
    搜索功能实现遇到的那些坑
    2023 年 42 周 - 学习 & 倦怠期回顾
    yum命令轻松升级到高版本gcc
  • 原文地址:https://blog.csdn.net/weixin_40496191/article/details/126142006