Activiti7_使用

Activiti7_使用


一、Activiti7

  1. 为了实现后端的咨询流转功能,学习Activiti7,记录下使用的过程及遇到的问题

二、绘制工作流

  1. 使用spring3的后端项目为基础,开发工具idea 2023.3.2,jdk,jdk17。
    点此链接link去idea官网下载插件Activiti BPMN,在idea的Settings里Plugins使用install plugin from disk把刚才的jar包导进去
  2. 在bpmn文件夹下创建bpmn文件:
    !
  3. 使用插件以画图形式编辑bpmn:

    主要使用了三种部件:开始、任务、结束

任务的内容填写如下,连线按住右上角的箭头拖拽到目标即可,里面的${user}表明设置为user的变量,一会可以在使用的时候绑定用户:

其中的分支路线我们直接使用两个互斥条件判断,不使用排他网关:

排他网关(也叫异或(XOR)网关,或叫基于数据的排他网关),用来在流程中实现决策。 当流程执行到这个网关,所有分支都会判断条件是否为 true,如果为 true 则执行该分支,注意,排他网关只会选择一个为 true 的分支执行。 (即使有两个分支条件都为 true, 排他网关也会只选择一条分支去执行)。如果从网关出去的线所有条件都不满足则系统抛出异常。说明 :经过排他网关必须要有一条且只有一条分支走。

bpmn文件绘制完成了,保存成同名png文件:

  1. 完整的bpmn代码如下:
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
  <process id="consult" name="consult" isExecutable="true">
    <startEvent id="sid-c41ecd07-74cd-41d5-9d7e-046bf71954c1"/>
    <userTask id="sid-7e47fd72-c056-43f6-8575-c229ff5b58b4" name="用户填写咨询表单" activiti:assignee="${user}">
      <documentation>用户填写咨询表单</documentation>
    </userTask>
    <userTask id="sid-03f0aec0-32b1-41e2-8826-5b8c73d51854" name="管理员指定业务人员" activiti:assignee="${admin}">
      <documentation>管理员指定业务人员</documentation>
    </userTask>
    <userTask id="sid-7b539102-6d65-479a-9958-5259a84c28b1" name="业务人员回复" activiti:assignee="${busPerson}">
      <documentation>业务人员回复</documentation>
    </userTask>
    <userTask id="sid-3af84618-4ba9-4686-a97f-6db4da96e916" name="管理员决定是否公示" activiti:assignee="${admin}">
      <documentation>管理员决定是否公示</documentation>
    </userTask>
    <endEvent id="sid-bd329163-e466-4ca7-bad1-9b95787e28a6"/>
    <sequenceFlow id="sid-c2da4d94-8eac-4acd-9cb0-16328237a136" sourceRef="sid-c41ecd07-74cd-41d5-9d7e-046bf71954c1" targetRef="sid-7e47fd72-c056-43f6-8575-c229ff5b58b4"/>
    <sequenceFlow id="sid-5be6635f-b5ef-4e0e-98af-1b35c6e085ae" sourceRef="sid-7e47fd72-c056-43f6-8575-c229ff5b58b4" targetRef="sid-03f0aec0-32b1-41e2-8826-5b8c73d51854"/>
    <sequenceFlow id="sid-5dc1e8b5-e2bc-45b7-b559-bffe2d3b5c24" sourceRef="sid-03f0aec0-32b1-41e2-8826-5b8c73d51854" targetRef="sid-7b539102-6d65-479a-9958-5259a84c28b1"/>
    <sequenceFlow id="sid-c3c3594c-d7d1-462f-b057-59b12dbeb190" sourceRef="sid-3af84618-4ba9-4686-a97f-6db4da96e916" targetRef="sid-bd329163-e466-4ca7-bad1-9b95787e28a6"/>
    <sequenceFlow id="sid-8a860827-e9ad-4c62-b931-939d312ddcd8" sourceRef="sid-7b539102-6d65-479a-9958-5259a84c28b1" targetRef="sid-03f0aec0-32b1-41e2-8826-5b8c73d51854">
      <conditionExpression>${evection.num&gt;1}</conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="sid-f4dc4277-d16a-415e-9cac-fe51d1c6ee65" sourceRef="sid-7b539102-6d65-479a-9958-5259a84c28b1" targetRef="sid-3af84618-4ba9-4686-a97f-6db4da96e916">
      <conditionExpression>${evection.num&lt;=1}</conditionExpression>
    </sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_consult">
    <bpmndi:BPMNPlane bpmnElement="consult" id="BPMNPlane_consult">
      <bpmndi:BPMNShape id="shape-b1791cfb-c3c9-42a9-9bd8-b7e0a8906f99" bpmnElement="sid-c41ecd07-74cd-41d5-9d7e-046bf71954c1">
        <omgdc:Bounds x="-15.0" y="-120.0" width="30.0" height="30.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-33324ea7-5905-4b2a-b615-2bfe666a0117" bpmnElement="sid-7e47fd72-c056-43f6-8575-c229ff5b58b4">
        <omgdc:Bounds x="-50.0" y="-60.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-955afe5f-f9b7-40f0-887f-70aeb5afc173" bpmnElement="sid-03f0aec0-32b1-41e2-8826-5b8c73d51854">
        <omgdc:Bounds x="-50.0" y="40.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-7a2e9e19-c268-4a46-af9c-aa6621dd9b86" bpmnElement="sid-7b539102-6d65-479a-9958-5259a84c28b1">
        <omgdc:Bounds x="-50.0" y="150.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-86aead71-8e5b-4de3-8d8c-ca5f0dcc63ea" bpmnElement="sid-3af84618-4ba9-4686-a97f-6db4da96e916">
        <omgdc:Bounds x="-50.0" y="255.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-1d13b250-9f5c-42db-a745-482b2c9acf56" bpmnElement="sid-bd329163-e466-4ca7-bad1-9b95787e28a6">
        <omgdc:Bounds x="-15.0" y="360.0" width="30.0" height="30.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-c60fd374-56ca-4630-9f88-c9d61baa048b" bpmnElement="sid-c2da4d94-8eac-4acd-9cb0-16328237a136">
        <omgdi:waypoint x="0.0" y="-90.0"/>
        <omgdi:waypoint x="0.0" y="-60.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="edge-4a1da47a-a9b5-4db2-a8a9-002220e5c52a" bpmnElement="sid-5be6635f-b5ef-4e0e-98af-1b35c6e085ae">
        <omgdi:waypoint x="0.0" y="20.0"/>
        <omgdi:waypoint x="0.0" y="40.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="edge-3d9c4ead-a6cd-4aa2-82c7-ad1f20171327" bpmnElement="sid-5dc1e8b5-e2bc-45b7-b559-bffe2d3b5c24">
        <omgdi:waypoint x="0.0" y="120.0"/>
        <omgdi:waypoint x="0.0" y="150.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="edge-2116f8bb-51a7-4c43-a48b-7c4954868724" bpmnElement="sid-c3c3594c-d7d1-462f-b057-59b12dbeb190">
        <omgdi:waypoint x="0.0" y="335.0"/>
        <omgdi:waypoint x="0.0" y="360.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="edge-ce0e6fc3-032f-4333-83ec-7807846b046f" bpmnElement="sid-8a860827-e9ad-4c62-b931-939d312ddcd8">
        <omgdi:waypoint x="-50.0" y="190.0"/>
        <omgdi:waypoint x="-125.0" y="135.0"/>
        <omgdi:waypoint x="-50.0" y="80.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="edge-87fa2036-1930-4551-bede-92f275696c68" bpmnElement="sid-f4dc4277-d16a-415e-9cac-fe51d1c6ee65">
        <omgdi:waypoint x="0.0" y="230.0"/>
        <omgdi:waypoint x="0.0" y="242.5"/>
        <omgdi:waypoint x="0.0" y="255.0"/>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

三、通过代码部署流程,再对流程进行实例化,完整运行一遍流程即可

需要序列化一个evection:

java 复制代码
package com.sumo.ipd;

import java.io.Serializable;

public class Evection implements Serializable {
    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    private int num;
}

在test里面创建ActivitiDemo类,内容:

java 复制代码
package com.sumo.ipd;

import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class ActivitiDemo {

    /**
     * 部署流程定义测试,查询,删除
     */
    @Test
    public void DeployTest() {
        // 1. 创建ProcessEngine流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2、得到RepositoryService实例
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3、使用RepositoryService进行部署,定义一个流程名字,把bpmn和png部署到数据库中
        Deployment deployment = repositoryService.createDeployment()    // 创建一个部署流程
                .name("咨询流程")                                    // 给部署流程命名
                .addClasspathResource("bpmn/consult.bpmn20.xml")        // 添加类路径下的资源文件
                .addClasspathResource("bpmn/consult.png")
                .deploy();                                                // 执行流程部署
        // 4、输出部署信息
        System.out.println("流程部署id:" + deployment.getId());
        System.out.println("流程部署名称:" + deployment.getName());
    }

    @Test
    public void queryProceccDefinition() {
        // 流程定义key
        String processDefinitionKey = "consult";
        // 创建ProcessEngine流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 查询流程定义
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        //遍历查询结果
        List<ProcessDefinition> list = processDefinitionQuery.processDefinitionKey(processDefinitionKey).orderByProcessDefinitionVersion().desc().list();
        for (ProcessDefinition processDefinition : list) {
            System.out.println("------------------------");
            System.out.println(" 流 程 部 署 id : " +processDefinition.getDeploymentId());
            System.out.println("流程定义id: " + processDefinition.getId());
            System.out.println("流程定义名称: " + processDefinition.getName());
            System.out.println("流程定义key: " + processDefinition.getKey());
            System.out.println("流程定义版本: " + processDefinition.getVersion());
        }
    }

    @Test
    public void deleteDeployment() {
        // 流程部署id
        String deploymentId = "47501";
        // 通过流程引擎获取repositoryService
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
//        删除启动的流程实例
        RuntimeService runtimeService = processEngine.getRuntimeService();
        runtimeService.deleteProcessInstance("50001","用户撤销");
                //删除流程定义, 如果该流程定义已有流程实例启动则删除时出错
        //repositoryService.deleteDeployment(deploymentId);
        //设置true 级联删除流程定义,即使该流程有流程实例启动也可以删除,设
        //置为false非级别删除方式,如果流程
        repositoryService.deleteDeployment(deploymentId, true);
    }




    /**
     * 启动流程实例
     */
    @Test
    public void startProcessTest() {
        //businessKey用于绑定外部任务表单的id
        String businessKey = "1";
        // 1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2、获取RunTimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();

        // 流程变量的map
        Map<String, Object> variables = new HashMap<>();


        // 设定任务的负责人
        variables.put("user", "523097198902120431");
        variables.put("admin", "123456");
        variables.put("busPerson", "123456789");

        Evection evection = new Evection();
        evection.setNum(3);
        // 把流程变量的pojo放入map
        variables.put("evection",evection);


        // 3、根据流程定义Id启动流程,并获取流程实例
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("consult", businessKey, variables);

        // 输出内容
        System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例id:" + processInstance.getId());
        System.out.println("当前活动Id:" + processInstance.getActivityId());
        System.out.println("businessKey==" + processInstance.getBusinessKey());
    }


    /**
     * 查询当前个人待执行的任务
     */
    public void findTaskListTest(String assignee) {
        // 1.创建流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取TaskService
        TaskService taskService = processEngine.getTaskService();
        // 3.根据流程key 和 任务负责人 查询任务
        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey("consult")        //流程Key
                .taskAssignee(assignee)                    //只查询当前任务负责人的任务
                .list();
        Task task = taskService.createTaskQuery()
//                .processInstanceId("15001")            //流程实例id
                .processDefinitionKey("consult")     //流程Key
                .taskAssignee(assignee)                 //只查询当前任务负责人的任务
                .singleResult();
        String processInstanceId = task.getProcessInstanceId();
        // 2、获取RunTimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        String businessKey = processInstance.getBusinessKey();

//        list.forEach(task -> {
            System.out.println("-----------------------------------------");
            System.out.println("流程实例id:" + task.getProcessInstanceId());
            System.out.println("任务id:" + task.getId());
            System.out.println("任务负责人:" + task.getAssignee());
            System.out.println("任务名称:" + task.getName());
            System.out.println("businessKey==" + businessKey);
//        });

        Evection eve = (Evection)taskService.getVariable(task.getId(), "evection");
        System.out.println(eve.getNum());
        System.out.println("获取流程变量成功");
    }


    /**
     * 完成个人代办任务及查询下一步
     */
    @Test
    public void completTaskTest() {
        findTaskListTest("523097198902120431");
        completTask("523097198902120431");

        findTaskListTest("123456");
        completTask2("123456");

        findTaskListTest("123456789");
        completTask("123456789");

        findTaskListTest("123456");
        completTask("123456");
    }

    /**
     * 普通的完成任务
     * @param assignee
     */
    public void completTask(String assignee) {
        // 1.创建流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2. 获取TaskService实例
        TaskService taskService = processEngine.getTaskService();
        // 3.根据流程key 和 任务的负责人 查询任务
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("consult")     //流程Key
                .taskAssignee(assignee)                 //只查询当前任务负责人的任务
                .singleResult();

        System.out.println("流程实例id:" + task.getProcessInstanceId());
        System.out.println("任务id:" + task.getId());
        System.out.println("任务负责人:" + task.getAssignee());
        System.out.println("任务名称:" + task.getName()+" 完成!");
        
        // 4.完成待办任务,参数:任务id
        taskService.complete(task.getId());
    }

    /**
     * 在完成任务时修改变量调整分支走向
     * @param assignee
     */
    public void completTask2(String assignee) {
        // 1.创建流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2. 获取TaskService实例
        TaskService taskService = processEngine.getTaskService();
        // 3.根据流程key 和 任务的负责人 查询任务
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("consult")     //流程Key
                .taskAssignee(assignee)                 //只查询当前任务负责人的任务
                .singleResult();

        System.out.println("流程实例id:" + task.getProcessInstanceId());
        System.out.println("任务id:" + task.getId());
        System.out.println("任务负责人:" + task.getAssignee());
        System.out.println("任务名称:" + task.getName()+" 完成!");

        // 流程变量的map
        Map<String, Object> variables = new HashMap<>();

        Evection evection = new Evection();
        evection.setNum(1);
        // 把流程变量的pojo放入map
        variables.put("evection",evection);
        // 4.完成待办任务,参数:任务id
        taskService.complete(task.getId(),variables);

    }


    /**
     * 如果一个流程中有多个任务,可以用list
     */
    @Test
    public void completeTask3() {
        // 获取引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取操作任务的服务 TaskService
        TaskService taskService = processEngine.getTaskService();
        // 完成 经理 '李四' 的任务
        List<Task> tasks = taskService.createTaskQuery()
                .processDefinitionKey("evection")
                .taskAssignee("李四")
                .list();  // 多个任务,用list

        for (Task task : tasks) {
            if (true) {
                // 判断是哪任务
                System.out.println("流程实例id=" + task.getProcessInstanceId());
                System.out.println("任务Id=" + task.getId());
                System.out.println("任务负责人=" + task.getAssignee());
                System.out.println("任务名称=" + task.getName());
                taskService.complete(task.getId());
            }
        }
    }
}

运行ActivitiDemo完整运行一遍流程:

1DeployTest部署流程

2startProcessTest启动流程实例

3completTaskTest运行一遍流程

四、在springbooot中使用

依赖会出现报错,需要修改pom.xml

  1. 使用log4j会和springboot本身的logback冲突,排除logback
xml 复制代码
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-logging</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>
  1. 已经有mybatis了,把不用的注释掉

  2. 排除slf4j-log4j12的log4j,避免和外面的log4j冲突

xml 复制代码
		<dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
            <exclusions><!-- 排除slf4j-log4j12的log4j,避免和外面的log4j冲突 -->
                <exclusion>
                    <artifactId>log4j</artifactId>
                    <groupId>log4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>
相关推荐
没书读了26 分钟前
ssm框架-spring-spring声明式事务
java·数据库·spring
小二·34 分钟前
java基础面试题笔记(基础篇)
java·笔记·python
开心工作室_kaic1 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
懒洋洋大魔王1 小时前
RocketMQ的使⽤
java·rocketmq·java-rocketmq
武子康1 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神2 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
qq_327342732 小时前
Java实现离线身份证号码OCR识别
java·开发语言
阿龟在奔跑3 小时前
引用类型的局部变量线程安全问题分析——以多线程对方法局部变量List类型对象实例的add、remove操作为例
java·jvm·安全·list
飞滕人生TYF3 小时前
m个数 生成n个数的所有组合 详解
java·递归
代码小鑫3 小时前
A043-基于Spring Boot的秒杀系统设计与实现
java·开发语言·数据库·spring boot·后端·spring·毕业设计