工作流学习
一、了解工作流
工作流(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_*: 通用数据, 用于不同场景下。
四、框架的基本使用
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 候选用户
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 同13.使用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《=====如有不明白请跳转