1.Activiti 入门

工作流学习

一、了解工作流

工作流(Workflow),就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在多个参与者之间按照某种预定义的规则传递文档、信息或任务的过程自动进行,从而实现某个预期的业务目标,或者促使此目标的实现”。

工作流管理系统(Workflow Management System, WfMS)是一个软件系统,它完成工作量的定义和管理,并按照在系统中预先定义好的工作流逻辑进行工作流实例的执行。工作流管理系统不是企业的业务系统,而是为企业的业务系统的运行提供了一个软件的支撑环境。

常见的工作流框架

Activity5.13、JBPM4.4、OSWorkFlow、WorkFlow

工作流框架底层需要有数据库提供支持,activiti5.13版本,有23张表。JBPM4.4框架底层有数据库支持,18张表。JBPM底层使用hibernate操作数据库。Activiti框架底层使用的mybatis操作数据库。


二、初始化表结构

建表之前,说一下activiti的工作全部依赖ProcessEngine工作引擎,而初始化表就是建立ProcessEngine实例的三种方式:

ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration() +建表配置+.buildProcessEngine();

ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml").buildProcessEngine()

ProcessEngineConfiguration.createProcessEngineConfigurationFromResourceDefault().buildProcessEngine()

2.1 初始化表操作

2.1.1 使用activiti框架提供的建表语句

在activiti框架包下面的 /activiti-x.xx/database/ceate/ 中

2.1.2 使用activiti框架自动建表

public void createActivitiTableByConfigration() {
         //    创建一个流程引擎配置对象
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
        //  设置数据源信息
        configuration.setJdbcDriver("com.mysql.jdbc.Driver");//mysql数据库驱动
        configuration.setJdbcUrl("jdbc:mysql://localhost:3306/activiti");//指定数据库
        configuration.setJdbcUsername("root");//用户名
        configuration.setJdbcPassword("");//密码
         //    设置自动建表configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
        //      创建一个流程引擎对象,在创建流程引擎对象中会自动建表
        ProcessEngine processEngine = configuration.buildProcessEngine();
        System.out.println(processEngine);
    }

2.1.3 使用xml配置文件初始化


public void createActivitiTableByXml() {
//      ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        //      创建一个流程引擎对象,在创建流程引擎对象中会自动建表
//      ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        
        ProcessEngine processEngine = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml").buildProcessEngine();
        System.out.println(processEngine);
    }

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" xmlns:p="http://www.springframework.org/schema/p"
    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="jdbcDriver" value="com.mysql.jdbc.Driver"></property>
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activiti"></property>
            <property name="jdbcUsername" value="root"></property>
            <property name="jdbcPassword" value=""></property>
            
            <!-- 没有表创建表 -->
            <property name="databaseSchemaUpdate" value="true"></property>
        </bean>
</beans>

2.1.4 使用默认的xml配置(要求配置文件名称必须为activiti-context.xml或者activiti.cfg.xml)

/**
     * 使用默认创建ProcessEngineConfiguration,读取的是classpath下的activiti.cfg.xml文件
     */
    public void createActivitiTableByDefault() {
         ProcessEngine processEngine = ProcessEngineConfiguration.createProcessEngineConfigurationFromResourceDefault().buildProcessEngine();
         System.out.println(processEngine);
    }

三、了解表

activiti初始化表,会建立23张以act_开头的表,第二个部分的字母表明用途,用途也跟服务api对应

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

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

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

  • ACT_HI_*: 'HI'表示history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。

  • ACT_GE_*: 通用数据, 用于不同场景下。

image

四、框架的基本使用

activiti提供服务是基于service的,主要是:

  • RepositoryService----操作静态的资源(流程定义,bpmn、png)

  • RuntimeService-----操作流程实例(启动流程实例、查询流程实例、结束流程实例)

  • TaskService-----操作任务(查询任务、办理任务)

  • HistoryService----操作历史数据

Activiti框架提供的对象(和表有对应关系)

  • Deployment-----act_re_deployment

  • ProcessDefinition----act_re_procdef

  • ProcessInstance-----act_ru_execution

  • Task-----act_ru_task

4.1 部署流程定义

部署流程就涉及到bpmn文件的使用,使用Eclipse或Idea的BPMN编辑插件绘制流程图,并导出bpmn文件和png文件。(插件的安装及使用自行百度。笔者用的是eclipse,当插件安装好后,进入window->preferences->Activiti->Save,勾选Create process .....意思是当保存bpmn文件时自动生成png文件),其中bpmn文件是给系统使用的,png文件是给用户看的。

部署流程有很多种,笔者只试了两种:


public void deploymentProcess() {
        // 获得一个部署构建器对象,用于加载流程定义文件(test.bpmn test.png)完成流程定义的部署
        Deployment deployment = processEngine.getRepositoryService()
                        .createDeployment()
                        .addClasspathResource("bpmn/helloworld.bpmn")
                        .addClasspathResource("bpmn/helloworld.png")
//                      .addZipInputStream(this.getClass().getClassLoader().getResourceAsStream("bpmn/helloworld.zip"))//将bpmn文件和png文件压缩放在zip包下,一定要是zip
                        .name("helloworld")
                        .deploy();
        System.out.println(deployment);
        
    }

4.2 查询流程定义表 ==> act_re_procdef

public void queryProcessDefinition() {
//      String processDefinitionKey = "myProcess";
        List<ProcessDefinition> list = processEngine.getRepositoryService()//    流程定义查询对象,用于查询act_re_procdef
                        .createProcessDefinitionQuery()
//                      .processDefinitionKey(processDefinitionKey)//添加过滤条件
//                      .orderByProcessDefinitionVersion().asc() //    添加排序条件
                        .list();//查询结果为集合
        
        if(list != null && list.size()>0) {
            for(ProcessDefinition pd:list) {
                System.out.println("流程定义的id:"+pd.getId());
                System.out.println("流程定义的key:"+pd.getKey());
                System.out.println("流程定义的部署id:"+pd.getDeploymentId());
                System.out.println("流程定义的流程图名(bpmn):"+pd.getDiagramResourceName());
                System.out.println("流程定义的流程图:"+pd.getResourceName());
                System.out.println("流程定义的名字:"+pd.getName());
                System.out.println("流程定义的版本:"+pd.getVersion());
                System.out.println("------------------------------------------------------------------");
            }
        }
    }

4.3 启动流程

流程实例是根据一个流程定义具体的一次执行过程就是一个流程实例,一个流程定义对应多个流程实例(一对多关系)

/**
     * 根据流程定义 启动一个流程实例
     * 根据流程定义的一次具体执行过程,就是一个流程实例
     */
    @Test
    public void startProcessDefinition() {
        String processDefinitionId = "helloword:1:10004";
        ProcessInstance processInstance = processEngine.getRuntimeService()
//                      .startProcessInstanceByKey(processDefinitionKey);//根据key启动的是最新版本的流程,建议使用
                        .startProcessInstanceById(processDefinitionId);
        System.out.println("流程启动实例id:"+processInstance.getId());
    }

4.4 查询个人任务

public void queryTask() {
        String key = "usertask1";
        List<Task> list = processEngine.getTaskService()
                        .createTaskQuery()
                        //条件查询,可以指定条件
//                      .taskAssignee(assignee)
                        .taskDefinitionKey(key)
                        .list();
        if(list != null && list.size()>0) {
            for(Task ts:list) {
                System.out.println(ts.getId() + "——" + ts.getName());
                System.out.println("-------------------------------------------------------");
            }
        }
    }

4.5 办理任务

public void completeTask(){
        String taskId = "12504";
        processEngine.getTaskService()
                        .complete(taskId);
         System.out.println("办理成功");
    }

五、Acitiviti提供了网页版流程设计器

1.将Activiti的包中activiti-explorer.war复制到tomcat的/webapps目录中。

2.启动Tomcat,访问http://lcoalhost:8080/activiti-explorer

3.登录。登录账号和密码为:kermit

六、activiti的api

6.1 查询流程部署列表 ==> act_re_deployment

public void queryProcessDeployment() {
        List<Deployment> list = processEngine.getRepositoryService()
                        .createDeploymentQuery()//部署查询对象,查询act_re_deployment 部署表
                        .list();
        for (Deployment dp : list) {
            System.out.println("部署id:"+dp.getId());
            System.out.println("部署名:"+dp.getName());
            System.out.println("部署时间:"+dp.getDeploymentTime());
            System.out.println("-------------------------------------------------------");
        }
    }

6.2 删除部署信息

public void deleteProcessDeployment() {
        String deploymentId = "2501";
        //deleteDeployment有两个参数 第一个删除 部署的内容的id,第二个是否级联删除,默认为false
        //通过删除部署信息也可以达到删除流程定义的目的
        processEngine.getRepositoryService().deleteDeployment(deploymentId,true);
    }

6.3 查询正在执行的流程 act_ru_execution

public void queryRunTimeProcess() {
        String processDefinitionKey = "helloworld";
        List<ProcessInstance> list = processEngine.getRuntimeService()
                        .createProcessInstanceQuery()//流程实例查询对象,查询act_ru_execution表
                        .processDefinitionKey(processDefinitionKey)
                        .list();
        for (ProcessInstance pi : list) {
            System.out.println(pi.getId() + "--" + pi.getActivityId());
            System.out.println("-------------------------------------------------------");
        }
    }

6.4 删除运行时的流程 act_re_excution,act_ru_task

public void deleteRunTimeProcess() {
        String processInstanceId = "12501";
        processEngine.getRuntimeService()
                        .deleteProcessInstance(processInstanceId, "想删,任性");
    }

6.5 查询最新版本的流程定义列表


public void queryLatestVersionProcessDefination() {
        List<ProcessDefinition> list = processEngine.getRepositoryService()
                        .createProcessDefinitionQuery()
                        .orderByProcessDefinitionVersion().asc()//按版本升序排列
                        .list();
         Map<String, ProcessDefinition> map = new HashMap<>();
        //根据map的key特性,当key相同时,后者覆盖前者,达到取得最新版本效果
         for (ProcessDefinition pd : list) {
             map.put(pd.getKey(),pd);
         }
         System.out.println(map);
    }

6.6 流程的修改

流程的修改:添加新的流程版本,如果已经在执行的流程,按照原来的流程继续执行。新的流程按照最新版本进行执行。

6.7 历史数据查询 ==> act_hi_procinst

public void queryHistoricProcessInstance() {
        List<HistoricProcessInstance> list = processEngine.getHistoryService()
                        .createHistoricProcessInstanceQuery()
                        .list();
        for (HistoricProcessInstance hi : list) {
            System.out.println("历史记录id:"+hi.getId());
            System.out.println("部署id:"+hi.getDeploymentId());
            System.out.println("记录名:"+hi.getName());
            System.out.println("-------------------------------------------------------------");
        }
    }

6.8 历史活动数据查询 ==> act_hi_actinst


public void queryHistoricActivityInstance() {
        List<HistoricActivityInstance> list = processEngine.getHistoryService()
                        .createHistoricActivityInstanceQuery()
                        .list();
        for (HistoricActivityInstance hi : list) {
            System.out.println("历史活动id:"+hi.getActivityId());
            System.out.println("活动id:"+hi.getActivityName());
            System.out.println("活动类型:"+hi.getActivityType());
            System.out.println("-------------------------------------------------------------");
        }
        
    }

6.9 历史任务数据查询 ==> act_hi_taskinst

public void queryHistoricTaskInstance() {
        List<HistoricTaskInstance> list = processEngine.getHistoryService()
                        .createHistoricTaskInstanceQuery()
                        .list();
        for (HistoricTaskInstance hi:list){
            System.out.println("代理人:"+hi.getAssignee());
            System.out.println("名称:"+hi.getName());
            System.out.println("开始时间:"+hi.getStartTime());
            System.out.println("-------------------------------------------------------------");
        }
    }

七、任务类型

7.1 个人任务

由某一个负责办理,在任务表中通过assignee字段记录。

7.2 公共任务(组任务)

当前的任务可以由多个人其中的某一个人办理, 可以在设计流程图时指定多个办理人。Candidate Users 候选用户

image

7.2.1 查询公共任务


public void test() {
//    根据候选人过滤
        String candidateUser = "测试1";
        List<Task> list = processEngine.getTaskService().createTaskQuery()
                        .taskCandidateUser(candidateUser)
                        .list();
        for (Task task:list){
            System.out.println("任务名:"+task.getName());
            System.out.println("任务id:"+task.getId());
        }
    }

7.2.2 将公共任务变为个人任务(拾取公共任务)

public void changePublicTask2Personal(){
        String taskId="1602";
        String userId="测试2";
        processEngine.getTaskService().claim(taskId,userId);
    }

7.2.3 将个人任务重新变为公共任务(退回任务)

public void rollbackPersonalTask2Public(){
        String taskId="1602";
        processEngine.getTaskService().setAssignee(taskId,null);
    }

7.2.4 流程处理

接收任务不是由某个人负责办理,通过signal方法让流程执行的

public void signalGroupTask() {
        String excutionId = "2501";
        processEngine.getRuntimeService().signal(excutionId);
    }

八、网关

此处引用到流程中的变量使用:

8.1 变量设置

8.1.1 变量设值

  • 1.启动流程时设置
    processEngine.getRuntimeService().startProcessInstanceByKey(processDefinitionKey, variables)
    其中variables是map对象,存放要设置的变量,key为变量名,value是值

  • 2.办理任务时设置
    getTaskService().complete(taskId, variables)
    variables 同1

  • 3.使用RuntimeService的方法设置
    getRuntimeService().setVariable(excutionId, variableName, value)
    excutionId 流程实例id variableName 变量名 value 变量的值

  • 4.使用TaskService的方法设置
    getTaskService().setVariables(taskId, variables)
    variables 同1

8.1.2 变量取值

  • 1.使用RuntimeService的方法获取
    getRuntimeService().getVariable(executionId, "变量名") -> 返回的是Object对象

  • 2.使用TaskService的方法获取

    getTaskService().getVariables(taskId) 获取所有的变量,返回的是map集合

8.2 排他网关(ExclusiveGateway)

用来在流程中实现决策。当流程执行到排他网关,所有数据就会被执行一遍,满足条件的就会让流程继续运行。需要注意的是:排他网关只会选择一条满足条件的执行。

  • 第一步:设计流程图,使用排他网关

  • 第二步:执行流程,由框架根据设置的流程变量选择执行其中的一个分支,在分支的线上设置参数 如:Condition:#{age>18}

  • 第三步:办理业务

public void dealExclusiveGatewayTask() {
        String taskId = "802";
        Map<String, Object> variables = new HashMap<>();
        variables.put("age",18);//排他网关会自动判断 age变量的值,选择执行分支
        processEngine.getTaskService().complete(taskId,variables);
    }

8.3 并行网关(ParallelGateway)

它允许将流程分成多条分支,也可以把多条分支汇聚成一条。

分支:经过并行网关的所有流,都会并行执行

汇聚:等所有流都到达并行网关之后,流程才会通过并行网关。

并行网关,没有条件判断。流程通过网关之后,有几条分支,就会有几个执行对象同时执行。需要注意的是:并行网关一定是成对出现的,有分支也有汇聚。

这就是简单的activiti入门博客编写参考=====》//www.greatytc.com/p/33085a975e47《=====如有不明白请跳转

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 229,327评论 6 537
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 98,996评论 3 423
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 177,316评论 0 382
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,406评论 1 316
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,128评论 6 410
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,524评论 1 324
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,576评论 3 444
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,759评论 0 289
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,310评论 1 335
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,065评论 3 356
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,249评论 1 371
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,821评论 5 362
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,479评论 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,909评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,140评论 1 290
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,984评论 3 395
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,228评论 2 375