Activiti工作流引擎使用详解(一)

LD is tigger forever,CG are not brothers forever, throw the pot and shine forever.
Modesty is not false, solid is not naive, treacherous but not deceitful, stay with good people, and stay away from poor people.
talk is cheap, show others the code and KPI, Keep progress,make a better result.
Survive during the day and develop at night。

目录

概 述

一.安装:
在插件库中查找actiBPM,安装该插件,如果找不到该插件,请到插件库中下载该包手动安装,插件地址

http://plugins.jetbrains.com/plugin/7429-actibpm 安装后重启IDEA

配置文件

第三步:基础环境搭建

2.1 actiBPM插件使用示例
将需要用到的activiti包引入到工程中

org.activiti activiti-engine 5.17.0

右键new,点击BpmnFeil,然后取个名:
鼠标左键拖拽StartEvent到界面上,同样再弄几个其他图标。
鼠标放到图标中心会变成黑白扇形,拖拽连线到另一个图标进行画图:
生成png文件
点击箭头指的图标,选择生成位置即可

2.2 初始化activiti表结构

public class TestActiviti {
    /**
     * 使用代码创建工作流使用的23张表
     */
    @Test
    public void createTable(){
        //创建引擎配置类
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
        configuration.setJdbcDriver("com.mysql.jdbc.Driver");
        configuration.setJdbcUrl("jdbc:mysql://192.168.27.14:3306/activiti");
        configuration.setJdbcUsername("root");
        configuration.setJdbcPassword("root");

        //不自动创建表,需要表存在 DB_SCHEMA_UPDATE_FALSE = "false";
        //先删除表,再创建表 DB_SCHEMA_UPDATE_CREATE_DROP = "create-drop";
        //如果表不存在,先创建表 DB_SCHEMA_UPDATE_TRUE = "true";
        configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
        //创建工作流核心对象
        ProcessEngine processEngine = configuration.buildProcessEngine();
        System.out.println(processEngine);
    }
}

2.2.2 配置文件方式

通过配置文件方式配置数据库等,resourses目录下添加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">

    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <!-- 连接数据的配置 -->
        <property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://192.168.27.14:3306/activiti?characterEncoding=utf8"/>
        <property name="jdbcUsername" value="root"/>
        <property name="jdbcPassword" value="root"/>
        <!--  不自动创建表,需要表存在 "false";
              先删除表,再创建表  "create-drop";
              如果表不存在,先创建表"true";
        -->
        <property name="databaseSchemaUpdate" value="true"/>
    </bean>
</beans>
@Test
public void createTable2(){
    ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml")
            .buildProcessEngine();
}

2.2.3 那么,能不能再给力一点?前面看到了两种创建ProcessEngine(流程引擎)的方式,而这里要简化很多,调用ProcessEngines的getDefaultProceeEngine方法时会自动加载classpath下名为activiti.cfg.xml文件。

三、activiti核心api讲解:
3.1ProcessEngine
在Activiti中最核心的类,其他的类都是由他而来,由工作流引擎可以创建各个Service,这些Service是调用工作流23张表的服务:

@Test
public void getService(){
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

    //管理流程定义
    RepositoryService repositoryService = processEngine.getRepositoryService();
    //执行管理,包括启动、推进、删除流程实例等
    RuntimeService runtimeService = processEngine.getRuntimeService();
    //任务管理
    TaskService taskService = processEngine.getTaskService();
    //历史管理(执行完的数据的管理
    HistoryService historyService = processEngine.getHistoryService();
    //组织机构管理
    IdentityService identityService = processEngine.getIdentityService();
    //可选服务,任务表单管理
    FormService formService = processEngine.getFormService();
    
    ManagementService managementService = processEngine.getManagementService();
}

3.2 RepositoryService
是Activiti的仓库服务类。所谓的仓库指流程定义文档的两个文件:bpmn文件和流程图片。

@Test
public void testRespositoryService(){
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    RepositoryService repositoryService = processEngine.getRepositoryService();
    //可产生DeploymentBuilder用来定义流程部署的相关参数
    DeploymentBuilder deployment = repositoryService.createDeployment();
    //删除流程定义
    repositoryService.deleteDeployment("deploymentId");
}

3.3 RuntimeService
是activiti的流程执行服务类。可以从这个服务类中获取很多关于流程执行相关的信息。
3.4 TaskService
是activiti的任务服务类。可以从这个类中获取任务的信息。
3.5 HistoryService
是activiti的查询历史信息的类。在一个流程执行完成后,这个对象为我们提供查询历史信息。

3.6 流程定义类。可以从这里获得资源文件等。
3.7 ProcessInstance
代表流程定义的执行实例。如小明请了一天的假,就必须发出一个流程实例的申请。一个流程实例包括了所有的运行节点。我们可以利用这个对象来了解当前流程实例的进度等信息。流程实例就表示一个流程从开始到结束的最大的流程分支,即一个流程中流程实例只有一个。
3.8 Execution
Activiti用这个对象去描述流程执行的每一个节点。在没有并发的情况下,Execution就是同ProcessInstance。流程按照流程定义的规则执行一次的过程,就可以表示执行对象Execution。

四。一个简单的HelloWorld程序事例在这里插入图片描述

在这里插入图片描述

4.2 部署流程定义

@Test
public void deploymentProcessDefinition(){

    //获取流程定义与部署相关Service
    Deployment deployment = processEngine.getRepositoryService()
            .createDeployment()     //创建一个部署对象
            .name("helloworld入门程序")
            .addClasspathResource("diagrams/helloworld.bpmn")//加载资源文件
            .deploy();//完成部署
    System.out.println(deployment.getId());
    System.out.println(deployment.getName());
}

4.3 启动流程实例
ProcessInstance processInstance = processEngine.getRuntimeService()
//使用流程定义的key启动实例,key对应bpmn文件中id的属性值,默认按照最新版本流程启动
.startProcessInstanceByKey(“helloworld”);

System.out.println(processInstance.getId());
System.out.println(processInstance.getProcessDefinitionId());
4.4 查看我的个人任务

@Test
public void findPersonalTask(){
    //与正在执行的任务相关的Service
    List<Task> list = processEngine.getTaskService()
            .createTaskQuery()  //创建查询任务对象
            .taskAssignee("王五")     //指定个人任务查询,指定办理人
            .list();
    if(list != null && list.size() > 0){
        for(Task task : list){
            System.out.println(task.getId());
            System.out.println(task.getName());
            System.out.println(task.getCreateTime());
            System.out.println(task.getAssignee());
            System.out.println(task.getProcessInstanceId());
            System.out.println(task.getExecutionId());
            System.out.println(task.getProcessDefinitionId());
        }
    }
}

4.5 完成我的个人任务

/**
 * 完成我的任务
 */
@Test
public void completePersonalTask(){
    processEngine.getTaskService()
            .complete("7502");
}

5.1 部署流程定义
通过classpath部署流程定义

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

通过zip文件部署流程定义

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

这一步在数据库中将操作三张表:
a) act_re_deployment(部署对象表)
存放流程定义的显示名和部署时间,每部署一次增加一条记录
b) act_re_procdef(流程定义表)
存放流程定义的属性信息,部署每个新的流程定义都会在这张表中增加一条记录。
注意:当流程定义的key相同的情况下,使用的是版本升级

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

5.2 查看流程定义:
@Test
public void findProcessDefinition(){
List list = processEngine.getRepositoryService()//与流程定义和部署对象相关的Service。 .createProcessDefinitionQuery()//创建一个流程定义的查询
.orderByProcessDefinitionVersion().asc()//按照版本的升序排列
.list();//返回一个集合列表,封装流程定义
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());
System.out.println("#########################################################");
}
}

总结:

可以看到流程定义的key值相同的情况下,版本是从1开始逐次升级的,流程定义的Id是【key:版本:生成ID】。由运行结果可以看出:Key和Name的值为:bpmn文件process节点的id和name的属性值。key属性被用来区别不同的流程定义。带有特定key的流程定义第一次部署时,version为1。
之后每次部署都会在当前最高版本号上加1,Id的值的生成规则为:{processDefinitionKey}:{processDefinitionVersion}:{generated-id},
这里的generated-id是一个自动生成的唯一的数字,重复部署一次,deploymentId的值以一定的形式变化,规则act_ge_property表生成。这里的generated-id是一个自动生成的唯一的数字,重复部署一次,deploymentId的值以一定的形式变化,规则act_ge_property表生成。

5.3 删除流程定义

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

    /**
     * 级联删除
     *       不管流程是否启动,都能可以删除
     */
    processEngine.getRepositoryService()//
            .deleteDeployment(deploymentId, true);
    System.out.println("删除成功!");
}

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

/**查看流程图
 * @throws IOException */
@Test
public void viewPic() throws IOException {
    /**将生成图片放到文件夹下*/
    String deploymentId = "801";
    //获取图片资源名称
    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);
    //将输入流的图片写到D盘下
    FileUtils.copyInputStreamToFile(in, file);
}

deploymentId为流程部署ID,resourceName为act_ge_bytearray表中NAME_列的值,使用repositoryService的getDeploymentResourceNames方法可以获取指定部署下得所有文件的名称,使用repositoryService的getResourceAsStream方法传入部署ID和资源图片名称可以获取部署下指定名称文件的输入流,最后的有关IO流的操作,使用FileUtils工具的copyInputStreamToFile方法完成流程流程到文件的拷贝,将资源文件以流的形式输出到指定文件夹下。deploymentId为流程部署ID,resourceName为act_ge_bytearray表中NAME_列的值,使用repositoryService的getDeploymentResourceNames方法可以获取指定部署下得所有文件的名称,使用repositoryService的getResourceAsStream方法传入部署ID和资源图片名称可以获取部署下指定名称文件的输入流,最后的有关IO流的操作,使用FileUtils工具的copyInputStreamToFile方法完成流程流程到文件的拷贝,将资源文件以流的形式输出到指定文件夹下。

5.5 查询最新版本的流程定义

@Test
public void findLastVersionProcessDefinition(){
    List<ProcessDefinition> list = processEngine.getRepositoryService()//
            .createProcessDefinitionQuery()//
            .orderByProcessDefinitionVersion().asc()//使用流程定义的版本升序排列
            .list();
    /**
     * Map<String,ProcessDefinition>
     map集合的key:流程定义的key
     map集合的value:流程定义的对象
     map集合的特点:当map集合key值相同的情况下,后一次的值将替换前一次的值
     */
    Map<String, ProcessDefinition> map = new LinkedHashMap<String, ProcessDefinition>();
    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());
            System.out.println("#########################################################");
        }
    }
}

删除流程定义

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

5.6 删除流程定义

@Test
public void deleteProcessDefinitionByKey(){
    //流程定义的key
    String processDefinitionKey = "helloworld";
    //先使用流程定义的key查询流程定义,查询出所有的版本
    List<ProcessDefinition> list = processEngine.getRepositoryService()//
            .createProcessDefinitionQuery()//
            .processDefinitionKey(processDefinitionKey)//使用流程定义的key查询
            .list();
    //遍历,获取每个流程定义的部署ID
    if(list!=null && list.size()>0){
        for(ProcessDefinition pd:list){
            //获取部署ID
            String deploymentId = pd.getDeploymentId();
            processEngine.getRepositoryService()//
                    .deleteDeployment(deploymentId, true);
        }
    }
}

六:流程实例、任务的执行
涉及到的表:
select * from act_ru_execution --正在执行的执行对象表
select * from act_hi_procinst --流程事例的历史表
select * from act_ru_task:–正在执行的任务表
select * fro act_hi_taskinst:任务历史表
select * from act_hi_actinst : 活动节点的历史表

@Test
    public void startProcessInstance(){
        //获取与正在执行的流程示例和执行对象相关的Service
        ProcessInstance processInstance = processEngine.getRuntimeService()
                //使用流程定义的key启动实例,key对应bpmn文件中id的属性值,默认按照最新版本流程启动
                .startProcessInstanceByKey("helloworld");
        System.out.println(processInstance.getId());
        System.out.println(processInstance.getProcessDefinitionId());
    }

6.2 查询我的个人任务:

 @Test
    public void findMyPersonalTask(){
        String assignee = "张三";
        List<Task> list = processEngine.getTaskService()//与正在执行的任务管理相关的Service
                .createTaskQuery()//创建任务查询对象
                /**查询条件(where部分)*/
                .taskAssignee(assignee)//指定个人任务查询,指定办理人
//                        .taskCandidateUser(candidateUser)//组任务的办理人查询
//                        .processDefinitionId(processDefinitionId)//使用流程定义ID查询
//                        .processInstanceId(processInstanceId)//使用流程实例ID查询
//                        .executionId(executionId)//使用执行对象ID查询
                /**排序*/
                .orderByTaskCreateTime().asc()//使用创建时间的升序排列
                /**返回结果集*/
//                        .singleResult()//返回惟一结果集
//                        .count()//返回结果集的数量
//                        .listPage(firstResult, maxResults);//分页查询
                .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());
                System.out.println("########################################################");
            }
        }
    }

相关工具如下:

分析:

小结:

springboot 整合 Activiti工作流引擎使用详解工作流 学习,请大家指正~

参考资料和推荐阅读

1.链接: 参考资料.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

执于代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值