栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Flowable 高级篇

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Flowable 高级篇

一、任务分配 固定分配

固定分配就是我们前面介绍的,在绘制流程图或者直接在流程文件中通过Assignee来指定的方式

表达式分配

值表达式: 解析为一个值。默认情况下,所有流程变量都可以使用。(若使用Spring)所有的Spring bean也可以用在表达式里。例如

${myVar}
${myBean.myProperty}

案例讲解:

先部署流程,然后在启动流程实例的时候绑定表达式对应的值

public class FlowableSeniorDemo {

    static ProcessEngine processEngine = null;

    
    @Before
    public void createEngine(){
        // 配置数据库相关信息 获取 ProcessEngineConfiguration
        ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
                .setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn?serverTimezone=UTC&nullCatalogMeansCurrent=true")
                .setJdbcUsername("root")
                .setJdbcPassword("root")
                .setJdbcDriver("com.mysql.cj.jdbc.Driver")
                .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
        // 获取流程引擎对象
        processEngine = cfg.buildProcessEngine();
    }

    
    @Test
    public void deploy(){
        // 部署流程 获取RepositoryService对象
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("请假流程模型.bpmn20.xml")
                .name("请假流程...")
                .category("请假") // 分类
                .deploy();
    }

    
    @Test
    public void runProcess(){
        // 启动流程实例通过 RuntimeService 对象
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 设置 assignee 的取值
        Map variables = new HashMap<>();
        variables.put("assignee0","张三") ;
        variables.put("assignee1","李四");
        // 启动流程实例,第一个参数是流程定义的id
        ProcessInstance processInstance = runtimeService
                .startProcessInstanceById("holiday-process:1:4", variables);
    }
}

 在流程变量表中我们可以看到对应的流程变量信息

同时在Task表中,可以看到流程当前的分配人是张三,说明UEL表达式被解析了  

方法表达式

方法表达式 Method expression: 调用一个方法,可以带或不带参数。当调用不带参数的方法时,要确保在方法名后添加空括号(以避免与值表达式混淆)。传递的参数可以是字面值(literal value),也可以是表达式,它们会被自动解析。例如:

${printer.print()}
${myBean.addNewOrder('orderName')}
${myBean.doSomething(myVar, execution)}

myBean是Spring容器中的个Bean对象,表示调用的是bean的addNewOrder方法

监听器分配

可以使用监听器来完成很多Flowable的流程业务。

我们在此处使用监听器来完成负责人的指定,那么我们在流程设计的时候就不需要指定assignee

创建自定义监听器:

public class MyTaskListener implements TaskListener {

    @Override
    public void notify(DelegateTask delegateTask) {
        System.out.println("监听器触发了:" + delegateTask.getName());
        if("提交请假流程".equals(delegateTask.getName()) &&
                "create".equals(delegateTask.getEventName())){
            // 指定任务的负责人
            delegateTask.setAssignee("小明");
        }else {
            delegateTask.setAssignee("小张");
        }
    }
}

然后在FlowableUI中关联对应的监听器

create:任务创建后触发
assignment:任务分配后触发
Delete:任务完成后触发
All:所有事件都触发

然后我们先启动流程实例,然后在Task表中我们可以看到对应的分配人为小明说明通过监听也完成了任务分配的工作了


二、流程变量

 流程实例按步骤执行时,需要使用一些数据。在Flowable中,这些数据称作变量(variable),并会存储在数据库中。变量可以用在表达式中(例如在排他网关中用于选择正确的出口路径),也可以在Java服务任务(service task)中用于调用外部服务(例如为服务调用提供输入或结果存储),等等。

  流程实例可以持有变量(称作流程变量 process variables);用户任务以及执行(executions)也可以持有变量。流程实例可以持有任意数量的变量,每个变量存储为ACT_RU_VARIABLE数据库表的一行。

  所有的startProcessInstanceXXX方法都有一个可选参数,用于在流程实例创建及启动时设置变量。例如,在RuntimeService中:

ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map variables);

也可以在流程执行中加入变量。例如,(RuntimeService):

void setVariable(String executionId, String variableName, Object value);
void setVariableLocal(String executionId, String variableName, Object value);
void setVariables(String executionId, Map variables);
void setVariablesLocal(String executionId, Map variables);

全局变量

流程变量的默认作用域是流程实例。当一个流程变量的作用域为流程实例时,可以称为 global 变量

注意:global 变量中变量名不允许重复,设置相同名称的变量,后设置的值会覆盖前设置的变量值。

局部变量

任务和执行实例仅仅是针对一个任务和一个执行实例范围,范围没有流程实例大, 称为 local 变量。

Local 变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同没有影响。Local 变量名也可以和 global 变量名相同,没有影响。

案例讲解

需求:员工创建出差申请单,由部门经理审核,部门经理申请通过后3天以下由财务直接申批,3天以上先由总经理审批,总经理审批通过后再由财务审批。

连接先设置条件 

 启动流程实例:并且指定全局流程变量

    @Test
    public void runProcess(){
        // 启动流程实例通过 RuntimeService 对象
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 设置流程变量
        Map variables = new HashMap<>();
        // 设置assignee的取值
        variables.put("assignee0","张三");
        variables.put("assignee1","李四");
        variables.put("assignee2","王五");
        variables.put("assignee3","赵财务");
        // 启动流程实例,第一个参数是流程定义的id
        ProcessInstance processInstance = runtimeService
                .startProcessInstanceById("businessTravel:1:47504",variables);// 启动流程实例
        // 输出相关的流程实例信息
        System.out.println("流程定义的ID:" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例的ID:" + processInstance.getId());
        System.out.println("当前活动的ID:" + processInstance.getActivityId());
    }

完成Task任务,同时也可以指定流程变量

    @Test
    public void completeTask(){
        // 获取流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery()
                .processDefinitionId("businessTravel:1:47504")
                .taskAssignee("李四")
                .singleResult();
        // 添加流程变量
        Map map = task.getProcessVariables();
        map.put("num",1);

        // 完成任务
        taskService.complete(task.getId(),map);
    }

 由于部门经理李四设置了天数小于3,使得流程没有经过总经理审批


三、候选人和候选人组

        在流程定义中在任务结点的 assignee 固定设置任务负责人,在流程定义时将参与者固定设置在.bpmn 文件中,如果临时任务负责人变更则需要修改流程定义,系统可扩展性差。针对这种情况可以给任务设置多个候选人或者候选人组,可以从候选人中选择参与者来完成任务。

候选人 定义流程图

定义流程图,同时指定候选人

部署和启动流程实例

部署流程,并且在启动流程实例的时候对UEL表达式赋值

    @Test
    public void deploy(){
        // 部署流程 获取RepositoryService对象
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("候选人审批流程.bpmn20.xml")
                .name("请假流程")
                .deploy();
        System.out.println("deploy.getId() = " + deploy.getId());
        System.out.println("deploy.getName() = " + deploy.getName());
    }

    
    @Test
    public void runProcess(){
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 给流程定义中的UEL表达式赋值
        Map variables = new HashMap<>();
        variables.put("candidate1","张三");
        variables.put("candidate2","李四");
        variables.put("candidate3","王五");
        runtimeService.startProcessInstanceById("candidate-process:1:4",variables);
    }

在对应的表结构中我们可以看到流程变量已经有了,但是对于的Task的Assignee还是为空

任务的查询

根据当前登录的用户,查询对应的候选任务

    @Test
    public void queryTaskCandidate(){
        TaskService taskService = processEngine.getTaskService();
        List list = taskService.createTaskQuery()
                .processInstanceId("2501")
                .taskCandidateUser("张三")
                .list();
        for (Task task : list) {
            System.out.println("task.getId() = " + task.getId());
            System.out.println("task.getName() = " + task.getName());
        }
    }

可以看到查询的结果 

task.getId() = 2509
task.getName() = 申请休假

任务的拾取

知道了我有可拾取的任务后,拾取任务。

    @Test
    public void claimTaskCandidate(){
        TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery()
                .processInstanceId("2501")
                .taskCandidateUser("张三")
                .singleResult();
        if(task != null){
            // 拾取对应的任务
            taskService.claim(task.getId(),"张三");
            System.out.println("任务拾取成功");
        }
    }

拾取任务后,该任务的assignee才会显示为张三

任务的归还
    @Test
    public void returnTaskCandidate(){
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery()
                .processInstanceId("2501")
                .taskAssignee("张三")
                .singleResult();
        if(task != null){
            taskService.unclaim(task.getId());
            System.out.println("归还任务成功");
        }
    }

张三归还任务后,任务表里的assignee变成空了,这个时候其他候选人又可以拾取任务了

任务的交接
    @Test
    public void taskCandidate(){
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery()
                .processInstanceId("2501")
                .taskAssignee("张三")
                .singleResult();
        if(task != null){
            // 任务的交接
            taskService.setAssignee(task.getId(),"李四");
            System.out.println("任务交接给了李四");
        }
    }

 任务成功交接给候选人李四

任务的完成

正常的任务处理

    @Test
    public void completeTask(){
        TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery()
                .processInstanceId("2501")
                .taskAssignee("李四")
                .singleResult();
        if(task != null){
            // 完成任务
            taskService.complete(task.getId());
            System.out.println("完成Task");
        }
    }
候选人组

当候选人很多的情况下,我们可以分组来处理。先创建组,然后把用户分配到这个组中。

用户管理

我们需要先单独维护用户信息。后台对应的表结构是ACT_ID_USER.

    @Test
    public void createUser(){
        // 通过 IdentityService 完成相关的用户和组的管理
        IdentityService identityService = processEngine.getIdentityService();

        List list = new ArrayList<>();
        User user = identityService.newUser("小红");
        user.setFirstName("小");
        user.setLastName("红");
        user.setEmail("xiaohong@qq.com");

        User user1 = identityService.newUser("小王");
        user1.setFirstName("小");
        user1.setLastName("王");
        user1.setEmail("xiaowang@qq.com");

        User user2 = identityService.newUser("小明");
        user2.setFirstName("小");
        user2.setLastName("明");
        user2.setEmail("小明@qq.com");

        list.add(user);
        list.add(user1);
        list.add(user2);

        list.forEach(o->identityService.saveUser(o));
    }

Group管理

维护对应的Group信息,后台对应的表结构是ACT_ID_GROUP

    @Test
    public void createGroup(){
        IdentityService identityService = processEngine.getIdentityService();
        // 创建Group对象并指定相关的信息
        List list = new ArrayList<>();

        Group group = identityService.newGroup("group1");
        group.setName("销售部");
        group.setType("type1");

        Group group2 = identityService.newGroup("group2");
        group2.setName("开发部");
        group2.setType("type2");

        list.add(group);
        list.add(group2);

        // 创建Group对应的表结构数据
        list.forEach(o->identityService.saveGroup(o));
    }

用户分配组
    @Test
    public void userGroup(){
        IdentityService identityService = processEngine.getIdentityService();
        // 根据组的编号找到对应的Group对象
        Group group = identityService.createGroupQuery().groupId("group1").singleResult();
        List list = identityService.createUserQuery().list();
        for (User user : list) {
            // 将用户分配给对应的组
            identityService.createMembership(user.getId(),group.getId());
        }
    }

候选人组应用

搞清楚了用户和用户组的关系后我们就可以来使用候选人组的应用了

创建流程图

流程的部署运行

然后我们把流程部署和运行,注意对UEL表达式赋值,关联上Group

static ProcessEngine processEngine = null;

    
    @Before
    public void createEngine(){
        // 配置数据库相关信息 获取 ProcessEngineConfiguration
        ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
                .setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn?serverTimezone=UTC&nullCatalogMeansCurrent=true")
                .setJdbcUsername("root")
                .setJdbcPassword("root")
                .setJdbcDriver("com.mysql.cj.jdbc.Driver")
                .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
        // 获取流程引擎对象
        processEngine = cfg.buildProcessEngine();
    }

    
    @Test
    public void deploy(){
        // 部署流程 获取RepositoryService对象
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("请假流程—候选人组.bpmn20.xml")
                .name("请假流程-候选人组")
                .deploy();
        System.out.println("deploy.getId() = " + deploy.getId());
        System.out.println("deploy.getName() = " + deploy.getName());
    }

    
    @Test
    public void runProcess(){
        IdentityService identityService = processEngine.getIdentityService();
        Group group = identityService.createGroupQuery().groupId("group1").singleResult();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 给流程定义中的UEL表达式赋值
        Map variables = new HashMap<>();
        variables.put("g1",group.getId()); // 给流程定义中的UEL表达式赋值
        runtimeService.startProcessInstanceById("candidateGroup-process:1:4",variables);
    }

对应表结构中就有对应的体现

任务的拾取和完成

    
    @Test
    public void claimTaskCandidate(){
        String userId = "小明";
        // 根据当前登录的用户找到对应的组
        IdentityService identityService = processEngine.getIdentityService();
        // 当前用户所在的组
        Group group = identityService.createGroupQuery().groupMember(userId).singleResult();
        TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery()
                .processInstanceId("2501")
                .taskCandidateGroup(group.getId())
                .singleResult();
        if(task != null) {
            // 任务拾取
            taskService.claim(task.getId(),userId);
            System.out.println("任务拾取成功");
        }
    }
    
    @Test
    public void completeTask(){
        TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery()
                .processInstanceId("2501")
                .taskAssignee("小明")
                .singleResult();
        if(task != null){
            taskService.complete(task.getId());
            System.out.println("完成Task");
        }
    }
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1027479.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号