Activiti7(图文并茂)

简介: Activiti7(图文并茂)

一 介绍


1.1 Activiti 介绍


Activiti 是由 jBPM (BPM,Business Process Management 即业务流程管理) 的创建者 Tom Baeyens 离开 JBoss 之后建立的项目,构建在开发 jBPM 版本 1 到 4 时积累的多年经验的基础之上,旨在创建下一代的 BPM 解 决方案。


Activiti 作为一个开源的工作流引擎,它实现了BPMN 2.0规范,可以发布设计好的流程定义,并通过api进行流程调 度。 Activiti 作为一个遵从 Apache 许可的工作流和业务流程管理开源平台,其核心是基于Java的超快速、超稳定的 BPMN2.0 流程引擎,强调流程服务的可嵌入性和可扩展性,同时更加强调面向业务人员。


Activiti 流程引擎重点关注在系统开发的易用性和轻量性上。每一项 BPM 业务功能 Activiti 流程引擎都以服务的形 式提供给开发人员。通过使用这些服务,开发人员能够构建出功能丰富、轻便且高效的 BPM 应用程序。 Activiti是一个针对企业用户、开发人员、系统管理员的轻量级工作流业务管理平台,其核心是使用Java开发的快 速、稳定的BPMN 2.0流程引擎。Activiti是在ApacheV2许可下发布的,可以运行在任何类型的Java程序中,例如服 务器、集群、云服务等。


Activiti可以完美地与Spring集成。同时,基于简约思想的设计使Activiti非常轻量级。 官网:


https://www.activiti.org/


1.2 Activiti 开发流程


  1. 画流程定义模型: 遵守BPMN的流程规范,使用BPMN的流程定义工具,通过 流程符号 把整个业务流程定义出来,可以将流程 定义文件字节流保存到模型数据表中(Model)。


  1. 部署流程定义: 加载画好的流程定义文件,将它转换成流程定义数据(ProcessDefinition),保存到流程定义数据表中。


  1. 启动流程(提交流程申请): 生成流程实例数据(ProcessInstance),生成第1节点任务数据(Task)。


  1. 处理人审批流程节点任务: 完成任务审批,生成审批结果,生成下一节点任务数据。


1.3 BPMN 2.0 规范是什么


业务流程模型注解(Business Process Modeling Notation - BPMN)是业务流程模型的一种标准图形注解。这个 标准是由对象管理组(Object Management Group - OMG)维护的。


标准的早期版本(1.2版以及之前)仅仅限制在模型上, 目标是在所有的利益相关者之间形成通用的理解, 在文 档,讨论和实现业务流程之上。 BPMN标准证明了它自己,现在市场上许多建模工具都使用了BPMN标准中的元素 和结构。


BPMN规范的2.0版本,当前已经处于最终阶段了, 允许添加精确的技术细节在BPMN的图形和元素中, 同时制定 BPMN元素的执行语法。 通过使用XML语言来指定业务流程的可执行语法, BPMN规范已经演变为业务流程的语 言, 可以执行在任何兼容BPMN2的流程引擎中, 同时依然可以使用强大的图形注解。


目前BPMN2.0是最新的版本,它用于在BPM上下文中进行布局和可视化的沟通。BPMN 2.0是使用一些符号来明确 业务流程设计流程图的一整套符号规范,它能增进业务建模时的沟通效率。


1.4 BPMN 2.0 基本流程符号


1.4.1 事件 Event


开始 中间事件 结束



1.4.2 活动


活动是工作或任务的一个通用术语。一个活动可以是一个任务,还可以是一个当前流程的子处理流程;


1.4.3 网关 Gateway


网关用来处理决策:



  • 排他网关 (x)


只有一条路径会被选择。流程执行到该网关时,按照输出流的顺序逐个计算,当条件的计算结果为true时,继 续执行当前网关的输出流; 如果多条线路计算结果都是 true,则会执行第一个值为 true 的线路。如果所有网关计算结果没有true,则引 擎会抛出异常。 排他网关需要和条件顺序流结合使用,default 属性指定默认顺序流,当所有的条件不满足时会执行默认顺序流。


  • 并行网关 (+)


所有路径会被同时选择 分支: 并行执行所有输出顺序流,为每一条顺序流创建一个并行执行线路。 汇聚 :所有从并行网关拆分并执行完成的线路均在此等候,直到所有的线路都执行完成才继续向下执行。


  • 包含网关 (o)


可以同时执行多条线路,也可以在网关上设置条件分支:计算每条线路上的表达式,当表达式计算结果为true时,创建一个并行线路并继续执行 汇聚:所有从并行网关拆分并执行完成的线路均在此等候,直到所有的线路都执行完成才继续向下执行。


  1. 事件网关 (o+)


专门为中间捕获事件设置的,允许设置多个输出流指向多个不同的中间捕获事件。当流程执行到事件网关 后,流程处于等待状态,需要等待抛出事件才能将等待状态转换为活动状态。


1.5 Activiti API 服务接口


Activiti 流程引擎包含了25张表,而且表之间的关系也比较复杂,比如包含各种外键约束。


按照传统的方式,有了数据库表后,就应该为每张表创建 Entity 实体类,然后为其创建对应的 DAO 接口,然 后再创建对应的 Service来实现对表数据的增删改查;


但是按照传统方式的,就会有一个很严峻的问题,表的数量太多,并且关系复杂,还要兼顾流程引擎的处理方 式,自己去搞一套,几乎不可能;


其实不需要我们去创建Entity 、 DAO、Service、Controller,因为Activiti已经把这些东西给搞好了,只需要 调用即可。


Process Engine API 和服务


引擎 API 是与 Activiti 交互的最常见方式。


可以从ProcessEngine中获取包含工作流/ BPM方法的各种服务。


ProcessEngine和服务对象是线程安全的。因此,可以为整个服务器保留对其中之一的引用。


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



1.5.1 核心Service接口及其获取


// 会在首次调用时初始化并构建一个流程引擎,此后始终返回相同的流程引擎。
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 引擎管理类
ManagementService managementService = processEngine.getManagementService();
// 动态修改流程管理类
DynamicBpmnService dynamicBpmnService = processEngine.getDynamicBpmnService();
// 流程运行管理类
RuntimeService runtimeService = processEngine.getRuntimeService();
// 流程仓库管理类
RepositoryService repositoryService = processEngine.getRepositoryService();
// 任务管理类
TaskService taskService = processEngine.getTaskService();
// 历史管理类
HistoryService historyService = processEngine.getHistoryService();


二 表


2.1 建表


前提:在数据库中建库 并和配置文件中的连接信息保持一致。


在test中执行如下语句,即可建表成功:


@Autowired
ProcessEngine processEngine;
@Test
public void getProcessEngine() {
System.out.println("processEngine: " + processEngine);
}


建好表后,执行两条语句,使其完整:


ALTER TABLE ACT_RE_DEPLOYMENT ADD COLUMN VERSION_ VARCHAR(255);
ALTER TABLE ACT_RE_DEPLOYMENT ADD COLUMN PROJECT_RELEASE_VERSION_ VARCHAR(255);


2.2 表介绍


Acitiviti数据库中表的命名都是以 ACT_ 开头的。第二部分是一个两个字符用例表的标识。此用例大体与服务API是 匹配的。


ACT_GE_* : GE 表示 general 。通用数据,各种情况都使用的数据 ,如存放资源文件(图片,规则等)。


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


ACT_RE_xxx : RE 表示repository。带此前缀的表包含的是静态信息,如,流程定义,流程的资源(图片,规则 等)。 Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直 很小速度很快。


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


ACT_EVT_* :EVT表示EVENT,流程引擎的通用事件日志记录表,方便管理员跟踪处理。


表分类 表名 说明
通用数据
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_re_deployment 部署信息表
act_re_model 流程设计模型表
act_re_procdef 流程设计模型表
流程运行表
act_ru_deadletter_job 作业死亡信息表,如果作业失败超过重试次数,则写入到此表
act_ru_event_subscr throwEvent、catchEvent时间监听信息表
act_ru_execution 运行时流程执行实例表
aact_ru_identitylink 运行时流程人员表,主要存储任务节点与参与者的相关信息
act_ru_integration 运行时积分表
act_ru_job 定时异步任务数据表

act_ru_suspended_job
运行时作业暂停表, 比如流程中有一个定时任务,如果把这个任 务停止工作了,这个任务写入到此表中
act_ru_task 运行时任务节点表
act_ru_timer_job 运行时定时器作业表
act_ru_variable 运行时流程变量数据表
其他表
act_procdef_info 流程定义的动态变更信息
act_evt_log 流程引擎的通用事件日志记录表


三 关于model


3.1 model画图


画图前,先指定如下三处



必须有个开始 和 结束 :



加入任务:



注意:双击节点可以指定节点名称


指定任务办理人:



然后到下一步(此时是以写死的方式来指定办理人的)



完成整个流程绘图后,点击左上角保存



点击保存后出现如下框,填写完 点保存就好



动态分配办理人


方式1:指定变量




此时是指定了一个表达式的样子来指定的动态办理人,为该表达式赋值的时机是流程到达该节点之前,如果该节点之前是 开始 ,那么就在流程启动的时候指定,如果该节点之前是 任务 ,那么就在完成上一步任务的同时指定下一步办理人。


如何加流程参数在本文档的第九节。


方式2:指定对象属性名




在启动流程或者完成上一步任务办理的同时,指定一个user对象进去就好了。


如何加流程参数在本文档的第九节。


方式3:方法表达式




注意:userService是Spring容器中的一个bean实例,对应调用getUsername()方法。

如何加流程参数在本文档的第九节。


3.2 操作model


3.2.1 模型查询对象


@Autowired
RepositoryService repositoryService;
/**
* 查询所有流程定义模型
*/
@Test
public void modelList() {
    ModelQuery query = repositoryService.createModelQuery();
    List<Model> list = query.orderByCreateTime()
        .desc()
        .list();
    for (Model model : list) {
        System.out.print("模型id:" + model.getId());
        System.out.print(", 模型名称:" + model.getName());
        System.out.print(",模型描述: " + model.getMetaInfo());
        System.out.print(",模型标识key:" + model.getKey());
        System.out.println(",模型版本号:" + model.getVersion());
    }
}


3.2.2 删除模型对象


@Autowired
RepositoryService repositoryService; 
/**
 * 删除流程定义模型
 * 会影响到的表:ACT_RE_MODE 和 ACT_GE_BYTEARRAY
 */
 @Test
 public void deleteModel() {
     // modelId 为表ACT_RE_MODE 中的ID字段
     String modelId = "0a499790-7c1d-11f6-9001-2c337a6d7e1d";
     repositoryService.deleteModel(modelId);
     System.out.println("删除成功");
 }


3.2.3 导出流程定义模型资源的zip压缩包


@Autowired
RepositoryService repositoryService;
@Test
public void exportZip() throws IOException {
    // 1. 查询模型基本信息 (modelId 为表ACT_RE_MODE 中的ID字段)
    String modelId = "da0fbf5c-7c1d-11f6-949f-2c337a6d7e1d";
    Model model = repositoryService.getModel(modelId);
    if(model != null) {
        // 2. 查询流程定义模型的json字节码
        byte[] bpmnJsonBytes = repositoryService.getModelEditorSource(modelId);
        // 2.1 将json字节码转换为xml字节码
        byte[] xmlBytes = bpmnJsonXmlBytes(bpmnJsonBytes);
        if(xmlBytes == null) {
            System.out.println("模型数据为空-请先设计流程定义模型,再导出");
        }else {
            // 压缩包文件名
            String zipName = model.getName() + "." + model.getKey() + ".zip";
            File file = new File("D:/" + zipName);
            FileOutputStream outputStream = new FileOutputStream(file);
            // 实例化zip输出流
            ZipOutputStream zipos = new ZipOutputStream(outputStream);
            // 将xml添加到压缩包中(指定xml文件名:请假流程.bpmn20.xml )
            zipos.putNextEntry(new ZipEntry(model.getName() + ".bpmn20.xml"));
            zipos.write(xmlBytes);
            // 3. 查询流程定义模型的图片字节码
            byte[] pngBytes = repositoryService.getModelEditorSourceExtra(modelId);
            if(pngBytes != null) {
                // 图片文件名(请假流程.leaveProcess.png)
                zipos.putNextEntry(new ZipEntry(model.getName() + "." + model.getKey() + ".png"));
                zipos.write(pngBytes);
            }
            // 4. 以压缩包的方式导出流程定义模型文件
            zipos.closeEntry();
            zipos.close();
            System.out.println("导出流程定义模型zip成功");
        }
    }else {
        System.out.println("模型不存在");
    }
}
private byte[] bpmnJsonXmlBytes(byte[] jsonBytes) throws IOException {
    if(jsonBytes == null) {
        return null;
    }
    // 1. json字节码转成 BpmnModel 对象
    JsonNode jsonNode = objectMapper.readTree(jsonBytes);
    BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(jsonNode);
    if(bpmnModel.getProcesses().size() == 0) {
        return null;
    }
    // 2. BpmnModel 对象转为xml字节码
    byte[] xmlBytes = new BpmnXMLConverter().convertToXML(bpmnModel);
    return xmlBytes;
}


3.2.4 导出流程定义模型资源的.xml文件


@Test
public void exportXml() throws IOException {
    // 1. 查询模型基本信息
    String modelId = "da0fbf5c-7c1d-11f6-949f-2c337a6d7e1d";
    // 查询json字节码
    byte[] bytes = repositoryService.getModelEditorSource(modelId);
    String filename = null;
    ByteArrayInputStream in = null;
    if(bytes != null) {
        // 1. json字节码转成 BpmnModel 对象
        JsonNode jsonNode = objectMapper.readTree(bytes);
        BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(jsonNode);
        if(bpmnModel.getProcesses().size() > 0) {
            // 2. BpmnModel 对象转为xml字节码
            byte[] xmlBytes = new BpmnXMLConverter().convertToXML(bpmnModel);
            in = new ByteArrayInputStream(xmlBytes);
            filename = StringUtils.isBlank(bpmnModel.getMainProcess().getName())
                ? bpmnModel.getMainProcess().getId() : bpmnModel.getMainProcess().getName();
        }
    }
    if(filename == null) {
        filename = "模型数据为空,请先设计流程,再导出";
        in = new ByteArrayInputStream(filename.getBytes("utf-8"));
    }
    // 文件输出流
    FileOutputStream out = new FileOutputStream(new File("D:/" + filename + ".bpmn20.xml"));
    IOUtils.copy(in, out);
    out.close();
    in.close();
    System.out.println("导出xml成功");
}


3.2.5 通过流程定义模型数据部署流程定义


 /**
 * 会影响到的表:
 * ACT_RE_PROCDEF
 * ACT_RE_DEPLOYMENT
 * ACT_GE_BYTEARRAY
 * ACT_RE_MODEL 更新流程部署id,将模型与部署的流程定义绑定
 * @throws Exception
 */
 @Test
 public void deploy() throws Exception {
     // 1. 查询流程定义模型json字节码
     String modelId = "b8efa921-da43-11eb-8aa7-2c337a6d7e1d";
     byte[] jsonBytes = repositoryService.getModelEditorSource(modelId);
     if(jsonBytes == null) {
     System.out.println("模型数据为空,请先设计流程定义模型,再进行部署");
     return;
     }
     // 将json字节码转为 xml 字节码,因为bpmn2.0规范中关于流程模型的描述是xml格式的,而activiti遵守了这个规范
     byte[] xmlBytes = bpmnJsonXmlBytes(jsonBytes);
     if(xmlBytes == null) {
     System.out.println("数据模型不符合要求,请至少设计一条主线流程");
     return;
     }
     // 2. 查询流程定义模型的图片
     byte[] pngBytes = repositoryService.getModelEditorSourceExtra(modelId);
    // 查询模型的基本信息
    Model model = repositoryService.getModel(modelId);
    // xml资源的名称 ,对应act_ge_bytearray表中的name_字段
    String processName = model.getName() + ".bpmn20.xml";
    // 图片资源名称,对应act_ge_bytearray表中的name_字段
    String pngName = model.getName() + "." + model.getKey() + ".png";
    // 3. 调用部署相关的api方法进行部署流程定义
    Deployment deployment = repositoryService.createDeployment()
    .name(model.getName()) // 部署名称
    .addString(processName, new String(xmlBytes, "UTF-8")) // bpmn20.xml资源
    .addBytes(pngName, pngBytes) // png资源
    .deploy();
    // 更新 部署id 到流程定义模型数据表中
    model.setDeploymentId(deployment.getId());
    repositoryService.saveModel(model);
    System.out.println("部署成功");
}


四 操作部署信息


4.1 部署


4.1.1通过zip压缩包进行部署流程定义


 /**
 * 通过zip压缩包进行部署流程定义
 */
@Test
public void deployByZip() throws Exception {
    File file = new File("D:/请假流程模型xx.leaveProcess.zip");
    // 创建输入流
    FileInputStream inputStream = new FileInputStream(file);
    // 读取zip资源压缩包,转成输入流
    ZipInputStream zipInputStream = new ZipInputStream(inputStream);
    Deployment deployment = repositoryService.createDeployment()
        .addZipInputStream(zipInputStream)
        .name("请假申请流程222-压缩包")
        .deploy();
    // 4. 输出部署结果
    System.out.println("部署ID: " + deployment.getId());
    System.out.println("部署名称:" + deployment.getName());
}


4.1.2 通过.xml文件部署


@Test
public void deployByFile() throws FileNotFoundException {
    File file = new File("D:/请假申请流程.bpmn20.xml");
    // 文件输入流
    FileInputStream inputStream = new FileInputStream(file);
    // 资源名称
    String filename = file.getName();
    // 调用相关api方法进行部署
    Deployment deployment = repositoryService.createDeployment()
        .name("请假申请流程")
        .addInputStream(filename, inputStream)
        .deploy();
    // 输出部署结果
    System.out.println("部署ID: " + deployment.getId());
    System.out.println("部署名称:" + deployment.getName());
}


4.2 删除部署流程定义


/**
 * 根据部署ID来删除部署的流程定义数据
 * 影响到的表:
 * ACT_GE_BYTEARRAY
 * ACT_RE_DEPLOYMENT
 * ACT_RE_PROCDEF
 * ACT_RU_EVENT_SUBSCR
 * ACT_RU_IDENTITYLINK
 */
@Test
public void delete() {
    try {
        String deploymentId = "f88ccd79-db17-11eb-a1e0-2c337a6d7e1d";
        // 默认不是级联删除操作,如果有正在执行的流程实例,则删除时会抛出异常,并且不会删除历史表数据
        //repositoryService.deleteDeployment(deploymentId);
        // 如果为true则是级联删除操作(小心使用~)
        //  如果流程定义启动了对应的流程实例,也可以进行删除,并且会删除历史数据
        //repositoryService.deleteDeployment(deploymentId, true);
        System.out.println("删除流程定义数据成功");
    }catch (Exception e) {
        e.printStackTrace();
        if(e.getMessage().indexOf("a foreign key constraint fails") > 0) {
            System.out.println("有正在执行的流程实例,不允许删除");
        }else {
            System.out.println("删除失败,原因: " + e.getMessage());
        }
    }
}


4.3 启动流程


@Autowired
RuntimeService runtimeService;
@Test
public void startProcessInstance() {
    // 启动流程实例(流程定义key processDefinitionKey)
    // 通过流程定义key启动的流程实例 ,找的是最新版本的流程定义数据
    // 根据key部署 这个案例里"leaveProcess" 为部署的key
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leaveProcess");
    System.out.println("流程定义id: " + processInstance.getProcessDefinitionId());
    System.out.println("流程实例id: " + processInstance.getId());
}


相关文章
|
6月前
|
XML Java 应用服务中间件
【小白误闯】Activiti 框架你不得不知道的一些事
Activiti 是一个轻量级的、以Java为中心的开源工作流和业务流程管理(BPM)平台。它允许用户在业务应用程序中定义、执行和监控业务流程。以下是Activiti的核心组件【5月更文挑战第8天】
591 1
|
XML Java 数据库连接
史上最全 Activiti 学习教程,一文搞定最强工作流引擎!(4)
史上最全 Activiti 学习教程,一文搞定最强工作流引擎!
|
Oracle Java 关系型数据库
史上最全 Activiti 学习教程,一文搞定最强工作流引擎!(2)
史上最全 Activiti 学习教程,一文搞定最强工作流引擎!
|
XML 前端开发 数据可视化
史上最全 Activiti 学习教程,一文搞定最强工作流引擎!(3)
史上最全 Activiti 学习教程,一文搞定最强工作流引擎!
|
XML 存储 供应链
史上最全 Activiti 学习教程,一文搞定最强工作流引擎!(1)
史上最全 Activiti 学习教程,一文搞定最强工作流引擎!
|
XML 存储 API
工作流 jbpm(图文并茂)(下)
工作流 jbpm(图文并茂)
|
XML 存储 Java
工作流 jbpm(图文并茂)
工作流 jbpm(图文并茂)
|
XML 监控 安全
Activiti整理
一个完整的工作流生命周期会经过5步,并且迭代循环。 定义:工作流生命周期总是从流程定义开始。这个过程包括收集需求,将其转化成流程定义,也就流程图、相关变量、角色定义。 发布:由开发人员打包各种资源,然后在系统管理中发布流程定义。包括:bpmn.xml、自定义表单、任务监听类等。 执行:具体的流程引擎按照事先定义的流程处理路线以任务驱动的方式执行业务流程。 监控:此阶段是依赖执行阶段。业务人员在办理任务的同时收集每个任务(Task)的结果,然后根据结果做出相应处理。 优化:在此阶段,一个完整的流程已经结束,或许能满足业务需求,或者需要优化。
250 0
Activiti整理
|
XML 数据可视化 Java
史上最全的工作流引擎 Activiti 学习教程(值得收藏)(三)
史上最全的工作流引擎 Activiti 学习教程(值得收藏)(三)
史上最全的工作流引擎 Activiti 学习教程(值得收藏)(三)