侧边栏壁纸
博主头像
coydone博主等级

记录学习,分享生活的个人站点

  • 累计撰写 306 篇文章
  • 累计创建 51 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Activiti入门

coydone
2022-11-06 / 0 评论 / 0 点赞 / 643 阅读 / 10,544 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-07-03,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

完成创建一个Activiti工作流,并启动这个流程。

创建Activiti工作流主要包含以下几步:

  1. 定义流程,按照BPMN的规范,使用流程定义工具,用流程符号把整个流程描述出来;

  2. 部署流程,把画好的流程定义文件,加载到数据库中,生成表的数据;

  3. 启动流程,使用java代码来操作数据库表中的内容。

流程符号

BPMN2.0是业务流程建模符号2.0的缩写。

它由Business Process Management Initiative这个非营利协会创建并不断发展。作为一种标识,BPMN 2.0是使用一些符号来明确业务流程设计流程图的一整套符号规范,它能增进业务建模时的沟通效率。

目前BPMN2.0是最新的版本,它用于在BPM上下文中进行布局和可视化的沟通。

BPMN2.0的基本符号主要包含:

1、事件Event

2、活动Activity:活动是工作或任务的一个通用术语。一个活动可以是一个任务,还可以是一个当前流程的子处理流程; 其次,你还可以为活动指定不同的类型。常见活动如下:

3、网关GateWay:网关用来处理决策。

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

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

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

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

4、流向Flow:流是连接两个流程节点的连线。

使用Activiti Designer

Palette(画板),在idea中安装插件即可使用,画板中包括以下结点:

  • Connection——连接

  • Event——事件

  • Task——任务

  • Gateway——网关

  • Container——容器

  • Boundary event——边界事件

  • Intermediate event——中间事件

流程图设计完毕保存生成.bpmn文件。

新建流程

1、选中存放图形的目录(选择resources下的bpmn目录),点击菜单:New→BpmnFile。

2、弹出框中输入evection表示出差审批流程,起完名字evection后(默认扩展名为bpmn),就可以看到流程设计页面,如图所示:

中间区域是绘图区,右侧区域是palette画板区域,鼠标先点击画板的元素即可在中间绘图。

绘制流程

使用滑板来绘制流程,通过从右侧把图标拖拽到左侧的画板,最终效果如下:

流程定义key即流程定义的标识,通过properties视图查看流程的key。

指定任务负责人

在properties视图指定每个任务结点的负责人,在Assignee中填写,如:填写出差申请的负责人为zhangsan;经理审批负责人为lisi;总经理审批负责人为wangwu;财务审批负责人为zhaoliu。

生成PNG文件

bpmn文件本质上是XML文件,因为安装actiBPw插件,才能可视化的看到流程内容。

生成PNG文件:把bpmn文件后缀改为xml,在这个文件上右键选择Diagrams→show BPNN2.0 Desinger,打开窗口,点击导出文件选择导出文件类型为PNG。

把png文件拷贝到resources下的bpmn目录,并且把evection.xml改名为evection.bpmn。

流程操作

流程定义部署

将上面在设计器中定义的流程部署到Activiti数据库中,就是流程定义部署。使用Activiti提供的API把流程图的内容写入数据库中属于资源类操作,使用RepositoryService。

单文件部署:把bpmn文件和png文件一个一个处理。

/**
 * 流程定义部署:定义→部署→添加资源
 * act_re_procdef流程定义表,部署每个新的流程定义都会在这张表中增加一条记录
 * act_re_deployment流程定义部署表,每部署一次增加一条记录
 * act_ge_bytearray资源表
 */
@Test
public void deployProcess() {
    // 1、获取流程引擎
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 2、获取RepositoryService
    RepositoryService repositoryService = processEngine.getRepositoryService();
    // 3、使用service进行流程的部署,定义一个流程的名字,把bpmn和png部署到数据中
    Deployment deploy = repositoryService.createDeployment()
            .name("出差申请流程")
            .addClasspathResource("bpmn/evection.bpmn")
            .addClasspathResource("bpmn/evection.png")
            .deploy();
    // 4、输出部署信息
    System.out.println("流程部署id=" + deploy.getId());
    System.out.println("流程部署名字=" + deploy.getName());
}

压缩包部署:把bpmn文件和png打压缩包来处理。

/**
 * 使用zip包进行批量的部署
 */
@Test
public void deployProcessByZip() {
    // 获取流程引擎
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 获取RepositoryService
    RepositoryService repositoryService = processEngine.getRepositoryService();
    // 流程部署
    // 读取资源包文件,构造成inputStream
    InputStream inputStream = this.getClass()
            .getClassLoader()
            .getResourceAsStream("bpmn/evection.zip");
    // 用inputStream 构造ZipInputStream
    ZipInputStream zipInputStream = new ZipInputStream(inputStream);
    // 使用压缩包的流进行流程的部署
    Deployment deploy = repositoryService.createDeployment()
            .addZipInputStream(zipInputStream)
            .deploy();
    System.out.println("流程部署id=" + deploy.getId());
    System.out.println("流程部署的名称=" + deploy.getName());
}

启动流程实例

/**
 * 启动流程实例,操作的表:
 * act_hi_actinst       流程实例执行历史信息
 * act_hi_identitylink  流程参与用户的历史信息
 * act_hi_procinst      流程实例的历史信息
 * act_hi_taskinst      流程任务的历史信息
 * act_ru_execution     流程执行信息
 * act_ru_identitylink  流程的正在参与用户信息
 * act_ru_task          流程当前任务信息
 */
@Test
public void startProcess() {
    // 1、创建ProcessEngine
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 2、获取RunTimeService
    RuntimeService runtimeService = processEngine.getRuntimeService();
    // 3、根据流程定义的id启动流程
    ProcessInstance instance = runtimeService.startProcessInstanceByKey("myEvection");
    // 4、输出内容
    System.out.println("流程定义ID:" + instance.getProcessDefinitionId());
    System.out.println("流程实例ID:" + instance.getId());
    System.out.println("当前活动的ID:" + instance.getActivityId());
}

任务查询

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

/**
 * 查询个人待执行的任务
 */
@Test
public void findPersonalTaskList() {
    // 1、获取流程引擎
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 2、获取taskService
    TaskService taskService = processEngine.getTaskService();
    // 3、根据流程key 和 任务的负责人 查询任务
    List<Task> taskList = taskService.createTaskQuery()
            .processDefinitionKey("myEvection") // 流程Key
            .taskAssignee("zhangsan")  // 要查询的负责人
            .list();
    // 4、输出
    for (Task task : taskList) {
        System.out.println("流程实例id=" + task.getProcessInstanceId());
        System.out.println("任务Id=" + task.getId());
        System.out.println("任务负责人=" + task.getAssignee());
        System.out.println("任务名称=" + task.getName());
    }
}

流程任务处理

任务负责人查询待办任务,选择任务进行处理,完成任务。

/**
 * 完成个人任务
 */
@Test
public void completTask(){
    // 获取引擎
    // ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 获取操作任务的服务 TaskService
    // TaskService taskService = processEngine.getTaskService();
    // 完成任务,参数:任务id(act_ru_task表)
    // 完成zhangsan的任务
    // taskService.complete("2505");

    // 依次完成lisi的任务 、完成wangwu的任务、完成zhaoliu的任务
    completPersonalTask("lisi");
    completPersonalTask("wangwu");
    completPersonalTask("zhaoliu");
}

private static void completPersonalTask(String assignee) {
    // 获取引擎
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 获取操作任务的服务 TaskService
    TaskService taskService = processEngine.getTaskService();
    // 个人任务
    Task task = taskService.createTaskQuery()
            .processDefinitionKey("myEvection")
            .taskAssignee(assignee)
            .singleResult();
    System.out.println("流程实例id="+task.getProcessInstanceId());
    System.out.println("任务Id="+task.getId());
    System.out.println("任务负责人="+task.getAssignee());
    System.out.println("任务名称="+task.getName());
    // 完成个人任务,参数:任务id(act_ru_task表)
    taskService.complete(task.getId());
}

任务历史表记录

流程定义信息查询

查询流程相关信息,包含流程定义,流程部署,流程定义版本等。

/**
 * 查询流程定义
 */
@Test
public void queryProcessDefinition() {
    // 获取引擎
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 获取Repositoryservice
    RepositoryService repositoryService = processEngine.getRepositoryService();
    // 获取ProcessDifinitionQuery对象
    ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery();
    // 查询当前所有的流程定义 ,返回流程定义信息的集合
    // processDefinitionKey(流程定义Key)
    List<ProcessDefinition> definitionList = definitionQuery.processDefinitionKey("myEvection")
            .orderByProcessDefinitionVersion() // 进行排序
            .desc() // 倒叙
            .list(); //查询出所有的内容
    // 输出信息
    for (ProcessDefinition processDefinition : definitionList) {
        System.out.println("流程定义ID:" + processDefinition.getId());
        System.out.println("流程定义名称:" + processDefinition.getName());
        System.out.println("流程定义Key:" + processDefinition.getKey());
        System.out.println("流程定义版本:" + processDefinition.getVersion());
        System.out.println("流程部署ID:" + processDefinition.getDeploymentId());
    }
}

输出结果:

流程定义ID:myEvection:1:4
流程定义名称:出差申请
流程定义Key:myEvection
流程定义版本:1
流程部署ID:1

流程删除

/**
 * 删除流程部署信息,删除的表与创建流程定义的表一样
 * act_ge_bytearray
 * act_re_deployment
 * act_re_procdef
 * 当前的流程如果并没有完成,想要删除的话需要使用特殊方式,原理就是 级联删除
 */
@Test
public void deleteDeployment(){
    // 获取流程引擎
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 通过引擎来获取 RepositoryService
    RepositoryService repositoryService = processEngine.getRepositoryService();
    // 通过部署id(act_re_deployment)来删除流程部署信息
    String deploymentId = "1";
    // 删除流程定义,如果该流程定义已有流程实例启动则删除时出错
    // repositoryService.deleteDeployment(deploymentId);
    // 设置true,级联删除流程定义,即使该流程有流程实例启动也可以删除;设置为false非级别删除方式
    repositoryService.deleteDeployment(deploymentId,true);
}

说明:

1、使用RepositoryService删除流程定义,历史表信息不会被删除;

2、如果该流程定义下没有正在运行的流程,则可以用普通删除。

3、如果该流程定义下存在已经运行的流程,使用普通删除报错,可用级联删除方法将流程及相关记录全部删除。先删除没有完成流程节点,最后就可以完全删除流程定义信息。

4、项目开发中级联删除操作一般只开放给超级管理员使用。

流程资源下载

流程资源文件已经上传到数据库了,如果其他用户想要查看这些资源文件,可以从数据库中把资源文件下载到本地。

1、使用commons-io.jar 解决IO的操作,引入commons-io依赖包。

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

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

  • resource_name为act_ge_bytearray表中NAME_列的值。

  • 使用repositoryService的getDeploymentResourceNames方法可以获取指定部署下得所有文件的名称。

  • 使用repositoryService的getResourceAsStream方法传入部署ID和资源图片名称可以获取部署下指定名称文件的输入流。

  • 最后的将输入流中的图片资源进行输出。

/**
 * 下载 资源文件
 * 使用Activiti提供的api(RespositoryService)来下载资源文件,保存到文件目录
 * 解决IO操作:commons-io.jar
 */
@Test
public void getDeployment() throws IOException {
    // 1、得到引擎
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 2、获取api,RepositoryService
    RepositoryService repositoryService = processEngine.getRepositoryService();
    // 3、获取查询对象 ProcessDefinitionQuery查询流程定义信息
    ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
            .processDefinitionKey("myEvection")
            .singleResult();
    // 4、通过流程定义信息,获取部署ID
    String deploymentId = processDefinition.getDeploymentId();
    // 5、通过RepositoryService,传递部署id参数,读取资源信息(png 和 bpmn)
    // 5.1、获取png图片的流
    // 从流程定义表中,获取png图片的目录和名字
    String pngName = processDefinition.getDiagramResourceName();
    // 通过部署id和文件名字来获取图片的资源
    InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, pngName);
    // 5.2、获取bpmn的流
    String bpmnName = processDefinition.getResourceName();
    InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, bpmnName);
    // 6、构造OutputStream流
    File pngFile = new File("d:/evectionflow01.png");
    File bpmnFile = new File("d:/evectionflow01.bpmn");
    FileOutputStream pngOutStream = new FileOutputStream(pngFile);
    FileOutputStream bpmnOutStream = new FileOutputStream(bpmnFile);
    // 7、输入流,输出流的转换
    IOUtils.copy(pngInput, pngOutStream);
    IOUtils.copy(bpmnInput, bpmnOutStream);
    // 8、关闭流
    pngOutStream.close();
    bpmnOutStream.close();
    pngInput.close();
    bpmnInput.close();
}

流程历史信息的查看

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

/**
 * 查看历史信息
 */
@Test
public void findHistoryInfo() {
    // 获取引擎
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 获取HistoryService
    HistoryService historyService = processEngine.getHistoryService();
    // 获取 actinst表的查询对象
    HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
    // 查询 actinst表,条件:根据 InstanceId 查询
    // instanceQuery.processInstanceId("2501");
    // 查询 actinst表,条件:根据 DefinitionId 查询
    instanceQuery.processDefinitionId("myEvection:1:4");
    // 增加排序操作,orderByHistoricActivityInstanceStartTime 根据开始时间排序 asc 升序
    instanceQuery.orderByHistoricActivityInstanceStartTime().asc();
    // 查询所有内容
    List<HistoricActivityInstance> activityInstanceList = instanceQuery.list();
    // 输出
    for (HistoricActivityInstance hi : activityInstanceList) {
        System.out.println(hi.getActivityId());
        System.out.println(hi.getActivityName());
        System.out.println(hi.getProcessDefinitionId());
        System.out.println(hi.getProcessInstanceId());
        System.out.println("<==========================>");
    }
}
0

评论区