activiti7 - SpringBoot集成

概念

BPM(Business Process Management)- 业务流程管理,是一种规范化的构造端到端的业务流程,以持续的提高组织业务效率。常见商业管理教育如EMBA、MBA等均将BPM包含在内。

BPMN(Business Process Model AndNotation)- 业务流程模型和符号 是由BPMI(BusinessProcess Management Initiative)开发的一套标准的业务流程建模符号,使用BPMN提供的符号可以创建业务流程。

img

当前使用最广泛工作流引擎对比:

技术组成 Activiti7.1 jBPM7.25 Camunda Flowable6.3.1
数据库持久层ORM MyBatis3.4.2 JPA2.2二次封装 Hibernate4.2.0 JPA 2.2
持久化标准 JPA规范 JPA规范 JPA规范 JPA规范
事务管理 MyBatis机制/Spring事务控制 Bitronix,基于JTA事务管理 hibernate机制/Spring事务控制 hibernate机制,Spring事务控制
分布式事务 MyBatis机制/Spring事务控制 Bitronix,基于JTA事务管理 补偿机制,SAGA 模式
数据库连接方式 Jdbc/DataSource Jdbc/DataSource Jdbc/DataSource Jdbc/DataSource
支持数据库 Oracle、SQL Server、MySQL Oracle、SQL Server、MySQL Oracle、SQL Server、MySQL、db2 Oracle、SQL Server、MySQL、db2
设计模式 Command模式、观察者模式等
内部服务通讯 Service间通过API调用 基于Apache Mina异步通讯 Service间通过API调用 Service间通过API调用
集成接口 SOAP、Mule、RESTful 消息通讯 SOAP、Mule、RESTful SOAP、Mule、RESTful
支持的流程格式 BPMN2、xPDL、jPDL等 目前仅只支持BPMN2 xml BPMN2、xPDL、jPDL等 BPMN2、xPDL、jPDL等
引擎核心 PVM(流程虚拟机) Drools PVM
架构 spring boot 2.1.2, spring 5.1.4 Drools Flow activiti5 spring boot 1.5,spring 4.3, spring.security 4.2
支持J2EE 兼容 天然支持EJB,J2EE 兼容 兼容
技术前身 jBPM3、jBPM4 Drools Flow activiti5 activiti5
API文档 swagger1.5 swagger1.5
日志 slf4j1.7门面,logback1.2.3 slf4j1.5门面, log4j slf4j1.7门面,logback1.2.3 slf4j1.7门面
所属公司 Alfresco jBoss.org Camunda Flowable

表结构

表前缀规则

act_ge_ 通用数据表,ge是general的缩写

act_hi_ 历史数据表,hi是history的缩写,对应 HistoryService 接口

act_id_ 身份数据表,id是identity的缩写,对应 IdentityService 接口

act_re_ 流程存储表,re是repository的缩写,对应 RepositoryService 接口,存储流程部署和流程定义等静态数据

act_ru_ 运行时数据表,ru是runtime的缩写,对应 RuntimeService 接口和 TaskService 接口,存储流程实例和用户任务等动态数据

img

设计架构

img

服务接口

service名称 service作用
RepositoryService activiti的资源管理类
RuntimeService activiti的流程运行管理类
TaskService activiti的任务管理类
HistoryService activiti的历史管理类
ManagerService activiti的引擎管理类

任务监听

任务监听器是发生对应的任务相关事件时执行自定义 java 逻辑 或表达式。 任务相当事件包括:

Create:任务创建后触发

Assignment:任务分配后触发

Delete:任务完成后触发

All:所有事件发生都触发

定义任务监听类,且类必须实现 org.activiti.engine.delegate.TaskListener 接口

public class MyTaskListener implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {
        //业务代码
    }
} 

生命周期

   1 onCreate()
        :当一个Activity第一次启动时调用,表示一个Activity对象被创建一般情况下,我们会在该方法中做一些初始化的工作(初始化组件,设置事件监听,填充主布局,其他数据)
         @Override
          protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            }
    2 onStart()
        :在onCreate方法之后调用,该方法用于显示界面,完成后我们可以看见界面,但还不能进行交互
        @Override
        protected void onStart() {
            super.onStart();
            }
    3 onRestart()
        :   在当前Activity从停止状态重新被显示时会调用,接着会调用onStart--onResume
        @Override
        protected void onStart() {
         super.onStart();
        }
    4 onResume()
        :在onStart方法之后被调用,此方法完成后,界面可以进行交互,此时,Activity进入运行状态。该状态下可以实现还原状态的操作
        @Override
        protected void onResume() {
       super.onResume();
        }
    5 onPause()
        :当前Activity被另一个Activity不完全覆盖时被调用(或被一个窗口模式的Activity覆盖),此时Activity进入暂停状态,该状态下,如果设备内存不足时有可能被销毁
       :当覆盖当前Activity的另一个窗口模式的Activity出栈,此时会调用onResume方法,让Activity重新进入运行状态,该状态下可以保存Activity的状态,已在还原时继续执行
        @Override
        protected void onPause() {
         super.onPause();
      }
    6 onStop()
        :当前Activity被完全覆盖后被调用,此时Activity已经看不见,Activity进入停止状态,该状态下,如果设备内存不足时有可能被销毁
当前Activity重新显示时,会调用onReStart----onStart----onResume
        @Override
        protected void onStop() {
        super.onStop();
         }
     7 onDestory()
        :当Activity被出栈,销毁时调用,表示当前Activity进入killed状态,那么我们一般在该方法进行资源释放工作
        @Override
        protected void onDestroy() {
         super.onDestroy();
    }

项目集成

maven引入

<!-- 工作流activiti -->
<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-spring-boot-starter</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<!-- 生成流程图 -->
<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-image-generator</artifactId>
</dependency>

注意:排除activiti自带的mybatis,防止与项目的mybatis冲突

yml配置

spring:
  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
    #自动检查、部署流程定义文件 启动时自动部署定义的流程
    check-process-definitions: true
    # asyncExecutorActivate是指activiti在流程引擎启动就激活AsyncExecutor,异步:true-开启(默认)、false-关闭
    async-executor-activate: true
    #流程定义文件存放目录,要具体到某个目录
    process-definition-location-prefix: classpath:/processes/
    #process-definition-location-suffixes: #流程文件格式
    #  - **.bpmn20.xml
    #  - **.bpmn
  main:
    allow-bean-definition-overriding: true

注意: 启动如果bean生成失败,添加allow-bean-definition-overriding:true 允许bean被覆盖解决

执行流程代码

  1. 代码流程从发布-执行-完成-结束任务
    @GetMapping("/publishList")
    public AjaxResult publishList() {
        List<ProcessDefinition> list = repositoryService
                .createProcessDefinitionQuery()
                .orderByProcessDefinitionVersion()
                .desc()
                .list();
        for (ProcessDefinition item : list) {
            System.out.println("========");
            System.out.println(item.getDeploymentId());
            System.out.println(item.getId());
            System.out.println(item.getKey());
            System.out.println(item.getName());
        }
        return AjaxResult.success();
    }
    /**
     * 开启流程
     *
     * @return
     */
    @GetMapping("/startProcess")
    public AjaxResult startProcess(@RequestParam("key") String key) {
        ProcessInstance processInstance = runtimeService
                .startProcessInstanceByKey(key);
        if (processInstance != null) {
            System.out.println("=============");
            System.out.println(processInstance.getName());
            System.out.println(processInstance.getProcessDefinitionKey());
            System.out.println(processInstance.getId());
        }
        return AjaxResult.success();
    }

    /**
     * 查询正在运行的流程列表
     *
     * @return
     */
    @GetMapping("/runningList")
    public AjaxResult runningList(@RequestParam("instanceId") String instanceId,
                                  @RequestParam("key") String key) {
        List<ProcessInstance> list = runtimeService
                .createProcessInstanceQuery()
                .processInstanceId(instanceId)
                .processDefinitionKey(key)
                .list();
        list.forEach(item -> {
            System.out.println("============");
            System.out.println(item.getBusinessKey());
            System.out.println(item.getDeploymentId());
            System.out.println(item.getStartTime());
            System.out.println(item.getProcessDefinitionKey());
            System.out.println(item.getName());
        });
        return AjaxResult.success();
    }

    /**
     * 查询任务并且完成
     *
     * @param instanceId
     * @param key
     * @param assignee
     * @return
     */
    @GetMapping("accomplishTask")
    public AjaxResult accomplishTask(@RequestParam("instanceId") String instanceId,
                                     @RequestParam("key") String key,
                                     @RequestParam("assignee") String assignee) {
        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey(key)
                .taskAssignee(assignee)
                .processInstanceId(instanceId)
                .list();
//        设置任务id
        // taskService.setVariableLocal("862e5029-31e4-11ed-ab1a-005056c00008", "num", "4");
        // executionId 就当是processInstanceId
        //  runtimeService.setVariableLocal("862b1bd5-31e4-11ed-ab1a-005056c00008", "num", 3);
        for (int i = 0; i < list.size(); i++) {
            Task task = list.get(i);
//            taskService.complete(task.getId());
            System.out.println("==========");
            System.out.println(task.getId());
            System.out.println(task.getName());
            System.out.println(task.getAssignee());
            System.out.println(task.getProcessDefinitionId());
            System.out.println(task.getProcessInstanceId());
            System.out.println(task.getTaskDefinitionKey());
            System.out.println(task.getExecutionId());
        }
        return AjaxResult.success();
    }

    /**
     * 判断进程是否结束
     *
     * @param instanceId
     * @return
     */
    @GetMapping("ProcessFinish")
    public AjaxResult ProcessFinish(@RequestParam String instanceId) {
        HistoricProcessInstance historicProcessInstance = historyService
                .createHistoricProcessInstanceQuery()
                .processInstanceId(instanceId)
                .singleResult();
        if (historicProcessInstance != null) {
            if (historicProcessInstance.getEndTime() != null) {
                System.out.println("流程已结束!");
            } else {
                System.out.println("流程未结束!");
            }
        } else {
            System.out.println("流程不存在!");
        }
        return AjaxResult.success();
    }

    /**
     * 查看审批进程
     *
     * @param instanceId
     * @return
     */
    @GetMapping("viewApproval")
    public AjaxResult viewApproval(@RequestParam String instanceId) {
        // 历史节点
        List<HistoricActivityInstance> list = historyService
                .createHistoricActivityInstanceQuery()
                .processInstanceId(instanceId)
//                .orderByActivityId()
//                .desc()
                .orderByHistoricActivityInstanceEndTime()
                .asc()
                .finished()
  //              .unfinished()
                .list()
                .stream()
                .filter(item -> !StringUtils.containsAny(item.getActivityType(), "inclusiveGateway", "parallelGateway"))
                .collect(Collectors.toList());
        // 历史变量
        for (int i = 0; i < list.size(); i++) {
            System.out.println("========");
            HistoricActivityInstance historicActivityInstance = list.get(i);
//            System.out.println(historicActivityInstance.getActivityId());  // _2
            System.out.println(historicActivityInstance.getActivityName());
            String taskId = historicActivityInstance.getTaskId();
            System.out.println(taskId);
            String result = "";
            if (StringUtils.isNotEmpty(taskId)) {
                HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().taskId(taskId).variableName("result").singleResult();
                result = (String) historicVariableInstance.getValue();
                // 已经经过的节点不适用该方法查询变量
//                result = (String) taskService.getVariableLocal(taskId, "result");
            }
            System.out.println(historicActivityInstance.getAssignee() + "----" + result);
            System.out.println(historicActivityInstance.getStartTime());
            System.out.println(historicActivityInstance.getEndTime());
//            System.out.println("ExecutionId:" + historicActivityInstance.getExecutionId());
//            System.out.println("ProcessInstanceId:" + historicActivityInstance.getProcessInstanceId());
//            System.out.println(historicActivityInstance.getActivityType()); // userTask
        }
        return AjaxResult.success();
    }

    /**
     * 申请任务
     * @param key
     * @param assignee
     * @return
     */
    @GetMapping("applyTask")
    public AjaxResult applyTask(@RequestParam("key") String key,
                                @RequestParam("assignee") String assignee){
        if (StringUtils.isBlank(key)) {
            throw new RuntimeException("key不能为空!");
        }
        if (StringUtils.isBlank(assignee)) {
            throw new RuntimeException("assignee不能为空!");
        }
        Task task = taskService.createTaskQuery()
                .taskCandidateUser(assignee)
//                .taskId(taskId)
                .processInstanceBusinessKey(key)
                .singleResult();
        if (task != null) {
            taskService.claim(task.getId(), assignee);
            log.info(assignee + "申领到了任务!");
        }
        return AjaxResult.success();
    }

    /**
     * 放弃任务
     * @param key
     * @param assignee
     * @return
     */
    @GetMapping("abandonTask")
    public AjaxResult abandonTask(@RequestParam("key") String key,
                                  @RequestParam("assignee") String assignee){
        if (StringUtils.isBlank(key)) {
            throw new RuntimeException("businessKey不能为空!");
        }
        if (StringUtils.isBlank(assignee)) {
            throw new RuntimeException("assignee不能为空!");

        }
        Task task = taskService.createTaskQuery()
                .taskAssignee(assignee)
//                .taskId(taskId)
                .processInstanceBusinessKey(key)
                .singleResult();
        if (task != null) {
            taskService.setAssignee(task.getId(), null);
            log.info(assignee + "放弃了任务!");
        }
        return AjaxResult.success();
    }
posted @ 2023-02-28 17:18  让人生留下足迹  阅读(293)  评论(0编辑  收藏  举报