我们今天分享activiti 集成 springBoot 配置入门使用,入门是关键 也是我们成为大牛的必经之路,废话少说,上:

一、配置启动初始化

1、pom文件引入

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter</artifactId>
            <version>7.1.0.M6</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

2、数据库配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver #mysql 8.XX版本额驱动
    url: jdbc:mysql://16.2.8.1:3306/activiti?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT&nullCatalogMeansCurrent=true
    username: root
    password: 't6n?_'
  activiti:
    check-process-definitions: true #自动检查、部署流程定义文件
    #1.flase:默认值。activiti在启动时,对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常
    #2.true: activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建
    #3.create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)
    #4.drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)
    database-schema-update: true
    #activiti7默认不生成历史信息表,开启历史表
    db-history-used: true
    #记录历史等级 可配置的历史级别有none, activity, audit, full
    #none:不保存任何的历史数据,因此,在流程执行过程中,这是最高效的。
    #activity:级别高于none,保存流程实例与流程行为,其他数据不保存。
    #audit:除activity级别会保存的数据外,还会保存全部的流程任务及其属性。audit为history的默认值。
    #full:保存历史数据的最高级别,除了会保存audit级别的数据外,还会保存其他全部流程相关的细节数据,包括一些流程参数等。
    history-level: full

注意:如果配置的是8以上版本驱动,而你的数据库是5.7 ,你需要在数据库连接后面加上:


&nullCatalogMeansCurrent=true


如果不加可能报错:

Cause: java.sql.SQLSyntaxErrorException: Table ‘myactiviti.act_ge_property‘ doesn‘t exist

原因:

因为mysql使用schema标识库名而不是catalog,因此mysql会扫描所有的库来找表,如果其他库中有相同名称的表,activiti就以为找到了,本质上这个表在当前数据库中并不存在。
设置nullCatalogMeansCurrent=true,表示mysql默认当前数据库操作,在mysql-connector-java 5版本该参数默认为true,6版本以上默认为false,因此8版本驱动需要设置nullCatalogMeansCurrent=true。
 

3、bpmn 文件生成

先简单参考,此处仅贴出业务工作流图:

java spring activiti工作流 activiti整合springboot_mysql

4、服务启动初始化脚本25张表

@SpringBootApplication
public class ActivitiApplication {
    public static void main(String[] args) {
        SpringApplication.run(ActivitiApplication.class,args);
    }
}

结果如下图:

java spring activiti工作流 activiti整合springboot_java_02

 服务启动后、整个部署过程操作了四张数据表:

act_ge_bytearray  流程资源表 ,每个流程定义对应两个资源记录,bpmn和png。
	act_ge_property   参数配置表
	act_re_deployment 流程定义部署表,每部署一次增加一条记录
    act_re_procdef    流程定义表,部署每个新的流程定义都会在这张表中增加一条记录。记录中的key就是流程定义中最为重要的字段。

验证下面流程! 

二、测试验证流程

1、 启动工作流

@Test
    public void testStart(){
        ProcessInstance processInstance = runtimeService
                .startProcessInstanceByKey("myTestAct");
        System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例id:" + processInstance.getId());
        System.out.println("当前活动Id:" + processInstance.getActivityId());
    }

执行结果打印日志:

流程定义id:myTestAct:1:f4294519-c318-11ed-bd79-9a473ddfa0cf
流程实例id:79156f70-c319-11ed-9c09-9a473ddfa0cf
当前活动Id:null

此次操作涉及到几张日志表:

act_hi_actinst 流程实例执行历史
act_hi_identitylink 流程的参与用户历史信息
act_hi_procinst 流程实例历史信息
act_hi_taskinst 流程任务历史信息
act_ru_execution 流程执行信息
act_ru_identitylink 流程的参与用户信息
act_ru_task 任务信息

  2、查询当前人待执行的任务

@Test
    public void testFindPersonalTasks() {
//        任务负责人
        String assignee = "appler";
       // String assignee = "leader";
//        根据流程key 和 任务负责人 查询任务
        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey("myTestAct") //流程Key
                .taskAssignee(assignee)//只查询该任务负责人的任务
                .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());
        }
    }

查询结果日志:

流程实例id:79156f70-c319-11ed-9c09-9a473ddfa0cf
任务id:791a5174-c319-11ed-9c09-9a473ddfa0cf
任务负责人:appler
任务名称:请假申请

注意:工作流启动后,首先只有appler下会有任务(如上),如果此时你查leader、hrbp 下面是没有任务的;只有appler下的任务执行完成之后,流程才进入到leader下面;同理leader下的任务执行之后,会流到hrbp下面,这就是工作流的精髓所在!

3、提交完成任务

@Test
    public void testCompletTask(){
        /**
         * 根据流程key 和 任务的负责人 查询任务
         * 返回一个任务对象
         */
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("myTestAct") //流程Key
                .taskAssignee("appler")  //要查询的负责人
                .singleResult();
        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());//提交完成任务,参数:任务id
    }

执行后日志

流程实例id:79156f70-c319-11ed-9c09-9a473ddfa0cf
任务id:791a5174-c319-11ed-9c09-9a473ddfa0cf
任务负责人:appler
任务名称:请假申请

 注意:此时appler 提交执行完了,就可以查询并提交leader下面的任务了!

4、查询出当前所有的流程定义

@Test
    public void testQueryDefinition(){
        //得到ProcessDefinitionQuery 对象
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        //条件:processDefinitionKey =myTestAct
        List<ProcessDefinition> definitionList = processDefinitionQuery.processDefinitionKey("myTestAct")
                .orderByProcessDefinitionVersion()//orderByProcessDefinitionVersion 按照版本排序
                .desc()//desc倒叙
                .list();//返回集合
        for (ProcessDefinition processDefinition : definitionList) { //输出流程定义信息
            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());
        }
    }

结果日志

流程定义 id=myTestAct:1:f4294519-c318-11ed-bd79-9a473ddfa0cf
流程定义 name=员工请假审批流程
流程定义 key=myTestAct
流程定义 Version=1
流程部署ID =f40d7fb6-c318-11ed-bd79-9a473ddfa0cf

 此时只有一个流程正在执行,正常情况在可能有多个流程同时执行!

5、查询某个流程实例状态

@Test
    public void testQueryProcess() {
        String processDefinitionKey = "myTestAct";
        List<ProcessInstance> list = runtimeService
                .createProcessInstanceQuery()
                .processDefinitionKey(processDefinitionKey)//
                .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());
        }
    }

结果日志

流程实例id:79156f70-c319-11ed-9c09-9a473ddfa0cf
所属流程定义id:myTestAct:1:f4294519-c318-11ed-bd79-9a473ddfa0cf
是否执行完成:false
是否暂停:false
当前活动标识:null
业务关键字:null

 6、删除某个流程记录

@Test
    public void testDeleteDeployment() {
        // 流程部署id
        String deploymentId = "70302f48-c2f7-11ed-9448-9a473ddfa0cf";
        //删除流程定义,如果该流程定义已有流程实例启动则删除时出错
        repositoryService.deleteDeployment(deploymentId);
        //设置true 级联删除流程定义,即使该流程有流程实例启动也可以删除,设置为false非级别删除方式,如果流程
        //repositoryService.deleteDeployment(deploymentId, true);
    }

对应 act_re_deployment 张表里的数据,可以查询看看。 

注意:
1)、这里只删除了流程定义,不会删除历史表信息
2)、删除任务时,可以选择传入一个boolean型的变量cascade ,表示是否级联删除。默认是false,表示普通删除。如果该流程下存在已经运行的流程,使用普通删除会报错,而级联删除可以将流程及相关记录全部删除。删除没有完成的流程节点后,就可以完全删除流程定义信息了。项目开发中,级联删除操作一般只开放给超级管理员使用。

7、查看历史信息(已经结束的流程)

@Test
    public void testFindHistory(){
        //获取 actinst表的查询对象
        HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
        //查询 actinst表,条件:根据 InstanceId 查询,查询一个流程的所有历史信息
        instanceQuery.processInstanceId("79156f70-c319-11ed-9c09-9a473ddfa0cf");
        // .activityType("serviceTask")
         instanceQuery.finished();
        //查询 actinst表,条件:根据 DefinitionId 查询,查询一种流程的所有历史信息
        //增加排序操作,orderByHistoricActivityInstanceStartTime 根据开始时间排序 asc 升序
        instanceQuery.orderByHistoricActivityInstanceStartTime().asc();
        //查询所有内容
        List<HistoricActivityInstance> activityInstanceList = instanceQuery.list();
        for (HistoricActivityInstance hi : activityInstanceList) {
            System.out.println(hi.getActivityId());
            System.out.println(hi.getActivityName());
            System.out.println(hi.getProcessDefinitionId());
            System.out.println(hi.getProcessInstanceId());
        }
    }

结果日志

_2
StartEvent
myTestAct:1:f4294519-c318-11ed-bd79-9a473ddfa0cf
79156f70-c319-11ed-9c09-9a473ddfa0cf
_3
请假申请
myTestAct:1:f4294519-c318-11ed-bd79-9a473ddfa0cf
79156f70-c319-11ed-9c09-9a473ddfa0cf
_4
总监审批
myTestAct:1:f4294519-c318-11ed-bd79-9a473ddfa0cf
79156f70-c319-11ed-9c09-9a473ddfa0cf
_5
人事审批
myTestAct:1:f4294519-c318-11ed-bd79-9a473ddfa0cf
79156f70-c319-11ed-9c09-9a473ddfa0cf
_6
EndEvent
myTestAct:1:f4294519-c318-11ed-bd79-9a473ddfa0cf
79156f70-c319-11ed-9c09-9a473ddfa0cf

注意:
1)、关于流程历史信息,要注意,在删除流程时,如果是采取级联删除的方式,那这个历史信息也会随着一起删除。而普通删除方式不会删除历史信息。
2)、历史信息有不同的种类,具体可以通过historyService构建不同类型的Query对象来获取结果。 

到此、初级操作分享完成,后期我们分享其高级功能,敬请期待!