SpringBoot集成Activiti

SpringBoot集成Activiti

首先创建springboot项目,可以直接在IDEA上File -> New -> Project -> Spring Initializr -> Next 即可创建简单的springboot项目。

项目前提:

  • Jdk1.8
  • Mysql5.7+
  • Maven3.6+
项目需引入的依赖
   		<dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-spring-boot-starter-basicartifactId>
            <version>6.0.0version>
        dependency>
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>8.0.25version>
            <scope>runtimescope>
        dependency>

      <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>fastjsonartifactId>
            <version>1.2.44version>
        dependency>

配置application.yml 文件

server:
  port: 8888

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/activiti_test?useSSL=true
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: welcome123
  activiti:
    database-schema-update: true
    database-schema: activiti_test
    history-level: full
    db-history-used: true  # 检查历史表是否存在
    db-identity-used: false # 检查身份信息表是否存在
    check-process-definitions: false # 自动部署验证设置:true-开启(默认)、false-关闭

database-schema-update 分为 4 种

flase: 默认值。activiti在启动时,会对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常。(生产环境常用)
true: activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建。(开发时常用)
create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)。(单元测试常用)
drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)。


activiti的历史记录级别分为以下四种:none, activity, audit, full,级别分别由低到高能够显示不同的日志级别信息:

none: 不记录历史流程,性能高,流程结束后不可读取

activity: 归档流程实例和活动实例,流程变量不同步

audit: 默认值,在activiti基础上同步变量值,保存表单属性

full: 性能较差,记录所有实例和变量细节变化,最完整的历史记录,如果需要日后跟踪详细可以开启full(一般不建议开启)

编写单元测试验证

创建bpmn文件 MyProcess.bpmn20.xml

<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/test">
  <process id="myProcess" name="My process" isExecutable="true">
    <startEvent id="startevent1" name="Start">startEvent>
    <userTask id="s1" name="提交请假申请">userTask>
    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="s1">sequenceFlow>
    <userTask id="s2" name="领导审批" activiti:assignee="boss">userTask>
    <sequenceFlow id="flow2" sourceRef="s1" targetRef="s2">sequenceFlow>
    <userTask id="s3" name="总经理审批" activiti:candidateUsers="${houxuanren}">userTask>
    <sequenceFlow id="flow3" sourceRef="s2" targetRef="s3">sequenceFlow>
    <endEvent id="endevent1" name="End">endEvent>
    <sequenceFlow id="flow4" sourceRef="s3" targetRef="endevent1">sequenceFlow>
  process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_myProcess">
    <bpmndi:BPMNPlane bpmnElement="myProcess" id="BPMNPlane_myProcess">
      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="100.0" y="250.0">omgdc:Bounds>
      bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="s1" id="BPMNShape_s1">
        <omgdc:Bounds height="55.0" width="105.0" x="180.0" y="240.0">omgdc:Bounds>
      bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="s2" id="BPMNShape_s2">
        <omgdc:Bounds height="55.0" width="105.0" x="330.0" y="240.0">omgdc:Bounds>
      bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="s3" id="BPMNShape_s3">
        <omgdc:Bounds height="55.0" width="105.0" x="480.0" y="240.0">omgdc:Bounds>
      bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="630.0" y="250.0">omgdc:Bounds>
      bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
        <omgdi:waypoint x="135.0" y="267.0">omgdi:waypoint>
        <omgdi:waypoint x="180.0" y="267.0">omgdi:waypoint>
      bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
        <omgdi:waypoint x="285.0" y="267.0">omgdi:waypoint>
        <omgdi:waypoint x="330.0" y="267.0">omgdi:waypoint>
      bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
        <omgdi:waypoint x="435.0" y="267.0">omgdi:waypoint>
        <omgdi:waypoint x="480.0" y="267.0">omgdi:waypoint>
      bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
        <omgdi:waypoint x="585.0" y="267.0">omgdi:waypoint>
        <omgdi:waypoint x="630.0" y="267.0">omgdi:waypoint>
      bpmndi:BPMNEdge>
    bpmndi:BPMNPlane>
  bpmndi:BPMNDiagram>
definitions>
初始化activiti表,使其自动建表
    @Test
    public void init() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        processEngine.close();
    }
部署流程
    @Test
    public void testDeploy() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        Deployment deployment = processEngine.getRepositoryService()//与流程定义和部署对象相关的Service
                .createDeployment()//创建一个部署对象
                .name("请假流程")//添加部署名称
                .category("测试流程类别")
                .addClasspathResource("flow/MyProcess.bpmn20.xml")//从classpath的资源中加载,一次只能加载一个文件
                .deploy();//完成部署
        System.out.println("部署ID:" + deployment.getId());
        System.out.println("部署名称:" + deployment.getName());
    }
查询流程定义
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        List<ProcessDefinition> list = processEngine.getRepositoryService()//与流程定义和部署对象相关的Service
                .createProcessDefinitionQuery()//创建一个流程定义查询
                /*指定查询条件,where条件*/
                //.deploymentId(deploymentId)//使用部署对象ID查询
                //.processDefinitionId(processDefinitionId)//使用流程定义ID查询
                //.processDefinitionKey(processDefinitionKey)//使用流程定义的KEY查询
                //.processDefinitionNameLike(processDefinitionNameLike)//使用流程定义的名称模糊查询

                /*排序*/
                .orderByProcessDefinitionVersion().asc()//按照版本的升序排列
                //.orderByProcessDefinitionName().desc()//按照流程定义的名称降序排列

                .list();//返回一个集合列表,封装流程定义
        //.singleResult();//返回唯一结果集
        //.count();//返回结果集数量
        //.listPage(firstResult, maxResults)//分页查询

        if (list != null && list.size() > 0) {
            for (ProcessDefinition processDefinition : list) {
                System.out.println("流程定义ID:" + processDefinition.getId());//流程定义的key+版本+随机生成数
                System.out.println("流程定义名称:" + processDefinition.getName());//对应HelloWorld.bpmn文件中的name属性值
                System.out.println("流程定义的key:" + processDefinition.getKey());//对应HelloWorld.bpmn文件中的id属性值
                System.out.println("流程定义的版本:" + processDefinition.getVersion());//当流程定义的key值相同的情况下,版本升级,默认从1开始
                System.out.println("资源名称bpmn文件:" + processDefinition.getResourceName());
                System.out.println("资源名称png文件:" + processDefinition.getDiagramResourceName());
                System.out.println("部署对象ID:" + processDefinition.getDeploymentId());
            }
        }
启动流程
   @Test
    public void startProcess() {
        String processDefineId = "myProcess";  // xml定义的流程id
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        ProcessInstance instance = processEngine.getRuntimeService().startProcessInstanceByKey(processDefineId);
        //未流程定义设置名称
        processEngine.getRuntimeService().setProcessInstanceName(instance.getId(),"请假流程");
    }
查询流程实例
    @Test
    public void queryInstance() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        List<HistoricProcessInstance> list = processEngine.getHistoryService().createHistoricProcessInstanceQuery().list();
        for (HistoricProcessInstance processInstance : list) {
            System.out.println(processInstance.getName());
        }
    }
查询任务节点信息
    @Test
    public void queryTask() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        TaskQuery taskQuery = taskService.createTaskQuery();
//        taskQuery.taskAssignee("张三");
        List<Task> list = taskQuery.list();
        for (Task task : list) {
            System.out.println(task.getName());
            System.out.println(task.getId());
            System.out.println(task.getAssignee());
            System.out.println(task.getClaimTime());
            System.out.println(task.getProcessDefinitionId());
            System.out.println(task.getProcessInstanceId());
            Map<String, VariableInstance> variableInstances = taskService.getVariableInstances(task.getId());
            System.out.println(variableInstances);
            Map<String, Object> variablesLocal = taskService.getVariablesLocal(task.getId());
            System.out.println(variablesLocal);
        }
    }
查询流程的任务
 @Test
    public void queryHistoryTask() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        List<HistoricTaskInstance> list = processEngine.getHistoryService().createHistoricTaskInstanceQuery().orderByTaskCreateTime().desc()
                .list();
        if (!CollectionUtils.isEmpty(list)) {
            Map<String, List<HistoricTaskInstance>> map = list.stream().collect(Collectors.groupingBy(HistoricTaskInstance::getExecutionId));
            for (Map.Entry<String, List<HistoricTaskInstance>> entry : map.entrySet()) {
                List<HistoricTaskInstance> value = entry.getValue();
                System.out.print("流程实例:(" + value.get(0).getProcessInstanceId() + ")");
                for (HistoricTaskInstance instance : value) {
                    System.out.print(instance.getName() + "(" + instance.getAssignee() + ") ---->");
                }
                if (value.get(value.size() - 1).getEndTime() != null) {
                    System.out.print("end");
                } else {
                    System.out.print("processing");
                }
                System.out.println("------------------------------------------");
            }

        }
    }
给任务节点设置处理人
        String taskId = "15005";
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        task.setAssignee("tom");
        Map<String, Object> map1 = new HashMap<>();
        map1.put("apply", "小米");
        map1.put("age", 12);
        taskService.setVariables(taskId, map1);
        Map<String, Object> map2 = new HashMap<>();
        map2.put("aaaaaaaaaa", 1234);
        taskService.setVariablesLocal(taskId, map2);
指派任务
    @Test
    public void claim() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery().orderByTaskCreateTime().desc().list().get(0);
        if (task.getAssignee() != null) {
            System.out.println("已签收");
        } else {
            taskService.claim(task.getId(), "张三");
        }
    }
放弃任务
    @Test
    public void unClaim() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery().orderByTaskCreateTime().desc().list().get(0);
        if (task.getAssignee() == null) {
            System.out.println("未指派");
        } else {
            taskService.unclaim(task.getId());
        }
    }
完成任务
    @Test
    public void complete() {
        String taskId = "57505";
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        Map<String, Object> map1 = new HashMap<>();
        map1.put("test", "22222");
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        taskService.complete(task.getId(), map1);

        List<Task> tasks = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
        if (!CollectionUtils.isEmpty(tasks)) {
            for (Task task1 : tasks) {
                taskService.setVariable(task1.getId(),"status",false);
                taskService.setVariableLocal(task1.getId(), "taskStatus", "processing");
            }
        }
    }

单元例子涉及流程变量和任务变量的设置,详细学习需自己手动敲例子去感受Activiti里面更多的API

Activiti 5.22 数据库设计

Activiti使用到的表都是ACT_前缀,列名都是有下划线后缀,防止关键字冲突。

ACT_RE_*:

’RE’表示repository(存储 ),RepositoryService接口所操作的表。带此前缀的表包含的是静态信息,如,流程定义,流程的资源(图片,规则等)。

ACT_RU_*:

‘RU’表示runtime,运行时表-RuntimeService。这是运行时的表存储着流程变量,用户任务,变量,职责(job)等运行时的数据。Activiti只存储实例执行期间的运行时数据,当流程实例结束时,将删除这些记录。这就保证了这些运行时的表小且快。

ACT_ID_*:

’ID’表示identity (组织机构),IdentityService接口所操作的表。用户记录,流程中使用到的用户和组。这些表包含标识的信息,如用户,用户组,等等。

ACT_HI_*:

’HI’表示history,历史数据表,HistoryService。就是这些表包含着流程执行的历史相关数据,如结束的流程实例,变量,任务,等等

ACT_GE_*:

全局通用数据及设置(general),各种情况都使用的数据。

表名 描述
ACT_EVT_LOG 事件日志表
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_ID_GROUP 用户组信息表
ACT_ID_INFO 用户扩展信息表
ACT_ID_MEMBERSHIP 用户与用户组关系信息表
ACT_ID_USER 用户信息表
ACT_PROCDEF_INFO
ACT_RE_DEPLOYMENT 部署信息表
ACT_RE_MODEL 流程设计模型部署表
ACT_RE_PROCDEF 流程定义数据表
ACT_RU_EVENT_SUBSCR throwEvent、catchEvent时间监听信息表
ACT_RU_EXECUTION 运行时流程执行实例表
ACT_RU_IDENTITYLINK 运行时流程人员表,主要存储任务节点与参与者相关信息
ACT_RU_JOB 运行时定时任务数据表
ACT_RU_TASK 运行时任务节点表
ACT_RU_VARIABLE 运行时流程变量数据表

你可能感兴趣的:(Activiti,spring,boot,Activiti)