• Activiti工作流简单入门 (zhuan)


    https://my.oschina.NET/Barudisshu/blog/309721

    ***********************************************

    摘要: 自jBPM创始人Tom离开之后,jBPM和Activiti就开始大相径庭,jBPM被迫使用新的LGPL协议,而Activiti则使用一种更为宽松的Apache License 2.0协议。不管使用jBPM还是Activiti,两者都遵循BPMN 2.0规范,都可满足项目的一般需求,相比于jBPM,Activiti使用起来不会进行太大的二次改动,但jBPM则是使用Drools较为强大的规则引擎作为后盾,至于两者谁优谁劣,需要在实际项目中权衡利弊。

    BPMN 2.0

    BPMN最初由业务流程倡议组织(BPMI)定案,现在BPMI并入到OMG(Object Management Group)了,则由OMG建立规范和维护。

    BPMN 2.0正式更名为(Business Process Model And Notation)业务流程符号和模型,也有人继续称呼为业务流程建模标记法(Business Process Modeling Notaion),不过无所谓,不管是jBPM、Activiti还是国人开发的FixFlow,都遵循BPMN规范。

    Maven配置

    JBoss的开源框架都是比较庞大的,不过相对Activiti体积要小一点。下面为配置的依赖项。

    <!--Junit-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
    </dependency>
    
    <!--activiti-->
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-engine</artifactId>
        <version>${activiti.version}</version>
    </dependency>
    
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-bpmn-layout</artifactId>
        <version>${activiti.version}</version>
    </dependency>
    
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-spring</artifactId>
        <version>${activiti.version}</version>
    </dependency>
    
    <!--apache组件-->
    ...

    整合数据库

    为什么要整合数据库?如果不整合数据库,我们大可以使用Quartz这些框架来做流程任务。实际上,Work Flow是用于一种长周期的几乎异步的项目运行环境中,并且我们时刻需要将工作流程的状态记录下来,就是一种既注重结果,又注重过程的事务中,因此,整合数据库很有必要。

    下面为配置源数据的XML文件,并且将databaseSchemaUpdate属性配置为drop-create,即在运行前删除原有的数据内容。

    <?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="databaseSchemaUpdate" value="drop-create"/>
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/db_activiti?useUnicode=true&amp;characterEncoding=utf-8"/>
            <property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>
            <property name="jdbcUsername" value="root"/>
            <property name="jdbcPassword" value="****"/>
            <property name="jobExecutorActivate" value="true"/>
        </bean>
    </beans>

    默认配置文件名为activiti.cfg.xml,可以在源文件中找到。

    另外,如果有必要,请将MySQL设置为区分大小写,即lower_case_table_names = 0。

    数据内容会在运行前自动创建,详细表结构内容可参考官网完整信息。

    创建工作流文件

    由于BPMN规范的作用,一些高级的IDE会自动识别后缀为*.bpmn的文件,不过这些都无所谓,bpmn文件实际上就是XML文件,只是加上了一些图形的标记,如width、height、x和y的坐标,下面为一个招聘面试流程,只包含流程节点,不包含位置标记节点。

    <?xml version="1.0" encoding="UTF-8"?>
    <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
                 xmlns:activiti="http://activiti.org/bpmn"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 targetNamespace="Examples"
                 xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL
                 http://www.omg.org/spec/BPMN/2.0/20100501/BPMN20.xsd">
        <process id="Interview" name="某公司2012年实习生招聘流程">
            <documentation>招聘工作流程</documentation>
            <startEvent id="start" name="实习生招聘启动"/>
            <userTask id="bishi" name="笔试" activiti:candidateGroups="人力资源部"/>
            <sequenceFlow id="flow1" name="" sourceRef="start" targetRef="bishi"/>
            <userTask id="yimian" name="技术一面" activiti:candidateGroups="技术部"/>
            <sequenceFlow id="flow2" name="" sourceRef="bishi" targetRef="yimian"/>
            <userTask id="ermian" name="技术二面" activiti:candidateGroups="技术部"/>
            <sequenceFlow id="flow3" name="" sourceRef="yimian" targetRef="ermian"/>
            <userTask id="hrmian" name="HR面" activiti:candidateGroups="人力资源部"/>
            <sequenceFlow id="flow4" name="" sourceRef="ermian" targetRef="hrmian"/>
            <userTask id="luyong" name="录用,发放Offer" activiti:candidateGroups="人力资源部"/>
            <sequenceFlow id="flow5" name="" sourceRef="hrmian" targetRef="luyong"/>
            <endEvent id="end" name="实习生招聘结束"/>
            <sequenceFlow id="flow6" name="" sourceRef="luyong" targetRef="end"/>
        </process>
    
    </definitions>

    为了便于阅读,一些高级IDE可以转化为图形符号,如下图:

    测试运行

    有了流程引擎的配置文件和流程文件后,就可以编写代码启动流程引擎并加载该流程文件了。测试清单如下:

    @Test
    public void processTests(){
        // 加载配置文件
        ProcessEngine processEngine = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml").buildProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        repositoryService.createDeployment().addClasspathResource("Interview.bpmn").deploy();
        String processId = runtimeService.startProcessInstanceByKey("Interview").getId();
    
        TaskService taskService = processEngine.getTaskService();
        //得到笔试的流程
        System.out.println("
    ***************笔试流程开始***************");
    
        List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("人力资源部").list();
        for (Task task : tasks) {
            System.out.println("人力资源部的任务:name:"+task.getName()+",id:"+task.getId());
            taskService.claim(task.getId(), "张三");
        }
    
        System.out.println("张三的任务数量:"+taskService.createTaskQuery().taskAssignee("张三").count());
        tasks = taskService.createTaskQuery().taskAssignee("张三").list();
        for (Task task : tasks) {
            System.out.println("张三的任务:name:"+task.getName()+",id:"+task.getId());
            taskService.complete(task.getId());
        }
    
        System.out.println("张三的任务数量:"+taskService.createTaskQuery().taskAssignee("张三").count());
        System.out.println("***************笔试流程结束***************");
    
        System.out.println("
    ***************一面流程开始***************");
        tasks = taskService.createTaskQuery().taskCandidateGroup("技术部").list();
        for (Task task : tasks) {
            System.out.println("技术部的任务:name:"+task.getName()+",id:"+task.getId());
            taskService.claim(task.getId(), "李四");
        }
    
        System.out.println("李四的任务数量:"+taskService.createTaskQuery().taskAssignee("李四").count());
        for (Task task : tasks) {
            System.out.println("李四的任务:name:"+task.getName()+",id:"+task.getId());
            taskService.complete(task.getId());
        }
    
        System.out.println("李四的任务数量:"+taskService.createTaskQuery().taskAssignee("李四").count());
        System.out.println("***************一面流程结束***************");
    
        System.out.println("
    ***************二面流程开始***************");
        tasks = taskService.createTaskQuery().taskCandidateGroup("技术部").list();
        for (Task task : tasks) {
            System.out.println("技术部的任务:name:"+task.getName()+",id:"+task.getId());
            taskService.claim(task.getId(), "李四");
        }
    
        System.out.println("李四的任务数量:"+taskService.createTaskQuery().taskAssignee("李四").count());
        for (Task task : tasks) {
            System.out.println("李四的任务:name:"+task.getName()+",id:"+task.getId());
            taskService.complete(task.getId());
        }
    
        System.out.println("李四的任务数量:"+taskService.createTaskQuery().taskAssignee("李四").count());
        System.out.println("***************二面流程结束***************");
    
        System.out.println("***************HR面流程开始***************");
        tasks = taskService.createTaskQuery().taskCandidateGroup("人力资源部").list();
        for (Task task : tasks) {
            System.out.println("技术部的任务:name:"+task.getName()+",id:"+task.getId());
            taskService.claim(task.getId(), "李四");
        }
    
        System.out.println("李四的任务数量:"+taskService.createTaskQuery().taskAssignee("李四").count());
        for (Task task : tasks) {
            System.out.println("李四的任务:name:"+task.getName()+",id:"+task.getId());
            taskService.complete(task.getId());
        }
    
        System.out.println("李四的任务数量:"+taskService.createTaskQuery().taskAssignee("李四").count());
        System.out.println("***************HR面流程结束***************");
    
        System.out.println("
    ***************录用流程开始***************");
        tasks = taskService.createTaskQuery().taskCandidateGroup("人力资源部").list();
        for (Task task : tasks) {
            System.out.println("技术部的任务:name:"+task.getName()+",id:"+task.getId());
            taskService.claim(task.getId(), "李四");
        }
    
        System.out.println("李四的任务数量:"+taskService.createTaskQuery().taskAssignee("李四").count());
        for (Task task : tasks) {
            System.out.println("李四的任务:name:"+task.getName()+",id:"+task.getId());
            taskService.complete(task.getId());
        }
    
        System.out.println("李四的任务数量:"+taskService.createTaskQuery().taskAssignee("李四").count());
        System.out.println("***************录用流程结束***************");
    
        HistoryService historyService = processEngine.getHistoryService();
        HistoricProcessInstance historicProcessInstance = historyService
                .createHistoricProcessInstanceQuery()
                .processInstanceId(processId).singleResult();
        System.out.println("
    流程结束时间:"+historicProcessInstance.getEndTime());
    }

    代码清单中使用 ProcessEngines类加载默认的流程配置文件(activiti.cfg.xml),再获取各个服务组件的实例。 RepositoryService主要用于管理流程的资源, RuntimeService主要用于流程运行时的流程管理,TaskService主要用于管理流程任务。最后, HistoricProcessInstance会将工作的流程历史记录下来。

  • 相关阅读:
    数组与字符串中的关于截取的总结
    js函数哪些事
    BFC的基础理解及应用场景
    idea永久激活码20211107
    SpringBoot加载properties配置文件的顺序
    Java排序算法之归并排序
    sort与sorted排序
    自定义的迭代器之 生成器
    通过可迭代对象,迭代器,理解dict,list,filter,map,zip,dict,list之间的联系
    迭代器原理 、for循环原理、自定义一个迭代器
  • 原文地址:https://www.cnblogs.com/zhao1949/p/5977622.html
Copyright © 2020-2023  润新知