• Activiti学习记录(二)


    1.初始化数据库

    使用工作流引擎创建23张表

    public class TestActiviti {
        /**
         * 使用代码创建工作流需要的23张表
         */
        @Test
        public void createTable() {
            ProcessEngineConfiguration createStandaloneProcessEngineConfiguration = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
            createStandaloneProcessEngineConfiguration.setJdbcDriver("com.mysql.jdbc.Driver");
            createStandaloneProcessEngineConfiguration.setJdbcUrl("jdbc:mysql://localhost:3306/activiti0710?useUnicode=true&characterEncoding=utf8");
            createStandaloneProcessEngineConfiguration.setJdbcUsername("root");
            
            /** 
              public static final String DB_SCHEMA_UPDATE_FALSE = "false"; 不能自动创建表,需要表存在
              public static final String DB_SCHEMA_UPDATE_CREATE_DROP = "create-drop"; 表示先删除表,在创建表
              public static final String DB_SCHEMA_UPDATE_TRUE = "true";如果表不存在,自动创建表
              */
            createStandaloneProcessEngineConfiguration.setDatabaseSchemaUpdate(createStandaloneProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
            //工作流的核心对象
            ProcessEngine buildProcessEngine = createStandaloneProcessEngineConfiguration.buildProcessEngine();
            System.out.println(buildProcessEngine);
            
        }
    }

    Activiti中,在创建核心的流程引擎对象时会自动建表。如果程序正常执行,mysql会自动建库,然后创建23张表。

    2.添加并制定配置文件

    Actiiti5中定制流程必定会操作到数据库,如果都像上面那样写一大段代码会非常麻烦,所以我们可以把数据库连接配置写入配置文件。

    创建activiti.cfg.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">
    
        <!-- 
        ProcessEngineConfiguration createStandaloneProcessEngineConfiguration = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
            createStandaloneProcessEngineConfiguration.setJdbcDriver("com.mysql.jdbc.Driver");
            createStandaloneProcessEngineConfiguration.setJdbcUrl("jdbc:mysql://localhost:3306/activiti0710?useUnicode=true&characterEncoding=utf8");
            createStandaloneProcessEngineConfiguration.setJdbcUsername("root");
            
            /** 
              public static final String DB_SCHEMA_UPDATE_FALSE = "false"; 不能自动创建表,需要表存在
              public static final String DB_SCHEMA_UPDATE_CREATE_DROP = "create-drop"; 表示先删除表,在创建表
              public static final String DB_SCHEMA_UPDATE_TRUE = "true";如果表不存在,自动创建表
              */
            createStandaloneProcessEngineConfiguration.setDatabaseSchemaUpdate(createStandaloneProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
            //工作流的核心对象
            ProcessEngine buildProcessEngine = createStandaloneProcessEngineConfiguration.buildProcessEngine();
            
         -->
        <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
            <!-- 连接数据库配置 -->
            <property name="jdbcDriver" value="com.mysql.jdbc.Driver"></property>
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activiti0710?useUnicode=true&amp;characterEncoding=utf8"></property>
            <property name="jdbcUsername" value="root"></property>
            <!-- 没有表创建表 -->
            <property name="databaseSchemaUpdate" value="true"></property>
        </bean>
    
    </beans>

    java代码:

    /**
         * 使用配置文件创建工作流需要的23张表
         */
        @Test
        public void createTable_2() {
            ProcessEngineConfiguration createProcessEngineConfigurationFromResource = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
            ProcessEngine buildProcessEngine = createProcessEngineConfigurationFromResource.buildProcessEngine();
            System.out.println(buildProcessEngine);
        }

     3. HelloWorld程序(模拟流程的执行)

    先新建一个bpmn文件

     

    编写junit测试类

    public class helloWorld {
    
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        /**
         * 部署流程定义
         */
        @Test
        public void deployProcessDefinition() {
            Deployment deploy = processEngine.getRepositoryService()//与流程定义和部署对象相关的Service
                         .createDeployment()//创建一个部署对象
                         .name("helloWorld入门程序")//添加部署的名称
                         .addClasspathResource("diagrams/HelloWorld.bpmn")//一次只能加载一个文件
                         .addClasspathResource("diagrams/HelloWorld.png")
                         .deploy();//完成部署
            System.out.println(deploy.getId());
            System.out.println(deploy.getName());
        }
        
        /**
         * 启动流程实例
         */
        @Test
        public void startProcessInstance() {
            //流程定义的key
            String processDefinitionKey = "helloWorld";
            ProcessInstance startProcessInstanceByKey = processEngine.getRuntimeService()//与正在执行的流程实例和执行对象相关的Service
                         .startProcessInstanceByKey(processDefinitionKey);//使用流程定义的key启动流程实例,key对应HelloWorld.bpmn中的id属性,使用key启动,默认是最新版本的流程定义启动
            System.out.println("流程实例id" + startProcessInstanceByKey.getId());//流程实例id
            System.out.println("流程定义id" + startProcessInstanceByKey.getProcessDefinitionId());//流程定义id
        }
        
        /**
         * 查询当前人的个人任务
         */
        @Test
        public void findMyPersonTask() {
            String assignee = "王五";
            List<Task> list = processEngine.getTaskService()//与正在执行的任务管理相关的service
                         .createTaskQuery()//创建任务查询对象
                         .taskAssignee(assignee)//指定个人任务查询,指定办理人
                         .list();
            if (list != null && list.size() > 0) {
                for (Task task : list) {
                    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());
                    System.out.println("执行对象ID:"+task.getExecutionId());
                    System.out.println("流程定义ID:"+task.getProcessDefinitionId());
                }
            }
        }
        
        /**
         * 完成个人任务
         */
        @Test
        public void completMyPersonTask() {
            String taskId = "302";
            processEngine.getTaskService()//与正在执行的任务管理相关的service
                         .complete(taskId);
            System.out.println("完成任务:任务ID"+taskId);
        }
    }

    4.部署流程定义(classpath路径加载文件)

    说明:

    1) 先获取流程引擎对象:在创建时会自动加载classpath下的activiti.cfg.xml

    2) 首先获得默认的流程引擎,通过流程引擎获取了一个RepositoryService对象(仓库对象)

    3) 由仓库的服务对象产生一个部署对象配置对象,用来封装部署操作的相关配置。

    4) 这是一个链式编程,在部署配置对象中设置显示名,上传流程定义规则文件

    5) 向数据库表中存放流程定义的规则信息。

    6) 这一步在数据库中将操作三张表:

    a) act_re_deployment(部署对象表)

    存放流程定义的显示名和部署时间,每部署一次增加一条记录

    b) act_re_procdef(流程定义表)

    存放流程定义的属性信息,部署每个新的流程定义都会在这张表中增加一条记录。

    注意:当流程定义的key相同的情况下,使用的是版本升级

    c) act_ge_bytearray(资源文件表)

    存储流程定义相关的部署信息。即流程定义文档的存放地。每部署一次就会增加两条记录,一条是关于bpmn规则文件的,一条是图片的(如果部署时只指定了bpmn一个文件,activiti会在部署时解析bpmn文件内容自动生成流程图)。两个文件不是很大,都是以二进制形式存储在数据库中。

    /**
         * 部署流程定义(从classpath)
         */
        @Test
        public void deployProcessDefinition_classpath() {
            Deployment deploy = processEngine.getRepositoryService()//与流程定义和部署对象相关的Service
                         .createDeployment()//创建一个部署对象
                         .name("流程定义")//添加部署的名称
                         .addClasspathResource("diagrams/HelloWorld.bpmn")//一次只能加载一个文件
                         .addClasspathResource("diagrams/HelloWorld.png")
                         .deploy();//完成部署
            System.out.println(deploy.getId());
            System.out.println(deploy.getName());
        }

    5. 部署流程定义(zip格式文件)

    /**
         * 部署流程定义(从zip)
         */
        @Test
        public void deployProcessDefinition_zip() {
            InputStream in = this.getClass().getClassLoader().getResourceAsStream("diagrams/HelloWorld.zip");
            ZipInputStream zipInputStream = new ZipInputStream(in);
            Deployment deploy = processEngine.getRepositoryService()//与流程定义和部署对象相关的Service
                    .createDeployment()//创建一个部署对象
                    .name("流程定义")//添加部署的名称
                    .addZipInputStream(zipInputStream)//一次只能加载一个文件
                    .deploy();//完成部署
            System.out.println(deploy.getId());
            System.out.println(deploy.getName());
        }
        

    6. 查看流程定义

    查询流程定义的信息

    /**
         * 查询流程定义
         */
        @Test
        public void findProcessDefinition() {
            List<ProcessDefinition> list = processEngine.getRepositoryService()//与流程定义和部署对象相关的Service
                         .createProcessDefinitionQuery()//创建流程定义查询
    //                     .deploymentId(deploymentId) //使用部署对象ID查询    
    //                     .processDefinitionKey(processDefinitionKey) //使用流程定义的key查询
    //                     .processDefinitionId(processDefinitionId) //使用流程定义的id查询
    //                     .processDefinitionKeyLike(processDefinitionKeyLike) //使用流程定义的id模糊查询
    //                     .processDefinitionNameLike(processDefinitionNameLike) //使用流程定义的name模糊查询
                         /** 排序 **/
                         .orderByProcessDefinitionVersion().asc() //按照版本升序排列
    //                     .orderByProcessDefinitionName().desc() // 按照流程定义的名称降序排序
                         .list(); //返回一个集合列表,封装流程定义
    //                     .singleResult() //返回唯一结果集
    //                     .listPage(firstResult, maxResults) //分页查询
    //                     .count() //返回结果集数量
            if (list != null && list.size() > 0) {
                for (ProcessDefinition pd : list) {
                    System.out.println("流程定义ID:"+ pd.getId());//流程定义的key+版本+随机生成数
                    System.out.println("流程定义的名称:"+pd.getName());//对应helloworld.bpmn文件中的name属性值
                    System.out.println("流程定义的key:"+pd.getKey());//对应helloworld.bpmn文件中的id属性值
                    System.out.println("流程定义的版本"+pd.getVersion());//当流程定义的key相同时,版本从1开始逐次升级
                    System.out.println("资源名称bpmn文件:"+pd.getResourceName());
                    System.out.println("资源名称png文件:"+pd.getDiagramResourceName());
                    System.out.println("部署对象ID:"+pd.getDeploymentId());
                }
            }
                         
        }

    说明:

    1) 流程定义和部署对象相关的Service都是RepositoryService

    2) 创建流程定义查询对象,可以在ProcessDefinitionQuery上设置查询的相关参数

    3) 调用ProcessDefinitionQuery对象的list方法,执行查询,获得符合条件的流程定义列表

    4) 由运行结果可以看出:

    KeyName的值为:bpmn文件process节点的idname的属性值

     

    5) key属性被用来区别不同的流程定义。

    6) 带有特定key的流程定义第一次部署时,version1。之后每次部署都会在当前最高版本号上加1

    7) Id的值的生成规则为:{processDefinitionKey}:{processDefinitionVersion}:{generated-id}, 这里的generated-id是一个自动生成的唯一的数字

    8) 重复部署一次,deploymentId的值以一定的形式变化

       规则act_ge_property表生成

     7.删除流程定义

    删除部署到activiti中的流程定义。

        /**
         * 删除流程定义
         */
        @Test
        public void delProcessDefinition() {
            //使用部署ID,完成删除
            String deploymentId = "601";
            /**
             * 不带级联删除
             * 只能删除没有启动的流程,如果流程启动,就会抛出异常
             */
            /*processEngine.getRepositoryService()
                         .deleteDeployment(deploymentId);*/
            /**
             * 级联删除
             * 不管流程是否启动,都能删除
             */
            processEngine.getRepositoryService()
                         .deleteDeployment(deploymentId, true);
            System.out.println("删除成功!");
        }

    8. 获取流程定义文档的资源(查看流程图附件)

    查询出流程定义文档。主要查的是图片,用于显示流程用。

    /**
         * 查看流程图
         * @throws IOException 
         */
        @Test
        public void viewPic() throws IOException {
            //将生成的图片放置到文件夹下
            String deploymentId = "901";
            //获取图片资源名称
            List<String> list = processEngine.getRepositoryService()
                             .getDeploymentResourceNames(deploymentId);
            String resourceName = "";
            if (list != null && list.size() > 0) {
                for (String name : list) {
                    if (name.indexOf(".png") >= 0) {
                        resourceName = name;
                    }
                    
                }
            }
            
            //获取图片输入流
            InputStream in = processEngine.getRepositoryService()
                         .getResourceAsStream(deploymentId, resourceName);
            
            //将图片生成到D盘目录下
            File file = new File("D:/"+resourceName);
            FileUtils.copyInputStreamToFile(in, file);
        }

    说明:

    1) deploymentId为流程部署ID

    2) resourceNameact_ge_bytearray表中NAME_列的值

    3) 使用repositoryServicegetDeploymentResourceNames方法可以获取指定部署下得所有文件的名称

    4) 使用repositoryServicegetResourceAsStream方法传入部署ID和资源图片名称可以获取部署下指定名称文件的输入流

    最后的有关IO流的操作,使用FileUtils工具的copyInputStreamToFile方法完成流程流程到文件的拷贝,将资源文件以流的形式输出到指定文件夹下

    9.流程定义是无法修改的

    控制修改:使用流程定义的key相同情况下,版本升级

    10.附加功能:查询最新版本的流程定义

    /**
         * 附加功能:查询最新版本的流程定义
         */
        @Test
        public void findLastVersionProcessDefinition() {
            List<ProcessDefinition> list = processEngine.getRepositoryService()
                         .createProcessDefinitionQuery()
                         .orderByProcessDefinitionVersion().desc()//使用流程定义的版本升序排列
                         .list();
            
            /**
             * map集合的key:流程定义的key
             * map集合的value:流程定义的对象
             * map集合的特点:当map集合key相同的情况下,后一次的值将替换前一次的值
             */
            Map<String, ProcessDefinition> map = new LinkedHashMap<>();
            if (list != null && list.size() > 0) {
                for (ProcessDefinition pd : list) {
                    map.put(pd.getKey(), pd);
                }
            }
            List<ProcessDefinition> pdList = new ArrayList<ProcessDefinition>(map.values());
            if (pdList != null && pdList.size() > 0) {
                for (ProcessDefinition pd : pdList) {
                    System.out.println("流程定义ID:"+ pd.getId());//流程定义的key+版本+随机生成数
                    System.out.println("流程定义的名称:"+pd.getName());//对应helloworld.bpmn文件中的name属性值
                    System.out.println("流程定义的key:"+pd.getKey());//对应helloworld.bpmn文件中的id属性值
                    System.out.println("流程定义的版本:"+pd.getVersion());//当流程定义的key相同时,版本从1开始逐次升级
                    System.out.println("资源名称bpmn文件:"+pd.getResourceName());
                    System.out.println("资源名称png文件:"+pd.getDiagramResourceName());
                    System.out.println("部署对象ID:"+pd.getDeploymentId());
                }
            }
        }

    11.附加功能:删除流程定义(删除key相同的所有不同版本的流程定义)

    /**
         * 附加功能: 删除流程定义(删除key相同的所有流程版本不同的流程定义)
         */
        @Test
        public void delProcessDefinitionByKey() {
            //流程定义的key
            String processDefinitionKey = "helloWorld";
            //先使用流程定义的key查询流程定义,查询所有的版本
            List<ProcessDefinition> list = processEngine.getRepositoryService()
                         .createProcessDefinitionQuery()
                         .processDefinitionKey(processDefinitionKey)
                         .list();
            if (list != null && list.size() > 0) {
                for (ProcessDefinition pd : list) {
                    String deploymentId = pd.getDeploymentId();
                    processEngine.getRepositoryService().deleteDeployment(deploymentId, true);
                }
            }
        }

    12.流程实例,任务和执行

    Execution   执行对象

     按流程定义的规则执行一次的过程.

     对应的表:

      act_ru_execution 正在执行的信息

      act_hi_procinst:已经执行完的历史流程实例信息

      act_hi_actinst:存放历史所有完成的活动

    ProcessInstance  流程实例

     特指流程从开始到结束的那个最大的执行分支,一个执行的流程中,流程实例只有1

    注意

        1)如果是单例流程,执行对象ID就是流程实例ID

        2)如果一个流程有分支和聚合,那么执行对象ID和流程实例ID就不相同

        3)一个流程中,流程实例只有1个,执行对象可以存在多个。

    Task 任务

     执行到某任务环节时生成的任务信息。

     对应的表:

      act_ru_task正在执行的任务信息

      act_hi_taskinst已经执行完的历史任务信息

  • 相关阅读:
    [LeetCode] 143. 重排链表
    [LeetCode] 342. 4的幂
    [LeetCode] 1744. 你能在你最喜欢的那天吃到你最喜欢的糖果吗?
    [LeetCode] 148. 排序链表
    [LeetCode] 525. 连续数组
    [LeetCode] 160. 相交链表
    [LeetCode] 134. 加油站
    [LeetCode] 474. 一和零
    CentOS 升级 OpenSSH
    AWS 证书取消挂靠
  • 原文地址:https://www.cnblogs.com/FanJava/p/9289740.html
Copyright © 2020-2023  润新知