这篇文章主要讲以下三个方面
- 工作流介绍
- 工作流执行过程
- 工作流模拟执行
工作流介绍
以我们公司的报销流程为例:
小明--->提交申请--->人事审批-->经理审批-->财务审批--->结束
我们先思考一下,需要实现这的一个需求我们需要怎么做?
我们可能需要去维护一个变量,来不断传递过去下一个处理者,或者是建相关的任务表之类的,如果需求不会变,没有什么条件处理,这样也好设计。
但是,如果有条件【不同职位员工审批方式不一样】,需求更改了【不需要人事审批了】,那么我们的代码就会乱,不好维护。
再来看这种问题就是一种流式的控制管理,基于这么一个原因,我们需要学习一个框架来帮我们完成并管理这样的报销流程,他可以在上级点击同意后自动将提交记录录到电脑并流转到下一节点,这就是我们这里要讲的工作流技术。
工作流(Workflow),就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在多个参与者之间按照某种预定义的规则传递文档、信息或任务的过程自动进行,从而实现某个预期的业务目标,或者促使此目标的实现”
这里我们也可以比对出工作流的优点:
- 提高系统的柔性,适应业务流程的变化
- 实现更好的业务过程控制,提高顾客服务质量
- 降低系统开发和维护成本
工作流执行过程
我们以官网提供的示例包演示:
官网https://www.activiti.org/get-started下载对应的jar包,解压出来,在wars包目录下有个activiti-app.war,把这个包放到tomgcat运行(运行之前我把数据库配置改成我本地的mysql:WEB-INF\classes\META-INF\activiti-app\activiti-app.properties)
项目启动成功进入到首页
- Kickstart App:主要用于流程模型管理、表单管理及应用(App)管理,一个应用可以包含多个流程模型,应用可发布给其他用户使用。
- Task App:用于管理整个activiti-app的任务,在该功能里面也可以启动流程
- Idenity management:身份信息管理,可以管理用户、用户组等数据
进入第三个菜单Identity management
新建用户:这边新建用户小明假设他为员工,王五是经理
定义流程
在主界面点击Kickstart App,点击create Process按钮弹出新建流程模型界面
上图中定义了一个开始事件、两个用户任务、一个结束事件。我们定义的请假业务,需要将该用户任务分配给 小明。点击第一个用户任务,并修改“Assignment”属性,将“提交申请”任务分配给“xiaoming”用户。保存成功后,再使用同样的方法将“部门经理审批”任务分配给 王五用户,保存流程模型后,就可以将流程发布。
发布流程
在 activiti-app 中,一个 App 可包含多个流程模型,因此在发布流程前,先新建一个 App并为其设置流程模型。点击 Apps 菜单,再点击“Creaea App”按钮,新建一个 App,该App就包含我们前面所设计的请假流程模型
建好之后需要为其设置流程模型
点击一下即可,在关闭
点击进入到app中,点击发布public进行发布
发布成功后使用小明账户登录,进入到首页可以看到
进入请假流程模型App并且点击“Processes”菜单,在界面左上角,可以看到“Start a process”按钮,点击启动请假流程后,可以看到界面如图所示
点击complete,完成,任务跳转到下一个执行人
直至整个流程审批完成,结束
工作流模拟执行
在我们模拟工作流流程之前在介绍下工作流引擎
ProcessEngine对象,这是Activiti工作的核心。负责生成流程运行时的各种实例及数据、监控和管理流程的运行,其主要有以下两个职责
- 定义流程,也就是给我们提供某种规范来定义规则,以及如何定义一个流程的这种规范,同事我们可以根据工作流引擎提供的相关概念来定义更为复杂的流程,这就是工作流引擎做的第一件事叫做定义流程。
- 执行流程,也就是工作流引擎需要解释这个规则,还要负责流程,它相当于流程的调度者,监控每个流程的执行情况,并将流程操作发往下一步,或者根据条件休眠或终止流程的这么一个过程就叫做执行流程。
了解完工作流引擎的这两个职责,我相信对于什么是工作流引擎一定已经有了一定的认识了,我们在用一句稍微有点官方的话来总结一下工作流引擎:工作流引擎为我们提供相关规则概念的定义,给我们提供了相关的API来调用这个引擎去执行流程。流程的操作实际上就是工作流引擎提供相关的api我们去调用它。
activiti.cfg.xml(activiti的配置文件)
Activiti核心配置文件,配置流程引擎创建工具的基本参数和数据库连接池参数
定义数据库配置参数
- jdbcUrl: 数据库的JDBC URL。
- jdbcDriver: 对应不同数据库类型的驱动。
- jdbcUsername: 连接数据库的用户名。
- jdbcPassword: 连接数据库的密码。
基于JDBC参数配置的数据库连接 会使用默认的MyBatis连接池。 下面的参数可以用来配置连接池(来自MyBatis参数)
- jdbcMaxActiveConnections: 连接池中处于被使用状态的连接的最大值。默认为10。
- jdbcMaxIdleConnections: 连接池中处于空闲状态的连接的最大值。
- jdbcMaxCheckoutTime: 连接被取出使用的最长时间,超过时间会被强制回收。 默认为20000(20秒)。
- jdbcMaxWaitTime: 这是一个底层配置,让连接池可以在长时间无法获得连接时, 打印一条日志,并重新尝试获取一个连接。(避免因为错误配置导致沉默的操作失败)。 默认为20000(20秒)
下面所有的操作都需要用到工作流引擎对象,我们可以如下方式获取:
ProcessEngine processEngine= ProcessEngines.getDefaultProcessEngine();
这里默认会去资源路径下读取配置文件activiti.cfg.xml
我们再来回顾下工作流执行过程,首先需要画好流程图,然后部署到app上
这个步骤我们叫:部署流程定义
public void deploymentProcessDefinition(){
Deployment deploy = processEngine.getRepositoryService() //与流程定义和部署对象相关的Service
.createDeployment() //创建一个部署对象
.name("审批流程") //添加部署名称
.addClasspathResource("diagrams/audit.xml") //从classPath资源中加载,一次只能加载一个文件
.addClasspathResource("diagrams/audit.png")
.deploy(); //完成部署
}
说明:
- 首先获得默认的流程引擎,通过流程引擎获取了一个RepositoryService对象(仓库对象)
- 由仓库的服务对象产生一个部署对象配置对象,用来封装部署操作的相关配置。
- 这是一个链式编程,在部署配置对象中设置显示名,上传流程定义规则文件
- 向数据库表中存放流程定义的规则信息。
这一步在数据库中将操作三张表
- act_re_deployment(部署对象表)
存放流程定义的显示名和部署时间,每部署一次增加一条记录 - act_re_procdef(流程定义表)
存放流程定义的属性信息,部署每个新的流程定义都会在这张表中增加一条记录。
注意:当流程定义的key相同的情况下,使用的是版本升级 - act_ge_bytearray(资源文件表)
存储流程定义相关的部署信息。即流程定义文档的存放地。每部署一次就会增加两条记录,一条是关于bpmn规则文件的,一条是图片的(如果部署时只指定了bpmn一个文件,activiti会在部署时解析bpmn文件内容自动生成流程图)。两个文件不是很大,都是以二进制形式存储在数据库中
然后需要发布:启动流程
public void startProcess(){
ProcessInstance process = processEngine.getRuntimeService().startProcessInstanceByKey("myProcess_1");
}
操作数据库的act_ru_execution表,如果是用户任务节点,同时也会在act_ru_task添加一条记录,我们可以看到小明会有一条任务,查询操作如下:
List<Task> taskList = processEngine.getTaskService()//与正在执行的任务管理相关的Service
.createTaskQuery()//创建任务查询对象
/**查询条件(where部分)*/
.taskAssignee("小明")//指定个人任务查询,指定办理人
// .taskCandidateUser(candidateUser)//组任务的办理人查询
// .processDefinitionId(processDefinitionId)//使用流程定义ID查询
// .processInstanceId(processInstanceId)//使用流程实例ID查询
// .executionId(executionId)//使用执行对象ID查询
/**排序*/
.orderByTaskCreateTime().asc()//使用创建时间的升序排列
/**返回结果集*/
// .singleResult()//返回惟一结果集
// .count()//返回结果集的数量
// .listPage(firstResult, maxResults);//分页查询
.list();//返回列表
for (Task task:taskList){
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());
}
说明
- 因为是任务查询,所以从processEngine中应该得到TaskService
- 使用TaskService获取到任务查询对象TaskQuery
- 为查询对象添加查询过滤条件,使用taskAssignee指定任务的办理者(即查询指定用户的代办任务),同时可以添加分页排序等过滤条件
- 调用list方法执行查询,返回办理者为指定用户的任务列表
- 任务ID、名称、办理人、创建时间可以从act_ru_task表中查到。
- 一个Task节点和Execution节点是1对1的情况,在task对象中使用Execution_来表示他们之间的关系
- 任务ID在数据库表act_ru_task中对应“ID_”列
完成任务
public void completeMyPersonalTask(){
processEngine.getTaskService(). //正在执行任务相关的Service
complete("104"); //根据taskid完成任务
}
说明
- 是办理任务,所以从ProcessEngine得到的是TaskService。
- 当执行完这段代码,再以员工的身份去执行查询的时候,会发现这个时候已经没有数据了,因为正在执行的任务中没有数据。
- 对于执行完的任务,activiti将从act_ru_task表中删除该任务,下一个任务会被插入进来。
- 以”部门经理”的身份进行查询,可以查到结果。因为流程执行到部门经理审批这个节点了。
- 再执行办理任务代码,执行完以后以”部门经理”身份进行查询,没有结果。
- 重复第4和5步直到流程执行完。
综上,我们可以总结出这个几个Service
- RepositoryService
是Activiti的仓库服务类。所谓的仓库指流程定义文档的两个文件:bpmn文件和流程图片。 - RuntimeService
是activiti的流程执行服务类。可以从这个服务类中获取很多关于流程执行相关的信息。 - TaskService
是activiti的任务服务类。可以从这个类中获取任务的信息。 - HistoryService
是activiti的查询历史信息的类。在一个流程执行完成后,这个对象为我们提供查询历史信息。
亦可以总结所用到的表
- ACT_RE_*: 'RE'表示repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
- ACT_RU_*: 'RU'表示runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。
- ACT_ID_*: 'ID'表示identity。 这些表包含身份信息,比如用户,组等等。
- ACT_HI_*: 'HI'表示history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。
- ACT_GE_*: 通用数据, 用于不同场景下,如存放资源文件。
资源库流程规则表
- act_re_deployment 部署信息表
- act_re_model 流程设计模型部署表
- act_re_procdef 流程定义数据表
运行时数据库表 - act_ru_execution 运行时流程执行实例表
- act_ru_identitylink 运行时流程人员表,主要存储任务节点与参与者的相关信息
- act_ru_task 运行时任务节点表
- act_ru_variable 运行时流程变量数据表
- act_ru_job 工作数据表
- act_ru_event_subscr 事件描述表
历史数据库表 - act_hi_actinst 历史节点表
- act_hi_attachment 历史附件表
- act_hi_comment 历史意见表
- act_hi_identitylink 历史流程人员表
- act_hi_detail 历史详情表,提供历史变量的查询
- act_hi_procinst 历史流程实例表
- act_hi_taskinst 历史任务实例表
- act_hi_varinst 历史变量表
组织机构表 - act_id_group 用户组信息表
- act_id_info 用户扩展信息表
- act_id_membership 用户与用户组对应信息表
- act_id_user 用户信息表
通用数据表 - act_ge_bytearray 二进制数据表
-
act_ge_property 属性数据表存储整个流程引擎级别的数据,初始化表结构时,会默认插入三条记录,
企业中的应用
未完