Activity7从入门到部署

1、Activity7-工作流

一、工作流解释

将带有类似审批的环节,控制审批做自动化处理

工作流的目标:减小业务与审批的耦合关系。当业务逻辑复杂的时候不同的角色权限又不同的审批流程。未使用工作流的业务,审批流程耦合是非常高的

二、BPMN-建模语言

定义业务流程模型和符号

三、activiti 使用步骤

1.部署activiti

  • 获取jar包

2.流程定义

  • 使用建模工具定义流程(.bpmn文件)

3.流程部署

  • 将定义好的流程内容,存储到数据库

4.流程实例

  • 流程实例:processInstance
  • 通俗来讲,也就是申请人发的一次起流程实例(this),比如张三发起的请假、李四发起的出差。各自都是流程实例。

5.待办任务(Task)

  • 用户可以查询当前流程的具体信息,具体任务等,使用接口获取,不用自己去数据库查找

6.处理任务

  • 通过activiti处理审批流程

四、activiti 环境

  • jdk 1.8及以上
  • Mysql 5.0 及以上
  • Tomcat 8.5 及以上

*[activiti流程定义工具插件在IDEA和Eclipse上都可以运行]

五、activiti 数据库

支持数据库版本

需要在数据库使用25张表

数据库版本
h21.3.168
mysql5.1.21
oracle12.2.0.1.0
postgres8.1
db2DB2 10.1
mssql2008 using sqljdbc4

六、activiti 配置

6.1-activiti7原生配置


配置activit的日志信息

log4j配置-非必要配置

# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x -
%m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
#指定文件存放位置
log4j.appender.LOGFILE.File=D:\act\activiti.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x -%m\n

注意事项

activiti 配置分为两只配

  • 默认配置方式–需要在resources文件夹下创建activiti.cfg.xml文件。源码固定了到此目录读取此文件
    • [听说activiti7已支持写入springboot的配置,也就是在application.yml中配置,此处我没有试过]

使用默认配置

6.1.1-默认配置
  1. 配置文件名固定为:activiti.cfg.xml

  2. 配置文件中bean对象也需要固定idclass

    • <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"/>
      
  3. Java中使用ProcessEngines创建生成表,或者调用servcie等等

    •     ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
      

activiti.cfg.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--  默认方式下bean的id固定为:processEngineConfiguration  -->
    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">

        <!--  配置数据库 -我使用的是mysql 8.0,如果初选 表不存在的的异常,则设置nullCatalogMeansCurrent=true   -->
        <property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://121.89.222.205:3306/activiti7?characterEncoding=UTF-8&amp;nullCatalogMeansCurrent=true&amp;useSSL=false" />
        <property name="jdbcUsername" value="root"/>
        <property name="jdbcPassword" value="wuhong"/>

        <!--  配置activiti数据库表的生成策略      -->

        <!--  表存在则直接使用,不存在则创建表      -->
        <property name="databaseSchemaUpdate"  value="true"/>
    </bean>

</beans>

配置好xml之后,直接调用getDefaultProcessEngine(),调用默认设置在数据库中生成表

    /*
     * 使用 Activiti的默认方式创建数据库表
     */
    @Test
    public void createDBTable(){

        /*
        1.使用Activiti的工具类,ProcessEngines.getDefaultProcessEngine()  --  .getDefault默认方法,使用默认配置,读取默认的固定配置文件 "activiti.cfg.xml"
        2.此方法会在数据库中创建 activiti的表
         */
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

一般配置

6.1.2-一般配置
  1. 配置文件名字可以自定义,可以通过java对象指定文件名字读取

  2. 通过流程引擎配置类ProcessEngineConfiguration

    •        ProcessEngineConfiguration processEngineConfiguration2 = ProcessEngineConfiguration
                      //读取配置文件名
                      .createProcessEngineConfigurationFromResource("activiti.cfg.xml");
            
              ProcessEngineConfiguration processEngineConfiguration2 = ProcessEngineConfiguration
                      //读取配置文件名,读取xml中配置类配置的bean-id,或者 bean-name
                      .createProcessEngineConfiidgurationFromResource("activiti.cfg.xml","processEngineConfiguration");
      

自定义的activit配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">


    <!-- 二、流程引擎配置   -->
    <!--  DBCP 数据库连接池配置  -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://121.89.222.205:3306/activiti7?characterEncoding=UTF-8&amp;nullCatalogMeansCurrent=true&amp;useSSL=false"/>
        <property name="username" value="root"/>
        <property name="password" value="wuhong"/>
        <property name="maxActive" value="3"/>
        <property name="maxIdle" value="1"/>
    </bean>

    <!--  流程引擎processEngine的配置类配置  -->
    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <property name="dataSource" ref="dataSource"/>
        <!--  activiti数据库表的生成策略,和默认一样      -->
        <property name="databaseSchemaUpdate"  value="true"/>
    </bean>
</beans>

七、activiti 表结构

  • activiti运行中需要用到25张表

表结构

  • ACT_GE: = general 表示通用,普通的数据。各种情况都需要用到
  • ACT_HI: = history 表示历史记录的表
  • ACT_RE: = Repository(仓库),这些表中保存一些‘静态’信息,如流程定义和流程资源(如图片、规则等)
  • ACT_RU: = runtime 运行是需要用到的表

image-20220424130213825

表分类表名解释
一般数据
[ACT_GE_BYTEARRAY]通用的流程定义和流程资源
[ACT_GE_PROPERTY]系统相关属性
流程历史记录
[ACT_HI_ACTINST]历史的流程实例
[ACT_HI_ATTACHMENT]历史的流程附件
[ACT_HI_COMMENT]历史的说明性信息
[ACT_HI_DETAIL]历史的流程运行中的细节信息
[ACT_HI_IDENTITYLINK]历史的流程运行过程中用户关系
[ACT_HI_PROCINST]历史的流程实例
[ACT_HI_TASKINST]历史的任务实例
[ACT_HI_VARINST]历史的流程运行中的变量信息
流程定义表
[ACT_RE_DEPLOYMENT]部署单元信息
[ACT_RE_MODEL]模型信息
[ACT_RE_PROCDEF]已部署的流程实例
运行实例表
[ACT_RU_EVENT_SUBSCR]运行时事件
[ACT_RU_EXECUTION]运行时流程执行实例
[ACT_RU_IDENTITYLINK]运行时用户关系信息,存储任务节点与参与者的相关信息
[ACT_RU_JOB]运行时作业
[ACT_RU_TASK]运行时任务
[ACT_RU_VARIABLE]运行时变量表

八、activiti 类关系

image-20220424135710469

  1. processEngineConfiguration对象获取配置信息
  2. processEngineConfiguration对象可以得到ProcessEngine
  3. ProcessEngine可以获取各种Activiti操作DAO的service
  4. 例如RepositoryService可以操作和 act_re***相关的表,处理和部署有关的工作流业务
  5. 例如RuntimeService就可以操作和运行时的一些工作流业务信息
  6. 其他service作用类似

九、activiti Service

service名称service作用
RepositoryServiceactiviti的资源管理类
RuntimeServiceactiviti的流程运行管理类
TaskServiceactiviti的任务管理类
HistoryServiceactiviti的历史管理类
ManagerServiceactiviti的引擎管理类

十、BPMN-流程设计器

  1. 使用工具或插件,画出BPMN建模语言的流程图
  2. 加载流程文件部署到数据库
  3. 可以导出流程图作为png的图片显示

插件下载

  • 插件网站可以下载Activit BPMN visualizer

  • 也安装camunda-modeler工具实现流程设计

  • 链接: https://pan.baidu.com/s/12l6GylwK16iXlviCFid-OA 提取码: c36m

需要设置中加载工具,可参考网络搜索结果,

image-20220426174235770

image-20220426174245698

导出流程图

  • 右键文件–>Digrames --> show XXX信息

image-20220426120233025

image-20220426120331406

注意:

使用camunda的流程设计器,设计activit的流程图的话,需要修改xml

  • 流程图中设置assignee:负责人时,使用camunda使用uel表达式,设置为生成文件后直接部署,流程中,数据库表读取不到assigne。
  • 数据库读不到你传入值
  • 需要改xml文件

image-20220510174443840

image-20220511102550928

camunda头部信息改为一下设置

<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"
                   xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
                   xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
                   xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
                   xmlns:activiti="http://activiti.org/bpmn"
                   id="sample-diagram"
                   targetNamespace="http://bpmn.io/schema/bpmn"
                   xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">

十、流程部署

将画好的流程图文件通过api部署

此处为原生部署方式:


  • 将画好的流程图通过目录读取到数据库中
        //1.获取配置类processEngineConfiguration
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration
                .createProcessEngineConfigurationFromResource("activiti.cfg.xml","processEngineConfiguration");

        //2.获取配置类processEngine工作流引擎
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();

        //3.获取配资源部署类的相关service -[ Repository ]
        RepositoryService repositoryService = processEngine.getRepositoryService();

        //4.创建流程部署
        DeploymentBuilder builder = repositoryService.createDeployment();
        builder.name("出差申请流程");
        builder.addClasspathResource("bpmn/evection.bpmn20.xml");
        builder.addClasspathResource("bpmn/evection.png");

        Deployment deployment = builder.deploy();
  • 还可以将多个流程图打包为Zip文件,进行批量部署
    /**
     * 使用Zip打包 部署资源
     * [之前单独添加的一个资源文件,现在将多个bpmn打包文件通过zip打包]
     */
    @Test
    public void deployProcessByZip(){

        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();

        InputStream inputStream =this.
                getClass().         //获取类的信息
                getClassLoader().   //获取整个工程的信息
                getResourceAsStream("bpmn/newAct.zip"); //读取打包了的文件


        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        Deployment deploy = repositoryService.createDeployment()
                .addZipInputStream(zipInputStream)
                .deploy();

        System.out.println("部署信息:"+deploy);
        System.out.println("流程name:"+deploy.getName());

        //        部署信息:DeploymentEntity[id=1, name=null]
        //        流程name:null
    }

十一、流程下载

  1. 流程资源部署后,在数据库中以**BLOB(longblob)**二进制方式存储
  2. 下载流程可以通过repositoryService实现、或者是自定义操作表的下载

一、使用Activiti服务下载

  • 通过repositoryService服务实现下载
  • IOUtils是来着 commons-io的包
    /**
     * 下载资源文件
     */
    @Test
    public void downRepository() throws Exception {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
        
        ProcessDefinition evection = repositoryService.createProcessDefinitionQuery().processDefinitionKey("evection").singleResult();


        String deploymentId = evection.getDeploymentId();
        String diagramImageName = evection.getDiagramResourceName();
        String resourceName = evection.getResourceName();

        InputStream inIoImage =repositoryService.getResourceAsStream(deploymentId, diagramImageName);
        InputStream inIoBPMN = repositoryService.getResourceAsStream(deploymentId, resourceName);


        FileOutputStream fileBpmn = new FileOutputStream(new File("D:\\IDEA-workspace\\private\\Learning_test\\Activti7\\evection.bpmn"));
        FileOutputStream filePng = new FileOutputStream(new File("D:\\IDEA-workspace\\private\\Learning_test\\Activti7\\evection.png"));

        IOUtils.copy(inIoImage, filePng);
        IOUtils.copy(inIoBPMN, fileBpmn);

        inIoBPMN.close();
        inIoImage.close();
        fileBpmn.close();
        filePng.close();

    }

二、通过操作表,自定义实现下载

  • 需要读取数据库中的byte字节数据,实现数据转换、文件下载
public class ActivitiDemo {

    //测试部署
    @Test
    public void testDeeploment() {

        //1.获取配置类processEngineConfiguration
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration
                .createProcessEngineConfigurationFromResource("activiti.cfg.xml", "processEngineConfiguration");

        //2.获取配置类processEngine工作流引擎
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();

        //3.获取配资源部署类的相关service -[ Repository ]
        RepositoryService repositoryService = processEngine.getRepositoryService();

        //4.创建流程部署
        DeploymentBuilder builder = repositoryService.createDeployment();
        builder.name("出差申请流程");
        builder.addClasspathResource("bpmn/evection.bpmn20.xml");
        builder.addClasspathResource("bpmn/evection.png");

        Deployment deployment = builder.deploy();
        System.out.println("流程部署id=" + deployment.getId());
        System.out.println("流程部署name=" + deployment.getName());

    }

    /**
     * 开启流程:
     */
    @Test
    public void testRuntimeDemo() {

        //采用默认方式获取工作流引擎
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();

        RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
        ProcessInstance evection = runtimeService.startProcessInstanceByKey("evection");

        System.out.println("流程定义ID=" + evection.getProcessDefinitionId());
        System.out.println("流程实例ID=" + evection.getId());
        System.out.println("当前活动ID=" + evection.getActivityId());

    }


    /**
     * 查询个人待执行的任务
     */
    @Test
    public void testFindPersonalTaskList() {
        //1.获取引擎
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        //2.获取taskService
        TaskService taskService = defaultProcessEngine.getTaskService();
        //3.根据key查询任务
        List<Task> list = taskService.
                createTaskQuery().//创建查询
                processDefinitionKey("evection").//流程实例的key
                taskAssignee("张三").//要查询的负责人
                list();

        for (Task task : list) {
            System.out.println("实例-id" + task.getProcessInstanceId());
            System.out.println("任务-id" + task.getId());
            System.out.println("任务当前负责人信息" + task.getAssignee());
            System.out.println("任务名字" + task.getName());
        }

    }

    /**
     * 查询个人待执行的任务
     */
    @Test
    public void compeletTask() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = defaultProcessEngine.getTaskService();
        taskService.complete("5005");
    }


    @Test
    public void taskBy李四() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = defaultProcessEngine.getTaskService();
        //获取李四对应的任务
        Task task = taskService.createTaskQuery().processDefinitionKey("evection").taskAssignee("李四").singleResult();
        System.out.println(task);
        taskService.complete(task.getId());
    }

    @Test
    public void taskBy王五() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = defaultProcessEngine.getTaskService();
        //获取王五 对应的任务
        Task task = taskService.createTaskQuery().processDefinitionKey("evection").taskAssignee("王五").singleResult();
        System.out.println(task);
        taskService.complete(task.getId());
    }

    @Test
    public void taskBy赵六() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = defaultProcessEngine.getTaskService();
        //获取赵六 对应的任务
        Task task = taskService.createTaskQuery().processDefinitionKey("evection").taskAssignee("赵六").singleResult();
        System.out.println(task);
        taskService.complete(task.getId());
    }


}

十二、流程删除

  • 使用repositoryService服务进行流程删除
  • 删除流程需要删除re相关的表和通用表中的资源信息(act_ge_bytearray)
  • 流程部署且被开启的情况下,需要强制删除部署的话,需要使用级联删除
    /**
     * 删除已经部署的流程
     */
    @Test
     public void deleteProcess(){
         ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
         RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();

         //通过部署id删除部署
         repositoryService.deleteDeployment("1");
         
         //使用True,开启级联删除
        repositoryService.deleteDeployment("2501",true);
     }

十三、流程启动

步骤解析

  1. 部署流程,BPMN流程图画好后传到数据库,存入到 act_re_procdef(流程部署实例表)
  2. 开始流程,调用RuntimeService开启流程,通过部署实例的信息,在数据库 *act_ru_ **开头的表中操作任务(Task)的流程
  3. 结束流程,结束流程之后,与之相关runtime的表中的信息将会删除,完整的流程信息保存到Histroy表中
public class ActivitiDemo {

    //测试部署
    @Test
    public void testDeeploment() {

        //1.获取配置类processEngineConfiguration
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration
                .createProcessEngineConfigurationFromResource("activiti.cfg.xml", "processEngineConfiguration");

        //2.获取配置类processEngine工作流引擎
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();

        //3.获取配资源部署类的相关service -[ Repository ]
        RepositoryService repositoryService = processEngine.getRepositoryService();

        //4.创建流程部署
        DeploymentBuilder builder = repositoryService.createDeployment();
        builder.name("出差申请流程");
        builder.addClasspathResource("bpmn/evection.bpmn20.xml");
        builder.addClasspathResource("bpmn/evection.png");

        Deployment deployment = builder.deploy();
        System.out.println("流程部署id=" + deployment.getId());
        System.out.println("流程部署name=" + deployment.getName());

    }

    /**
     * 开启流程:
     */
    @Test
    public void testRuntimeDemo() {

        //采用默认方式获取工作流引擎
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();

        RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
        ProcessInstance evection = runtimeService.startProcessInstanceByKey("evection");

        System.out.println("流程定义ID=" + evection.getProcessDefinitionId());
        System.out.println("流程实例ID=" + evection.getId());
        System.out.println("当前活动ID=" + evection.getActivityId());

    }


    /**
     * 查询个人待执行的任务
     */
    @Test
    public void testFindPersonalTaskList() {
        //1.获取引擎
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        //2.获取taskService
        TaskService taskService = defaultProcessEngine.getTaskService();
        //3.根据key查询任务
        List<Task> list = taskService.
                createTaskQuery().//创建查询
                processDefinitionKey("evection").//流程实例的key
                taskAssignee("张三").//要查询的负责人
                list();

        for (Task task : list) {
            System.out.println("实例-id" + task.getProcessInstanceId());
            System.out.println("任务-id" + task.getId());
            System.out.println("任务当前负责人信息" + task.getAssignee());
            System.out.println("任务名字" + task.getName());
        }

    }

    /**
     * 查询个人待执行的任务
     */
    @Test
    public void compeletTask() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = defaultProcessEngine.getTaskService();
        taskService.complete("5005");
    }


    @Test
    public void taskBy李四() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = defaultProcessEngine.getTaskService();
        //获取李四对应的任务
        Task task = taskService.createTaskQuery().processDefinitionKey("evection").taskAssignee("李四").singleResult();
        System.out.println(task);
        taskService.complete(task.getId());
    }

    @Test
    public void taskBy王五() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = defaultProcessEngine.getTaskService();
        //获取王五 对应的任务
        Task task = taskService.createTaskQuery().processDefinitionKey("evection").taskAssignee("王五").singleResult();
        System.out.println(task);
        taskService.complete(task.getId());
    }

    @Test
    public void taskBy赵六() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = defaultProcessEngine.getTaskService();
        //获取赵六 对应的任务
        Task task = taskService.createTaskQuery().processDefinitionKey("evection").taskAssignee("赵六").singleResult();
        System.out.println(task);
        taskService.complete(task.getId());
    }


}

十四、流程与业务关联

实现步骤

Activiti流程运行时操作的都是数据库中 Runtime相关的表,实现思想就是将业务逻辑中代笔审批一个key,加入到Activiti的表中

  1. act_ru_execution(运行流程实例表)中的 **BUSINESS_KEY_**字段,作为添加的业务字段
    /*
        1.添加业务中id到Activiti的表中
     */
    @Test
    public void test1(){

        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
        //参数1:流程实例key,    参数2:BusinessKey 代笔业务的id
        //假设这里 “UUID1001”代表是一个人员发起的某种审批申请
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("evection", "UUID1001");
        
    }

十五、流程挂起、激活

原因解释

为了应对不同的应用场景,类似于公司内部举行盘点、月末最后一天不接收审批等特殊场景下,工作流存在挂起、激活的转台,表示此时的流程状态为特殊状态,不能继续往下处理流程

  • 注意区别单个流程挂起和多个流程挂起的区别

操作代码

挂起、激活所有同类型的流程

    /*
       批量流程挂起、流程激活
     */
    @Test
    public void test2() {
        /**
         * 1.查询流程信息--当需要操作多个运行中的流程实例时,从流程定义的id中获取信息,比一个一个的获取流程运行实例更高效
         * 2.获取当前的信息是被挂起、或是激活转状态
         * 3.根据业务需求对不同状态的流程做操作
         * 单词--Suspended:暂停、activate:激活
         */
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();

        //获取流程的查询对象
        ProcessDefinition evection = repositoryService.createProcessDefinitionQuery().processDefinitionKey("evection").singleResult();

        //是否是挂起状态
        boolean suspended = evection.isSuspended();

        //如果是挂起,就激活、否则就挂起
        if (suspended) {
            //激活操作
            //参数1:流程Id、参数2:是否激活、参数3:时间(可以传null)
            repositoryService.activateProcessDefinitionById(evection.getId(), true, null);
        } else {
            //挂起操作
            //参数1:流程Id、参数2:是否挂起、参数3:时间(可以传null)
            repositoryService.suspendProcessDefinitionById(evection.getId(), true, null);
        }
    }

挂起、激活某一单独的流程

    /*
       单个实例挂起、激活操作
     */
    @Test
    public void test3() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
		//从数据库中取值的流程实例id -22501
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId("22501").singleResult();
        System.out.println(processInstance.toString());

        if (processInstance.isSuspended()){
            runtimeService.activateProcessInstanceById("22501");
        }else {

            runtimeService.suspendProcessInstanceById("22501");
        }
        System.out.println(runtimeService.createProcessInstanceQuery().processInstanceId("22501").toString());
    }

操作原理

  • 调用暂停(挂起)、激活状态,需要传入流程实例id。可以是部署流程实例,可以挂起此流程(比如部署的请假流程)的所有运行流程实例(张三、李四的请假流程)都可以同时挂起。当然也可以通过具体的某流程挂起
  • 数据库中,suspension_status字段。激活状态 suspension_status =1,暂停挂起状态==suspension_status=2==
    • act_re_procedf:流程实例定义信息表中,有suspension_status字段。
    • act_ru_execution:运行中流程实例表中,有suspension_status字段。
    • act_ru_task:任务表中,有suspension_status字段。

2、BPMN-流程设计

一、BPMN-表达式

  • Activiti 使用 UEL 表达式UEL-value 和 UEL-method

  • **UEL叫做统一表达式语言,${}在括号可以填入变量、支持逻辑运行[ ==,!=]等 **

  • 表达式支持解析基础类型、 bean、 list、 array 和 map,也可作为条件判断。如:${order.price > 100 && order.price < 250}

使用方式

在流程图设计中,可以使用表达式传入 Assignee(审核人UserTask信息)字段值,从此达到动态传值的目标,而不是写入固定的值

image-20220427102700644

在项目中使用将表达式内容通过Map集合传入

    /*
        测试uel表达式
     */
    @Test
    public void test1(){

        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();

        Map<String,Object> assigneeMap = new HashMap<>();

        assigneeMap.put("account1", "小李");
        assigneeMap.put("account2", "张经理");
        assigneeMap.put("account3", "赵总经理");
        assigneeMap.put("account4", "财务审批");
       runtimeService.startProcessInstanceByKey("newEvection",assigneeMap );
    }

表达式是支持动态设置

  1. 流程图中设置好表达式逻辑

image-20220510152748128

image-20220510152803598

  1. 在程序中添加变量设置,以map方式添加表达式实例
  2. 可以在startProcess开启任务时、complete完成一个审批时、run运行时setVariable设置变量对象
     Map<String, Object> map = new HashMap<>();
        Student student = new Student();
        student.setDays(5);
        student.setName("张三");
        map.put("student", student);
		

        runtimeService.startProcessInstanceByKey("studentProcess", map);//启动时
        taskService.complete(task.getId(),map);//完成其中一个审批时
 		runtimeService.setVariable(task.getId(),"student",map);//运行状态时

注意事项

由于使用了表达式分配,必须保证在任务执行过程表达式执行成功,比如:
某个任务使用了表达式${order.price > 100 && order.price < 250},当执行该任务时必须保证 order 在
流程变量中存在,否则 activiti 异常。

  1. 流程图中表达式变量名不存在会报错
  2. 流程图中表达式变量值为NULL,流程流程会结束
  3. 表达式都不符合条件,流程结束
  4. 表达式联系不设置条件,两个都走

二、BPMN-监听器

  • 使用监听器指定负责人,在流程设计中就不需要指定Assignee

  • 监听器中可以设置事件(Event)、类型(Type)、类(class)等等属性

Event

表示触发事件

事件类型事件含义
Create任务创建后触发
Assignment任务分配后触发
Delete任务完成后触发
All所有事件发生都触发
complete任务完成后触发
update任务更新后触发
timeout任务超时后触发

设置好监听器的监听类型,在以上或如图的步骤时,会触发监听器

image-20220510151431153

Type

触发的类型

我这里使用的camundar-modeler设计器

表示监听器的类型

image-20220510151815863

class

class表示监听器实现类的地址:项目相对位置:*com.wuhong.listn.ActivitiListnener.写入到流程图中

image-20220510152125842

image-20220510151617915

public class ActivitiListnener implements TaskListener { //实现接口 - TaskListener


    @Override
    public void notify(DelegateTask delegateTask) {

        String taskName = delegateTask.getName();//任务名字
        String eventName = delegateTask.getEventName();//事件名字

        //根据业务要求,实现监听需求
        if (taskName.equals("经理审批") && "create".equals(eventName)) {
            delegateTask.setAssignee("张三");
        }
    }
}

三、组任务

一个环节可以同时设置多个审批人

image-20220510160026417

a、查询组任务

指定候选人,查询该候选人当前的待办任务。

候选人不能立即办理任务。

Task task = taskService.createTaskQuery().processDefinitionKey("studentProcess4").taskCandidateUser("王五").singleResult();

b、拾取(claim)任务

该组任务的所有候选人都能拾取。

将候选人的组任务,变成个人任务。原来候选人就变成了该任务的负责人。

如果拾取后不想办理该任务?

      //王五拾取任务
     taskService.claim(task.getId(),"王五");

c、查询个人任务

查询方式同个人任务部分,根据assignee查询用户负责的个人任务。

拾取前

image-20220510163247937

拾取后

image-20220510163259034

d、办理个人任务
拾取后做相关的流程操作

e、归还个人任务

    //组任务--归还任务
    @Test
    public void test10() {

        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = defaultProcessEngine.getTaskService();

        //候选人拾取后已经变成负责人了,所以要用taskAssignee 去查

        Task task = taskService.createTaskQuery().processDefinitionKey("studentProcess4").taskAssignee("王五").singleResult();

        //归还任务
        taskService.unclaim(task.getId());
    }

四、BPMN-网关

排他网关ExclusiveGateway

  • 注意:排他网关只会选择一个为true的分支执行。如果有两个分支条件都为true,排他网关会选择id值较小的一条分支去执行。

并行网关ParallelGateway

  • 会签

image-20220510165559185

网关必须一前一后,经前面的网关进入后,所有的UsertTask执行任务,才会汇聚到右边的网关

l fork分支:

并行后的所有外出顺序流,为每个顺序流都创建一个并发分支。

l join汇聚:

所有到达并行网关,在此等待的进入分支, 直到所有进入顺序流的分支都到达以后, 流程就会通过汇聚网关。

包含网关InclusiveGateway

可以认为是排他网关和并行网关的结合

image-20220510171111484

事件网关EventGateway

bibil黑马的视频学习这里居然没有了,就懒得看了。看整合的话可以搜一下别人的解决方案,黑马的整合包含了SpringSecurity的配置

  • 7
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值