Activiti框架学习记录-01

Activiti框架学习记录-01

本篇主要是Activiti工作流框架的学习记录,以及对于该框架的基本使用和一些浅显的理解:

  • 1、工作流框架基本概念
  • 2、在eclipse中使用工作流框架
  • 3、创建工作框架
  • 4、使用框架提供API,操作框架实现业务逻辑

1、工作流框架基本概念(摘自百度百科)

  • 工作流(Workflow),就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在多个参与者之间按照某种预定义的规则传递文档、信息或任务的过程自动进行,从而实现某个预期的业务目标,或者促使此目标的实现”。
  • 工作流管理系统(Workflow Management System, WfMS)是一个软件系统,它完成工作量的定义和管理,并按照在系统中预先定义好的工作流逻辑进行工作流实例的执行。工作流管理系统不是企业的业务系统,而是为企业的业务系统的运行提供了一个软件的支撑环境。
  • 常见的工作流框架:JBPM4.4、activiti5.13、OSWorkFlow;

2、在eclipse中使用工作流框架

1、可以离线安装插件,将activit文件夹拷贝到eclipse-luna的安装目录下的
盘符:\Eclipse\eclipse_luna\dropins\ 文件夹下,重启eclipse,进入eclipse后再Window下preference中出现Acitviti选项为安装插件成功,如下图1所示:
插件安装成功后的效果图
并且勾选create process definition image when saving the diagram,这样在我们保存一个流程的时候同时会保存一张png图片;

2、可以选择在线安装:
Name:Activiti BPMN 2.0 designer
Location:http://activiti.org/designer/update/
等待一会儿安装成功后操作以及界面同1所示;
当我们需要使用的时候,点击new->others,如下图2所示:
创建新的工作流


3、创建工作框架

  • 1、建立表结构(两种方式);
  • 2、初步分析23张表的结构与意义;
  • 3、框架中表的设计结构;

知识点分析1:表结构的建立
1)利用sql文件创建表,在我们activiti框架的目录:
…\activiti-5.13\database\create\
sql文件目录
执行sql文件,进入mysql命令行:

source E:\activiti-5.13\database\create\activiti.mysql.create.engine.sql
source E:\activiti-5.13\database\create\activiti.mysql.create.history.sql
source E:\activiti-5.13\database\create\activiti.mysql.create.identity.sql

2)利用API创建表
步骤一:配置文件,使用默认的配置文件:文件必须在类路径下,名称必须为activiti-context.xml
文件中bean的ID规定好的

<!-- activiti-context.xml 配置文件代码-->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    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
                        http://www.springframework.org/schema/context 
                        http://www.springframework.org/schema/context/spring-context-2.5.xsd
                        http://www.springframework.org/schema/tx 
                        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

    <!-- 配置流程引擎配置对象  activiti-day01 -->
    <bean id="processEngineConfiguration" 
        class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <!-- 注入数据源信息 -->
        <property name="jdbcDriver" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql:///activiti-demo01"></property>
        <property name="jdbcUsername" value="root" ></property>
        <property name="jdbcPassword" value="root"></property>
        <!-- 注入自动建表设置 -->
        <property name="databaseSchemaUpdate" value="true"></property>
    </bean>

    <!-- 提供工厂bean,创建流程引擎对象 -->
    <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
        <property name="processEngineConfiguration" ref="processEngineConfiguration"></property>
    </bean>
</beans>
//Java代码片段-01-使用配置文件
@Test
public void test() {
//使用的是默认文件的创建规则
ProcessEngine processEngine = 
ProcessEngines.getDefaultProcessEngine();
}
//Java代码片段-02-不使用配置文件
//使用activit框架提供的自动创建表的方式创建23张表
    /**
     * 自动建表的方式
     */
    @SuppressWarnings("unused")
    @Test
    public void test1() {
        //创建一个流程引擎配置对象
        ProcessEngineConfiguration configuration = 
                ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
        //设置数据源信息
        configuration.setJdbcDriver("com.mysql.jdbc.Driver");
        configuration.setJdbcUrl("jdbc:mysql:///activiti-day01");
        configuration.setJdbcUsername("root");
        configuration.setJdbcPassword("1234");
        //设置自动建表的操作
        configuration.setDatabaseSchemaUpdate("true");
        //使用配置对象创建一个流程引擎对象
        ProcessEngine processEngine = configuration.buildProcessEngine();
    }

知识点分析2:初步分析23张表的结构与意义
Activiti的后台是有数据库的支持,所有的表都以ACT_开头。 第二部分是表示表的用途的两个字母标识。 用途也和服务的API对应。

  • ACT_RE_*: ‘RE’表示repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。

  • ACT_RU_*: ‘RU’表示runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。

  • ACT_ID_*: ‘ID’表示identity。 这些表包含身份信息,比如用户,组等等。

  • ACT_HI_*: ‘HI’表示history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。 ACT_GE_*: 通用数据, 用于不同场景下。

知识点分析3:初步分析23张表的结构与意义
Activiti的后台是有数据库中表的设计结构:
activiti框架中history表结构设计图
完整表结构图

4、使用API操作工作流框架

初步模拟 流程 使用代码片段如下:

1、画图:画出流程图

作出流程图

2、部署流程

1)部署流程定义

  /**
   * 初步模拟一个请假流程
   * 1、部署流程定义
   * 意义:将设计流程图插入到数据库中
   */
    @Test
    public void test4() {
        //流程部署定义
        //部署构建器,用于加载流程定义文件,部署流程定义
        DeploymentBuilder deploymentBuilder = 
                processEngine.getRepositoryService().createDeployment();
        //加载流程定义文件(bpmn、png)
        deploymentBuilder.addClasspathResource("demo01.bpmn");
        deploymentBuilder.addClasspathResource("demo01.png");
        //返回部署对象
        Deployment deployment = deploymentBuilder.deploy();
        //常看当前的流程部署ID
        System.out.println(deployment.getId());
    }

2)查询流程定义

    // 查询流程定义
    @Test
    public void test5() {
        //流程定义查询对象,操作的数据表act_re_prodef
        ProcessDefinitionQuery query = 
                processEngine.getRepositoryService().createProcessDefinitionQuery();
        //查询到流程定义(流程定义表的而查询)
        //可以添加过滤条件
        query.processDefinitionNameLike("请假流程");
        //添加排序条件
        query.orderByProcessDefinitionVersion().desc();

        List<ProcessDefinition> list = 
                query.listPage(0, 1); // 分页查询

        //流程定义对象的遍历
        for (ProcessDefinition processDefinition : list) {
            String id   = processDefinition.getId();
            String name = processDefinition.getName();
            int version = processDefinition.getVersion();
            String deploymentId = processDefinition.getDeploymentId();
            String resourceName = processDefinition.getResourceName();
            System.out.println(id + "\t" + name + "\t" + version);
            System.out.println(deploymentId + "\t" + resourceName);
        }
    }

3)根据流程定义的ID查询实例

    // act_ac_execution:存放的当前启动的实例信息
    // act_ru_task: 存放当前产生的任务(整个流程向下推进十分重要)
    @Test
    public void test6() {
        String processDefinitionId = "qjlc:4:304"; //流程定义ID自己根据数据库表中数据修改
        ProcessInstance processInstance = 
                processEngine.getRuntimeService().startProcessInstanceById(processDefinitionId);
        System.out.println(processInstance.getId());
    }

4)查询个人任务行为

    @Test
    public void test7() {
        //任务查询对象,查询任务表
        TaskQuery query = 
                processEngine.getTaskService().createTaskQuery();
        //添加过滤条件,根据任务的办理人过滤
        query.taskAssignee("张三");
        List<Task> list = query.list();
        for (Task task : list) {
            System.out.println(task.getId() + "====" + task.getName());
        }
    } 

4)办理个人任务行为

    @Test
    public void test8() {
        String taskId = "1804"; // 任务ID,根据数据库中task表中的数据进行修改
        //自动推向到下一个任务人
        processEngine.getTaskService().complete(taskId);
    }

5)清理数据库activiti表中的所有数据

    @Test
    public void test() {
        DeploymentQuery query = processEngine.getRepositoryService().createDeploymentQuery();
        List<Deployment> list = query.list();
        for (Deployment deployment : list) {
            //完全清理数据,级联清理数据
            processEngine.getRepositoryService().deleteDeployment(deployment.getId(), true);
        }
    }

流程实例的操作(代码为了保证完整性的功能与上述代码功能会有部分重复)
1)首先声明一个流程操作引擎,基本在整个框架的声明周期中都会有所使用

//在项目中可以使用spring的注入技术进行处理,现在暂时使用普通方法
ProcessEngine pe = ProcessEngines.getDefaultProcessEngine();

2)部署流程定义
* 方式一:加载单个的流程定义文件
* 方式二:加载zip压缩文件(将bpmn文件以及png文件进行打包为process.zip)
代码中使用的文件截图

@Test
    public void test1() {
        DeploymentBuilder deploymentBuilder = 
                pe.getRepositoryService().createDeployment();
//      ZipInputStream zipInputStream_file = null;
        // 方式一:加载单个流程定义文件
//      deploymentBuilder.addClasspathResource("demo01.bpmn");
//      deploymentBuilder.addClasspathResource("demo01.png");
//      Deployment deployment = deploymentBuilder.deploy();

        // 方式二:加载zip压缩文件PS: 只支持zip
        // Web项目中使用该方式
//      try {
//          zipInputStream_file = new ZipInputStream(new FileInputStream(new File("d:\\process.zip")));
//      } catch (FileNotFoundException e) {
//          // TODO Auto-generated catch block
//          e.printStackTrace();
//      }
        ZipInputStream zipInputStream 
            = new ZipInputStream(this.getClass().getClassLoader().getResourceAsStream("process.zip"));
        deploymentBuilder.addZipInputStream(zipInputStream);
        deploymentBuilder.name("部署名称测试");
        Deployment deployment = deploymentBuilder.deploy();
        String id = deployment.getId();
        System.out.println(id);
    }

3)查询部署信息,查询的通用写法

      pe.getXXXService().createXXXQuery().list()
@Test
    public void test2() {
//      pe.getRepositoryService().createDeploymentQuery().list();
//      pe.getRepositoryService().createProcessDefinitionQuery().list();
//      pe.getRuntimeService().createProcessInstanceQuery().list();
//      pe.getTaskService().createTaskQuery().list();
//      pe.getHistoryService().createHistoricActivityInstanceQuery().list();

        List<Deployment> list = pe.getRepositoryService().createDeploymentQuery().list();
        for (Deployment deployment : list) {
            System.out.println(deployment.getId() + "\t" + deployment.getDeploymentTime());
        }

    }

3)删除部署信息

    // 删除部署信息
    @Test
    public void test3() {
        //删除deploymentId为501的部署信息数据,同样会影响几张表
        String deploymentId = "501";
        //是否级联删除(会删除更多的表)
        boolean cascade = true;
        pe.getRepositoryService().deleteDeployment(deploymentId,cascade);
    }

3)查询流程定义数据

@Test
    public void test4() {
        List<ProcessDefinition> list = pe.getRepositoryService().createProcessDefinitionQuery().list();
        for (ProcessDefinition processDefinition : list) {
            System.out.println(processDefinition.getId() + "\t" + 
                    processDefinition.getKey() + "\t" + 
                    processDefinition.getResourceName() + "\t" + 
                    processDefinition.getVersion());
        }
    }

4) 删除流程定义数据,通过删除部署信息达到删除流程定义的目的

@Test
    public void test5() {
        //删除部署的时候会自动删除流程定义
        String deploymentId = "501";
        pe.getRepositoryService().deleteDeployment(deploymentId);
    }

5)查询相关

    /**
     * 查询最新版本的流程定义数据
     */
    @Test
    public void test6() {
        //查询的是所有的
        pe.getRepositoryService().createDeploymentQuery().list();
        //查询最新的
        List<ProcessDefinition> list = pe.getRepositoryService().createProcessDefinitionQuery().latestVersion().list();
        for (ProcessDefinition processDefinition : list) {
            System.out.println(processDefinition.getVersion() + "\t" + processDefinition.getDeploymentId());
        }
    }

    @Test
    public void test7() {
        //没有提供过滤条件就需要自己来写
        ProcessDefinitionQuery query = pe.getRepositoryService().createProcessDefinitionQuery();
        //按照version升序排列
        query.orderByProcessDefinitionVersion().asc(); //排序的方法
        List<ProcessDefinition> list = query.list();   //list展示
        Map<String, ProcessDefinition> map = new HashMap<String, ProcessDefinition>();
        for (ProcessDefinition processDefinition : list) {
            map.put(processDefinition.getKey(), processDefinition);
        }
        System.out.println(map);

        list = new ArrayList<ProcessDefinition>(map.values());
        for (ProcessDefinition processDefinition : list) {
            System.out.println(processDefinition.getName() + "\t" + processDefinition.getId());
        }
    }

    /**
     * 查询一次部署的对应的流程定义文件名称和输入流
     * @throws IOException 
     */
    @Test
    public void test8() throws IOException {
        String deploymentId = "1101"; // 部署ID
        List<String> names = pe.getRepositoryService().getDeploymentResourceNames(deploymentId);
        for (String name : names) {
            System.out.println(name);
            //文件输入流(是用来读取BLOB字段的文件的)
            InputStream inputStream = pe.getRepositoryService().getResourceAsStream(deploymentId, name);
            //读取出数据

            FileUtils.copyInputStreamToFile(inputStream, new File("d:\\" + name));

//          byte[] bytes = new byte[1024];
//          while(inputStream.read(bytes) != -1) {
//              i++;
//              inputStream.read(bytes);
//              outputStream = new FileOutputStream(new File("d:\\" + name));
//              outputStream.write(bytes);
//          }
//          
            inputStream.close();
//          outputStream.close();
        }
    }

    /**
     * 获得图片的输入流
     * @throws IOException 
     */
    @Test
    public void test9() throws IOException {
        //从页面上获取一个流程ID
        String processDefinitionId = "qjlc:9:1404"; // 流程定义ID
        InputStream inputStream = pe.getRepositoryService().getProcessDiagram(processDefinitionId);
        FileUtils.copyInputStreamToFile(inputStream, new File("d:\\my.png"));
        inputStream.close();
    }

6)启动流程实例

    /**
     * 启动流程实例
     * 方式一:根据流程定义的ID启动实例
     * 方式二:根据流程定义的key启动实例 (建议使用,会自动选择最新版本)
     */
    @Test
    public void test10() {
        String processDefinitionId = "qjlc:7:1204"; // 流程定义ID
        //不会管是不是最新的流程版本
        //方式一:根据流程定义的ID启动流程实例
        ProcessInstance pi = pe.getRuntimeService().startProcessInstanceById(processDefinitionId);
        System.out.println(pi.getId());

        String processDefinitionKey = "qjlc";
        //方式二:根据流程定义的key启动流程
        //会根据最新的流程进行启动
        ProcessInstance pi_ = pe.getRuntimeService().startProcessInstanceByKey(processDefinitionKey);
        System.out.println(pi_.getProcessDefinitionId());
    }

7)查询流程实例

    /**
     * 查询流程实例
     */
    @Test
    public void test11() {
        //流程实例查询对象,查询表act_ru_execution
        ProcessInstanceQuery query = pe.getRuntimeService().createProcessInstanceQuery();
        List<ProcessInstance> list = query.list();
        for (ProcessInstance processInstance : list) {
            System.out.println(processInstance.getId()+"\t"+processInstance.getActivityId());
        }
    }

8)删除流程实例

/**
     * 删除流程实例
     */
    @Test
    public void test12() {
        String processInstanceId = "1601"; // 流程实例ID
        String deleteReason = "不请假了";      // 删除流程实例原因
        //删除一个流程实例
        pe.getRuntimeService().deleteProcessInstance(processInstanceId, deleteReason);
    }

9)查询个人任务

    /**
     * 查询个人任务
     */
    @Test
    public void test13() {
        TaskQuery query = pe.getTaskService().createTaskQuery();
        String assignee = "王五";
        query.taskAssignee(assignee);
        List<Task> list = query.list();
        for (Task task : list) {
            System.out.println(task.getId() + "\t" + task.getName());
        }
    }

10)办理个人任务

    /**
     * 办理个人任务
     */
    public void test14() {
        String taskId = "1509"; //注意此处数据必须存在于数据库的taskId表中
        pe.getTaskService().complete(taskId);
    }
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
做一个最简单的HellWorld流程用代码的方式实现并且走完流程。 1.首先是需要部署流程定义。 2.启动流程实例。 3.查看流程任务以及完成流程任务。 创建一个单元测试类ActivitiHelloWorldTest,首先第一操作流程就必须要获取引擎实例: [java] view plain copy 1. <span 2. * 获取默认的流程引擎实例 会自动读取activiti.cfg.xml文件 3. */ 4. private ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();</span> 把绘制的流程定义图(我在上一篇博文上绘制过),部署下: [java] view plain copy 1. <span 2. * 部署流程定义 3. */ 4. @Test 5. public void deploy(){ 6. // 获取部署对象 7. Deployment deployment=processEngine.getRepositoryService() // 部署Service 8. .createDeployment() // 创建部署 9. .addClasspathResource("diagrams/helloWorld.bpmn") // 加载资源文件 10. .addClasspathResource("diagrams/helloWorld.png") // 加载资源文件 11. .name("HelloWorld流程") // 流程名称 12. .deploy(); // 部署 13. System.out.println("流程部署ID:"+deployment.getId()); 14. System.out.println("流程部署Name:"+deployment.getName()); 15. }</span> 接着需要启动流程实例,这样一个流程才开始: [java] view plain copy 1. <span 2. * 启动流程实例 3. */ 4. @Test 5. public void start(){ 6. // 启动并获取流程实例 7. ProcessInstance processInstance=processEngine.getRuntimeService() // 运行时流程实例Service 8. .startProcessInstanceByKey("myFirstProcess"); // 流程定义表的KEY字段值 9. System.out.println("流程实例ID:"+processInstance.getId()); 10. System.out.println("流程定义ID:"+processInstance.getProcessDefinitionId()); 11. }</span> 查看一下李四这个用户的任务信息: [java] view plain copy 1. <span 2. * 查看任务 3. */ 4. @Test 5. public void findTask(){ 6. // 查询并且返回任务即可 7. List<Task> taskList=processEngine.getTaskService() // 任务相关Service 8. .createTaskQuery() // 创建任务查询 9. .taskAssignee("李四") // 指定某个人 10. .list(); 11. for(Task task:taskList){ 12. System.out.println("任务ID:"+task.getId()); 13. System.out.println("任务名称:"+task.getName()); 14. System.out.println("任务创建时间:"+task.getCreateTime()); 15. System.out.println("任务委派人:"+task.getAssignee()); 16. System.out.println("流程实例ID:"+task.getProcessInstanceId()); 17. } 18. }</span> 最后完成HelloWorld节点任务,把流程走完: [java] view plain copy 1. <span 2. * 完成任务 3. */ 4. @Test 5. public void completeTask(){ 6. <span </span>processEngine.getTaskService() // 任务相关Service 7. .complete("2504"); // 指定要完成的任务ID 8. }</span> 有个很重要的概念,流程定义和流程实例的关系,可以把这两种关系理解成是类和对象的关系。 流程定义是一个模板,而流程实例就是通过模板演变出来的具体的可用的东西。 首先当运行:deploy()部署流程定义方法,在数据库中流程定义表会发生一些变化新增了一条数据, act_re_deployment流程定义部署表: 然后act_re_prodef流程定义表也会有一条数据插入: 还有一个act_ge_bytearray表用来存储资源信息: 接着来运行start()启动流程实例: act_ru_task运行时流程任务表新增了一条数据: act_ru_execution运行时流程执行表: act_ru_identitulink是用于执行主体相关信息表: 可以查看刚刚"李四”这个用户的任务: 运行findTask()查看用户任务,控制台输出如下: [java] view plain copy 1. <span Failed to load class "org.slf4j.impl.StaticLoggerBinder". 2. SLF4J: Defaulting to no-operation (NOP) logger implementation 3. SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. 4. 任务ID:5004 5. 任务名称:HelloWorld 6. 任务创建时间:Mon Mar 13 11:15:18 CST 2017 7. 任务委派人:李四 8. 流程实例ID:5001</span> 查询到了数据就说明这个用户有任务可以执行,接着运行completeTask()方法完成任务: 然后数据库中ru开头的运行时候所有表的数据都没了,因为现在流程结束,不需要这些数据了。 在hi开头的表里,会新增不少数据,这些数据主要是用来归档查询用的,也就是历史数据。 act_hi_taskinst 历史流程实例任务表加了一条任务数据; act_hi_procinst 历史流程实例实例表加了一条流程实例相关信息的数据(包括开始时间,结束时间等等信息); act_hi_identitylink 历史流程实例参数者的表加了一条数据; act_hi_actinst 历史活动节点表加了三条流程活动节点信息的数据(每个流程实例具体的执行活动节点的信息);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值