Activiti初识

news2024/11/24 16:51:59

以前

在没有工作流引擎的时候,要实现流程控制,我们需要在数据库中定义表,然后采用状态字段去跟踪流程的变化:比如是否到下一个流程;
然后到下一个角色执行的时候,我们需要判断用户是否具有审批的权限,如果可以就讲状态设置为一个值。
缺点:
当流程发生变更,代码变化较大

现在

Activiti 可以做到业务流程变化之后,我们的程序可以不用改变,如果可以实现这样的效果,那么我们的业务系统的适应能力就得到了极大提升

1.部署

使用activiti提供的api把流程定义内容存储起来,在Activiti执行过程中可以查询定义的内容

Activiti执行把流程定义内容存储在数据库中
1.我们首先先定义一个afg.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration" id="processEngineConfiguration">
        <property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///activiti2?characterEncoding=utf-8&amp;nullCatalogMeansCurrent=true&amp;serverTimezone=UTC&amp;useSSL=false" />
        <property name="jdbcUsername" value="root" />
        <property name="jdbcPassword" value="123" />
        <property name="databaseSchemaUpdate" value="true" />
        <!--<property name="dataSource" ref="dataSource" />-->
    </bean>
    <!--<bean class="org.apache.commons.dbcp.BasicDataSource" id="dataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
        <property name="url" value="jdbc:mysql:///activiti2?characterEncoding=utf-8&amp;serverTimezone=UTC"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="maxActive" value="3" />
        <property name="maxIdle" value="2" />
    </bean>-->
</beans>

然后还得创建一个log4j.properties

# 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:\log\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

2.然后我们通过Java代码创建我们的工作流程引擎

   /**
     * 1.生成Activiti的相关的表结构
     */
    @Test
    public void test01(){
        // 使用classpath下的activiti.cfg.xml中的配置来创建 ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        System.out.println(engine);

    }

会得到很多表结构

表结构分析

在这里插入图片描述
在这里插入图片描述

Service服务接口

Service是工作流引擎提供用于进行工作流部署、执行、管理的服务接口,我们使用这些接口可以就是操作服务对应的数据表

1.创建方式:

RuntimeService runtimeService = processEngine.getRuntimeService();
RepositoryService repositoryService = processEngine.getRepositoryService();
TaskService taskService = processEngine.getTaskService();

2.Service总览:
RepositioryService:activiti的资源管理类
RuntimeService: activiti的流程运行管理类
TaskService:activiti的任务管理类
ManagerService:activiti的引擎管理类

Repository

activiti的资源管理类,提供了管理和控制流程发布包和流程定义的操作。使用工作流建模工具设计的
业务流程图需要使用此service将流程定义文件的内容部署到计算机。

除了部署流程定义以外还可以:查询引擎中的发布包和流程定义
暂停或激活发布包,对应全部和特定流程定义。 暂停意味着它们不能再执行任何操作了,激活是对应的
反向操作。获得多种资源,像是包含在发布包里的文件, 或引擎自动生成的流程图。
获得流程定义的pojo版本, 可以用来通过java解析流程,而不必通过xml。

RuntimeService

Activiti的流程运行管理类。可以从这个服务类中获取很多关于流程执行相关的信息

  1. 启动流程及对流程数据的控制。
  2. 流程实例【ProcessInstance】和执行流【Execution】查询。
  3. 触发流程操作、接受消息和信号。

流程实例与执行流的概念

  • 在Activiti总,启动一个流程就会创建一个流程实例(ProcessInstance),每个流程实例至少会有一个执行流(Execution),当流程实例没有流程分支时,一般情况下只会存在一个执行流;假设流程出现两个分支,此时Activiti将会有三个执行流,第一个为原来流程的主执行流,而其余两个为子执行流

  • Processlnstance是一个接口,一个Processlnstance实例表示一个流程实例,Processlnstance实际上是执行流(Execution)的子接口,流程实例也是一个执行流。Processlnstance中有Execution没有的属性,例如流程定义和业务主键。当得到的是一个Processlnstance实例时,就将其看作一个流程实例;当得到一个Execution实例时,它就是一个执行流。流程实例与执行流的数据保存在执行表ACT_RU_EXECUTION中,对应的映射实体为ExecutionEntitylmpl

TaskService

Activiti的任务管理类。可以从这个类中获取任务的信息。

HistoryService

Activiti的历史管理类,可以查询历史信息,执行流程时,引擎会保存很多数据(根据配置),比如流程
实例启动时间,任务的参与者, 完成任务的时间,每个流程实例的执行路径,等等。 这个服务主要通过
查询功能来获得这些数据。

ManagementService

Activiti的引擎管理类,提供了对 Activiti 流程引擎的管理和维护功能,这些功能不在工作流驱动的应用
程序中使用,主要用于 Activiti 系统的日常维护

流程的一些概念

  • ProcessDefinition
    流程定义类。可以从这里获得资源文件等。
  • ProcessInstance
    代表流程定义的执行实例。如范冰冰请了一天的假,她就必须发出一个流程实例的申请。一个流程实例包括了所有的运行节点。我们可以利用这个对象来了解当前流程实例的进度等信息。流程实例就表示一个流程从开始到结束的最大的流程分支,即一个流程中流程实例只有一个。
  • Execution
    Activiti用这个对象去描述流程执行的每一个节点。在没有并发的情况下,Execution就是同ProcessInstance。流程按照流程定义的规则执行一次的过程,就可以表示执行对象Execution。

操作数据表

流程部署后,最关键的是三张表
1.act_re_deployment:流程定义部署表,每部署一次就增加一条记录
2.act_re_procdef:流程定义表,部署每个新的流程定义都会在这张表中增加一条记录
3.act_ge_bytearray :流程资源表,流程部署的 bpmn文件和png图片会保存在该表中

1.启动流程实例

启动一个流程表示发起一个新的出差申请单,这就相当于Java类和Java对象的关系,类定义好了后需要new创建一个对象使用,当然可以new出多个对象来,对于出差申请流程,张三可以发起一个出差申请单需要启动一个流程实例.

流程实例代表流程定义的执行实例,一个流程实例包含了所有的运行节点,我们可以利用这个对象来了解当前流程实例的具体进度等信息

如:用户或程序按照流程定义内容发起一个流程,这就是一个流程实例。
在这里插入图片描述

  /**
     * 5.启动一个流程实例
     */
    @Test
    public void test05(){
        // 1.创建ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取RuntimeService对象
        RuntimeService runtimeService = engine.getRuntimeService();
        // 3.根据流程定义的id启动流程
        String id= "evection";
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(id);
        // 4.输出相关的流程实例信息
        System.out.println("流程定义的ID:" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例的ID:" + processInstance.getId());
        System.out.println("当前活动的ID:" + processInstance.getActivityId());
    }

2.启动流程实例 并添加Businesskey(业务标识)

流程定义部署在activiti后,就可以在系统中通过activiti去管理该流程的执行,执行流程表示流程的一次执行

比如部署系统出差流程后,如果某用户要申请出差这时就需要执行这个流程,如果另外一个用户也要申请出差则也需要执行该流程,每个执行互不影响,每个执行是单独的流程实例

启动流程实例时,指定的businesskey,就会在act_ru_execution #流程实例的执行表中存储businesskey。

**Businesskey:**业务标识,通常为业务表的主键,业务标识和流程实例一一对应。业务标识来源于业务系统。存储业务标识就是根据业务标识来关联查询业务系统的数据。

比如:出差流程启动一个流程实例,就可以将出差单的id作为业务标识存储到activiti中,将来查询activiti的流程实例信息就可以获取出差单的id从而关联查询业务系统数据库得到出差单信息请添加图片描述

    /**
     * 启动流程实例,添加businessKey
     */
    @Test
    public void addBusinessKey(){
//        1、得到ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        2、得到RunTimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
//        3、启动流程实例,同时还要指定业务标识businessKey,也就是出差申请单id,这里是1001
        ProcessInstance processInstance = runtimeService.
                startProcessInstanceByKey("myEvection","1001");
//        4、输出processInstance相关属性
        System.out.println("业务id=="+processInstance.getBusinessKey());

    }

请添加图片描述

3.任务查找

流程启动后,任务的负责人就可以查询自己当前能够处理的任务了,查询出来的任务都是当前用户的待办任务

  /**
     * 任务查询
     */
    @Test
    public void test06(){
        //1.负责人
        String assignee ="zhansan";
        //2.得到工作流对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        //3.任务查询 需要获取一个 TaskService 对象
        TaskService taskService = engine.getTaskService();
        //4.根据流程的key和任务负责人 查询任务
        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey("evection")
                .taskAssignee(assignee)
                .list();

        //5.输出当前用户具有的任务
        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());
        }
    }

4.流程任务的处理

通过taskService.createTaskQuery().processDefinitionKey().taskAssingee().list():根据流程定义id和人员查询人员代办任务,我们可以选择任务进行处理

 /**
     * 流程任务的处理
     */
    @Test
    public void test07(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("evection")
                .taskAssignee("zhansan")
                .singleResult();
        // 完成任务
        taskService.complete(task.getId());
    }

关键在于taskService.complete(task.getId())能够根据任务的id执行任务,执行完后,流程就会转向下一步
在这里插入图片描述

6.流程处理后再查询

/**
     * 查询流程的定义
     */
    @Test
    public void test08(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = engine.getRepositoryService();
        // 获取一个 ProcessDefinitionQuery对象 用来查询操作
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        List<ProcessDefinition> list = processDefinitionQuery.processDefinitionKey("evection")
                .orderByProcessDefinitionVersion() // 安装版本排序
                .desc() // 倒序
                .list();
        // 输出流程定义的信息
        for (ProcessDefinition processDefinition : list) {
            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());
        }
    }

7.删除流程

/**
     * 删除流程
     */
    @Test
    public void test09(){
        //1.先得到工作流的引擎
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = engine.getRepositoryService();
        repositoryService.deleteDeployment("12501");
    }

8.读取数据库中act_bytearray的资源文件

老套路,首先得到ProcessEngine对象(负责管理所有流程引擎,完成流程实例对象的注册获取,注销等操作)

/**
     * 读取数据库中的资源文件
     */
    @Test
    public void test10() throws Exception{
        // 1.得到ProcessEngine对象
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取RepositoryService对象
        RepositoryService repositoryService = engine.getRepositoryService();
        // 3.得到查询器
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("evection")
                .singleResult();
        // 4.获取流程部署的id
        String deploymentId = definition.getDeploymentId();

        // 5.通过repositoryService对象的相关方法 来获取图片信息和bpmn信息
        // png图片
        InputStream pngInput = repositoryService
                .getResourceAsStream(deploymentId, definition.getDiagramResourceName());
        // bpmn 文件的流
        InputStream bpmnInput = repositoryService
                .getResourceAsStream(deploymentId, definition.getResourceName());
        // 6.文件的保存
        File filePng = new File("d:/evection.png");
        File fileBpmn = new File("d:/evection.bpmn");
        OutputStream pngOut = new FileOutputStream(filePng);
        OutputStream bpmnOut = new FileOutputStream(fileBpmn);

        IOUtils.copy(pngInput,pngOut);
        IOUtils.copy(bpmnInput,bpmnOut);

        pngInput.close();
        pngOut.close();
        bpmnInput.close();
        bpmnOut.close();
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/101258.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HFSS使用经验

目录 一、如何找到Project工程变量 二、coverlines是什么东西 三、参数建模的第一步 四、让HFSS模型居中的快捷键CtrlD 五、关于介质颜色的修改 六、如何在HFSS中添加变量 七、如何绘制微带线 八、如何绘制带缺口的微带线谐振腔 九、如何设置激励源 十、HFSS如何镜像…

关于一致性问题的简单总结

一、场景引入 在随着人类的发展过程&#xff0c;由于人类是一群人&#xff0c;而非单个人&#xff0c;并相互联系&#xff0c;为了基本的生存或更美好的精神追求&#xff0c;出现了分工协作&#xff08;单个人无法完成&#xff09;的概念。人性是具有追求极致、美化的特性&…

【SQL】字符串处理函数

文章目录修复表中的名字left(string, count)substr(string, pos, len)按日期分组销售产品group_concat患某种疾病的患者修复表中的名字 将name的首字母大写&#xff0c;其余字母小写 select user_id, concat(upper(left(name, 1)), lower(substr(name, 2))) as name from User…

【Python机器学习】神经网络中全连接层与线性回归的讲解及实战(Tensorflow、MindSpore平台 附源码)

需要全部代码请点赞关注收藏后评论区留言私信~~~ 全连接层与线性回归 神经网络模型也是参数学习模型&#xff0c;因为对它的学习只是得到神经网络参数的最优值&#xff0c;而神经网络的结构必须事先设计好。如果确实不能通过改进学习过程来达到理想效果&#xff0c;则要重新设…

linux基础学习-用户权限相关命令

用户权限相关命令 用户和权限的基本概念 基本概念 用户是linux系统工作中的重要的一环&#xff0c;用户管理包括 用户 和 组 管理在linux系统下&#xff0c;不论是由本机还是远程登录系统&#xff0c;每个系统都必须有一个账号&#xff0c;并且对于不同的系统资源拥有不同的使用…

银河系中心黑洞的首张照片

说到黑洞&#xff0c;那就不得不提起我们的家园银河系中心的大黑洞&#xff0c;在今天这张照片出来之前&#xff0c;所有关于银河系黑洞的描述都是推测、理论&#xff0c;而今天成为了现实&#xff01; 2019年&#xff0c;同一团队拍摄了梅西耶87星系&#xff08;M87&#xff0…

文本分类优化方法

文本分类优化方法 文本分类是NLP的基础工作之一&#xff0c;也是文本机器学习中最常见的监督学习任务之一&#xff0c;情感分类&#xff0c;新闻分类&#xff0c;相似度判断、问答匹配、意图识别、推断等等领域都使用到了文本分类的相关知识或技术。文本分类技术在机器学习的发…

用 Markdown 快速生成漂亮的 Latex 伪代码

参考&#xff1a;在 Markdown 中书写伪代码 文章目录配置 VSCode编写 Latex 源码生成 pseudocode配置 VSCode 组合&#xff1a; VSCode Markdown Preview Enhanced pseudocode.js 安装好 VSCode 和 Markdown Preview Enhanced 插件 按下快捷键 Ctrl Shift P&#xff0c;打…

定时器/计数器的基本概念

80C51单片机中有两个计数器&#xff0c;即T0和T1。 单片机内有一个定时器/计数器T0&#xff0c;可以用编程的方法将它设为计数器。当用作计数器时&#xff0c;它是一个16位计数器&#xff0c;它的最大计数值为65536。 定时器/计数器T0和T1分别是由TH0、TL0和TH1、TL1两个8位计数…

Vue3与Vue2生命周期不同点

一、前言 随着Vue3发布了两年多的时间&#xff0c;越来越多的小伙伴已经将老项目中的Vue2版本进行升级或者在新项目中使用到了Vue3.x的版本&#xff0c;今天就来总结以下Vue3相较于Vue2升级的生命周期不同点在哪。 二、生命周期 下面是生命周期对比图&#xff1a; Vue2Vue3…

JMeter基础入门

目录&#xff1a;导读 一、概述 二、Jmeter目录文件讲解 结语 一、概述 JMeter是Apache下一款在国外非常流行和受欢迎的开源性能测试工具&#xff0c;JMeter可用于模拟大量负载来测试一台服务器&#xff0c;网络或者对象的健壮性或者分析不同负载下的整体性能。 1、压测不同…

ValidateCode验证码的使用详解(初学看完都会用)

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;Java案例分…

Android 进阶——性能优化之电量优化全攻略及实战小结(二)

文章大纲引言一、在低电耗模式和应用待机模式下进行测试1、在低电耗模式下测试您的应用2、在应用待机模式下测试您的应用3、列入白名单的可接受用例4、确定当前充电状态5、监控充电状态变化6、确定当前电池电量7、监控显著的电池电量变化二、Wakelock 机制1、WakeLock分类2、申…

Linux系统x86-64架构下,从零实现一个系统调用。Ubuntu22.04LTS

名称版本OSUbuntu 22.04 LTSCurrent Kernel5.15.0-56-genericDestination Kernel5.16.60首先要会编译linux内核的源码,这块在我的另外一片文章里面。 https://blog.csdn.net/jl19861101/article/details/128327069 打开linux内核源码目录/arch/x86/entry/syscalls/syscall_64.t…

前端面试比较好的回答

介绍一下Connection:keep-alive 什么是keep-alive 我们知道HTTP协议采用“请求-应答”模式&#xff0c;当使用普通模式&#xff0c;即非KeepAlive模式时&#xff0c;每个请求/应答客户和服务器都要新建一个连接&#xff0c;完成 之后立即断开连接&#xff08;HTTP协议为无连接…

【笔记】canvas 绘制足球 —— 第一步 画个球体

文章目录一、球体分析二、足球结构分析三、canvas常用API四、画个球体1.初始化2.代码五、加上足球的皮肤一、球体分析 先上两张图 球坐标转直角坐标 xρsin(φ)cos(θ)x \rho \times sin(\varphi) \times cos(\theta) xρsin(φ)cos(θ) yρsin(φ)sin(θ)y \rho \times si…

柴油,光伏模块,风力涡轮机,电池和水力抽水蓄能组成的混合隔离微电网的设计(Matlab实现)

目录 0 引言 1 概述 2 HYMOD 软件操作 2.1 设计的三个阶段 3 HYMOD 软件架构 4 系统和元件的可靠性 5 微电网设计示例 6 Matlab代码与结论 7 操作指南 7.1 概述 7.2 操作 7.3 软件具体操作 0 引言 本文介绍了混合微电网优化设计 (Hymod) 软件。该软件具有最先进…

Redis发布和订阅

Redis发布和订阅1.什么是发布和订阅2.Redis命令演示发布订阅1.什么是发布和订阅 Redis发布订阅(pub/sub)是一种消息通信模式&#xff1a;发布者(pub)发送消息&#xff0c;订阅者(sub)接收消息。 Redis客户端可以订阅任意数量的频道。 2.Redis命令演示发布订阅 打开两个终端 终…

python教程二十 输入和输出

输出格式美化 Python两种输出值的方式: 表达式语句和 print() 函数。 第三种方式是使用文件对象的 write() 方法&#xff0c;标准输出文件可以用 sys.stdout 引用。 如果你希望输出的形式更加多样&#xff0c;可以使用 str.format() 函数来格式化输出值。 如果你希望将输出…

记录在苹果mac os系统上使用51单片机仿真软件Proteus

目录 1.安装Wineskin shell 指令 2.安装Wrapper 点击update ​​​​​​​ 1.安装Wineskin 首先我们需要安装一个程序&#xff1a; 可以将在Windows系统上才能运行exe文件打包为mac系统可执行的文件。 shell 指令 brew install --no-quarantine gcenx/wine/unofficial…