一. Flowable API

参考:Flowable学习笔记(一、入门) - 三分恶 - 博客园

我们开发Flowable涉及到了一些Flowable的API,在开发的时候经常需要与这些API打交道。

入口点为:ProcessEngine,我们有多种方式来创建它。

通过ProcessEngine,我们可以获取工作流的不同服务类型,ProcessEngine和服务都是线程安全的,因此我们可以用作单例对象来使用这些服务。

// 第一次会初始化和创建一个ProcessEngine,后续调用都会从缓存中直接返回,全局创建一次
// ProcessEngines.init()与ProcessEngines.destroy(). 初始化和消耗与ProcessEngines
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

RuntimeService runtimeService = processEngine.getRuntimeService();
RepositoryService repositoryService = processEngine.getRepositoryService();
TaskService taskService = processEngine.getTaskService();
ManagementService managementService = processEngine.getManagementService();
IdentityService identityService = processEngine.getIdentityService();
HistoryService historyService = processEngine.getHistoryService();
FormService formService = processEngine.getFormService();
DynamicBpmnService dynamicBpmnService = processEngine.getDynamicBpmnService();

  • RepositoryService: 操作和管理流程的定义和部署,deployment(部署)是ProcessEngine的基本单元
  • RuntimeService:每一个流程都可以创建许多的运行实例,RuntimeService启动流程的实例,检索和存储实例的变量信息
  • IdentityService:管理组和用户的身份认证信息
  • FormService:可选的服务
  • HistoryService:检索ProcessEngine的历史数据
  • ManagementService:检索数据库的元数据和表的信息,在编程的时候一般用不到
  • DynamicBpmnService:动态的改变流程的定义,并且不需要重新部署,在生产环境很少使用

二。流程图及XML

参考:基于BPMN2.0的工作流(Workflow) - 简书

流程定义的说明:

  • 我们假定启动流程需要提供一些信息,例如雇员名字、请假时长以及说明。当然,这些可以单独建模为流程中的第一步。 但是如果将它们作为流程的“输入信息”,就能保证只有在实际请求时才会建立一个流程实例。否则(将提交作为流程的第一步),用户可能在提交之前改变主意并取消,但流程实例已经创建了。 在某些场景中,就可能影响重要的指标(例如启动了多少申请,但还未完成),取决于业务目标。

  • 左侧的圆圈叫做启动事件(start event)。这是一个流程实例的起点。

  • 第一个矩形是一个用户任务(user task)。这是流程中人类用户操作的步骤。在这个例子中,经理需要批准或驳回申请。

  • 取决于经理的决定,排他网关(exclusive gateway) (带叉的菱形)会将流程实例路由至批准或驳回路径。

  • 如果批准,则需要将申请注册至某个外部系统,并跟着另一个用户任务,将经理的决定通知给申请人。当然也可以改为发送邮件。

  • 如果驳回,则为雇员发送一封邮件通知他。

这里我们直接撰写XML,以熟悉BPMN 2.0及其概念。

以下是与上面展示的流程图对应的BPMN 2.0 XML。这里只包含了“流程部分”。如果使用图形化建模工具,实际的XML文件还将包含“可视化部分”,用于描述图形信息,如流程定义中各个元素的坐标(所有的图形化信息包含在XML的BPMNDiagram标签中,作为definitions标签的子元素)。

在src/main/resources文件夹下创建为holiday-request.bpmn20.xml文件:

<?xml version="1.0" encoding="utf-8" ?>

<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
             xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
             xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
             xmlns:flowable="http://flowable.org/bpmn"
             typeLanguage="http://www.w3.org/2001/XMLSchema"
             expressionLanguage="http://www.w3.org/1999/XPath"
             targetNamespace="http://www.flowable.org/processdef">

    <process id="holiday-request" name="Holiday Request" isExecutable="true">
        <!--开始事件:流程实例的起点-->
        <startEvent id="startEvent"/>
        <!--顺序流:执行时会从一个活动流向另一个活动-->
        <sequenceFlow sourceRef="startEvent" targetRef="approveTask"/>

        <!--用户任务:需要人工来进行操作-->
        <userTask id="approveTask" name="Approve or reject request"/>
        <sequenceFlow sourceRef="approveTask" targetRef="decision"/>

        <!--排他网关-->
        <exclusiveGateway id="decision"/>
        <sequenceFlow sourceRef="decision" targetRef="externalSystemCall">
            <!--顺序流条件:以表达式(expression)的形式定义了条件(condition) -->
            <conditionExpression xsi:type="tFormalExpression">
                <!--条件表达式:是${approved == true}的简写-->
                <![CDATA[
                  ${approved}
                ]]>
            </conditionExpression>
        </sequenceFlow>
        <sequenceFlow sourceRef="decision" targetRef="sendRejectionMail">
            <conditionExpression xsi:type="tFormalExpression">
                <![CDATA[
                  ${!approved}
                ]]>
            </conditionExpression>
        </sequenceFlow>

        <!--服务任务,一个自动活动,它会调用一些服务-->
        <serviceTask id="externalSystemCall" name="Enter holidays in external system" flowable:class="edu.hpu.process.CallExternalSystemDelegate"/>

        <userTask id="holidayApprovedTask" name="Holiday Approve!"/>
        <sequenceFlow sourceRef="holidayApprovedTask" targetRef="approveEnd"/>

        <serviceTask id="sendRejectionMail" name="Send out rejection email" flowable:class="edu.hpu.process.SendRejectionMail"/>
        <sequenceFlow sourceRef="sendRejectionMail" targetRef="rejectEnd"/>

        <!--结束事件-->
        <endEvent id="approveEnd"/>
        <endEvent id="rejectEnd"/>
    </process>

</definitions>
  • 每一个步骤(在BPMN 2.0术语中称作活动(activity))都有一个id属性,为其提供一个在XML文件中唯一的标识符。所有的活动都可以设置一个名字,以提高流程图的可读性。

  • 活动之间通过顺序流(sequence flow)连接,在流程图中是一个有向箭头。在执行流程实例时,执行(execution)会从启动事件沿着顺序流流向下一个活动。

  • 离开排他网关(带有X的菱形)的顺序流很特别:都以表达式(expression)的形式定义了条件(condition) 。当流程实例的执行到达这个网关时,会计算条件,并使用第一个计算为true的顺序流。这就是排他的含义:只选择一个。当然如果需要不同的路由策略,可以使用其他类型的网关。

  • 这里用作条件的表达式为𝑎𝑝𝑝𝑟𝑜𝑣𝑒𝑑,这是approved,这是{approved == true}的简写。变量’approved’被称作流程变量(process variable)。流程变量是持久化的数据,与流程实例存储在一起,并可以在流程实例的生命周期中使用。在这个例子里,我们需要在特定的地方(当经理用户任务提交时,或者以Flowable的术语来说,完成(complete)时)设置这个流程变量,因为这不是流程实例启动时就能获取的数据。

三 .数据库表

ACT_RE_:’RE’表示repository(存储 ),RepositoryService接口所操作的表。带此前缀的表包含的是静态信息,如,流程定义,流程的资源(图片,规则等)。
2、ACT_RU_:‘RU’表示runtime,运行时表-RuntimeService。这是运行时的表存储着流程变量,用户任务,变量,职责(job)等运行时的数据。Activiti只存储实例执行期间的运行时数据,当流程实例结束时,将删除这些记录。这就保证了这些运行时的表小且快。
3、ACT_ID_:’ID’表示identity (组织机构),IdentityService接口所操作的表。用户记录,流程中使用到的用户和组。这些表包含标识的信息,如用户,用户组,等等。
4、ACT_HI_:’HI’表示history,历史数据表,HistoryService。就是这些表包含着流程执行的历史相关数据,如结束的流程实例,变量,任务,等等
5、ACT_GE_*:全局通用数据及设置(general),各种情况都使用的数据。

 

四.流程操作

参考:Flowable 流程实例_tengyunyang的博客-CSDN博客

1. 部署流程

        ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
                .setJdbcPassword("")
                .setJdbcUrl("jdbc:mysql://127.0.0.1:3306/flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8")
                .setJdbcUsername("aihe")
                .setJdbcPassword("123456")
                .setJdbcDriver("com.mysql.jdbc.Driver")

                // 如果数据表不存在的时候,自动创建数据表
                .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);

        // 执行完成后,就可以开始创建我们的流程了
        ProcessEngine processEngine = cfg.buildProcessEngine();

        // 使用BPMN 2.0定义process。存储为XML,同时也是可以可视化的。NPMN 2.0标准可以让技术人员与业务人员都
        // 参与讨论业务流程中来

        // 部署流程
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("holiday-request.bpmn20.xml")
                .deploy();

2. 启动流程实例

使用RuntimeService启动流程实例

操作的是act_ru_execution表,如果是用户任务节点,同时也会在act_ru_task添加一条记录

 String processDefinitionKey = "leave";
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey);
    System.out.println(processInstance.getId()+","+processInstance.getActivityId());

3. 查询个人任务 TaskService(act_ru_task)

从processEngine中应该得到TaskService

使用TaskService获取到任务查询对象TaskQuery

为查询对象添加过滤条件,使用taskAssignee指定任务的办理者(即查询指定用户的待办任务),同时可以添加分页排序等过滤条件

调用list方法进行查询

 String assignee = "张三";
    String processDefinitionKey = "leave";
    List<Task> list = taskService.createTaskQuery()
            .taskAssignee(assignee)
            .processDefinitionKey(processDefinitionKey).list();
    list.forEach(v -> System.out.println(v.getId() + " "
            + v.getName() + " " + v.getTaskDefinitionKey()
            + " " + v.getExecutionId() + " " + v.getProcessInstanceId() + " " + v.getCreateTime()));

4.完成个人任务

对于执行完的任务,Flowable将从act_ru_task表中删除该任务,下一个任务会被插入进来(这两个操作是在一个事物中)

 String taskId = "20006";
    taskService.complete(taskId);

5. 查询流程状态

查询流程实例状态 判断流程正在执行还是结束

String processInstanceId = "30001";
    ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
            .processInstanceId(processInstanceId).singleResult();
    if (processInstance != null) {
        System.out.println("当前流程实例正在运行");
    } else {
        System.out.println("当前流程实例正在运行");
    }

6. 流程发起人设置

String authenticatedUserId = "tyy";
    identityService.setAuthenticatedUserId(authenticatedUserId);
    String processDefinitionKey = "leave";
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey);
    System.out.println(processInstance.getId() + "," + processInstance.getActivityId());

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐