flowable流程引擎

Flowable流程引擎


一、流程引擎API和服务

引擎 API 是与 Flowable 交互的最常见方式。主要起点是 ProcessEngine,它可以通过多种方式创建,如配置部分所述。从 ProcessEngine,您可以获得包含工作流/BPM 方法的各种服务。ProcessEngine 和 services 对象是线程安全的,因此您可以为整个服务器保留对其中一个的引用。

api.services

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();

常用类:
ProcessEngines–流程引擎管理类
ProcessEngine–流程引擎类
ProcessEngineImpl–流程引擎实现类
ProcessEngineConfiguration–流程引擎配置类
ProcessEngineInfo–流程引擎信息类

ProcessEngines

//key:流程引擎的名称   value:流程引擎的实例对象
Map<String, ProcessEngine> processEngines = new HashMap<>();
//key:流程引擎的名称   value:流程引擎信息类的实例对象
Map<String, EngineInfo> processEngineInfosByName = new HashMap<>();
//key:流程引擎资源的名称   value:流程引擎信息类的实例对象
Map<String, EngineInfo> processEngineInfosByResourceUrl = new HashMap<>();
//存储流程引擎信息类实例对象
 List<EngineInfo> processEngineInfos = new ArrayList<>();

初始化时类加载器默认加载:根路径下的 flowable.cfg.xml

在这里插入图片描述

flowable和activiti的对比

1、flowable已经支持所有的历史数据使用mongdb存储,activiti没有。

2、flowable支持事务子流程,activiti没有。

3、flowable支持多实例加签、减签,activiti没有。

4、flowable支持httpTask等新的类型节点,activiti没有。

5、flowable支持在流程中动态添加任务节点,activiti没有。

6、flowable支持历史任务数据通过消息中间件发送,activiti没有。

7、flowable支持java11,activiti没有。

8、flowable支持动态脚本,,activiti没有。

9、flowable支持条件表达式中自定义juel函数,activiti没有。

10、flowable支持cmmn规范,activiti没有。

11、flowable修复了dmn规范设计器,activit用的dmn设计器还是旧的框架,bug太多。

12、flowable屏蔽了pvm,activiti6也屏蔽了pvm(因为6版本官方提供了加签功能,发现pvm设计的过于臃肿,索性直接移除,这样加签实现起来更简洁、事实确实如此,如果需要获取节点、连线等信息可以使用bpmnmodel替代)。

13、flowable与activiti提供了新的事务监听器。activiti5版本只有事件监听器、任务监听器、执行监听器。

14、flowable对activiti的代码大量的进行了重构。

15、activiti以及flowable支持的数据库有h2、hsql、mysql、oracle、postgres、mssql、db2。其他数据库不支持的。使用国产数据库的可能有点失望了,需要修改源码了。

16、flowable支持jms、rabbitmq、mongodb方式处理历史数据,activiti没有。

支持的数据库:AbstractEngineConfiguration
在这里插入图片描述

二、.RepositoryService服务

/**
 * ****************************************************************************************************
 * 1.RepositoryService
 * 仓库服务类,定义bpmn文件和png图片
 * 流程图片的生产方式
 *  (1)设计流程图的时候产生
 *  (2)通过API的方式根据流程文件生成
 * 引擎配置类构造代码ProcessEngineConfigurationImpl
 * 注意:流程引擎类(ProcessEngineImpl)通过流程引擎配置类(ProcessEngineConfigurationImpl)来获取服务对象的
 * ****************************************************************************************************
 * RepositoryService
 * (可以派生的类:DeploymentBuilder、ProcessDefinitionQuery、NativeProcessDefinitionQuery、DeploymentQuery)
 * (1)DeploymentBuilder:用来定义流程部署相关的参数。
 * (2)ProcessDefinitionQuery:用来构造查询流程定义相关的参数。
 * (3)NativeProcessDefinitionQuery:用来构造本地SQL查询流程定义相关的参数。
 * (4)NativeProcessDefinitionQuery:用来构造查询部署对象相关的参数。
 * *****************************************************************************************************
 * */

在这里插入图片描述

在这里插入图片描述

 /**
     * ****************************************************************************************************
     * 1.RepositoryService
     * 仓库服务类,定义bpmn文件和png图片
     * 流程图片的生产方式
     *  (1)设计流程图的时候产生
     *  (2)通过API的方式根据流程文件生成
     * 引擎配置类构造代码ProcessEngineConfigurationImpl
     * 注意:流程引擎类(ProcessEngineImpl)通过流程引擎配置类(ProcessEngineConfigurationImpl)来获取服务对象的
     * ****************************************************************************************************
     * RepositoryService
     * (可以派生的类:DeploymentBuilder、ProcessDefinitionQuery、NativeProcessDefinitionQuery、DeploymentQuery)
     * (1)DeploymentBuilder:用来定义流程部署相关的参数。
     * (2)ProcessDefinitionQuery:用来构造查询流程定义相关的参数。
     * (3)NativeProcessDefinitionQuery:用来构造本地SQL查询流程定义相关的参数。
     * (4)NativeProcessDefinitionQuery:用来构造查询部署对象相关的参数。
     * *****************************************************************************************************
     * */
    public void repositoryService(){
        //获取流程仓库引擎的服务类
        RepositoryService repositoryService= processEngine.getRepositoryService();
        //用来定义流程部署相关的参数
        DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
        //用来构造查询流程定义相关的参数
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        //用来构造本地SQL查询流程定义相关的参数
        NativeProcessDefinitionQuery nativeProcessDefinitionQuery =
                repositoryService.createNativeProcessDefinitionQuery();
        //用来构造查询部署对象相关的参数
        DeploymentQuery deploymentQuery = repositoryService.createDeploymentQuery();
    }
1.资源部署的多种方式
 //用来定义流程部署相关的参数
        DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
        deploymentBuilder
                .category("学习flowable测试分类")
                .name("自定义资源部署的名字")
                .tenantId("设置租户ID")
                .addClasspathResource("bpmn文件路径(在根路径下直接写文件全名)")
                .deploy();
*************************************************************************************************************
/**
     * 文本方式部署
     * 资源的名称必须是"bpmn20.xml", "bpmn"这两个结尾的才能部
     * 署到流程定义表中(act_re_procdef),不然只有部署表中才有,
     * 定义表中没有相应的数据
     * */
    @Test
    public void testDeployByText(){
        String text= IoUtil.readFileAsString("days.xml");
        Deployment deploy = processEngine.getRepositoryService()
                .createDeployment()
                .name("文本方式部署资源")
                .category("测试文本部署分类")
                .key("设置key值")
                .tenantId("租户的ID")
                .addString("days.bpmn", text)//
                .deploy();
        System.out.println("获取部署对象的id="+deploy.getId());
    }
*************************************************************************************************************
  /**
     * 输入流的方式部署
    * */
    @Test
    public void testDeploymentByInputStream(){
        //InputStream resourceAsStream = GetProcessEngine.class.getClassLoader().getResourceAsStream("days.xml");
        InputStream resource =getClass().getClassLoader().getResourceAsStream("days.xml");
        Deployment deploy = processEngine.getRepositoryService()
                .createDeployment()
                .name("测试输入流的方式部署")
                .category("测试输入流方式部署分类")
                .key("key值")
                .tenantId("租户的ID")
                .addInputStream("inputStream.bpmn", resource)
                .deploy();
        System.out.println("输入流的方式部署获取部署对象的id="+deploy.getId());
    }
*************************************************************************************************************
   /**
     * 压缩流的方式部署资源
     * */
    @Test
    public void testDeploymentByZipInputStream(){
        InputStream resourceAsStream = GetProcessEngine.class.getClassLoader().getResourceAsStream("resources.zip");
        //InputStream resource =getClass().getClassLoader().getResourceAsStream("resources.zip");
        ZipInputStream zipInputStream = new ZipInputStream(resourceAsStream);
        Deployment deploy = processEngine.getRepositoryService()
                .createDeployment()
                .name("测试压缩流的方式部署")
                .category("测试压缩流方式部署分类")
                .key("压缩key值")
                .tenantId("租户的ID压缩")
                .addZipInputStream(zipInputStream)
                .deploy();
        System.out.println("输入流的方式部署获取部署对象的id="+deploy.getId());
    }
*************************************************************************************************************
 /**
     * 字节的方式部署资源
     * */
    @Test
    public void testDeploymentByBytes(){
        InputStream resourceAsStream = GetProcessEngine.class.getClassLoader().getResourceAsStream("days.xml");
        //InputStream resource =getClass().getClassLoader().getResourceAsStream("days.xml");
        byte[] bytes =IoUtil.readInputStream(resourceAsStream,"Bytes InputStream");
        Deployment deploy = processEngine.getRepositoryService()
                .createDeployment()
                .name("测试字节流的方式部署")
                .category("测试字节流方式部署分类")
                .key("字节key值")
                .tenantId("字节租户的ID")
                .addBytes("happy.bpmn",bytes)
                .deploy();
        System.out.println("字节的方式部署获取部署对象的id="+deploy.getId());
    }   
*************************************************************************************************************
1.通过输入流的方式部署  
DeploymentBuilder addInputStream(String resourceName, InputStream inputStream);
2.同过根路径(classpath)的方式部署
DeploymentBuilder addClasspathResource(String resource);
3.通过文本的方式部署
DeploymentBuilder addString(String resourceName, String text);
4.通过字节放是部署
DeploymentBuilder addBytes(String resourceName, byte[] bytes);
5.通过压缩流的方式部署(一次可以部署多个文件)
DeploymentBuilder addZipInputStream(ZipInputStream zipInputStream);
6.通过模型的方式部署
DeploymentBuilder addBpmnModel(String resourceName, BpmnModel bpmnModel);

文本的形式部署资源的名称必须是bpmn20.xml或者bpmn结束的

在这里插入图片描述

2.部署完成后对应表的变化
  • act_re_deployment(部署对象表)
    存放流程定义的信息(如名字、类别、租户ID等信息),每部署一次多一条记录。

  • act_re_procdef(流程定义表)
    存放流程定义的属性信息,没部署一个新的流程就会新增一条记录,当流程定义的key相同的话,没部署一次版本号加一(对应数据库字段 “REV_ ” 默认版本号从1开始)。

  • act_ge_bytearray(资源文件表)

    以二进制的形式存储流程定义中部署的bpmn文件和png图片(注:如果只是指定了bpmn文件没有png图片,flowable会在部署解析bpmn文件时生成流程图保存在该表中)。

3.查询流程定义
 /**
     * 查询流程定义信息
     * */
    @Test
    public void createProcessDefinitionQuery(){
        List<ProcessDefinition> processDefinitions = processEngine.getRepositoryService()
                .createProcessDefinitionQuery()
                //.latestVersion()//根据最后一个版本查询
                //.deploymentId("部署的ID")//根据部署的ID查询
                //.processDefinitionCategory("类别")//根据类别查询
                .list();
        for (ProcessDefinition processDefinition : processDefinitions) {
            System.out.println("获取流程定义的ID:"+processDefinition.getId());
            System.out.println("获取流程定义的名字:"+processDefinition.getName());
            System.out.println("获取租户ID:"+processDefinition.getTenantId());
            System.out.println("获取key:"+processDefinition.getKey());
            System.out.println("获取流程定义的类别:"+processDefinition.getCategory());
        }
    }
  • 流程定义和流程部署相关的Service都是RepositoryService
  • 创建流程定义查询对象,可以再ProcessDefinitionQuery上设置查询相关的参数
  • key值用来区分不同的流程定义的
  • 流程的定义id的生成规则:(流程定义的key:流程定义的版本:随机生成的数字)/({processDefinitionKey}:{processDefinitionVersion}:{generated-id}) 如:days:1:27504
  • 部署表(act_re_deployment)的ID按照一定规律变化(参考act_ge_property中的next.dbid的value值)

在这里插入图片描述

4.删除流程定义
  /**
     * 流程定义的删除
     * */
    @Test
    public void deleteDeployment(){
        //根据部署ID删除
        processEngine.getRepositoryService().deleteDeployment("40001");
        //根据部署ID级联删除(会删除当前流程定义下的所有流程实例)
        processEngine.getRepositoryService().deleteDeployment("30001",true);
    }
5.获取流程定义的文档资源
 /**
     * 获取流程定义的资源文件(图片)
     * */
    @Test
    public void getDeploymentResource() throws IOException {
        String deploymentId="32501";
        List<String> names = processEngine
                .getRepositoryService()
                .getDeploymentResourceNames(deploymentId);
        String imageName=null;
        for (String name : names) {
            if (name.indexOf(".png")>0){
                imageName=name;
            }
        }
        if (imageName!=null){
            File file = new File("F:\\自己1\\MyCompany\\flowable"+imageName);
            InputStream resourceAsStream = processEngine.getRepositoryService()
                    .getResourceAsStream(deploymentId, imageName);
            FileUtils.copyInputStreamToFile(resourceAsStream,file);

        }
    }
  • deploymentId为act_re_deployment表的ID。
  • resourceName(imageName)为act_ge_bytearray表中的NAME_的值。
  • getRepositoryService().getDeploymentResourceNames(deploymentId)方法获取指定部署下的文件名称。
  • getRepositoryService().getResourceAsStream(deploymentId, imageName)根据部署的ID和资源文件的名称可以获取指定部署下的文件的输入流。
6.自定义SQL进行本地查询
 /**
     * 自定义SQL本地查询
     * */
    @Test
    public void definitionSQLQuery(){
        //根据部署ID删除
        List<Deployment> deployments = processEngine.getRepositoryService()
                .createNativeDeploymentQuery()
                .sql("select*from act_re_deployment")
                .list();
        for (Deployment deployment : deployments) {
            System.out.println("部署ID="+deployment.getId());
            System.out.println("部署名称="+deployment.getName());
        }
    }
7.自定义主键的生成策略
1.flowable.cfg.xml加如这条属性
<!--设置ID生成,每次增加1000:部署表(act_re_deployment)的ID按照一定规律变化
        (参考act_ge_property中的next.dbid的value值(默认每次增加2500))-->
   <property name="idBlockSize" value="1000"></property>

**************************************************************************************************
2.UUID的生成策略(flowable.cfg.xml加如这条属性)
<property name="idGenerator" ref="strongUuidGenerator"></property>
   
创建一个bean
 <bean id="strongUuidGenerator" class="org.flowable.common.engine.impl.persistence.StrongUuidGenerator"></bean>
***************************************************************************************************
3.自定义主键的生成策略
创建自定义类
/**
 * @author lb
 * @date 2021-06-18 9:18
 * @description 自定义ID生成器
 */
public class strongUUIDGenerator implements IdGenerator {
    @Override
    public String getNextId() {
        String id="luobo"+UUID.randomUUID().toString();
        return id;
    }
}
将该类通过bean注入到xml文件中
<bean id="strongUuidGenerator" class="com.lb.config.strongUUIDGenerator"></bean>
在flowable的配置bean中引入
<property name="idGenerator" ref="strongUuidGenerator"></property>

三、RuntimeService服务

启动流程实例的方式

1.通过给定的key值启动
ProcessInstance startProcessInstanceByKey(String processDefinitionKey)
2.通过流程定义的ID启动
ProcessInstance startProcessInstanceById(String processDefinitionId);
3.通过流程定义的ID和租户的ID启动
ProcessInstance startProcessInstanceByKeyAndTenantId(String processDefinitionKey, String tenantId);
4.根据message启动
ProcessInstance startProcessInstanceByMessage(String messageName);
5.根据message和租户ID启动
ProcessInstance startProcessInstanceByMessageAndTenantId(String messageName, String tenantId);

一个流程中,执行对象可以有多个,但是执行流程实例至于一个

启动一个实例–>执行实例–>更新实例节点–>实例结束

1.流程实例执行

操作的数据库表为act_ru_execution,当处于用户节点时,会在表act_ru_task中插入一条数据。
执行实例走到任务节点的时候,会暂时处于等待状态,只有当该节点的任务完成后,才能继续流程的运转。

   /**
     * 执行流程实例
     * */
    @Test
    public void startProcessInstance(){
        ProcessInstance processInstance = processEngine
                .getRuntimeService()
                .startProcessInstanceById("days:8:luobob524e831-0711-4c66-8c88-8e46b557734e");
        System.out.println("流程实例ID="+processInstance.getId());
        System.out.println("流程实例名字="+processInstance.getName());
    }
2.查询的任务

一个task节点(act_ru_task)和Execution(act_ru_execution)是一对一的关系

    /**
     *查询任务
     * */
    @Test
    public void queryProcessInstance(){
        List<Task> tasks = processEngine
                .getTaskService()
                .createTaskQuery()
                .list();
               // .processDefinitionId("luobofa67b3ff-5459-4682-882a-12902ed608a5");
        for (Task task : tasks) {
            System.out.println("任务名字:"+task.getName());
            System.out.println("任务ID="+task.getId());
            System.out.println("任务分类:"+task.getCategory());
        }
    }
3.完成任务

任务完成后,该节点的任务会被删除,插入下个节点的任务信息,同时将删除的任务节点信息插入到历史记录表中去。(在同一个事物中操作)。

当所有的任务节点都完成表act_ru_task中就没有数据了。

 /**
     * 完成任务
     *
     * */
    @Test
    public void completeTaskOneByOne(){
        String name="经理审批";
        List<Task> tasks = processEngine.getTaskService().createTaskQuery().taskName(name).list();
        LinkedHashMap<String, Object> variables = new LinkedHashMap<>();
        variables.put("message","同意");
        if (!CollectionUtils.isEmpty(tasks)){
            for (Task task : tasks) {
                System.out.println("获取的任务节点ID="+task.getId());
                processEngine.getTaskService().complete(task.getId(),variables);
            }
        }
    }
4.查询流程的状态(判断结束还是在执行)

1.在流程的执行过程中,创建的历程实例ID在整个过程中都不会改变,当流程结束后,流程实例将会在正正在执行的执行对象表中(act_ru_execution)被删除。
2.由于一个流程实例ID对应一个实例,所以使用singleResult()执行查询返回唯一的结果,如果返回的结果数量大于1,会抛出异常。
3.判断指定的ID实例是否存在,如果为空就会代表执行流程结束,在执行表中被删除,存到历史数据表中去。

    /**
     * 查询流程执行的状态(判断流程执行是否结束)
     * */
    @Test
    public void queryProcessInstanceStatus(){
        ProcessInstance processInstance =
                processEngine.getRuntimeService()
                        .createProcessInstanceQuery()
                        .processInstanceId("luobo1df98a85-df89-4c0f-bdfd-276448b4732e")
                        .singleResult();
        if (processInstance==null){
            System.out.println("流程实例执行完毕!");
        }else {
            System.out.println("流程实例还在执行中!");
        }
    }
5.查询执行实例(act_ru_execution)
 /**
     * 查询执行实例
     * */
    @Test
    public void queryExecuteInstance(){
        List<Execution>  executions= processEngine.getRuntimeService()
                .createExecutionQuery()
                .list();
        if(!CollectionUtils.isEmpty(executions)){
            for (Execution execution : executions) {
                System.out.println("执行实例的ID="+execution.getId());
                System.out.println("执行实例的名字="+execution.getName());
            }
        }else {
            System.out.println("执行实例不存在!");
        }
    }
6.历史流程实例数据查询(act_hi_procinst)

历史节点活动数据存储再act_hi_actinst表中

 /**
     * 历史流程查询
     */
    @Test
    public void queryHistoryProcess() {
        HistoricProcessInstance history = processEngine.getHistoryService()
                .createHistoricProcessInstanceQuery()
                .processInstanceId("luobo1df98a85-df89-4c0f-bdfd-276448b4732e")
                .singleResult();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        System.out.println("流程定义ID"+history.getProcessDefinitionId());
        System.out.println("开始时间:"+simpleDateFormat.format(history.getStartTime()));
        System.out.println("结束时间:"+simpleDateFormat.format(history.getEndTime()));
    }
7.历史任务查询(act_hi_taskinst)

历史任务表的数据和运行任务表的数据一起插入数据库的,并且在一个事物里面执行的。
如果表act_hi_taskinst中的END_TIME_(结束时间)字段有值,那说明任务已经完成了,没有值说明任务还在执行。

    /**
     * 查询所有的历史任务
     */
    @Test
    public void queryHistoryTaskAll() {
        List<HistoricTaskInstance> taskInstanceList = processEngine.getHistoryService()
                .createHistoricTaskInstanceQuery()
                .list();
        for (HistoricTaskInstance historicTaskInstance : taskInstanceList) {
            System.out.println("历史任务的ID="+historicTaskInstance.getId());
        }
    }

说明:

  • act_ru_execution 正在执行的信息
  • act_ru_task 当前节点正在执行的 任务信息
  • act_hi_procinst 已经执行完的历史流程实例信息
  • act_hi_actinst 存放历史所有完成的活动
  • act_hi_taskinst 已经执行完的历史任务信息
8.流程任务的发起者

initiator跟任务的发起者配合使用才会有效果,否则没有意义。

     * 获取表单的属性
     * */
    @Test
    public void getProperties(){
        StartFormData startFormData = processEngine.getFormService().getStartFormData("formService:1:99004");
        System.out.println(startFormData);
        System.out.println("获取流程定义"+startFormData.getProcessDefinition());
        List<FormProperty> formProperties = startFormData.getFormProperties();
        for (FormProperty formProperty : formProperties) {
            System.out.println("获取id:"+formProperty.getId());
            System.out.println("获取名字:"+formProperty.getName());
            System.out.println("获取类型:"+formProperty.getType());
            System.out.println("获取值:"+formProperty.getValue());
        }
}
 /**
     * 流程任务的发起人
     */
    @Test
    public void identityPeople() {
        //(方式一)设置流程的发起人
        String authenticatedUserId="luobo";
        processEngine.getIdentityService().setAuthenticatedUserId(authenticatedUserId);
        //(方式二)
        //Authentication.setAuthenticatedUserId(authenticatedUserId);
        //启动流程实例
        ProcessInstance processInstance = processEngine
                .getRuntimeService()
                .startProcessInstanceById("days:8:luobob524e831-0711-4c66-8c88-8e46b557734e");
        System.out.println("流程实例ID=" + processInstance.getId());
        System.out.println("流程实例名字=" + processInstance.getName());

    }
9.流程实例删除

删除后历史表中的数据还是存在的

    /**
     * 流程实例的删除
     * */
    @Test
    public void deleteProcessInstance() {
        String processInstanceId="luoboab5875a3-576a-4503-8b9e-c983503d84a0";
        String deleteReason="测试通过RuntimeService删除流程实例";
        processEngine.getRuntimeService().deleteProcessInstance(processInstanceId,deleteReason);
    }

级联删除:删除后历史表中的数据不存在了


10.获取流程运行的活动节点
    /**
     * 获取流程运行的活动节点
     * */
    @Test
    public void gainActivityPoint() {
        String executionId="luobo819bd398-9985-4a9b-aefc-3c5e3c49ffba";
        List<String> activeActivityIds = processEngine.getRuntimeService().getActiveActivityIds(executionId);
        for (String activeActivityId : activeActivityIds) {
            System.out.println(activeActivityId);
        }
    }
//结果:manager
11.流程定义的挂起和激活

流程实例挂起后流程实例下面的所有执行实例都会被挂起

    /**
     * 查看流程定义是否挂起
     * */
    @Test
    public void processDefinitionSuspended() {
        String processDefinitionId="days:1:27504";
        boolean suspended =
                processEngine.getRepositoryService().isProcessDefinitionSuspended(processDefinitionId);
        System.out.println(suspended);//false:没有挂起    true:挂起
    }
    /**
     * 使流程定义挂起
     *(SUSPENSION_STATE_)状态为2被挂起
     *(SUSPENSION_STATE_) 状态为1没有被挂起
     * 流程被挂起后是不能够启动流程实例的(启动会报错)
     * */
    @Test
    public void processDefinitionSuspended() {
        String processDefinitionId="days:1:27504";
        //根据指定日期挂起
        //processEngine.getRepositoryService().suspendProcessDefinitionById(String processDefinitionId, boolean suspendProcessInstances, Date suspensionDate);
        processEngine.getRepositoryService().suspendProcessDefinitionById(processDefinitionId);
    }
    /**
     * 解挂,激活流程定义
     * */
    @Test
    public void releaseProcessDefinitionSuspended() {
        String processDefinitionId="days:1:27504";
        processEngine.getRepositoryService().activateProcessDefinitionById(processDefinitionId);
    }

四、节点

1.开始节点

开始节点时每个流程实例的起点,开始节点只能有一个,不能有多个,有多个开始节点部署会报错。

2.结束节点

在一个部署文件中结束节点可以存在多个,当流程实例运行到结束节点的时候,则表示当前的执行实例结束了,执行实例结束那么流程实力也就结束了。

flowable中有事件、类型、网关节点。
事件节点:开始节点事件、结束节点事件。
活动类型:人工任务节点、服务任务节点、用户任务节点等。
活动节点大致分为:
等待节点—实例走到这个节点的时候,会停留在这里,需要我们手动处理去完成当前的节点,这样流程实例才会往下走。
非等待节点—实例走到该节点,会直接完成这个节点的任务,然后实例继续往下走。

3.接收任务节点

接收任务会等待消息的到达,当流程到达结束任务时,流程的状态会保存到数据库中。

任务创建后流程进入等待状态,直到引擎接收了一个特定的消息,这会触发流程穿过接收任务继续执行。

 /**
     * 部署资源
     * */
    @Test
    public void deployProcess(){
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deployment = repositoryService
                .createDeployment()
                .name("超市营业额报备(接收任务)")
                .category("money")
                .tenantId("myCompany")
                .key("今天收益多少")
                .addClasspathResource("money.png")
                .addClasspathResource("money.bpmn")
                .deploy();
        System.out.println("部署流程名字:" + deployment.getName());
        System.out.println("部署流程的id:" + deployment.getId());
    }
/**
     * 执行流程实例
     */
    @Test
    public void startProcessInstance() {
        ProcessInstance processInstance = processEngine
                .getRuntimeService()
                .startProcessInstanceById("receive:2:51004");
        System.out.println("流程实例ID=" + processInstance.getId());
        System.out.println("流程实例名字=" + processInstance.getName());
    }
    /**
     * 查询流程执行实例
     * sql:Preparing: select distinct RES.* , P.KEY_ as ProcessDefinitionKey, P.ID_ as ProcessDefinitionId
     * from ACT_RU_EXECUTION RES inner join ACT_RE_PROCDEF P on RES.PROC_DEF_ID_ = P.ID_
     * WHERE RES.ACT_ID_ = ? and RES.IS_ACTIVE_ = ? order by RES.ID_ asc
     * */
    @Test
    public void queryExecutionInstance(){
        //活动ID,表act_ru_execution中的ACT_ID_字段
        String activityId="count";
        Execution execution = processEngine.getRuntimeService()
                .createExecutionQuery()
                .activityId(activityId)
                .singleResult();
        System.out.println("执行实例的名字"+execution.getName());
        System.out.println("执行实例的id"+execution.getId());
    }
    /**
     * 完成接收任务
     * 触发执行实例继续往下节点走(将外部触发器发送到在给定执行中等待的活动实例)
     * 触发需要的参数是执行实例的ID(表act_tu_execution),不是流程实例的ID
     * */
    @Test
    public void trigger(){
        //活动ID,表act_ru_execution中的ACT_ID_字段
        String executionId="52002";
        processEngine.getRuntimeService().trigger(executionId);
    }

五、TaskService服务(用户任务)

主要分为个人任务和任务组
个人任务:指定某个确定的办理者,这个任务就是私有任务,即个人任务。
任务组:没法将这个任务指定个某个具体的人,但是可以分配到多个人活着一到多个小组中去,让小组中的成员来办理。

个人任务
1.测试个人任务:在画流程图的时候指定Assignee为具体的人

部署资源

 /**
     * 部署个人任务
     * */
    @Test
    public void deploy(){
            Deployment deploy = processEngine.getRepositoryService()
                    .createDeployment()
                    .name("个人任务")
                    .category("个人任务分配")
                    .key("personTask")
                    .tenantId("person")
                    .addClasspathResource("personaltask.bpmn")
                    .addClasspathResource("personaltask.png")
                    .deploy();
            System.out.println("获取部署对象的id=" + deploy.getId());
            System.out.println("获取key" + deploy.getKey());
    }

执行任务

    /**
     * 执行任务
     * */
    @Test
    public void startProcessInstance(){
        ProcessInstance task = processEngine.getRuntimeService().startProcessInstanceById("task:1:55004");
        System.out.println("流程实例ID=" + task.getId());
        System.out.println("流程实例名字=" + task.getName());

    }

查询某个人需要处理的任务

    /**
     * 查询某个人需要处理的任务
     *select distinct RES.* from ACT_RU_TASK RES WHERE RES.ASSIGNEE_ = ? order by RES.ID_ asc
     * */
    @Test
    public void queryTaskByPeople(){
        String userName="lb";
        List<Task> tasks = processEngine.getTaskService()
                .createTaskQuery()
                .taskAssignee(userName)
                .list();
        for (Task task : tasks) {
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务的ID:"+task.getId());

        }
    }
2.测试动态分配任务处理人:在画流程图的时候指定Assignee为变量(#{userId})

部署资源

 /**
     * 输入流的方式部署
     * */
    @Test
    public void testDeploymentByInputStream(){
        //InputStream resourceAsStream = GetProcessEngine.class.getClassLoader().getResourceAsStream("days.xml");
        InputStream resource =getClass().getClassLoader().getResourceAsStream("personaltask2.xml");
        Deployment deploy = processEngine.getRepositoryService()
                .createDeployment()
                .name("动态分配任务处理人")
                .category("任务处理")
                .key("flowable")
                .tenantId("租户的ID")
                .addInputStream("myTask.bpmn", resource)
                .deploy();
        System.out.println("输入流的方式部署获取部署对象的id="+deploy.getId());
    }

执行任务,设置流程变量,指定任务的执行人

 /**
     * 执行任务
     * 因为在部署流程的xml文件中设置了任务的处理人变量userId,如果此处不设置执行流程会出出错
     * 错误信息:org.flowable.common.engine.api.FlowableException: Unknown property used in expression: #{userId}
     * 所以在此处要引入流程变量
     * */
    @Test
    public void startProcessInstanceById(){
        LinkedHashMap<String, Object> variables = new LinkedHashMap<>();
        variables.put("userId","lb");
        ProcessInstance task = processEngine.getRuntimeService().startProcessInstanceById("task:1:58004",variables);
        System.out.println("流程实例ID=" + task.getId());
        System.out.println("流程实例名字=" + task.getName());

    }

修改任务的处理人

/**
 * 认领任务(可以修改任务的执行人,并且修改一次数据库表(act_ru_task)中的版本号(REV_)加一)
 * */
@Test
public void setAssigine(){
    String id="60007";
    String userId="lb1";
    processEngine.getTaskService().setAssignee(id,userId);
}
3.组任务
1.指定候选人

在绘制流程图的时候可以设置 Candidate users
例: 设置为 (你,我 ,他)
注意:逗号要是英文的

部署资源
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/testm1624169623439" 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="m1624169623439" name="" targetNamespace="http://www.activiti.org/testm1624169623439" typeLanguage="http://www.w3.org/2001/XMLSchema">
  <process id="task" isClosed="false" isExecutable="true" name="personaltask" processType="None">
    <startEvent id="startTask" name="StartEvent"/>
    <userTask  activiti:candidateUsers="我,你,他" activiti:exclusive="true" id="_3" name="审批"/>
    <endEvent id="endTask" name="EndEvent"/>
    <sequenceFlow id="_5" sourceRef="startTask" targetRef="_3"/>
    <sequenceFlow id="_6" sourceRef="_3" targetRef="endTask"/>
  </process>
</definitions>
 /**
     * 输入流的方式部署
     * */
    @Test
    public void testDeploymentByInputStream(){
        //InputStream resourceAsStream = GetProcessEngine.class.getClassLoader().getResourceAsStream("days.xml");
        InputStream resource =getClass().getClassLoader().getResourceAsStream("personaltask3.xml");
        Deployment deploy = processEngine.getRepositoryService()
                .createDeployment()
                .name("组任务测试")
                .category("组任务")
                .key("flowable")
                .tenantId("租户的ID")
                .addInputStream("groupTask.bpmn", resource)
                .deploy();
        System.out.println("输入流的方式部署获取部署对象的id="+deploy.getId());
    }

执行任务

 /**
     * 执行任务
     * */
    @Test
    public void startProcessInstanceById(){
        ProcessInstance task = processEngine.getRuntimeService()
                .startProcessInstanceById("task:2:63004");
        System.out.println("流程实例ID=" + task.getId());
        System.out.println("流程实例名字=" + task.getName());
    }

查询组任务

/**
     * 查询组任务
     * sql:select distinct RES.* from
     * ACT_RU_TASK RES WHERE RES.ASSIGNEE_ is null
     * and
     * exists
     * (select LINK.ID_ from
     * ACT_RU_IDENTITYLINK LINK where LINK.TYPE_ = 'candidate'
     * and
     * LINK.TASK_ID_ = RES.ID_ and ( LINK.USER_ID_ = ? ) )
     * order by RES.ID_ asc
     *
     * */
    @Test
    public void queryGroupTaskByPeopleName(){
        String userName="我";
        List<Task> tasks = processEngine.getTaskService()
                .createTaskQuery()
                .taskCandidateUser(userName)
                .list();
        for (Task task : tasks) {
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务的ID:"+task.getId());

        }
    }

查询组任务的处理人

 /**
     * 查询组任务的处理人
     *sql:select * from ACT_RU_IDENTITYLINK where TASK_ID_ = ?
     * */
    @Test
    public void queryTaskDealPeople(){
        String taskId="64006";
        List<IdentityLink> taskPeople = processEngine.getTaskService().getIdentityLinksForTask(taskId);
        for (IdentityLink taskPerson : taskPeople) {
            System.out.println(taskPerson.getProcessDefinitionId());
            System.out.println(taskPerson.getGroupId());
            System.out.println(taskPerson.getUserId());
        }
    }

查询组任务的历史处理人

/**
 * 查询组任务的历史处理人
 *sql: select * from ACT_HI_IDENTITYLINK where TASK_ID_ = ?
 * */
@Test
public void queryHistoryTaskDealPeople(){
    String taskId="64006";
    List<HistoricIdentityLink>  historicIdentityLinks=
            processEngine.getHistoryService().getHistoricIdentityLinksForTask(taskId);
    for (HistoricIdentityLink historicIdentityLink : historicIdentityLinks) {
        //System.out.println(historicIdentityLink.getProcessDefinitionId());
        System.out.println(historicIdentityLink.getGroupId());
        System.out.println(historicIdentityLink.getUserId ());
    }
}

组任务认领

 /**
     * 认领任务(可以修改任务的执行人,并且修改一次数据库表(act_ru_task)中的版本号(REV_)加一)
     * sql:update ACT_RU_ACTINST SET REV_ = ?, PROC_DEF_ID_ = ?, ASSIGNEE_ = ? where ID_ = ? and REV_ = ?
     * sql: update ACT_HI_TASKINST SET REV_ = ?, ASSIGNEE_ = ?, CLAIM_TIME_ = ?, LAST_UPDATED_TIME_ = ? where ID_ = ? and REV_ = ?
     * */
    @Test
    public void setAssignee(){
        String id="64006";
        String userId="你";
        processEngine.getTaskService().claim(id,userId);
    }
2.通过流程变量添加组成员

在绘制流程图的时候可以设置 Candidate users
例: #{userIds}
注意:添加流程变量的时候要用英文的逗号隔开字符串的处理人 variables.put(“userIds”,“小火,小炎,小焱,小燚”);

部署流程

<?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/testm1624169623439" 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="m1624169623439" name="" targetNamespace="http://www.activiti.org/testm1624169623439" typeLanguage="http://www.w3.org/2001/XMLSchema">
  <process id="task" isClosed="false" isExecutable="true" name="personaltask" processType="None">
    <startEvent id="startTask" name="StartEvent"/>
    <userTask  activiti:candidateUsers="#{userIds}" activiti:exclusive="true" id="_3" name="审批"/>
    <endEvent id="endTask" name="EndEvent"/>
    <sequenceFlow id="_5" sourceRef="startTask" targetRef="_3"/>
    <sequenceFlow id="_6" sourceRef="_3" targetRef="endTask"/>
  </process>
</definitions>
 /**
     * 输入流的方式部署
     * */
    @Test
    public void testDeploymentByInputStream4(){
        //InputStream resourceAsStream = GetProcessEngine.class.getClassLoader().getResourceAsStream("days.xml");
        InputStream resource =getClass().getClassLoader().getResourceAsStream("personaltask4.xml");
        Deployment deploy = processEngine.getRepositoryService()
                .createDeployment()
                .name("组任务测试4")
                .category("组任务4")
                .key("flowable4")
                .tenantId("租户的ID4")
                .addInputStream("groupTask4.bpmn", resource)
                .deploy();
        System.out.println("输入流的方式部署获取部署对象的id="+deploy.getId());
    }

执行流程

 /**
     * 执行任务
     *
     *因为在部署流程的xml文件中设置了任务的处理人变量userId,如果此处不设置执行流程会出出错
     *错误信息:org.flowable.common.engine.api.FlowableException: Unknown property used in expression: #{userIds}
     *所以在此处要引入变量
     * */
    @Test
    public void startProcessInstanceById4(){
        LinkedHashMap<String, Object> variables = new LinkedHashMap<>();
        variables.put("userIds","小火,小炎,小焱,小燚");
        ProcessInstance task = processEngine.getRuntimeService()
                .startProcessInstanceById("task:1:66004",variables);
        System.out.println("流程实例ID=" + task.getId());
        System.out.println("流程实例名字=" + task.getName());
    }

查询任务组

    /**
     * 查询组任务
     * */
    @Test
    public void queryGroupTaskByPeopleName4(){
        String userName="小火";
        List<Task> tasks = processEngine.getTaskService()
                .createTaskQuery()
                .taskCandidateUser(userName)
                .list();
        for (Task task : tasks) {
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务的ID:"+task.getId());

        }
    }

查询组任务的处理人、查询组任务的历史处理人和组任务认领和上面的指定候选人类似。

3.通过监听器实现添加组成员

监听器实现TaskListener接口重写notify方法。

接口:

public class GroupTaskListener  implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {
        System.out.println("*************************************调用监听接口!*********************************");
        //添加候选人
        delegateTask.addCandidateUser("小燕子");
        delegateTask.addCandidateUser("小鱼儿");
        delegateTask.addCandidateUser("小蜂子");

    }
}

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/testm1624169623439"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             targetNamespace="http://www.activiti.org/testm1624169623439" xmlns:flowable="http://flowable.org/bpmn"
             typeLanguage="http://www.w3.org/2001/XMLSchema">
  <process id="task" isClosed="false" isExecutable="true" name="personaltask" processType="None">
    <startEvent id="startTask" name="StartEvent"/>
    <userTask  activiti:exclusive="true" id="_3" name="审批">
      <extensionElements>
        <flowable:taskListener event="create" class="com.lb.config.GroupTaskListener">
        </flowable:taskListener>
      </extensionElements>
    </userTask>
    <endEvent id="endTask" name="EndEvent"/>
    <sequenceFlow id="_5" sourceRef="startTask" targetRef="_3"/>
    <sequenceFlow id="_6" sourceRef="_3" targetRef="endTask"/>
  </process>
</definitions>
/**
     * 输入流的方式部署
     * */
    @Test
    public void testDeploymentByInputStream5(){
        //InputStream resourceAsStream = GetProcessEngine.class.getClassLoader().getResourceAsStream("days.xml");
        InputStream resource =getClass().getClassLoader().getResourceAsStream("personaltask5.xml");
        Deployment deploy = processEngine.getRepositoryService()
                .createDeployment()
                .name("组任务测试5")
                .category("组任务5")
                .key("flowable5")
                .tenantId("租户的ID5")
                .addInputStream("groupTask5.bpmn", resource)
                .deploy();
        System.out.println("输入流的方式部署获取部署对象的id="+deploy.getId());
    }

    @Test
    public void delete5(){
        processEngine.getRepositoryService().deleteDeployment("63001");
    }

    /**
     * 执行任务
     *
     *因为在部署流程的xml文件中设置了任务的处理人变量userId,如果此处不设置执行流程会出出错
     *错误信息:org.flowable.common.engine.api.FlowableException: Unknown property used in expression: #{userIds}
     *所以在此处要引入变量
     * */
    @Test
    public void startProcessInstanceById5(){
        ProcessInstance task = processEngine.getRuntimeService()
                .startProcessInstanceById("task:1:68004");
        System.out.println("流程实例ID=" + task.getId());
        System.out.println("流程实例名字=" + task.getName());
    }

    /**
     * 查询组任务
     * sql:select distinct RES.* from
     * ACT_RU_TASK RES WHERE RES.ASSIGNEE_ is null
     * and
     * exists
     * (select LINK.ID_ from
     * ACT_RU_IDENTITYLINK LINK where LINK.TYPE_ = 'candidate'
     * and
     * LINK.TASK_ID_ = RES.ID_ and ( LINK.USER_ID_ = ? ) )
     * order by RES.ID_ asc
     *
     * */
    @Test
    public void queryGroupTaskByPeopleName5(){
        String userName="小燕子";
        List<Task> tasks = processEngine.getTaskService()
                .createTaskQuery()
                .taskCandidateUser(userName)
                .list();
        for (Task task : tasks) {
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务的ID:"+task.getId());
        }
    }

    /**
     * 查询组任务的处理人
     *sql:select * from ACT_RU_IDENTITYLINK where TASK_ID_ = ?
     * */
    @Test
    public void queryTaskDealPeople5(){
        String taskId="69006";
        List<IdentityLink> taskPeople = processEngine.getTaskService().getIdentityLinksForTask(taskId);
        for (IdentityLink taskPerson : taskPeople) {
            System.out.println(taskPerson.getProcessDefinitionId());
            System.out.println(taskPerson.getGroupId());
            System.out.println(taskPerson.getUserId());
        }
    }

    /**
     * 查询组任务的历史处理人
     *sql: select * from ACT_HI_IDENTITYLINK where TASK_ID_ = ?
     * */
    @Test
    public void queryHistoryTaskDealPeople5(){
        String taskId="64006";
        List<HistoricIdentityLink>  historicIdentityLinks=
                processEngine.getHistoryService().getHistoricIdentityLinksForTask(taskId);
        for (HistoricIdentityLink historicIdentityLink : historicIdentityLinks) {
            //System.out.println(historicIdentityLink.getProcessDefinitionId());
            System.out.println(historicIdentityLink.getGroupId());
            System.out.println(historicIdentityLink.getUserId());
        }
    }


    /**
     * 认领任务(可以修改任务的执行人,并且修改一次数据库表(act_ru_task)中的版本号(REV_)加一)
     * sql:update ACT_RU_ACTINST SET REV_ = ?, PROC_DEF_ID_ = ?, ASSIGNEE_ = ? where ID_ = ? and REV_ = ?
     * sql: update ACT_HI_TASKINST SET REV_ = ?, ASSIGNEE_ = ?, CLAIM_TIME_ = ?, LAST_UPDATED_TIME_ = ? where ID_ = ? and REV_ = ?
     * */
    @Test
    public void setAssignee5(){
        String id="69006";
        String userId="小蜂子";
        processEngine.getTaskService().claim(id,userId);
    }

    @Test
    public void completeTask(){
        processEngine.getTaskService().complete("69006");
        System.out.println("任务完成!");
    }

在认领任务后可以回退

    //某人认领任务后想回退到上一个步骤,就可以将认领人设置为空
   /**
     * 个人任务分配给组任务
     * */
    @Test
    public void setAssigneeBack(){
        String taskId="69006";
        processEngine.getTaskService().setAssignee(taskId,null);
    }

在执行过程中突然想添加一个候选人

    /**
     * 添加任务的候选人
     * */
    @Test
    public void setAssigneeByUserId(){
        String taskId="69006";
        String userId="小虫子";
        processEngine.getTaskService().addCandidateUser(taskId,userId);
    }

在执行过程中删除候选人

    /**
     * 删除任务的候选人
     * */
    @Test
    public void deleteAssigneeByUserId(){
        String taskId="69006";
        String userId="小虫子";
        processEngine.getTaskService().deleteCandidateUser(taskId,userId);
    }
  • 通过实现TaskListener接口,可以添加组任务的办理人,也就是delegate.addCandidateUser(用户的id)。
  • processEngine.getTaskService().claim(taskId,userId)可以将组任务分配给某个指定的人,即认领任务。
  • deleteCandidateUser(taskId,userId)可以删除组任务中的某个成员。

组任务分配给个人:processEngine.getTaskService().claim(taskId,userId);

个人任务分配给组任务:processEngine.getTaskService().setAssignee(taskId,null);

组任务和个人任务存放办理人对应的表:
1.act_ru_identitylink 存放任务的办理人,包括各人任务和组任务,表示正在执行的任务。

2.act_hi_identitylink 存放任务的办理人,包括各人任务和组任务,表示历史任务。

3.如果是个人任务表(act_ru_identitylink,act_hi_identitylink)对应的TYPE_字段时particpant(参与者)

4.如果是个人任务表(act_ru_identitylink,act_hi_identitylink)对应的TYPE_字段时 candidate(候选人) 和 particpant(参与者)


六、网关

网关的分类:排他网关、并行网关、兼容网关

网关主要是满足一些特殊的业务,比如排他网关,可以让流程实例出现分支,当有多个条件满足的时候走一个执行分支。

并行网关有分流和聚合的功能。

兼容网关可以当做并行网使用,也可以当做排他网关使用。

1.排他网关
1.绘制流程图

连线task1的条件: ${0<=money&&money<1000}

连线task2的条件: ${1000<=money&&money<10000}

连线task3的条件: ${10000<=money}

在这里插入图片描述

2.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:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:tns="http://www.activiti.org/test" 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="m1624258853673" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema">
  <process id="gateway_test" isClosed="false" isExecutable="true" name="排他网关测试" processType="None">
    <startEvent id="_2" name="StartEvent"/>
    <userTask activiti:exclusive="true" id="one" name="任务一"/>
    <exclusiveGateway gatewayDirection="Unspecified" id="_4" name="ExclusiveGateway"/>
    <userTask activiti:exclusive="true" id="two" name="任务二"/>
    <userTask activiti:exclusive="true" id="three" name="任务三"/>
    <sequenceFlow id="_7" sourceRef="_2" targetRef="_4"/>
    <sequenceFlow id="_8" name="task1" sourceRef="_4" targetRef="one">
      <conditionExpression xsi:type="tFormalExpression">
        <![CDATA[${0<=money&&money<1000}]]>
      </conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="_9" name="task2" sourceRef="_4" targetRef="two">
      <conditionExpression xsi:type="tFormalExpression">
        <![CDATA[${1000<=money&&money<10000}]]>
      </conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="_10" name="task3" sourceRef="_4" targetRef="three">
      <conditionExpression xsi:type="tFormalExpression">
        <![CDATA[${10000<=money}]]>
      </conditionExpression>
    </sequenceFlow>
    <endEvent id="_11" name="EndEvent"/>
    <endEvent id="_12" name="EndEvent"/>
    <endEvent id="_13" name="EndEvent"/>
    <sequenceFlow id="_14" sourceRef="one" targetRef="_11"/>
    <sequenceFlow id="_15" sourceRef="two" targetRef="_12"/>
    <sequenceFlow id="_16" sourceRef="three" targetRef="_13"/>
  </process>
</definitions>
3.部署流程
 private ProcessEngine processEngine= ProcessEngines.getDefaultProcessEngine();
    /**
     * 部署流程定义
     * */
    @Test
    public void deployProcessInstance(){
        Deployment deploy = processEngine.getRepositoryService()
                .createDeployment()
                .name("排他网关测试")
                .category("网关")
                .tenantId("luobo")
                .addClasspathResource("gateway.bpmn")
                .deploy();
        System.out.println("部署ID="+deploy.getId());
        System.out.println("部署名称="+deploy.getName());
    }
4.执行流程

根据传入变量的值,流程会走到不同的流程分支。

/**
     * 执行流程
     * */
    @Test
    public void startProcessInstance(){
        LinkedHashMap<String, Object> variables = new LinkedHashMap<>();
        variables.put("money","10000000000");
        ProcessInstance processInstance = processEngine.getRuntimeService()
                .startProcessInstanceById("gateway_test:1:79004",variables);
    }
    /**
     * 完成任务
     * */
    @Test
    public void completeTask(){
        processEngine.getTaskService().complete("75009");
    }
2.并行网关
1.绘制流程图

说明:该流程中当任务一完成后,不会继续往下执行,只有等待任务二完成后才会一起往下个节点执行,任务一二完成后就进行汇总,到达任务一二汇总节点。

在这里插入图片描述

2.流程部署
 /**
     * 部署流程定义
     * */
    @Test
    public void deployProcessInstance(){
        Deployment deploy = processEngine.getRepositoryService()
                .createDeployment()
                .name("并行网关测试")
                .category("网关")
                .tenantId("yaner")
                .addClasspathResource("parallelGateway.bpmn")
                .deploy();
        System.out.println("部署ID="+deploy.getId());
        System.out.println("部署名称="+deploy.getName());
    }

   
3.执行流程
 /**
     * 执行流程
     * */
    @Test
    public void startProcessInstance(){
        //运行成后会在act_ru_task表中创建两个实例
        ProcessInstance processInstance = processEngine.getRuntimeService()
                .startProcessInstanceById("parallelGateway:1:83004");
    }

    /**
     * 完成任务
     * */
    @Test
    public void completeTask(){

        //根据在表act_ru_task中的两个实例ID来完成任务(要两个同时完成才会走向下一个节点,一个完成另一个处于等待状态)
        processEngine.getTaskService().complete("84012");
        processEngine.getTaskService().complete("84012");
    }

并行网关使用:

  • 并行网关通常是承兑出现的,第一个并行网关代表分流,第二个网关代表聚合。
  • 如果只有分流,没有聚合,那么整个流程是无法结束的。
  • 并行网关上面的条件是不会生效的。
3.兼容网关

1.兼容网关既可以当做排他网关使用,也可以当做并行网关使用。

2.兼容网关连线上面的条件是可以生效的。

3.兼容网关通常情况下是成对出现的(因为他有可能转化为并行网关)。

4.如果有多个顺序流满足条件,则会当做并行网关使用。

5.如果只有单个顺序流满足条件,则会当做排他网关使用。


七、流程变量

流程变量在整个工作流中扮演很重要的作用。
流程变量的作用于范围只对应一个流程实例,各个流程实例的流程变量之间互不影响。
流程实例结束后流程变量保存到历史数据表(act_hi_varinst)中。

流程变量设置

1.启动流程实例的时候。

2.完成任务的时候

3.手工去设置变量

RuntimeService对象可以设置流程变量和获取流程变量、TaskService可以设置和获取流程变量。
启动流程实例的时候可以设置流程变量。

1.绘制流程图

在这里插入图片描述

2.部署资源并执行流程
 	/**
     * 部署流程定义
     * */
    @Test
    public void deployProcessInstance(){
        Deployment deploy = processEngine.getRepositoryService()
                .createDeployment()
                .name("流程变量")
                .category("变量")
                .tenantId("熊熊")
                .addClasspathResource("variables.bpmn")
                .deploy();
        System.out.println("部署ID="+deploy.getId());
        System.out.println("部署名称="+deploy.getName());
    }
   /**
    * 执行流程
    * */
   @Test
   public void startProcessInstance(){
       ProcessInstance processInstance = processEngine.getRuntimeService()
               .startProcessInstanceById("variable:1:87004");
   }

3.设置流程变量
      /**
       * 查询任务
       * setVariableLocal(task.getId(),"请加天数",8);
       * 这种方式设置变量变act_ru_variable/act_hi_variable表中的TASK_ID_有值
       * */
      @Test
      public void queryTaskAndSetVariables(){
             Task task = processEngine.getTaskService()
                     .createTaskQuery()
                     .processDefinitionId("variable:1:87004")
                     .singleResult();
             processEngine.getTaskService().setVariable(task.getId(),"请假人员","略略");
             processEngine.getTaskService().setVariableLocal(task.getId(),"请假天数",8);
             LinkedHashMap<String, Object> variables = new LinkedHashMap<>();
             variables.put("请假日期",new Date());
             variables.put("请假原因","人数短暂及时行乐!");
             processEngine.getTaskService().setVariables(task.getId(),variables);
             System.out.println("获取执行任务的id="+task.getId());
      }
4.完成任务
 /**
     * 完成任务设置变量(完成人)
     * */
    @Test
    public void completeTask(){
           Task task = processEngine.getTaskService()
                   .createTaskQuery()
                   .processDefinitionId("variable:1:87004")
                   .singleResult();
           LinkedHashMap<String, Object> variables = new LinkedHashMap<>();
           variables.put("完成人","luobo");
           processEngine.getTaskService().complete(task.getId(),variables);
           System.out.println("获取执行任务的id="+task.getId());
    }
5.设置流程变量说明
  • 流程变量的作用于就是流程实例,所以无论在那个阶段设置就行了。
  • 基本类型设置流程变量,在taskService中使用ID,定义流程变量的名称,设置流程变量的值。
  • 如果是对象,则需要该对象实现序列化接口才能保存到数据库中。
  • 设置流程变量的时候会向act_ru_variable/act_hi_variable表中添加数据。
6.获取流程变量
    /**
     * 获取变量
     * */
    @Test
    public void getVariables(){
        Task task = processEngine.getTaskService()
                .createTaskQuery()
                .processDefinitionId("variable:1:87004")
                .singleResult();
        //获取所有的变量
        Map<String, Object> variables = processEngine.getTaskService().getVariables(task.getId());
        for (Object variable: variables.values()) {
            System.out.println(variable);
        }
        //获取某个变量
        Object name = processEngine.getTaskService().getVariable(task.getId(), "完成人");
        System.out.println(name);
    }
7.设置一个bean对象作为变量
1.User对象
@Data
public class User  implements Serializable {
    private static final Integer serialVersion=12345;
    private String name;
    private Integer age;

}
2.设置变量
 /**
     * 设置一个对象作为变量
     * */
    @Test
    public void setBeanVariables(){
        Task task = processEngine.getTaskService()
                .createTaskQuery()
                .processDefinitionId("variable:1:87004")
                .singleResult();
        LinkedHashMap<String, Object> variables = new LinkedHashMap<>();
        User user = new User();
        user.setAge(23);
        user.setName("陌陌");
        variables.put("user",user);
        processEngine.getRuntimeService().setVariables(task.getExecutionId(),variables);
    }
3.获取对象
 /**
     * 获取变量(对象)
     * */
    @Test
    public void getBeanVariables(){
        Task task = processEngine.getTaskService()
                .createTaskQuery()
                .processDefinitionId("variable:1:87004")
                .singleResult();
        Object user = processEngine.getRuntimeService().getVariable(task.getExecutionId(), "user");
        if (user instanceof User){
            System.out.println(user);
        }
    }
8.历史变量的查询
 /**
     * 获取历史变量(act_hi_varinst)
     */
    @Test
    public void getHistoryVariables() {
        List<HistoricVariableInstance> historicVariables = processEngine.getHistoryService()
                .createHistoricVariableInstanceQuery()
                .list();
        if (!CollectionUtils.isEmpty(historicVariables)) {
            for (HistoricVariableInstance historicVariable : historicVariables) {
                System.out.println("历史变量:" + historicVariable);
            }
        }
    }

setVariable(全局的):设置流程变量的时候,流程变量名称相同的时候,后一次的值替换前一次的值

setVariableLocal(局部的):设置流程变量的时候,针对当前活动的节点设置流程变量,如果一个流程中存在2个活动节点,对每个活动节点都设置流程变量,即使流程变量的名称相同,后一次的版本的值也不会替换前一次版本的值,它会使用不同的任务ID作为标识,存放2个流程变量值。
使用setVariableLocal说明了流生变量绑定了当前的任务,当流程继续执行时,下一个节点的任务是获取不到这个流程变量的(因为正在执行的流程变量中没有这个数据),所有查询正在执行的人任务不能查询到我们需要的数据,此时需要查询历史流程变量表。

9.临时变量

临时变量是不会保存到数据库中的,可以在启动流程的时候设置流程变量,也可以在完成任务的时候设置临时变量。

1.启动流程时设置流程变量
 /**
     * 设置临时变量
     */
    @Test
    public void setTransientVariables() {
        Map<String, Object> variables = new HashMap<>();
        variables.put("aaa", "测试临时变量");
        variables.put("bbb", "测试临时变量是否会存到数据库");
        ProcessInstanceBuilder builder =
                processEngine.getRuntimeService().createProcessInstanceBuilder();
        ProcessInstance start = builder.processDefinitionId("variable:1:87004")
                .name("哈哈哈")
                .transientVariables(variables)
                .start();
        System.out.println(start);
    }
2.完成时设置临时变量
 /**
     * 完成任务时设置流程临时变量
     */
    @Test
    public void completeTask() {
        Map<String, Object> variables = new HashMap<>();
        variables.put("ccc", "完成任务时测试临时变量");
        variables.put("ddd", "完成任务时测试临时变量是否会存到数据库");
        processEngine.getTaskService().complete("92006", null, variables);
    }

八、HistoryService服务

flowable的查询历史信息类,在一个流程执行完后,该对象为我们提供查询历史信息。

实现类HistoryServiceImpl

1.绘制流程图

在这里插入图片描述

2.部署资源并执行流程
/**
     * 部署流程定义
     */
    @Test
    public void deployProcessInstance() {
        Deployment deploy = processEngine.getRepositoryService()
                .createDeployment()
                .name("历史信息测试")
                .category("history")
                .tenantId("luobo")
                .addClasspathResource("history.bpmn")
                .deploy();
        System.out.println("部署ID=" + deploy.getId());
        System.out.println("部署名称=" + deploy.getName());
    }

    /**
     * 执行流程
     */
    @Test
    public void startProcessInstance() {
        ProcessInstance processInstance = processEngine.getRuntimeService()
                .startProcessInstanceById("history:1:93004");
    }
3.查看历史流程实例
 /**
     * 查询历史流程实例表(昨天启动成功)
     * select distinct RES.* , DEF.KEY_ as PROC_DEF_KEY_, DEF.NAME_ as PROC_DEF_NAME_, DEF.VERSION_ as
     * PROC_DEF_VERSION_, DEF.DEPLOYMENT_ID_ as DEPLOYMENT_ID_
     * from ACT_HI_PROCINST RES left outer join ACT_RE_PROCDEF DEFon RES.PROC_DEF_ID_ = DEF.ID_
     * WHERE RES.END_TIME_ is not NULL order by RES.ID_ asc
     */
    @Test
    public void queryHistoryProcessInstance() {
        List<HistoricProcessInstance> historicProcessInstances = processEngine.getHistoryService()
                .createHistoricProcessInstanceQuery()
                .finished()
                .list();
        for (HistoricProcessInstance historicProcessInstance : historicProcessInstances) {
            System.out.println("结束时间:" + historicProcessInstance.getEndTime());
        }
    }

   
  
4.查看所有历史活动
 /**
     * 查询历史活动(也就是所有节点的历史信息)
     * select RES.* from ACT_HI_ACTINST RES order by RES.ID_ asc
     */
    @Test
    public void queryHistoryActivity() {
        List<HistoricActivityInstance> historicActivityInstances = processEngine
                .getHistoryService()
                .createHistoricActivityInstanceQuery()
                .list();
        for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
            System.out.println("************************");
            System.out.println(historicActivityInstance.getActivityId());
            System.out.println(historicActivityInstance.getActivityName());
        }
    }
5.查看历史实例信息
 /**
     * 查询历史实例信息
     * select distinct RES.* from ACT_HI_TASKINST RES order by RES.ID_ asc
     */
    @Test
    public void queryHistoryInstance() {
        List<HistoricTaskInstance> historicActivityInstances = processEngine
                .getHistoryService()
                .createHistoricTaskInstanceQuery()
                .list();
        for (HistoricTaskInstance historicActivityInstance : historicActivityInstances) {
            System.out.println("************************");
            System.out.println("流程定义的ID"+historicActivityInstance.getProcessDefinitionId());
            System.out.println("结束时间"+historicActivityInstance.getEndTime());
        }
    }
6查看流程历史变量

    /**
     * 查询历史流程变量
     * select RES.* from ACT_HI_VARINST RES order by RES.ID_ asc
     * */
    @Test
    public void queryHistoryVariables() {
        List<HistoricVariableInstance> historicVariableInstances = processEngine
                .getHistoryService()
                .createHistoricVariableInstanceQuery()
                .list();
        for (HistoricVariableInstance historicVariableInstance : historicVariableInstances) {
            System.out.println("************************");
            System.out.println("流程定义的实例ID"+historicVariableInstance.getProcessInstanceId());
            System.out.println("变量的名称"+historicVariableInstance.getVariableName());
            System.out.println("变量的值"+historicVariableInstance.getValue());
        }
    }
6.历史权限表查询
 
    /**
     * 历史权限表查询
     * select * from ACT_HI_TASKINST where ID_ = ?
     * select * from ACT_HI_IDENTITYLINK where TASK_ID_ = ?
     * */
    @Test
    public void queryHistoricIdentityLinksForTask() {
        List<HistoricIdentityLink> historicIdentityLinks = processEngine
                .getHistoryService()
                .getHistoricIdentityLinksForTask("94006");
        for (HistoricIdentityLink historicIdentityLink : historicIdentityLinks) {
            System.out.println("************************");
            System.out.println("流程定义的ID"+historicIdentityLink.getScopeDefinitionId());
        }
    }
7.自定义SQL查询历史信息
    /**
     * 自定义SQL查询历史信息
     * */
    @Test
    public void sql() {
        List<HistoricActivityInstance> list = processEngine
                .getHistoryService()
                .createNativeHistoricActivityInstanceQuery()
                .sql("select res.*from act_hi_actinst res order by res.ID_ asc")
                .list();
        for (HistoricActivityInstance historicActivityInstance : list) {
            System.out.println(historicActivityInstance.getActivityName());
            System.out.println(historicActivityInstance.getProcessDefinitionId());
        }
    }
8.历史数据级别的配置

1.none: 所有的历史归档数据不会插入到数据库中,该级别对于流程实例运转的性能最高,因为不涉及到历史表相关的操作。

2.activity: 归档所有的流程实例和活动实例,不归档流程细节(如历史任务节点)。

3.audit: 缺省级别,归档所有的流程实例、活动实例以及提交的表单属性,所有与用户进行交互的数据都可以进行跟踪和统计。

4.full 历史数据挂挡的最高级别,该级别记录所有的历史数据。

在这里插入图片描述

默认配置为:audit

  public void initHistoryLevel() {
        if (historyLevel == null) {
            historyLevel = HistoryLevel.getHistoryLevelForKey(getHistory());
        }
    }

//getHistory():
  public String getHistory() {
        return history;
    }
 protected String history = HistoryLevel.AUDIT.getKey();

在配置文件中(flowable.cfg.xml)可以自定义

 <!--配置历史归档的级别-->
<property name="historyLevel" value="NONE"></property>

九、定时器

1.流程定义的挂起与激活

挂起:suspendProcessDefinitionBykey()

流程定义挂起,指定过期时间

激活:activateProcessDefinitionById()

判断流程定义是否挂起:isProcessDefinitionSuspend

如果设置了指定时间内启动流程定义,那么部署流程后,默认是挂起状态,act_re_procdef表的SUSPENSION_START_为2表示挂起

    /**
     * 部署流程定义
     */
    @Test
    public void deployProcessInstance() {
        Date date = new Date(new Date().getTime()+3*1000);
        Deployment deploy = processEngine.getRepositoryService()
                .createDeployment()
                .name("定时器测试")
                .category("activateAndSuspend")
                .tenantId("xiongxiong")
                .addClasspathResource("history.bpmn")
                .activateProcessDefinitionsOn(date)
                .deploy();
        System.out.println("部署ID=" + deploy.getId());
        System.out.println("部署名称=" + deploy.getName());
    }

如果想让定时器无法执行,我们可以在flowable.cfg.xml文件设置开关属性。

<!--不让开关属性生效-->
<property name="asyncExecutorActivate" value="true"></property>

选择定时挂起流程定义的时候,也可以选择是否挂起流程实例以及制定挂起的时间。
act_ru_timer_job表中会插入一条数据。
定时器运行之后,流程定义会被挂起,流程实例根据是否挂起参数决定是否挂起实例。
流程定义被挂起后就不能够启动流程实例了,如果在流程实例乖巧之前已经有流程实例在运行,那么当流程定义被挂起后这些流程实例下的所有活动都会被挂起,暂停运行。

2.判断使用flowable的版本
    /**
     * 获取版本(是5版本还是6版本)
     */
    @Test
    public void testVersion() {
        Boolean processDefinition = processEngine.getRepositoryService().isFlowable5ProcessDefinition(
                "history:1:93004");//false表示6版本
        System.out.println(processDefinition);
    }
3.判断流程定义是否被挂起
/**
     * 判断流程定义是否被挂起
     */
    @Test
    public void isSuspend() {
        Boolean processDefinition = processEngine.getRepositoryService().isProcessDefinitionSuspended(
                "history:2:96004");//true代表被挂起,false代表没有被挂起
        System.out.println("是否被挂起"+processDefinition);
    }

如果将实例挂起或者激活,那么首先会向白鸥act_ru_timer_job表中插入数据。
定时器在执行的时候,会将act_ru_timer_job中的数据删除,然后添加到定时作业任务表中(act_ru_job)

4.手动操作定时器(ManagerService服务)
    /**
     * 定时器在执行的时候,会将act_ru_timer_job中的数据删除,然后添加到定时作业任务表中(act_ru_job)
     */
    @Test
    public void managerService() {
        String jobId="5512";
        processEngine.getManagementService().moveTimerToExecutableJob(jobId);
    }
    /**
     * 设置重置次数
     * */
    @Test
    public void set() {
        String jobId="1564";
        processEngine.getManagementService().setJobRetries(jobId,10);
    }
    /**
     * 执行作业表移到死信作业表
     * 死信作业表(act_ru_deadletter_job)数据不会被执行,因为相关的任务在这个表中说明已经不需要在执行了。
     * */
    @Test
    public void moveJobToDeadLetterJob() {
        String jobId="5512";
        processEngine.getManagementService().moveJobToDeadLetterJob(jobId);
    }

    /**
     * 将act_ru_deadletter_job中的数据移动到act_ru_job中,变成可执行的任务。
     * */
    @Test
    public void moveDeadLetterJobToExecutableJob() {
        String jobId="5512";
        processEngine.getManagementService().moveDeadLetterJobToExecutableJob(jobId,10);
    }

十、表单FormService使用

表单使用的三种方式

  • 动态表单:只能定义表单中字段的一些配置信息,如字段的可读、可写、必须等信息,不能定义完成表单的页面。
  • 外置表单:只能定义表单的key,关于key的内容自己去维护。
  • 内置表单:内置表单定义以及渲染引擎

表单实现类:FormService–>实现类FormServiceImpl

表单定义支持的节点:开始节点、任务节点、其他节点都不支持。

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:flowable="http://flowable.org/bpmn"
             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"
             typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath"
             targetNamespace="http://www.flowable.org/processdef">
    <process id="formService" name="form" isExecutable="true">
        <startEvent id="startEvent1">
            <extensionElements>
                <flowable:formProperty id="start_date" name="开始时间" type="date" expression="yyyy-MM-dd HH:mm"
                                       required="true"></flowable:formProperty>
                <flowable:formProperty id="end_date" name="结束时间" type="date" expression="yyyy-MM-dd HH:mm"
                                       datePattern="MM-dd-yyyy hh:mm" required="true"></flowable:formProperty>
                <flowable:formProperty id="reason" name="请假的原因" type="string" required="true"></flowable:formProperty>
                <flowable:formProperty id="days" name="请假天数" type="long" required="true"></flowable:formProperty>
            </extensionElements>
        </startEvent>
        <userTask id="sid-9D9E120A-CFC5-4BB4-89A6-88D246598273" name="请假申请哦">
            <extensionElements>
                <flowable:formProperty id="start_date" name="开始时间" type="date" expression="yyyy-MM-dd HH:mm"
                                       readable="true"></flowable:formProperty>
                <flowable:formProperty id="end_date" name="结束时间" type="date" expression="yyyy-MM-dd HH:mm"
                                       datePattern="MM-dd-yyyy hh:mm" readable="true"></flowable:formProperty>
                <flowable:formProperty id="reason" name="请假的原因" type="string" required="true"></flowable:formProperty>
                <flowable:formProperty id="days" name="请假天数" type="long" required="true"></flowable:formProperty>
            </extensionElements>
        </userTask>

        <sequenceFlow id="sid-2B6B3030-A341-4210-9E2F-1C4F026CDDE4" sourceRef="startEvent1"
                      targetRef="sid-9D9E120A-CFC5-4BB4-89A6-88D246598273"></sequenceFlow>
        <userTask id="sid-E3D9B3D4-45C3-4149-A830-72AC83B25539" name="老大审批"></userTask>
        <sequenceFlow id="sid-51A2D0E0-54E2-4FCD-8A55-A147BEF16819" sourceRef="sid-9D9E120A-CFC5-4BB4-89A6-88D246598273"
                      targetRef="sid-E3D9B3D4-45C3-4149-A830-72AC83B25539"></sequenceFlow>
        <endEvent id="sid-5C58CE2B-1428-4901-B028-8617A96FAFCF"></endEvent>
        <sequenceFlow id="sid-CC68B1E5-9466-4988-941B-1CE659FB72C5" sourceRef="sid-E3D9B3D4-45C3-4149-A830-72AC83B25539"
                      targetRef="sid-5C58CE2B-1428-4901-B028-8617A96FAFCF"></sequenceFlow>
    </process>
</definitions>

部署

 /**
     * 部署流程定义
     */
    @Test
    public void deployProcessInstance() {
        Deployment deploy = processEngine.getRepositoryService()
                .createDeployment()
                .name("表单测试")
                .category("form")
                .tenantId("formId")
                .addClasspathResource("form.bpmn")
                .deploy();
        System.out.println("部署ID=" + deploy.getId());
        System.out.println("部署名称=" + deploy.getName());
    }

获取表单属性

    /**
     * 获取表单的属性
     * */
    @Test
    public void getProperties(){
        StartFormData startFormData = processEngine.getFormService().getStartFormData("formService:1:99004");
        System.out.println(startFormData);
        System.out.println("获取流程定义"+startFormData.getProcessDefinition());
        List<FormProperty> formProperties = startFormData.getFormProperties();
        for (FormProperty formProperty : formProperties) {
            System.out.println("获取id:"+formProperty.getId());
            System.out.println("获取名字:"+formProperty.getName());
            System.out.println("获取类型:"+formProperty.getType());
            System.out.println("获取值:"+formProperty.getValue());
        }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值