工作流引擎Activiti详解

工作流引擎Activiti

  • 1. 什么是工作流
    • 1.1 工作流介绍
    • 1.2 工作流系统
    • 1.3 工作流实现方式
    • 1.4 工作流实现原理
  • 2. Activiti7概述
    • 2.1 Activiti介绍
    • 2.2 Activiti使用
  • 3. Activiti环境配置
    • 3.1 创建数据库
    • 3.2 初始化数据库表:
    • 3.3 创建数据库表
    • 3.4 数据库表命名规则
  • 4. Activiti架构简介
  • 5. Activiti入门案例
    • 5.1 流程定义
    • 5.2 部署流程
    • 5.3 启动流程
    • 5.4 流程定义查询
    • 5.5 流程定义删除
    • 5.6 流程定义资源查询

1. 什么是工作流

1.1 工作流介绍

工作流(Workflow),就是通过计算机对业务流程自动化执行管理。它主要解决的是“使在多个参与者之间按照某种预定义的规则自动进行传递文档、信息或任务的过程,从而实现某个预期的业务目标,或者促使此目标的实现”。

1.2 工作流系统

什么是工作流系统
具有工作流程功能的软件系统。用于更好的管理业务流程。

适用行业,各行各业
比如,消费品行业,制造业,电信服务业,银证险等金融服务业,物流服务业,物业服务业,物业管理,大中型进出口贸易公司,政府事业机构,研究院所及教育服务业等,特别是大的跨国企业和集团公司。

具体场景,凡是涉及到业务流程的所有场景
(1) 关键业务流程:订单、报价处理、合同审核、客户电话处理、供应链管理等
(2) 行政管理类:出差申请、加班申请、请假申请、用车申请、各种办公用品申请、购买申请、日报周报等凡是原来手工流转处理的行政表单。
(3) 人事管理类:员工培训安排、绩效考评、职位变动处理、员工档案信息管理等。
(4) 财务相关类:付款请求、应收款处理、日常报销处理、出差报销、预算和计划申请等。
(5) 客户服务类:客户信息管理、客户投诉、请求处理、售后服务管理等。

1.3 工作流实现方式

目前常见的工作流程有两种方式:
(1)通过状态字段实现流程控制。原始,适合简单流程控制。
(2)工作流引擎实现流程控制。适用场景更广泛,扩展性更好。

1.4 工作流实现原理

Activiti牛批之处在于,它在不改变代码的前提下实现各种业务流程的管理,适用性,扩展性很优秀。

activiti通过创建流程实例引擎,可以实现不同流程的流转,通过不断读取创建的流程节点实现流程流转。

2. Activiti7概述

2.1 Activiti介绍

Activiti 是一个工作流引擎, activiti 可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言(BPMN2.0)进行定义,业务系统按照预先定义的流程进行执行,实现了业务系统的业务流程由 activiti 进行管理,减少业务系统由于流程变更进行系统升级改造的工作量,从而提高系统的健壮性,同时也减少了系统开发维护成本。

当然这里还有一些小故事,Alfresco 软件在 2010 年 5 月 17 日宣布 Activiti 业务流程管理(BPM)开源项目的正式启动, 其首席架构师由业务流程管理 BPM 的专家 Tom Baeyens 担任, Tom Baeyens 就是原来 jbpm 的架构师,而 jbpm 是一个非常有名的工作流引擎,当然 activiti 也是一个工作流引擎。
官方网站: https://www.activiti.org/

下边介绍三个名词概念,就不长篇大论了,简单总结下。
1.1 BPM:BPM(Business Process Management),即业务流程管理。
1.1 BPM系统:那就是业务流程管理的系统。
1.1 BPMN,这个比较噢重要,多说两句,具体往下看。
BPMN(Business Process Model And Notation) - 业务流程模型和符号 是由 BPMI(BusinessProcess Management Initiative)开发的一套标准的业务流程建模符号,使用 BPMN 提供的符号可以创建业务流程。

总结来说就是用来建模业务流程的标准规则,一个个符号!
工作流引擎Activiti详解_第1张图片

2.2 Activiti使用

一般情况下都是通过创建BPMN进行业务流程建模,两种方式,idea插件或者eclipse插件,通过符号创建流程。
idea安装bpmn插件
在 IDEA 的 File 菜单中找到子菜单”Settings”,后面我们再选择左侧的“plugins”菜单,如下图所示
工作流引擎Activiti详解_第2张图片工作流引擎Activiti详解_第3张图片

3. Activiti环境配置

3.1 创建数据库

CREATE DATABASE activiti DEFAULT CHARACTER SET utf8;

3.2 初始化数据库表:

  1. 创建Maven工程
    工作流引擎Activiti详解_第4张图片
  2. 加入依赖

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <groupId>com.activiti.demogroupId>
    <artifactId>activiti_demoartifactId>
    <version>1.0-SNAPSHOTversion>

    
    <properties>
        <slf4j.version>1.6.6slf4j.version>
        <log4j.version>1.2.12log4j.version>
    properties>

    <dependencies>
        
        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-engineartifactId>
            <version>7.0.0.Beta1version>
        dependency>

        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-springartifactId>
            <version>7.0.0.Beta1version>
        dependency>

        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-bpmn-modelartifactId>
            <version>7.0.0.Beta1version>
        dependency>

        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-bpmn-converterartifactId>
            <version>7.0.0.Beta1version>
        dependency>

        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-json-converterartifactId>
            <version>7.0.0.Beta1version>
        dependency>

        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-bpmn-layoutartifactId>
            <version>7.0.0.Beta1version>
        dependency>

        <dependency>
            <groupId>org.activiti.cloudgroupId>
            <artifactId>activiti-cloud-services-apiartifactId>
            <version>7.0.0.Beta1version>
        dependency>

        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.40version>
        dependency>

        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
        dependency>

        
        <dependency>
            <groupId>log4jgroupId>
            <artifactId>log4jartifactId>
            <version>${log4j.version}version>
        dependency>
        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-apiartifactId>
            <version>${slf4j.version}version>
        dependency>
        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-log4j12artifactId>
            <version>${slf4j.version}version>
        dependency>
        

        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.4.5version>
        dependency>

        <dependency>
            <groupId>commons-dbcpgroupId>
            <artifactId>commons-dbcpartifactId>
            <version>1.4version>
        dependency>

    dependencies>

    <repositories>
        <repository>
            <id>alfrescoid>
            <name>Activiti Releasesname>
            <url>https://artifacts.alfresco.com/nexus/content/repositories/activiti-releases/url>
            <releases>
                <enabled>trueenabled>
            releases>
        repository>
    repositories>

project>
  1. 配置日志
# 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:/axis.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


  1. 配置activity.cfg.xml

<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="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/activiti"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    bean>
    

    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        
        <property name="dataSource" ref="dataSource">property>

        

        
        <property name="databaseSchemaUpdate" value="true"/>

    bean>
beans>
  1. 编写代码

/**
 * Activiti初始化25张表
 * 执行的是activiti-engine-7.0.0.Beta1.jar包下对应不同内置好的sql语句
 * org\activiti\db\drop\activiti.db2.drop.engine.sql
 *
 * @author zrj
 * @date 2020/12/29
 * @since V1.0
 **/
public class ActivitiInit {

    /**
     * 方式一
     */
    @Test
    public void GenActivitiTables() {

        // 1.创建ProcessEngineConfiguration对象。第一个参数:配置文件名称;第二个参数:processEngineConfiguration的bean的id
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource( "activiti.cfg.xml", "processEngineConfiguration" );
        // 2.创建ProcessEngine对象
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        // 3.输出processEngine对象
        System.out.println( processEngine );

    }

    /**
     * 方式二
     */
    @Test
    public void GenActivitiTables2() {
        //条件:1.activiti配置文件名称:activiti.cfg.xml   2.bean的id="processEngineConfiguration"
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        System.out.println( processEngine );
    }
}

3.3 创建数据库表

执行上边的代码。

3.4 数据库表命名规则

工作流引擎Activiti详解_第5张图片

Activiti 的表都以 ACT_开头。 第二部分是表示表的用途的两个字母标识。 用途也和服务的 API 对应。

ACT_RE_*: 'RE'表示 repository。这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
ACT_RU_*: 'RU'表示 runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti 只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。
ACT_HI_*: 'HI'表示 history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。
ACT_GE_*: 'GE'表示 general。 通用数据, 用于不同场景下

4. Activiti架构简介

activiti.cfg.xml
activiti 的引擎配置文件,包括: ProcessEngineConfiguration 的定义、数据源定义、事务管理器等,此文件其实就是一个 spring 配置文件,下面是一个基本的配置只配置了 ProcessEngineConfiguration和数据源。

ProcessEngineConfiguration
流程引擎的配置类,通过 ProcessEngineConfiguration 可以创建工作流引擎 ProceccEngine,常用的两种方法。

ProcessEngine
工作流引擎,相当于一个门面接口,通过 ProcessEngineConfiguration 创建 processEngine,通过ProcessEngine 创建各个 service 接口。

Service
通过 ProcessEngine 创建 Service, Service 是工作流引擎提供用于进行工作流部署、执行、管理的服务接口。

工作流引擎Activiti详解_第6张图片

5. Activiti入门案例

5.1 流程定义

什么是流程定义
流程定义是线下按照 bpmn2.0 标准去描述 业务流程,通常使用 activiti-explorer(web 控制台)或 activiti-eclipse-designer 插件对业务流程进行建模,这两种方式都遵循 bpmn2.0 标准。本教程使用activiti-eclipse-designer 插件完成流程建模。使用 designer 设计器绘制流程,会生成两个文件: .bpmn和.png

创建bpmn文件
Palette(画板)

在 eclipse 或 idea 中安装 activiti-designer 插件即可使用,画板中包括以下结点:
Connection—连接
Event---事件
Task---任务
Gateway---网关
Container—容器
Boundary event—边界事件
Intermediate event- -中间事件
流程图设计完毕保存生成.bpmn 文件

idea创建bpmn
工作流引擎Activiti详解_第7张图片工作流引擎Activiti详解_第8张图片
生成png图片
第一步:将 holiday.bpmn 文件改为扩展名 xml 的文件名称: holiday.xml
第二步: 在 holiday.xml 文件上面,点右键并选择 Diagrams 菜单,再选择 Show BPMN2.0 Designe
工作流引擎Activiti详解_第9张图片
第三步: 打开后的效果图如下:
工作流引擎Activiti详解_第10张图片
打开如下窗口,注意填写文件名及扩展名,选择好保存图片的位置:
工作流引擎Activiti详解_第11张图片第五步:中文乱码的解决
1.打开 IDEA 安装路径,找到如下的安装目录
工作流引擎Activiti详解_第12张图片
根据自己所安装的版本来决定,我使用的是 64 位的 idea,所以在 idea64.exe.vmoptions 文件的最后
一行追加一条命令: -Dfile.encoding=UTF-8
如下所示
工作流引擎Activiti详解_第13张图片一定注意,不要有空格,否则重启 IDEA 时会打不开,然后 重启 IDEA,把原来的 png 图片删掉,再重新生成,即可解决乱码问题

5.2 部署流程

什么是流程部署
将线下定义的流程部署到 activiti 数据库中,这就是流程定义部署,通过调用 activiti 的 api 将流程定义的 bpmn 和 png 两个文件一个一个添加部署到 activiti 中,也可以将两个文件打成 zip 包进行部署。

单个文件部署方式
分别将 bpmn 文件和 png 图片文件部署
压缩包部署方式

/**
 * 流程定义的部署
 * activiti表有哪些?
 * act_re_deployment  部署信息
 * act_re_procdef     流程定义的一些信息
 * act_ge_bytearray   流程定义的bpmn文件及png文件
 *
 * @author zrj
 * @date 2020/12/29
 * @since V1.0
 **/
public class ActivitiDeployment {

    /**
     * 方式一
     * 分别将 bpmn 文件和 png 图片文件部署
     */
    @Test
    public void activitiDeploymentTest() {
        //1.创建ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.得到RepositoryService实例
        RepositoryService repositoryService = processEngine.getRepositoryService();

        //3.进行部署
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource( "diagram/holiday.bpmn" )
                .addClasspathResource( "diagram/holiday.png" )
                .name( "请假申请单流程" )
                .deploy();

        //4.输出部署的一些信息
        System.out.println( deployment.getName() );
        System.out.println( deployment.getId() );
    }

    /**
     * 方式二
     * 将 holiday.bpmn 和 holiday.png 压缩成 zip 包
     */
    @Test
    public void activitiDeploymentTest2() {
        //1.创建ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.得到RepositoryService实例
        RepositoryService repositoryService = processEngine.getRepositoryService();

        //3.转化出ZipInputStream流对象
        InputStream is = ActivitiDeployment.class.getClassLoader().getResourceAsStream( "diagram/holidayBPMN.zip" );

        //将 inputstream流转化为ZipInputStream流
        ZipInputStream zipInputStream = new ZipInputStream( is );

        //3.进行部署
        Deployment deployment = repositoryService.createDeployment()
                .addZipInputStream( zipInputStream )
                .name( "请假申请单流程" )
                .deploy();

        //4.输出部署的一些信息
        System.out.println( deployment.getName() );
        System.out.println( deployment.getId() );
    }

}

操作数据表

 -- activiti表有哪些?
 -- 部署信息
select * from act_re_deployment ;
 
-- 流程定义的一些信息
select * from act_re_procdef;
 
 -- 流程定义的bpmn文件及png文件
select * from act_ge_bytearray;

5.3 启动流程


/**
 * 启动流程实例:
 * 前提是先已经完成流程定义的部署工作
 * 背后影响的表:
 * act_hi_actinst     已完成的活动信息
 * act_hi_identitylink   参与者信息
 * act_hi_procinst   流程实例
 * act_hi_taskinst   任务实例
 * act_ru_execution   执行表
 * act_ru_identitylink   参与者信息
 * act_ru_task  任务
 *
 * @author zrj
 * @date 2020/12/29
 * @since V1.0
 **/
public class ActivitiStartInstance {
    public static void main(String[] args) {
        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.得到RunService对象
        RuntimeService runtimeService = processEngine.getRuntimeService();

        //3.创建流程实例  流程定义的key需要知道 holiday
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey( "holiday" );

        //4.输出实例的相关信息
        System.out.println( "流程部署ID" + processInstance.getDeploymentId() );
        System.out.println( "流程定义ID" + processInstance.getProcessDefinitionId() );
        System.out.println( "流程实例ID" + processInstance.getId() );
        System.out.println( "活动ID" + processInstance.getActivityId() );

    }
}

5.4 流程定义查询


/**
 * 流程定义查询
 *
 * @author zrj
 * @date 2020/12/29
 * @since V1.0
 **/
public class QueryProceccDefinition {

    @Test
    public void queryProceccDefinition() {
        // 流程定义key
        String processDefinitionKey = "holiday";
        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        // 获取repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 查询流程定义
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        //遍历查询结果
        List<ProcessDefinition> list = processDefinitionQuery
                .processDefinitionKey( processDefinitionKey )
                .orderByProcessDefinitionVersion().desc().list();

        for (ProcessDefinition processDefinition : list) {
            System.out.println( "------------------------" );
            System.out.println( " 流 程 部 署 id : " + processDefinition.getDeploymentId() );
            System.out.println( "流程定义id: " + processDefinition.getId() );
            System.out.println( "流程定义名称: " + processDefinition.getName() );
            System.out.println( "流程定义key: " + processDefinition.getKey() );
            System.out.println( "流程定义版本: " + processDefinition.getVersion() );
        }
    }
}

5.5 流程定义删除

   /**
     * 删除指定流程id的流程
     */
    public void deleteDeployment() {
        // 流程部署id
        String deploymentId = "8801";
        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        // 通过流程引擎获取repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //删除流程定义, 如果该流程定义已有流程实例启动则删除时出错
        repositoryService.deleteDeployment( deploymentId );
        //设置true 级联删除流程定义,即使该流程有流程实例启动也可以删除,设
        //置为false非级别删除方式,如果流程
        repositoryService.deleteDeployment( deploymentId, true );
    }

5.6 流程定义资源查询

   /**
     * 获取资源
     */
    @Test
    public void getProcessResources() throws IOException {
        // 流程定义id
        String processDefinitionId = "";
        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 流程定义对象
        ProcessDefinition processDefinition = repositoryService
                .createProcessDefinitionQuery()
                .processDefinitionId( processDefinitionId ).singleResult();
        //获取bpmn
        String resource_bpmn = processDefinition.getResourceName();
        //获取png
        String resource_png = processDefinition.getDiagramResourceName();
        // 资源信息
        System.out.println( "bpmn: " + resource_bpmn );
        System.out.println( "png: " + resource_png );
        File file_png = new File( "d:/purchasingflow01.png" );
        File file_bpmn = new File( "d:/purchasingflow01.bpmn" );
        // 输出bpmn
        InputStream resourceAsStream = null;
        resourceAsStream = repositoryService.getResourceAsStream( processDefinition.getDeploymentId(), resource_bpmn );
        FileOutputStream fileOutputStream = new FileOutputStream( file_bpmn );
        byte[] b = new byte[1024];
        int len = -1;
        while ((len = resourceAsStream.read( b, 0, 1024 )) != -1) {
            fileOutputStream.write( b, 0, len );
        }
        // 输出图片
        resourceAsStream = repositoryService.getResourceAsStream( processDefinition.getDeploymentId(), resource_png );
        fileOutputStream = new FileOutputStream( file_png );
        // byte[] b = new byte[1024];
        // int len = -1;
        while ((len = resourceAsStream.read( b, 0, 1024 )) != -1) {
            fileOutputStream.write( b, 0, len );
        }
    }

你可能感兴趣的:(基础框架,工作流引擎Activiti详解)