Avtiviti(三)之流程定义

1、流程定义

       流程定义是线下按照bpmn2.0标准去描述 业务流程,通常使用activiti-explorer(web控制台)或activiti-eclipse-designer插件对业务流程进行建模,这两种方式都遵循bpmn2.0标准。

1.1 .bpmn文件和.png图片文件

在IDEA开发工具中,使用activiti-desinger设计业务流程,会生成.bpmn文件,根据该文件可以生成.png图片文件,具体方法可以参考上一篇文章

.bpmn文件的实质是.xml文件,它的具体内容结构如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:tns="http://www.activiti.org/testm1564730183518" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1564730183518" name="" targetNamespace="http://www.activiti.org/testm1564730183518" typeLanguage="http://www.w3.org/2001/XMLSchema">
  <process id="myholiday" isClosed="false" isExecutable="true" processType="None">
    <startEvent id="_2" name="StartEvent"/>
    <userTask activiti:assignee="zhangsan" activiti:exclusive="true" id="_3" name="填写请假单"/>
    <sequenceFlow id="_4" sourceRef="_2" targetRef="_3"/>
    <userTask activiti:assignee="lisi" activiti:exclusive="true" id="_5" name="部门经理审批"/>
    <userTask activiti:assignee="wangwu" activiti:exclusive="true" id="_6" name="总经理审批"/>
    <userTask activiti:assignee="zhaoliu" activiti:exclusive="true" id="_7" name="财务审批"/>
    <endEvent id="_8" name="EndEvent"/>
    <sequenceFlow id="_9" sourceRef="_3" targetRef="_5"/>
    <sequenceFlow id="_10" sourceRef="_5" targetRef="_6"/>
    <sequenceFlow id="_11" sourceRef="_6" targetRef="_7"/>
    <sequenceFlow id="_12" sourceRef="_7" targetRef="_8"/>
  </process>
  <bpmndi:BPMNDiagram documentation="background=#FFFFFF;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
    <bpmndi:BPMNPlane bpmnElement="myholiday">
      <bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
        <dc:Bounds height="32.0" width="32.0" x="265.0" y="35.0"/>
        <bpmndi:BPMNLabel>
          <dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
        <dc:Bounds height="55.0" width="85.0" x="240.0" y="110.0"/>
        <bpmndi:BPMNLabel>
          <dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_5" id="Shape-_5">
        <dc:Bounds height="55.0" width="85.0" x="240.0" y="195.0"/>
        <bpmndi:BPMNLabel>
          <dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_6" id="Shape-_6">
        <dc:Bounds height="55.0" width="85.0" x="240.0" y="285.0"/>
        <bpmndi:BPMNLabel>
          <dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_7" id="Shape-_7">
        <dc:Bounds height="55.0" width="85.0" x="240.0" y="370.0"/>
        <bpmndi:BPMNLabel>
          <dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_8" id="Shape-_8">
        <dc:Bounds height="32.0" width="32.0" x="265.0" y="465.0"/>
        <bpmndi:BPMNLabel>
          <dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="_12" id="BPMNEdge__12" sourceElement="_7" targetElement="_8">
        <di:waypoint x="281.0" y="425.0"/>
        <di:waypoint x="281.0" y="465.0"/>
        <bpmndi:BPMNLabel>
          <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_4" id="BPMNEdge__4" sourceElement="_2" targetElement="_3">
        <di:waypoint x="281.0" y="67.0"/>
        <di:waypoint x="281.0" y="110.0"/>
        <bpmndi:BPMNLabel>
          <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_9" id="BPMNEdge__9" sourceElement="_3" targetElement="_5">
        <di:waypoint x="282.5" y="165.0"/>
        <di:waypoint x="282.5" y="195.0"/>
        <bpmndi:BPMNLabel>
          <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_11" id="BPMNEdge__11" sourceElement="_6" targetElement="_7">
        <di:waypoint x="282.5" y="340.0"/>
        <di:waypoint x="282.5" y="370.0"/>
        <bpmndi:BPMNLabel>
          <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_10" id="BPMNEdge__10" sourceElement="_5" targetElement="_6">
        <di:waypoint x="282.5" y="250.0"/>
        <di:waypoint x="282.5" y="285.0"/>
        <bpmndi:BPMNLabel>
          <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

BPMN 2.0根节点是definitions节点。 这个元素中,可以定义多个流程定义(不过我们建议每个文件只包含一个流程定义, 可以简化开发过程中的维护难度)。 注意,definitions元素 最少也要包含xmlns 和 targetNamespace的声明。 targetNamespace可以是任意值,它用来对流程实例进行分类。

流程定义部分:定义了流程每个结点的描述及结点之间的流程流转。
流程布局定义:定义流程每个结点在流程图上的位置坐标等信息。

2、流程定义部署

2.1 什么是流程定义部署

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

2.2 单个文件部署方式

单个文件部署方式,就是分别把.bpmn文件和.png文件部署到activiti数据库中。

package com.zdw.activiti;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;

import java.io.InputStream;
import java.util.zip.ZipInputStream;

/**
 * 流程定义部署
 *  activiti表有哪些?
 *    act_re_deployment  部署信息
      act_re_procdef     流程定义的一些信息
      act_ge_bytearray   流程定义的bpmn文件及png文件
 */
public class ActivitiDeployment {
    //流程定义部署  流程制作出来后要上传到服务器 zip文件更便于上传(bpmn和png单独上传也可以,下面也会演示)
    public static void main(String[] args) {
        //创建ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //得到RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();

        Deployment deployment = repositoryService.createDeployment().addClasspathResource("bpmn/holiday.bpmn")
                                    .addClasspathResource("bpmn/holiday.png").name("请假流程").deploy();

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

2.3 压缩包部署方式

       实际开发中,一般用的多的是这种方式,因为在项目中,一般是要通过把文件上传到服务器,然后进行部署的,进行压缩包部署就只需要上传一次就行了,比较简洁。不过activiti底层还是把这个压缩包解压成了.bpmn和.png文件存到了数据库中。

package com.zdw.activiti;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;

import java.io.InputStream;
import java.util.zip.ZipInputStream;

/**
 * 流程定义部署
 *  activiti表有哪些?
 *    act_re_deployment  部署信息
      act_re_procdef     流程定义的一些信息
      act_ge_bytearray   流程定义的bpmn文件及png文件
 */
public class ActivitiDeployment {
    //流程定义部署  流程制作出来后要上传到服务器 zip文件更便于上传(bpmn和png单独上传也可以,下面也会演示)
    public static void main(String[] args) {
        //创建ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //得到RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();

        //转化出ZipInputStream流对象
        InputStream inputStream = ActivitiDeployment.class.getClassLoader().getResourceAsStream("bpmn/holiday.zip");
        //将 inputstream流转化为ZipInputStream流
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);

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

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

2.4 操作数据表

流程定义部署后操作activiti数据表如下:
SELECT * FROM act_re_deployment         #流程定义部署表,记录流程部署信息
SELECT * FROM act_re_procdef               #流程定义表,记录流程定义信息
SELECT * FROM act_ge_bytearray           #资源表,存的是.png和.bpmn文件信息,还有一些序列化参数信息

说明:
       act_re_deployment和act_re_procdef一对多关系,一次部署在流程部署表生成一条记录,但一次部署可以部署多个流程定义,每个流程定义在流程定义表生成一条记录。每一个流程定义在act_ge_bytearray会存在两个资源记录,bpmn和png。
建议:一次部署一个流程,这样部署表和流程定义表是一对一有关系,方便读取流程部署及流程定义信息。

 

3、流程定义查询

3.1 查询部署的流程定义:

package com.zdw.activiti02;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;

import java.util.List;

/**
 * 流程定义查询
 */
public class QueryProceccDefinitionTest {
    public static void main(String[] args) {
        //得到工作流引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //得到RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //得到流程定义查询对象 ProcessDefinitionQuery
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        //根据流程定义的key查询所有的流程定义效果
        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.processDefinitionKey("myholiday").orderByProcessDefinitionKey().desc().list();
        for (ProcessDefinition processDefinition : processDefinitionList) {
            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());
        }
    }
}

3.2 流程定义删除

删除已经部署成功的流程定义:

package com.zdw.activiti02;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;

import java.util.List;

/**
 * 删除部署成功的流程定义
 */
public class DeleteProceccDefinitionTest {
    public static void main(String[] args) {
        //得到工作流引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //得到RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //得到流程定义查询对象 ProcessDefinitionQuery
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        //查询流程定义
        ProcessDefinition processDefinition = processDefinitionQuery.processDefinitionKey("myholiday").singleResult();
        //删除流程定义,如果该流程定义已有流程实例启动则删除时出错
        //repositoryService.deleteDeployment(processDefinition.getDeploymentId());
        //设置true 级联删除流程定义,即使该流程有流程实例启动也可以删除,设置为false非级别删除方式
        repositoryService.deleteDeployment(processDefinition.getDeploymentId(),true);
    }
}

说明:
1) 使用repositoryService删除流程定义
2) 如果该流程定义下没有正在运行的流程,则可以用普通删除。
3) 如果该流程定义下存在已经运行的流程,使用普通删除报错,可用级联删除方法将流程及相关记录全部删除。项目开发中使用级联删除的情况比较多,删除操作一般只开放给超级管理员使用。

4、流程定义资源查询

4.1 方式一

通过流程定义对象获取流程定义资源,获取bpmn和png。

package com.zdw.activiti02;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.apache.commons.io.IOUtils;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 得到流程定义的资源:.bpmn和.png文件
 * 需求:把流程定义的.bpmn和.png文件下载到本地电脑的  D  盘下面
 */
public class GetProcessResource {
    public static void main(String[] args) throws IOException {
        //得到工作流引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //得到RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //获取流程定义对象查询对象
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        //查询流程定义对象
        ProcessDefinition processDefinition = processDefinitionQuery.processDefinitionKey("myholiday").singleResult();
        //得到.bpmn和.png文件的名称
        String bpmn_name = processDefinition.getResourceName();
        String png_name = processDefinition.getDiagramResourceName();
        //得到.bpmn和.png文件的输入流对象
        InputStream bpmn_inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), bpmn_name);
        InputStream png_inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),png_name);

        //创建输出流对象
        FileOutputStream bpmn_outputStream = new FileOutputStream("d:/holiday.bpmn");
        FileOutputStream png_outputStream = new FileOutputStream("d:/holiday.png");
        //通过commons-io里面的IOUtils工具类把输入流内容复制到输出流中
        IOUtils.copy(bpmn_inputStream,bpmn_outputStream);
        IOUtils.copy(png_inputStream,png_outputStream);
        //释放资源
        bpmn_outputStream.close();
        png_outputStream.close();
        bpmn_inputStream.close();
        png_inputStream.close();
    }
}

4.2 方式2

通过查询流程部署信息获取流程定义资源

//获取流程定义图片资源
    public static void main(String[] args) throws IOException {
        //得到工作流引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //得到RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //流程部署ID
        String deploymentId = "7501";

        //读取资源名称
        List<String> resourceNames = repositoryService.getDeploymentResourceNames(deploymentId);
        //定义图片资源的名称
        String png_name = null;
        for (String resourceName : resourceNames) {
            if(resourceName.indexOf(".png")>0){
                png_name = resourceName;
            }
        }
        //得到图片输入流
        InputStream png_inputStream = repositoryService.getResourceAsStream(deploymentId,png_name);
        //定义输出流对象
        FileOutputStream png_outputStream = new FileOutputStream("d:/holiday.png");
        //通过commons-io里面的IOUtils工具类把输入流内容复制到输出流中
        IOUtils.copy(png_inputStream,png_outputStream);
        //释放资源
        png_outputStream.close();
        png_inputStream.close();
    }

说明:
1) deploymentId为流程部署ID
2) resource_name为act_ge_bytearray表中NAME_列的值
3) 使用repositoryService的getDeploymentResourceNames方法可以获取指定部署下得所有文件的名称
4) 使用repositoryService的getResourceAsStream方法传入部署ID和资源图片名称可以获取部署下指定名称文件的输入流
5) 最后的将输入流中的图片资源进行输出。

 

5、流程历史信息的查看

       即使流程定义已经删除了,流程执行的历史信息通过前面的分析,依然保存在activiti的act_hi_*相关的表中。所以我们还是可以查询流程执行的历史信息,可以通过HistoryService来查看相关的历史记录。

package com.zdw.activiti02;

import org.activiti.engine.HistoryService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;

import java.util.List;

/**
 * 查询流程实例的历史信息
 */
public class QueryHistoryProcessInfo {
    public static void main(String[] args) {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        HistoryService historyService = processEngine.getHistoryService();
        //得到活动的流程实例的历史查询对象
        HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
        //根据流程实例ID查询
        List<HistoricActivityInstance> list = historicActivityInstanceQuery.processInstanceId("10001").list();
        for (HistoricActivityInstance historicActivityInstance : list) {
            System.out.println(historicActivityInstance.getActivityId());
            System.out.println(historicActivityInstance.getActivityName());
            System.out.println(historicActivityInstance.getProcessDefinitionId());
            System.out.println(historicActivityInstance.getProcessInstanceId());
            System.out.println("==============================");
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值