activiti7快速入门经验分享

什么是工作流以及工作流有什么用

先来贴张图:

(该图来自百度百科,如有侵权,望及时告知)
是不是很抽象,不是很好理解?用简单的话说一下就是按照一定的规则绘制流程图,将这个流程图交给特定的引擎,由这个引擎来帮助我们推进流程的进行,而在这里我们这个引擎便是activiti。
此时你可能还没有理解工作流有什么用,因为第一时间想到的流程可能是请假或报销流程,并没有那么复杂,我们直接看张图,体会一下:
在这里插入图片描述
(上图来自百度百科,如有侵权,望及时告知)
现在你们可以想想要如何实现这个业务流程。如果用常规的方法来实现的话,可能会有许多if和同种不同类的sql,在完成一个任务之前还得及时监控之前要完成的任务是否都已完成,流程控制的代码会隐式地存在于业务代码中,当有一个地方要修改,可能会连带起很多地方都要修改。而工作流的引用,在一定程度上可以将流程的推进和业务逻辑解耦,你在绘制流程图的时候设定你的流程和部分跳转条件,然后将其交给activiti管理,之后只需在代码中及时推进流程的进行就可以了。

如何画流程图

在画流程图之前,首先要安装插件,idea是actiBPM,eclipse我不知道,安装的方法可以到网上去找,这里就不说了。
接下来新建一个bpmn文件demo2.bpmn,我们来大体看一下结构:
在这里插入图片描述
我们首先来了解一下,一个.bpmn文件到底意味着什么。一个.bpmn文件在某种意义上可以看成一个流程定义(ProcessDefinition),而activiti对流程的控制完全是按照这个来走的。后面会有具体说明,这里先继续介绍怎么画流程图。

开始与结束事件

开始事件:
在这里插入图片描述
结束事件:
在这里插入图片描述

任务

UserTask:这个任务是交给用户完成的,需要在业务逻辑代码中手动推进任务进行
在这里插入图片描述
设置用户与用户组:
注意idea的actiBPM最后一次更新是在14年,所以现在的idea可能不是很支持这个插件,可能出现各种各样的问题,比如修改了用户组,但没有保存也不会显示,这里没关系,只要保证.xml文件没有问题就可以了,所以下面用户组的设置我会从xml这向大家展示,首先将后缀名改为.xml,然后找到相应的userTask,添加如图的内容就行了:
在这里插入图片描述
ServiceTask:交给系统自动执行的任务,不需要我们手动推进
在这里插入图片描述
指定的类:
在这里插入图片描述
剩下的任务类型在这里就不讲了,需要的话可以百度一下

网关

首先我们要知道两个任务之间的连线上是可以设定条件的:
在这里插入图片描述
哪个条件满足了就往哪走,但是在不使用网关的情况下,要是满足了多个条件会怎么样你们可以自己试试,我印象中会报错,这个时候就要用网关了。
这里主要介绍三个网关,最后的事件网关用得少,就没必要讲了:
1、 互斥网关(ExclusiveGateway):
在这里插入图片描述
互斥网关的分支只能找一个符合条件的走,要是有多个分支符合条件,找id小的走。(但既然用了互斥网关,应该就会保证条件没有重合的部分了)

2、 并行网关(ParallelGateway):
在这里插入图片描述
简单来说就是到这会分叉,当这并行的多个任务都完成后才会继续推进。但要注意,并行网关不会识别条件,只要是并行网关的分支,都会执行。

3、 包容网关(InclusiveGateway):
在这里插入图片描述
可以看做是并行网关和互斥网关的结合体,满足条件的就走,当所有满足条件的任务都完成后,流程才会继续推进。

这里只是简单介绍一下,想要深入了解可以百度一下。

引入maven依赖以及设置配置文件

maven:

<dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-engine</artifactId>
            <version>7.0.0.Beta2</version>
</dependency>

创建activiti.cfg.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
						http://www.springframework.org/schema/contex http://www.springframework.org/schema/context/spring-context.xsd
						http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
        <property name="url" value="你的url" />
        <property name="username" value="你的用户名" />
        <property name="password" value="你的密码" />
    </bean>

    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <property name="dataSource" ref="dataSource"></property>
        <property name="databaseSchemaUpdate" value="true"/>
    </bean>

</beans>

运行下面的代码,也就是获取activiti的引擎后,activiti会自动帮我们创建25张表,而这25张表是activiti帮我们管理流程的基础:

    @Test
    public void test1() {
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration
                .createProcessEngineConfigurationFromResource("activiti.cfg.xml");

        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();

    }

这里简单介绍下比较重要的几张表:
在这里插入图片描述
这里不详细介绍了,要是想具体了解可以自行百度。
但要注意的是,不同版本的activiti创建表的数量和意义也不是完全相同的,就像activiti6是创建28张表,因为activiti6比7多了identityService,而springboot对activiti7的starter去除了用户表,强耦合了spring security,所以少了几张用户表。(当然别的表也不完全相同)

流程的部署、查询和推进

流程的部署

首先,我们可以通过JBoss jBPM来通过.xml文件导出个.png文件,在部署.bpmn文件的时候可以顺便也部署上.png文件,之后可以导出.png文件来看看流程图是什么样的,当然,这个.png文件不是必须的。
先将.bpmn文件后缀改为.xml,然后选中右键:
在这里插入图片描述
在这里插入图片描述
然后就可以导出png文件到指定文件夹了

首先我们来了解下activiti提供的几个接口:
RepositoryService -> 操作流程定义、部署流程定义
RuntimeService -> 开启流程,操作流程实例
TaskService -> 操作任务
HistoryService -> 操作历史记录
当然是不止这几个的,但是知道这几个入门还是够的。

言归正传,回到部署:

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 直接部署
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("processes/xxx.bpmn")
                .addClasspathResource("processes/xxx.png")
                .deploy();

这个ProcessEngines.getDefaultProcessEngine(),是当你按照一定的命名规则编写配置文件的时候,会默认加载该文件。默认格式比着上面的activiti.cfg.xml写就行,文件名和beanId不要变就行。

文件放在:
在这里插入图片描述
processes中,当然,也可以自己找存放的路径

也可以通过zip文件部署:

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // zip压缩文件部署
        InputStream is = ActivitiDeployment.class.getClassLoader().getResourceAsStream("processes/xxx.zip");
        ZipInputStream zipInputStream = new ZipInputStream(is);
        Deployment deployment = repositoryService.createDeployment()
                .addZipInputStream(zipInputStream)
                .deploy();

然后看数据库中的三张表:
1.act_ge_bytearray
在这里插入图片描述
2.act_re_procdef (存放流程定义(ProcessDefinition))
在这里插入图片描述
3.act_re_deployment
在这里插入图片描述
这里讲的比较细,在之后对数据库的讲解会少一些。
到此,流程的部署就完成了。

开始一个流程实例

首先来看几个关键词:
ProcessDefinition是流程定义,可以看做为java中的类,是流程的抽象;
每开始一个流程,都会通过流程定义来创建一个流程实例(ProcessInstance),可以看成对象。
一个流程定义对应一个key和一个id,可以通过他们来开启一个流程实例,而key就是我们画图时设置的id(这里有点混乱),而id是部署之后才有的。

先来看看我用来展示的流程图:
在这里插入图片描述

现在我们来开启一个流程实例:

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        Map<String,Object> map = new HashMap<>();
        map.put("amount",60F);
        map.put("memberStart","xxx");
        // 这个key是画流程图时设置的id
        ProcessInstance processInstance = runtimeService
                .startProcessInstanceByKey("tradeDemo","businessKey",map)
                //.startProcessInstanceById("tradeDemo:1:2503","businessKey",map)
                ;

在这里我们看到,可以通过key和id来开启一个流程实例。在这里有必要讲一下这里的businessKey和map。
首先我们得了解,数据库的25张表仅仅是管理流程进行的,而我们的数据还是得存在我们自己的表中的。我们通常可以通过两种方式关联,一是将我们的数据作为流程变量存到这25张表中,也就是参数中的map,k-v就是对应一个个的流程变量,但不推荐这么做,流程变量最好只放推动流程必须的变量,比如线上的条件,还记得之前设定的el表达式吗(在画流程图时设定的用户、线上的条件之类的),${xxx}对应的数据就是我们添加的k-v键值对中的数据,k对应的表达式中的xxx。另一个方法就是通过businessKey,我们可以把我们某条数据的id绑定到一个流程实例上(ProcessInstance),简单来说就是个外键。
当然,流程变量也分全局和局部的,全局的流程变量的作用域是一个流程实例,而局部的流程变量的作用域是一个任务(task)。这里的map设置的是全局的。之后会说怎么设置局部的流程变量,虽然这个用的不多。

开启一个流程实例后,我们来看看数据库的几张表:
1、act_ru_task
在这里插入图片描述
现在就出现了第一个任务,看到NAME_是HouseBuyerApply,也就是流程图开始事件后的第一个用户任务。
2、act_ru_variable
在这里插入图片描述
这张表存了我们的流程变量,但注意,序列化的数据会被放在act_ge_bytearray中:
在这里插入图片描述
部分类型的数据和对象会被序列化后存入到这张表中。要注意,要想把一个对象存入流程变量,需将其序列化,所以对应的类要实现序列化的接口。
3、act_ru_execution
在这里插入图片描述
这个execution和流程实例的关系大家可以去百度一下,这里就不详细解释了。
其他的表其实也会有变化,但这里也不详细一一解释了,可以在测试的时候看看具体是有哪些表发生了变化,看一下表名和字段名也能大概了解是怎么回事。

各种查询

首先是查询流程定义:

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        List<ProcessDefinition> definitions = repositoryService
                .createProcessDefinitionQuery()
                .processDefinitionKeys(new HashSet<>())
                .processDefinitionIds(new HashSet<>())
                .list();

查询流程实例:

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        List<ProcessInstance> instances = runtimeService
                .createProcessInstanceQuery()
                .processInstanceBusinessKey("businessKey")
                .processInstanceId("")
                .processDefinitionKey("")
                .list();

查询任务:

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        List<Task> tasks = taskService.createTaskQuery()
                .processDefinitionKey("tradeDemo")
                .taskAssignee("xxx")
                .taskCandidateGroup("manager")
                .list();

查询历史信息:

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        HistoryService historyService = processEngine.getHistoryService();
        List<HistoricTaskInstance> instances = historyService.createHistoricTaskInstanceQuery()
                .processDefinitionKey("")
                .processDefinitionId("")
                .list();

到此就不再多举例了,大家应该也看出规律了,都是采用的调用链的方式设置条件查询,实际上可用的条件非常多,大家可以自己看一下。甚至可以通过businessKey来查询一个流程实例。
而返回的数据的属性我也就不展示了,大家可以自己看看,也是非常多的。
历史查询也不是只能查任务,还可以查很多别的不同的数据。

完成任务

直接上代码:

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        //完成任务
        taskService.complete("taskId");
        //在任务执行过程中添加全局流程变量
        taskService.setVariables("taskId",new HashMap<>());
        //在任务执行过程中添加局部流程变量
        taskService.setVariablesLocal("taskId",new HashMap<>());
        //绑定执行人
        taskService.claim("taskId","用户的id或姓名");

要注意,activiti这几个service不会在完成任务时判断权限,你只要用了complete,不管你现在操作的用户是谁,这个任务都会被完成,所以要是想管理权限,要自己再封装一层,比如在执行某任务前,先判断当前用户是不是该任务绑定的执行人,如果不是,就不让执行。
不用管上面taskService调用方法的顺序,只是展示一下taskService除了完成任务还能干些什么(比如绑定执行人、设定流程变量等),完成任务肯定不是按照上面的顺序来的。

到此,基本的操作就结束了

Spring Boot整合

整合的时候你的springboot的版本要和activiti版本相对应,不然可能会出一些奇怪的问题。具体是怎么对应的这里我就不说了。
不过如果你要整合activiti7的springboot starter包,要注意这个包是耦合了Spring Security的,如果你没有配置Spring Security,在没登录的情况下会调用不了接口。

但这个starter也提供了几个runtime接口,耦合了security,简化了操作,这里我就不解释怎么使用了,都是大同小异的。

注意!!!
所以如果你不想整合security,那就可以不用starter,直接用引擎,我暂时就是这样使用的,也就是我上面给出的坐标那种类型的。要是用了starter,可以在.yml文件中配置activiti的一些属性,但没用starter的话就不行,得自己引入bean配置。但注意,在springboot项目中不使用starter而直接使用activiti引擎的包,可能会出什么问题也说不定,我这里只是提供一种绕过security的思路,具体在之后会遇到什么问题我是不敢保证的,要是你们要整合到实际的项目,还想使用这种方法来绕过security的话,一定要做充分的测试来预防出现别的问题。要是出现什么问题,可能是不好解决甚至是不能解决的,所以使用这个方法要慎重,真正出了问题这里是不负责的。

具体是怎么整合的我这就不说了,大家可以去别的地方找一下,这里就贴个配置类吧:

@Configuration
public class ActivitiConfig {
    @Autowired
    private DataSource dataSource;

    @Bean
    public StandaloneProcessEngineConfiguration processEngineConfiguration(){
        StandaloneProcessEngineConfiguration configuration = new StandaloneProcessEngineConfiguration();
        configuration.setDataSource(dataSource);
        configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
        configuration.setAsyncExecutorActivate(false);
        return configuration;
    }

    @Bean
    public ProcessEngine processEngine(){
        return processEngineConfiguration().buildProcessEngine();
    }

    @Bean
    public RepositoryService repositoryService(ProcessEngine processEngine){
        return processEngine.getRepositoryService();
    }

    @Bean
    public RuntimeService runtimeService(ProcessEngine processEngine){
        return processEngine.getRuntimeService();
    }

    @Bean
    public TaskService taskService(ProcessEngine processEngine){
        return processEngine.getTaskService();
    }
}

总结

**到这里就结束了,这里说的只是比较简单的问题,只看这个肯定是不够的,我写这篇博客的目的本来就是复习一下,然后分享下经验,给大家提供一点思路,这篇博客可以当一个学习目录用,你们可以自行百度来加深深度和纠正错误。因为我学习activiti也没几天,不敢保证所有的内容都是完全正确的,部分理解也可能不正确,部分解释也可能不合理,这里就靠你们自己在广泛搜索的过程中纠正了,而我之前在图片中说什么什么不重要并不是说真的不重要,只是说我觉得在初步学习的时候不是那么用得到。所以这里只推荐用作学习目录和大体了解,要是想深入学习,还是得找别的资料。要是有什么错误,可以评论一下,我再修改,谢谢观看。

我也封装了个工具类,这里贴几张截图,要是想要的话可以去空间找。这个工具类是模仿activiti7新的功能runtime来写的,这里也提供了个思路,要是想学习activiti7,也可以从他的源码中来学习。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
东西太多了,就随便截几张到这吧,拜拜
**

码云:
activiti7 demo

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值