上一讲我们画了一个简单的请假的业务流程图,这一讲我们把它部署到activiti7中,并将它执行完毕。先简单介绍下Activiti7工作流引擎。

一、Activiti7简介

1、Activiti7是什么?

Activiti7只是对BPMN2.0规范实现的一个java框架而已,他是一个工作流程控制和管理框架,就是来处理系统中的业务流程的,对整个业务系统起到辅助和支持作用。一般有两种存在方式,一种是和业务代码耦合在一块,另一种是依靠activiti7做成单独的微服务,实现功能的复用,成为真正的工作流“引擎”。

之所以将他称之为工作流引擎,我想有两个原因,第一activiti7是用来处理业务流程的,这些业务流程统称为工作流;第二,引擎的原因是他对代码对了高度封装,完全屏蔽掉了底层,暴露出很简单的操作API,只需要简单操作(实则底层做了大量工作)就能完成复杂的业务流程处理,就像发动机引擎一样,内部实现很复杂,但是用户使用起来确很简单,所以称之为引擎。

2、为什么要用它?或者说他解决了什么问题?

1)工作流引擎本身的目的就是为了辅助业务系统,处理复杂的业务流程,实现流程自动化处理,减轻开发人员的负担,提高企业运作效率,为企业赋能。对于开发人员来说,无论多么复杂的业务流程,只要是用BPMN2.0规范画的业务流程图,用activiti7都可以轻松应对,甚至有时当业务流程发生改变后,都不需要改原来的代码。这一切都源于BPMN2.0规范和acitivit7代码的高度封装屏蔽了底层的实现。

2)什么场景下适合使用工作流引擎?

  • 如果要做的是事需要多个节点参与,即需要走一个流程的时候,可以使用工作流引擎,因为他就是专门对流程进行处理、控制和管理的。
  • 如果业务流程可能会发生改变,要用工作流引擎,可以做到基本不用修改原来的代码。就从这一点来说,开发人员都要选择使用它。
  • 如果业务流程很复杂,要用工作流引擎,可以化繁为简,使代码变得简单。

3、要学习他的什么?

愚以为学习activiti7要重点关注以下几点,就算是基本完成activiti7的学习了:

1)熟悉 BPMN2.0规范并会画图。

2)熟悉activiti7的工作流程。

3)熟悉activiti7的API。

4)熟悉activiti7生成的数据表及其字段的含义。

5)熟悉activiti7的基本操作流程。

①、画业务流程图——对业务流程进行建模

②、部署流程图给activiti(解析xml,并保存到数据库中)

③、启动流程

④、查询待办任务

⑤、办理任务(④、⑤可能会循环好几遍)

⑥、流程结束

4、activiti7和activiti6的区别:

大部分的功能都是一样的,不同点是:activiti6是28张数据表,activiti7是25张,少了用户和组的三张表。相应的服务接口也少了俩:IdentityService和FormService。另外activiti7中对activiti6的API再次进行了封装,使得用户操作代码更简洁了,并新增加了分布式和云部署的功能,核心没变。

5、支持的数据库:

默认内置的内存数据库h2,mysql,oracle,postGreSql,db2

6、操作api架构图

前面也说了,activiti7和activiti6相比核心没变。一个默认在类路径下的配置文件activiti.cfg.xml,和配置文件对应的配置类ProcessEngineConfiguration,配置文件用于将配置类的属性信息在外部配置,配置类用于将配置文件的内容封装成java代码。一个核心流程引擎对象ProcessEngine,根据配置类的信息来创建和初始化。由ProcessEngine对象的getXXXService方法获取各种操作service对象,结构很清晰。

7、整体架构图

中间有一个命令拦截器CommandInterceptor,用于对上层的操作拦截并转化为底层可识别的命令,作用有点类似于业务网关,或者语言解释器。

8、用activiti开发工作流的一个基本开发模式

功能复用:对于像查询待办任务、已办任务、抄送我的、我发起的流程、流程部署、流程挂起与激活、生成流程图等这样的可以复用的功能,使用一套代码即可,提供统一的接口或service。

功能不复用:但是对于启动流程、完成任务这样的功能,因为每个流程的参数或流程变量不一样,并且任务完成之后做的回调事情也不一样,如果不能复用,则每一个流程都单独开发这样的功能。

目前采用的方式是:对于启动流程、完成任务抽象出一个interface,让不同的流程service实现各自不同的操作;创建一个简单工厂,根据流程类型实例化不同的流程service;对外只暴露出启动流程和完成任务两个接口,前端传递不同的流程类型,执行不同的service操作。

数据表扩展:如果activiti提供的数据表无法满足业务需求,可以建立关联表,辅助业务运行。
   
这样基本可以实现,即使当流程发生改动的时候,也只需要对启动流程、完成任务这样单独的功能,改动很少的代码就可以应对改动了。如果流程图是一条直线,删除其中的几个节点后,甚至都不需要改动代码。

二、Activiti7的HelloWorld

1、环境准备

由于是helloworld,本次就用maven+单元测试的方式实现,稍后会有activiti7与spring、springBoot的整合。

1、pom.xml中添加依赖

<properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><slf4j.version>1.6.6</slf4j.version><log4j.version>1.2.12</log4j.version></properties><dependencies><dependency><groupId>org.activiti</groupId><artifactId>activiti-engine</artifactId><version>7.0.0.Beta1</version></dependency><dependency><groupId>org.activiti</groupId><artifactId>activiti-spring</artifactId><version>7.0.0.Beta1</version></dependency><dependency><groupId>org.activiti</groupId><artifactId>activiti-bpmn-model</artifactId><version>7.0.0.Beta1</version></dependency><dependency><groupId>org.activiti</groupId><artifactId>activiti-bpmn-converter</artifactId><version>7.0.0.Beta1</version></dependency><dependency><groupId>org.activiti</groupId><artifactId>activiti-json-converter</artifactId><version>7.0.0.Beta1</version></dependency><dependency><groupId>org.activiti.cloud</groupId><artifactId>activiti-cloud-services-api</artifactId><version>7.0.0.Beta1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.40</version></dependency><!-- log start --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>${log4j.version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>${slf4j.version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>${slf4j.version}</version></dependency><!-- log end --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.5</version></dependency><!--数据源暂时用dbcp--><dependency><groupId>commons-dbcp</groupId><artifactId>commons-dbcp</artifactId><version>1.4</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency></dependencies>

2、类路径下添加activiti.cfg.xml和log4j.properties文件

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"><!--dbcp数据源--><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/activiti7_study"/><property name="username" value="root"/><property name="password" value="123456"/></bean><!--配置Activiti的ProcessEngineConfiguration对象,因为没有跟spring整合,所以这里使用单例的。--><bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"><!--注入数据源--><property name="dataSource" ref="dataSource"/><!--指定数据表生成策略,该策略是,若数据表不存在则创建,存在则更新--><property name="databaseSchemaUpdate" value="true"/></bean>
</beans>

log4j.properties:

log4j.rootCategory=debug, CONSOLE# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m

3、代码测试

确保类路径下有个processes文件夹,并将上一讲的holiday.bpmn文件放入其中。

1)流程部署代码

public class Activiti7HelloWorld {static ProcessEngine processEngine = null;static {/*** 初始化流程引擎对象,将会根据配置创建25数据表(创建了索引和外键)*/processEngine = ProcessEngines.getDefaultProcessEngine();}/*** 流程部署* 工作中常用zip包上传的方式来部署流程,zip包里面一个.bpmn文件,一个.png的文件,activiti会自动的解压缩,解析并放到数据表中*/@Testpublic void processDeployment(){RepositoryService repositoryService = processEngine.getRepositoryService();Deployment deployment = repositoryService.createDeployment().addClasspathResource("processes/holiday.bpmn").addClasspathResource("processes/holiday.png").name("请假流程测试").deploy();System.out.println(deployment.getId());//2501,activit生成的IDSystem.out.println(deployment.getName());//请假流程System.out.println(deployment.getKey());//nullSystem.out.println(deployment.getCategory());//nullSystem.out.println(deployment.getDeploymentTime());System.out.println(deployment.getTenantId());//null/*受影响的表:3个act_re_deployment:添加一条流程部署记录act_re_procdef::添加一条流程定义记录,一个流程定义记录和一个流程图一一对应,流程定义记录的key就是流程图的idact_ge_bytearray:blob形式保存部署的资源*//*流程部署意味着两件事:1、将流程定义文件放到activiti引擎配置的持久化存储中,以便activiti引擎重启时能再次读取部署的流程。2、解析bpmn文件并转化为activiti内存中的对象模型,然后就能使用acticiti提供的api对持久化的数据进行操作。*/}
}

2)启动流程代码

    /*** 启动一个流程实例*/@Testpublic void startProcessExecution(){String businessKey = "1";RuntimeService runtimeService = processEngine.getRuntimeService();//启动该流程实例时,附带一些附加的数据Map<String,Object> variables = new HashMap<>();variables.put("variable01","aa");variables.put("variable02","bb");ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holiday",businessKey,variables);//可以设置流程实例的名字runtimeService.setProcessInstanceName(processInstance.getId(),"这是一个流程实例的名字,准备给审批人看的!");System.out.println("流程实例的ID:"+processInstance.getId());//5001System.out.println("流程实例的名字:"+processInstance.getName());System.out.println("流程实例的ProcessInstanceId:"+processInstance.getProcessInstanceId());//5001System.out.println("所属流程部署的ID:"+processInstance.getDeploymentId());//nullSystem.out.println("所属流程定义的信息:流程定义ID:"+processInstance.getProcessDefinitionId()+",流程定义key:"+processInstance.getProcessDefinitionKey()+",流程定义name:"+processInstance.getProcessDefinitionName()+",流程定义的version:"+processInstance.getProcessDefinitionVersion());//流程定义ID:holiday:1:2504,流程定义key:holiday,流程定义name:测试流程,流程定义的version:1System.out.println("流程实例的附属变量数据:");for (Map.Entry<String, Object> entry : variables.entrySet()) {System.out.println("\t"+entry.getKey()+":"+entry.getValue());}System.out.println("该流程是否被挂起:"+processInstance.isSuspended()+"该流程是否已结束:"+processInstance.isEnded());//false,falseSystem.out.println("该流程的businessKey:"+processInstance.getBusinessKey());//null/*受影响的表:9个act_ru_execution:添加了一个流程实例记录和该流程实例记录下的一个执行实例记录,注意流程实例和执行实例的区别。act_ru_variable:添加该流程实例的变量,如果流程实例启动时附带了流程变量的话。act_ru_task:添加了该流程实例的一个待办任务——>填写请假单act_ru_identitylink:添加了一条身份记录,该流程实例的当前办理人变成了——>zhangsanact_hi_actinst:历史活跃的实例节点添加了两条《开始》和《填写请假单》,有相同的流程实例IDact_hi_procinst:历史流程实例添加了一条记录act_hi_taskinst:历史任务里面添加了一个填写请假单记录act_hi_varinst:历史流程变量添加了两条记录aa和bbact_ge_property:next.dbid字段值 变成 7501*/}

3)查询待办任务

/*** 查询某人的待办任务列表*/@Testpublic void selectTaskListByAssignee(){TaskService taskService = processEngine.getTaskService();List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("holiday").taskAssignee("zhangsan").list();for (Task task : taskList) {System.out.println("任务ID:"+task.getId());//5007System.out.println("任务所属执行实例ID:"+task.getExecutionId());//5007System.out.println("任务所属流程实例ID:"+task.getProcessInstanceId());//5001System.out.println("任务所属流程定义ID:"+task.getProcessDefinitionId());//holiday:1:2504System.out.println("任务的办理人assignee:"+task.getAssignee()+",任务的owner:"+task.getOwner());//zhangsan,nullSystem.out.println("任务的名字:"+task.getName());//填写请假单System.out.println("任务的key:"+task.getTaskDefinitionKey());//_3,是流程图中的任务节点的IDSystem.out.println("任务的领取时间:"+task.getClaimTime());//null}/*数据来源表:act_ru_task:*/}

4)办理待办任务

/*** 办理任务* activiti内部工作:根据taskId查询act_ru_task表任务并删除,然后从流程部署的xml文件中读取下一个任务,* 判断是否是结束节点,若不是则读取该节点放入数据表中;若是做一些数据表处理(删除该流程实例所有ru_*表中的数据,在历史数据表中做记录),然后结束** 值得注意的是:当一个流程实例执行完了,ru_*表中所有该实例相关数据会被全部删除,让运行时表足够小以保证数据库操作的效率。*/@Testpublic void handleTask(){//这个taskId就是上一步查询出来任务IDString taskId = "15007";TaskService taskService = processEngine.getTaskService();//给该任务附件一些数据Map<String,Object> variables = new HashMap<>();variables.put("variables03","cc");variables.put("variables04","dd");taskService.complete(taskId,variables);System.out.println("当前任务完成!");/*受影响的表:8个act_ru_task:《填写请假单任务》被删除,新添加了一个《部门经理》任务,即流程开始自动往下走了act_ru_variable:又增加了两条记录cc和ddact_ru_identitylink:运行时身份表中,增加了lisi这条记录act_hi_varinst:历史变量表中又增加了两条记录《cc和dd》act_hi_taskinst:历史任务表中新添加了一个《部门经理》任务act_hi_identitylink:历史身份表中增加了《lisi》这条记录act_hi_actinst:历史活跃的实例节点表中增加了一个《部门经理》记录act_ge_property:next.dbid的值变成了10001*/}

一次执行四个单元测试,观察数据表及数据字段值的变化。然后3)和4)步骤循环三次 ,即根据名字查询zhangsan、lisi、wangwu的待办任务,然后办理他们各自的任务,最后观察数据表的变化。

三、activiti7的工作原理

先看一张工作原理图:

解释:

activiti7的作用就是读图并执行,读上一步画好的bpmn图(bpmn图,外表看着是一个流程图,内部其实是一个xml文件,就好比网页的内部是html和css一样),这个图符合BPMN2.0规范。当流程图被部署后,保存到数据表中,启动流程时,将bpmn图加载到内存中,并解析其内部的xml文件,并将下一个节点的数据保存到流程实例表中,等待被办理,当前节点办理完后删除数据表中的数据,然后读取下一个节点的数据再保存到流程实例表中,以此类推。如果遇到的排他网关、并行网关之类的,因为这些都符合BPMN2.0规范,所以工作流引擎的代码内部,就可以照着这个规范,进行判断处理,执行流程,以实现流程的自动化,根本原因还是有一个好用的规范在里面。这样对于activiti7来说,他就有个确定的东西可以依靠了,虽然具体的业务流程不是确定的,但是使用的规范却是确定的。

引发的思考:

我觉得这个设计思想是很不错,通过几个确定的简单的标记,组合成各种各样的情况,只要使用这个bpmn规范,无论用户怎样画图,都逃不过组合的情况,以此对不明白的人称之为自动化、智能化,其实就是把所有的情况都考虑到了。这也和机器学习、人工智能为什么要进行大量的“数据训练”后,才能更精准,就是因为将几乎所有的情况都想到了,然后利用硬件的高性能,迅速分析做出反应。

总的来说:

activiti7就是将上述过程中如解析xml文件、生成数据表、对数据进行增删改查等操作,进行了代码的层层封装,隐藏了实现细节,对外暴露出了好用的API,我们只需要知道这些API怎么使用的,就可以愉快的使用activiti7处理复杂的不确定的业务流程了。

四、后记

以上只是个activiti7的helloworld,并不能运用到生产中,旨在了解activiti7的工作流程和操作流程,以及基本的api使用。下面会对这个helloworld进行改进,介绍activiti7的API中较实用的功能,这些功能将来会在生产环境中使用。

上一篇:

下一篇:

activiti7(三):Activiti7简介与HelloWorld相关推荐

  1. ML之FE:数据处理—特征工程之数据集划分成训练集、验证集、测试集三部分简介、代码实现、案例应用之详细攻略

    ML之FE:数据处理-特征工程之数据集划分成训练集.验证集.测试集三部分简介.代码实现.案例应用之详细攻略 目录 数据集划分成训练.验证.测试三种数据的简介 1.训练集.验证集的作用 2.验证数据集 ...

  2. php语言开始和结束分别为,0055 PHP语言简介和HelloWorld

    0055 PHP语言简介和HelloWorld 作者:PHPYuan 时间:2018-10-01 03:41:29 第3章学习了如何编写JavaScript代码来动态修改网页内容. 虽然JavaScr ...

  3. MOOS-ivp 实验三 MOOS简介(3)

    MOOS-ivp 实验三 MOOS简介(3) 继上一篇文章继续对实验进行记录 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 MOOS-ivp 实验三 MOOS简介(3) ...

  4. MOOS-ivp 实验三 MOOS简介(1)

    MOOS-ivp 实验三 MOOS简介(1) 实验三主要包含三个实验目标: 1.moos发布-订阅结构体系 2.启动MOOSDB并且进行交互 3.日志记录器的运行与生成 文章目录 MOOS-ivp 实 ...

  5. 数字逻辑电路(前三章简介)

    数字逻辑电路(前三章简介) 第一章 数字逻辑基础 1.码制 BCD码 格雷码 ASCll码奇偶校验码 2.逻辑运算 与,或,非,与非,或非,与或非,异或,同或. 3.基本公式 0-1律,互补律,还原律 ...

  6. MOOS-ivp 实验三 MOOS简介(2)

    MOOS-ivp 实验三 MOOS简介(2) 继上一篇文章继续对实验进行记录 文章目录 MOOS-ivp 实验三 MOOS简介(2) 四.Launching a Mission with pAntle ...

  7. 我国民用高分辨率光学传输型立体测图卫星-资源三号简介(文末附带示例数据)

    我国民用高分辨率光学传输型立体测图卫星-资源三号简介 目前资源三号由资源三号01星和资源三号02星组成: 资源三号01星(ZY3-01)是我国首颗民用高分辨率光学传输型立体测图卫星,于2012年1月9 ...

  8. OpenCL学习笔记(三):OpenCL安装,编程简介与helloworld

    欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.技术.应用感兴趣的同学加入. OpenCL安装 安装我不打算 ...

  9. dubbo学习笔记 第三章简介dubbo的工作原理

    一.工作原理图 这是dubbo官网的关于dubbo工作原理,其中最核心的应该是Registry注册中心,Monitor,Consumer消费者和Provider服务提供者四个部分,注册中心关系这消费者 ...

  10. 编写java程序的三步骤_帮助Java小白涨知识的教程(三)(运行HelloWorld程序)

    总共有三个步骤:编写----------编译-----------执行 要用的文件:文字编译器(notepad++\editplus...)------------------------------ ...

最新文章

  1. Java基础--反射Reflection
  2. luogu3233 世界树 (虚树)
  3. s28 LNMP架构服务搭建
  4. 趣谈设计模式 | 观察者模式(Observer) :消息的发布与订阅
  5. SAP CRM WebClient UI context node属性展开的执行逻辑
  6. python avg_python闭包
  7. QString::number()相关转换
  8. Spring-aop-AbstractAutoProxyCreator
  9. pcie总线连接两台电脑_基于PCIE总线多主互连系统的设计与实现
  10. keras分类器模型
  11. HttpRequest类
  12. php缩图代码是什么,php生成缩略图的类代码
  13. 应届生实习需要注意哪些方面?
  14. mysql 1055 - Expression 解决
  15. linux shell bash -c $IFS ${IFS}
  16. (通俗易懂~)Docker搭建Etcd集群
  17. 8086寻址方式图解
  18. at指令 meid_MTK平台手机写IMEI的方法
  19. Excel去重并进行统计(对列)
  20. struts2 漏洞

热门文章

  1. tif转双层pdf Java_TIF文件转双层PDF时 内存不足
  2. 854计算机专业基础,2020年哈工大考研《854计算机基础》考试大纲
  3. 【Python 3.7.9官方文档】之术语对照表
  4. 微信小程序实现视频功能(一):视频上传
  5. PPM 金字塔池化模块 - PSPNet
  6. 在vscode中php语言配置,vscode配置go语言开发环境
  7. Interior-point methods(内点法)学习笔记
  8. java CRC32
  9. 几个轻巧好用的代码检查工具!代码不在坏味道
  10. 数据库防火墙、数据库加密、数据库脱敏真的可用吗?