Activiti5使用

一、Activiti 的 25 张表的两种创建方式

/**
     * 生成Activiti需要的25表
     */
    @Test
    public void testCreateTable(){
ProcessEngineConfiguration pec=ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration(); // 获取流程引擎配置
        pec.setJdbcDriver("com.mysql.jdbc.Driver"); // 配置驱动
        pec.setJdbcUrl("jdbc:mysql://localhost:3306/db_activiti"); // 配置连接地址
        pec.setJdbcUsername("root"); // 用户名
        pec.setJdbcPassword("root"); // 密码
        /**
         * 配置模式  true 自动创建和更新表
         */
        pec.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
        
        // 获取流程引擎对象
        ProcessEngine pe=pec.buildProcessEngine(); 
    }
    
    /**
     * 生成Activiti需要的25表 使用配置文件
     */

在resources下新建一个activiti.cfg.xml文件  文件内容如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/db_activiti" />
    <property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
    <property name="jdbcUsername" value="root" />
    <property name="jdbcPassword" value="root" />
    <property name="databaseSchemaUpdate" value="true" />
  </bean>
</beans>
    @Test
    public void testCreateTableWithXml(){
         // 引擎配置
ProcessEngineConfiguration pec=ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        // 获取流程引擎对象
        ProcessEngine processEngine=pec.buildProcessEngine();
    }

二、在 Eclipse 上安装 Activiti 插件

1、 Help → Install New Software→Add.

2、Name:Activiti BPMN 2.0 designer

     Location:http://activiti.org/designer/update/

095139_xGO1_2995717.png

101409_X3E3_2995717.png

这个要勾选上  否则创建图片不能保存

三、第一个activiti 程序

public class HelloWorldProcess {

    /**
     * 获取默认流程引擎实例,会自动读取activiti.cfg.xml文件
     */
    private ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
    

部署流程定义


    /**
     * 部署流程定义
     */
    @Test
    public void deploy(){
        Deployment deployment=processEngine.getRepositoryService() // 获取部署相关Service
                .createDeployment() // 创建部署
                .addClasspathResource("diagrams/HelloWorld.bpmn") // 加载资源文件
                .addClasspathResource("diagrams/HelloWorld.png") // 加载资源文件
                .name("HelloWorld流程") // 流程名称
                .deploy(); // 部署
        System.out.println("流程部署ID:"+deployment.getId()); 
        System.out.println("流程部署Name:"+deployment.getName());
    }
    

启动流程实例


    /**
     * 启动流程实例
     */
    @Test
    public void start(){
        ProcessInstance pi=processEngine.getRuntimeService() // 运行时Service

//  .startProcessInstanceByKey("myFirstProcess"  "变量是一个map集合")  流程启动的时候就设置个变量         相 当于用 processEngine.getRuntimeService().setVariable(taskId, "date", new Date()) 相当于给这个流程初始化数据
            .startProcessInstanceByKey("myFirstProcess"); // 流程定义 act_re_procdef表的KEY字段值
        System.out.println("流程实例ID:"+pi.getId());
        System.out.println("流程定义ID:"+pi.getProcessDefinitionId()); 
    }
    

查看任务


    /**
     * 查看任务
     */
    @Test
    public void findTask(){
        List<Task> taskList=processEngine.getTaskService() // 任务相关Service
            .createTaskQuery() // 创建任务查询
            .taskAssignee("java1234_小锋") // 指定某个人  act_ru_task这个表里的 assignee_字段
            .list();
        for(Task task:taskList){
            System.out.println("任务ID:"+task.getId()); 
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务创建时间:"+task.getCreateTime());
            System.out.println("任务委派人:"+task.getAssignee());
            System.out.println("流程实例ID:"+task.getProcessInstanceId());
        }
    }
    

完成任务


    /**
     * 完成任务
     */
    @Test
    public void completeTask(){
        processEngine.getTaskService() // 任务相关Service
            .complete("30004"); //30004表示正在运行的任务id     task.getId()   表里的act_ru_task id_字段
    }

查询流程定义

  

/**
     * 查询流程定义 返回流程定义集合  对应表 act_re_procdef
     */
    @Test
    public void list(){
        String processDefinitionKey="myFirstProcess";
        List<ProcessDefinition> pdList=processEngine.getRepositoryService() // 获取service
            .createProcessDefinitionQuery() // 创建流程定义查询
            .processDefinitionKey(processDefinitionKey) // 通过key查询  act_re_procdef 表里的key_字段
            .list();  // 返回一个集合
        for(ProcessDefinition pd:pdList){
            System.out.println("ID_"+pd.getId());
            System.out.println("NAME_"+pd.getName());
            System.out.println("KEY_"+pd.getKey());
            System.out.println("VERSION_"+pd.getVersion());
            System.out.println("=========");
        }
    }

通过ID查询某个流程定义

 

/**
     * 通过ID查询某个流程定义
     */
    @Test
    public void getById(){
        String processDefinitionId="myFirstProcess:2:7504";
        ProcessDefinition pd=processEngine.getRepositoryService() // 获取service
            .createProcessDefinitionQuery() // 创建流程定义查询
            .processDefinitionId(processDefinitionId) // 通过id查询  act_re_procdef 中的 id_字段
            .singleResult();
        System.out.println("ID_"+pd.getId());
        System.out.println("NAME_"+pd.getName());
        System.out.println("KEY_"+pd.getKey());
        System.out.println("VERSION_"+pd.getVersion());
            
    }

查询最新版本的流程定义

 

//查询最新版本的流程定义
    @Test
    public void queryPng(){
        RepositoryService service = engine.getRepositoryService();
        List<ProcessDefinition> version = service.createProcessDefinitionQuery().latestVersion().list();
        for (ProcessDefinition processDefinition : version) {
            System.out.println(processDefinition.getName());
        }
    }

/**
     * 根据流程部署id和资源文件名称来查询流程图片
     * @throws Exception
     */
    @Test
    public void getImageById()throws Exception{
        InputStream inputStream=processEngine.getRepositoryService() // 获取sevice
            .getResourceAsStream("10001", "helloWorld/HelloWorld.png");
        FileUtils.copyInputStreamToFile(inputStream,new File("c:/helloWorld.png"));
    }

/**
     * 查询最新版本的流程定义
     * @throws Exception
     */
    @Test
    public void listLastVersion()throws Exception{

        List<ProcessDefinition> listAll=processEngine.getRepositoryService() // 获取service
            .createProcessDefinitionQuery() // 创建流程定义查询
            .orderByProcessDefinitionVersion().asc() // 根据流程定义版本升序
            .list();  // 返回一个集合
        
        // 定义有序Map,相同的Key,假如添加map的值  后者的值会覆盖前面相同的key的值
        Map<String,ProcessDefinition> map=new LinkedHashMap<String,ProcessDefinition>();
        // 遍历集合,根据key来覆盖前面的值,来保证最新的key覆盖前面所有老的key的值
        for(ProcessDefinition pd:listAll){
            map.put(pd.getKey(), pd);
        }
        
        List<ProcessDefinition> pdList=new LinkedList<ProcessDefinition>(map.values());
        for(ProcessDefinition pd:pdList){
            System.out.println("ID_"+pd.getId());
            System.out.println("NAME_"+pd.getName());
            System.out.println("KEY_"+pd.getKey());
            System.out.println("VERSION_"+pd.getVersion());
            System.out.println("=========");
        }
    }

删除所有key相同的流程定义

 

/**
     * 删除所有key相同的流程定义
     * @throws Exception
     */
    @Test
    public void deleteByKey()throws Exception{
        String processDefinitionKey="helloWorld2";
        List<ProcessDefinition> pdList=processEngine.getRepositoryService() // 获取service
                .createProcessDefinitionQuery() // 创建流程定义查询
                .processDefinitionKey(processDefinitionKey) // 根据key查询
                .list();  // 返回一个集合
        for(ProcessDefinition pd:pdList){
            processEngine.getRepositoryService()//按照部署流程id删除   true表示级联删除
                .deleteDeployment(pd.getDeploymentId(),true);   act_re_deployment这个表的 id_  
        }

查询流程状态

/**
     * 查询流程状态(正在执行 or 已经执行结束)
     */
    @Test
    public void processState(){
        ProcessInstance pi=processEngine.getRuntimeService() // 获取运行时Service
            .createProcessInstanceQuery() // 创建流程实例查询
            .processInstanceId("35001") // 用流程实例id查询  act_ru_execution 表中的proc_inst_id_
            .singleResult();
        if(pi!=null){
            System.out.println("流程正在执行!");
        }else{
            System.out.println("流程已经执行结束!");
        }
    }

历史任务查询

    /**
     * 历史任务查询  在act_hi_taskinst表里    只有任务的节点 不包括开始节点和结束节点
     */
    @Test
    public void historyTaskList(){
        List<HistoricTaskInstance> list=processEngine.getHistoryService() // 历史相关Service
            .createHistoricTaskInstanceQuery() // 创建历史任务实例查询
            .processInstanceId("35001") // 用流程实例id查询  act_hi_taskinst 表里的proc_inst_id_ 字段
            .finished() // 查询已经完成的任务
            .list(); 
        for(HistoricTaskInstance hti:list){
            System.out.println("任务ID:"+hti.getId());
            System.out.println("流程实例ID:"+hti.getProcessInstanceId());
            System.out.println("任务名称:"+hti.getName());
            System.out.println("办理人:"+hti.getAssignee());
            System.out.println("开始时间:"+hti.getStartTime());
            System.out.println("结束时间:"+hti.getEndTime());
            System.out.println("=================================");
        }
    }

历史活动查询

 

/**
     * 历史活动查询  在act_hi_actinst表里  包括开始节点和结束节点
     */
    @Test
    public void historyActInstanceList(){
        List<HistoricActivityInstance>  list=processEngine.getHistoryService() // 历史相关Service
            .createHistoricActivityInstanceQuery() // 创建历史活动实例查询
            .processInstanceId("35001") // 执行流程实例id  act_hi_actinst里的proc_inst_id_ 字段
            .finished()  //unfinished表示没完成的
            .list();
        for(HistoricActivityInstance hai:list){
            System.out.println("活动ID:"+hai.getId());
            System.out.println("流程实例ID:"+hai.getProcessInstanceId());
            System.out.println("活动名称:"+hai.getActivityName());
            System.out.println("办理人:"+hai.getAssignee());
            System.out.println("开始时间:"+hai.getStartTime());
            System.out.println("结束时间:"+hai.getEndTime());
            System.out.println("=================================");
        }
    }

/**
     * 设置流程变量数据
     */
    @Test
    public void setVariableValues(){
        TaskService taskService=processEngine.getTaskService(); // 任务Service
        String taskId="72504";
        taskService.setVariable(taskId, "days", 2);
        // taskService.setVariable(taskId, "date", new Date());
        taskService.setVariableLocal(taskId,"date", new Date());
        taskService.setVariable(taskId, "reason", "发烧");
        Student student=new Student();
        student.setId(1);
        student.setName("张三");
        taskService.setVariable(taskId, "student", student); // 存序列化对象
    }
    
    /**
     * 获取流程变量数据
     */
    @Test
    public void getVariableValues(){
        TaskService taskService=processEngine.getTaskService(); // 任务Service
        String taskId="80002";
        Integer days=(Integer) taskService.getVariable(taskId, "days");
        // Date date=(Date) taskService.getVariable(taskId, "date");
        Date date=(Date) taskService.getVariableLocal(taskId, "date");
        String reason=(String) taskService.getVariable(taskId, "reason");
        Student student=(Student) taskService.getVariable(taskId, "student"); 
        System.out.println("请假天数:"+days);
        System.out.println("请假日期:"+date);
        System.out.println("请假原因:"+reason);
        System.out.println("请假对象:"+student.getId()+","+student.getName());
    }


    
    用TaskService 设置流程变量数据


    
    /**
     * 设置流程变量数据
     */
    @Test
    public void setVariableValue(){
        TaskService taskService=processEngine.getTaskService(); // 任务Service
        String taskId="60004";  //正在执行的任务id
        Student student=new Student(); //如果传递的是实体对象 该对象必须要实现序列化
        student.setId(1);
        student.setName("张三");

        Map<String, Object> variables=new HashMap<String,Object>();
        variables.put("days", 2);
        variables.put("date", new Date());
        variables.put("reason", "回家");
        variables.put("student", student);
        taskService.setVariables(taskId, variables);

//        service.setVariable(taskId, "days", 5);     一次可以设置一个变量 也可以把变量放到map集合里  设置变量
//        service.setVariable(taskId, "reason", "回家");
//        service.setVariable(taskId, "student", s);

        // service.setVariableLocal(taskId, "key", "value"); 设置局部变量 用的较少
    }

用TaskService获取流程变量数据


    
    /**
     * 获取流程变量数据
     */
    @Test
    public void getVariableValues(){
        TaskService taskService=processEngine.getTaskService(); // 任务Service
        String taskId="65002";
        Map<String,Object> variables=taskService.getVariables(taskId);
        Integer days=(Integer) variables.get("days");
        Date date=(Date) variables.get("date");
        String reason=(String) variables.get("reason");
        Student student=(Student)variables.get("student"); 

    //service.getVariableLocal(taskId, "key") 根据key获取局部变量 用的较少

//        Integer days = (Integer)service.getVariable(taskId, "days");
//        String reason = (String) service.getVariable(taskId, "reason");
//        Student student = (Student) service.getVariable(taskId, "student");

        System.out.println("请假天数:"+days);
        System.out.println("请假日期:"+date);
        System.out.println("请假原因:"+reason);
        System.out.println("请假对象:"+student.getId()+","+student.getName());
    }

  用RuntimeService 设置流程变量数据 流程启动的时候就可以设置变量和taskservice差不多

 

/**
     * 设置流程变量数据
     */
    @Test
    public void setVariableValues(){
        RuntimeService runtimeService=processEngine.getRuntimeService(); // 任务Service
        String executionId="90001";
        runtimeService.setVariable(executionId, "days", 2);
        runtimeService.setVariable(executionId, "date", new Date());
        runtimeService.setVariable(executionId, "reason", "发烧");
        Student student=new Student();
        student.setId(1);
        student.setName("张三");
        runtimeService.setVariable(executionId, "student", student); // 存序列化对象
    }


     用RuntimeService 获取流程变量数据  


    /**
     * 获取流程变量数据
     */
    @Test
    public void getVariableValues(){
        RuntimeService runtimeService=processEngine.getRuntimeService(); // 任务Service
        String executionId="90001";  //ac_ru_execution 表中的id_
        Integer days=(Integer) runtimeService.getVariable(executionId, "days");
        Date date=(Date) runtimeService.getVariable(executionId, "date");
        String reason=(String) runtimeService.getVariable(executionId, "reason");
        Student student=(Student) runtimeService.getVariable(executionId, "student"); 
        System.out.println("请假天数:"+days);
        System.out.println("请假日期:"+date);
        System.out.println("请假原因:"+reason);
        System.out.println("请假对象:"+student.getId()+","+student.getName());
    }

启动流程实例时设置变量

/**
     * 启动流程实例
     */
    @Test
    public void start(){
        Student student=new Student();
        student.setId(1);
        student.setName("张三");

        Map<String, Object> variables=new HashMap<String,Object>();
        variables.put("days", 2);
        variables.put("date", new Date());
        variables.put("reason", "回家");
        variables.put("student", student);
        
        ProcessInstance pi=processEngine.getRuntimeService() // 运行时Service
            .startProcessInstanceByKey("studentLevaeProcess", variables); // 启动流程的时候,设置流程变量

        System.out.println("流程实例ID:"+pi.getId());
        System.out.println("流程定义ID:"+pi.getProcessDefinitionId()); 
    }

完成任务的时候设置流程变量

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

Student student=new Student();
        student.setId(1);
        student.setName("张三");

        Map<String, Object> variables=new HashMap<String,Object>();
        variables.put("days", 2);
        variables.put("date", new Date());
        variables.put("reason", "发烧");
        variables.put("student", student);
        processEngine.getTaskService() // 任务相关Service
            .complete("112504", variables); //完成任务的时候,设置流程变量
    }

}

四、流程部署加载的zip压缩包的方式

/**
     * 部署流程定义使用zip方式
     */
    public void deployWithZip(){
        InputStream inputStream=this.getClass() // 取得当前class对象
            .getClassLoader() // 获取类加载器
            .getResourceAsStream("diagrams/helloWorld.zip"); // 获取指定文件资源流
        
        ZipInputStream zipInputStream=new ZipInputStream(inputStream); // 实例化zip输入流
        Deployment deployment=processEngine.getRepositoryService() // 获取部署相关Service
                .createDeployment() // 创建部署
                .addZipInputStream(zipInputStream) // 添加zip输入流
                .name("HelloWorld流程") // 流程名称
                .deploy(); // 部署
        System.out.println("流程部署ID:"+deployment.getId()); 
        System.out.println("流程部署Name:"+deployment.getName());
    }

五、数据库表的变化

################################
# 部署流程定义涉及到的表

# 流程部署表
SELECT * FROM `act_re_deployment`

# 流程定义表
SELECT * FROM `act_re_procdef`

# 资源文件表
SELECT * FROM `act_ge_bytearray`

# 系统配置表 
SELECT * FROM `act_ge_property`

################################
# 启动流程实例涉及到的表

# 流程实例运行时 执行对象表
SELECT * FROM `act_ru_execution`

# 流程实例运行时 身份联系表
SELECT * FROM `act_ru_identitylink`

# 流程实例运行时 用户任务表
SELECT * FROM `act_ru_task`

# 活动节点历史表
SELECT * FROM `act_hi_actinst`

# 身份联系表 历史
SELECT * FROM `act_hi_identitylink`

# 流程实例表 历史
SELECT * FROM `act_hi_procinst`

# 历史任务表 
SELECT * FROM `act_hi_taskinst`

################################
# 结束流程实例涉及到的表
# 运行时  表数据全部清空
# 历史表  表数据修改 或者增加了数据


################################
# 设置流程变量涉及到的表

# 运行时流程变量表
SELECT * FROM `act_ru_variable`

# 历史流程变量表
SELECT * FROM `act_hi_varinst`

六、多种线路流程执行情况

连线

流程图如下

192726_Ozlm_2995717.png

当请假天数小于10天班长审批完直接结束

当请假天数大于10天时班长审批完班主任审批完才能结束

流程线表达式如下

192920_ArN4_2995717.png

//完成任务
    @Test
    public void compelet(){
        TaskService service = engine.getTaskService();
        Map<String,Object> map=new HashMap<String,Object>();
        map.put("days", 18);
        service.complete("105002",map); //在请假完成的时候带参数 或者设置一个全局变量 key的值一定要是days和表达式中的值要一致
    }

排它网关  排它网关和连线的区别  是排它网关如果没有匹配的条件时可以默认执行某条流程

流程图如下

223306_685u_2995717.png

当请假天数小于3天时班长审批

当请假天数大于3天小于7天班主任审批

当请假天数条件不满足前两个(也就是大于7天)的是校长审批

设置默认走校长审批  流程  配置如下   大于7天的那个条线是flow5   默认的flow5 这个一定不要设置大于几天的那个表达式 (condition) 因为前两个如果不满足的情况下回默认走flow5那个流程

223709_F3yj_2995717.png

做法和上面的连线是一样的  在请假完成的时候带参数 或者设置一个全局变量 key的值一定要是days和表达式中的值要一致

 

并行网关  并行网关 是多个流程一起走  当多个流程都走完时在继续向下执行

流程图如下

141959_AVn1_2995717.png

班长和班主任都审批通过后才可以在往下执行

七、用户和组的创建删除

创建用户

@Test
    public void testSaveUser(){
        IdentityService indentityService=processEngine.getIdentityService();
        User user=new UserEntity(); // 实例化用户实体  activiti提供的一个用户接口
        user.setId("wangwu");
        user.setPassword("123");
        user.setEmail("1234@qq.com");
        indentityService.saveUser(user); 
    }

删除用户

@Test
    public void testDeleteUser(){
        IdentityService indentityService=processEngine.getIdentityService();
        indentityService.deleteUser("wangwu"); //根据  act_id_user id_字段删除
    }

创建组

@Test
    public void testSaveGroup(){
        IdentityService indentityService=processEngine.getIdentityService();
        Group group=new GroupEntity();
        group.setId("test");
        indentityService.saveGroup(group); 
    }

删除组



    @Test
    public void testDeleteGroup(){
        IdentityService indentityService=processEngine.getIdentityService();
        indentityService.deleteGroup("test");   //根据  act_id_group id_字段删除
    }

把用户添加到组里


    @Test
    public void testSaveMembership(){
        IdentityService indentityService=processEngine.getIdentityService();
        indentityService.createMembership("wangwu", "test"); //第一个表示act_id_user中的id_字段第二个表示act_id_group中的id_字段
    }

删除用户和组的关联关系

@Test
    public void testDeleteMembership(){
        IdentityService indentityService=processEngine.getIdentityService();
        indentityService.deleteMembership("wangwu", "test");  /第一个表示act_id_user中的id_字段第二个表示act_id_group中的id_字段
    }

八、任务分配

个人任务分配

1、在流程图的Main config -> Assignee写个固定的值    (此方式不常用)

2、在启动或者完成任务的时候设置办理人  在配置表达式  如Main config -> Assignee    ${userId}

这种方式变量的key值一定要和assignee 配置的表达式的值一致

3、TaskListener 监听实现

新建一个类  实现 TaskListener接口  代码如下

public class MyTaskListener implements TaskListener{
    private static final long serialVersionUID = 1L;

    public void notify(DelegateTask delegateTask) {
        delegateTask.setAssignee("赵六"); // 指定办理人
    }

}

下图中的listeners中配置上  上面自定义的监听器类TaskListener   走到此流程的时候会执行这个类中notify方法的内容

160433_jKGJ_2995717.png

多用户任务分配    只要是配置的多个用户其中的一个完成任务即可

1、在流程图的Main config -> Candidate users(comma speparated)写个固定的值    (此方式不常用)

在流程图中配置方式如下

164017_cEBY_2995717.png
    /**
     * 查看任务
     */
    @Test
    public void findTask(){
        List<Task> taskList=processEngine.getTaskService() // 任务相关Service
            .createTaskQuery() // 创建任务查询
            //.taskAssignee("李四") // 指定某个人
            .taskCandidateUser("赵六") // 指定候选人
            .list();
        for(Task task:taskList){
            System.out.println("任务ID:"+task.getId()); 
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务创建时间:"+task.getCreateTime());
            System.out.println("任务委派人:"+task.getAssignee());
            System.out.println("流程实例ID:"+task.getProcessInstanceId());
        }
    }

2、在启动或者完成任务的时候设置办理人  在配置表达式  如Main config -> Candidate users(comma speparated)    ${userIds}

这种方式变量的key值一定要和Candidate users(comma speparated)配置的表达式的值一致

//完成任务
    @Test
    public void compelet(){
        TaskService service = engine.getTaskService();
        Map<String,Object> map=new HashMap<String, Object>();
        map.put("userIds", "bb,aa,cc"); //设置处理任务的候选人
        service.complete("247504",map);
    }

3、TaskListener 监听实现    和个人任务分配中的监听器一样

public class MyTaskListener implements TaskListener{
    private static final long serialVersionUID = 1L;

    public void notify(DelegateTask delegateTask) {
        // delegateTask.setAssignee("赵六"); // 指定办理人
        delegateTask.addCandidateUser("张三");
        delegateTask.addCandidateUser("李四");
        delegateTask.addCandidateUser("王五");
    }

}

组任务分配

租任务分配和个人 任务分配   多人任务分配是一样的

只要在这个组下的某一个用户都可以查看任务  并且处理任务

1、在流程图的Main config -> Candidate groups(comma speparated)写个固定的值    (此方式不常用)

配置如下

170951_Pa6J_2995717.png

2、使用流程变量 Main config -> Candidate groups(comma speparated)

配置如下   这种方式变量的key值一定要和Candidate groups(comma speparated)配置的表达式的值一致

172101_TSLg_2995717.png

3、TaskListener 监听实现    和个人任务分配中的监听器一样

public void notify(DelegateTask delegateTask) {
        delegateTask.addCandidateGroup("1");
        delegateTask.addCandidateGroup("3");
    }

九、审批被打回来流程图

175300_kkCh_2995717.png

如果请假天数超过3天  班主任审批不给通过  这里用的是排他网关

转载于:https://my.oschina.net/xiaozhou18/blog/978999

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值