Activiti5是由Alfresco软件在2010年5月17日发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理、工做流、服务协做等领域的一个开源的、灵活的、易扩展的可执行流程语言框架。Activiti基于Apache许可的开源BPM平台,创始人Tom Baeyens是JBoss jBPM的项目架构师,它特点是提供了eclipse插件,开发人员能够经过插件直接绘画出业务 流程图。.html
咱们即将学习的是一个业务流程管理框架, 常见开源工做流引擎框架 : OSWorkFlow、jBPM(jboss business process management),Activiti工做流(是对jBPM升级)。通常咱们称做为工做流框架..java
那咱们为何要学习业务流程管理框架呢???学习它干吗???工做流(Workflow),就是“业务过程的部分或总体在计算机应用环境下的自动化”mysql
咱们来提出一个常见的需求来更好地理解:web
咱们在学生时代,确定会遇到请假写请假条的状况,若是学校的请假抓得很是严,就须要通过多层的赞成才能肯定能不能请假..spring
班主任->任课老师->教学总监->校长这么一个流程,首先咱们先明确一点:咱们做为一个学生,不可能直接跳过老师,去找校长申请请假的【校长是你随便找的吗??】sql
所以咱们请假的流程是一步一步的,并不能作跳跃数据库
也就是说,当班主任没有批准请假的时候,即便你去找任课老师了,任课老师会让你回去找班主任的,做为任课老师了,只关注班主任有没有批准你请假,同理,做为校长,只关注教学总监有没有批准你请假!express
进一步说:当教学总监尚未批准你请假时,你请假的请求是不会出如今校长的范围里的。json
实际上是很是好理解的,就是一步步往下执行,当尚未执行到本身处理的点子上时,是不会有对应的处理请求的。分工有序api
对上面的请假流程进行分析**,若是咱们没有使用框架,而把这么一个请假流程写到咱们的网站中,咱们会怎么作呢**??
咱们须要维护一个变量,来不断传递过去给下一个处理者...若是一切正常,需求不会变,并无条件的处理。这是咱们很是但愿看到的...可是,若是有条件判断【请假三天如下、请假三天以上的处理方式不同】,需求会变【不须要校长批准了,教学总监批准完,你就可以请假了】,那么咱们的代码就会变得乱
基于这么一个缘由,咱们是须要学习一个框架来帮咱们完成工做流的...
采用工做流管理系统的优势
首先咱们来梳理一下Activiti的开发步骤:
业务流程建模与标注(Business Process Model and Notation,BPMN) ,描述流程的基本符号,包括这些图元如何组合成一个业务流程图(Business Process Diagram)
BPMN这个就是咱们所谓把工做流定义出来的流程图..
咱们在执行工做流步骤的时候会涉及到不少数据【执行该流程的人是谁、所须要的参数是什么、包括想查看以前流程执行的记录等等】,所以咱们会须要用到数据库的表来保存数据...
因为咱们使用的是Activiti框架,这个框架会自动帮咱们把对应的数据库表建立起来,它涉及的表有23个,可是经常使用的并非不少,所以也不用很慌...
下面就列举一下表的状况
Activiti的后台是有数据库的支持,全部的表都以ACT_开头。 第二部分是表示表的用途的两个字母标识。 用途也和服务的API对应。
ACT_RE_*: 'RE'表示repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
ACT_RU_*: 'RU'表示runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti只在流程实例执行过程当中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表能够一直很小速度很快。
ACT_ID_*: 'ID'表示identity。 这些表包含身份信息,好比用户,组等等。
ACT_HI_*: 'HI'表示history。 这些表包含历史数据,好比历史流程实例, 变量,任务等等。
ACT_GE_*: 通用数据, 用于不一样场景下,如存放资源文件。
复制代码
我这里使用的Intellij idea来使用Activiti,首先,咱们得下载插件来使用Activiti【由于定义流程图须要用到插件】
详情能够看这篇博文:blog.sina.com.cn/s/blog_4b31…
Activiti插件中文乱码问题:
流程以前的连线是经过图中的蓝色小点点拖动来进行链接的...
导入对应的jar包
上面已经说过了,咱们要想使用Activiti就须要有数据库的支持,虽然Activiti是自动帮咱们建立对应的数据库表,可是咱们是须要配置数据库的信息的。咱们配置数据库的信息,接着拿到Activiti最重要的API------Activiti引擎
Activiti提供使用代码的方式来配置数据库的信息:
@Test
public void createActivitiEngine(){
/* *1.经过代码形式建立 * - 取得ProcessEngineConfiguration对象 * - 设置数据库链接属性 * - 设置建立表的策略 (当没有表时,自动建立表) * - 经过ProcessEngineConfiguration对象建立 ProcessEngine 对象*/
//取得ProcessEngineConfiguration对象
ProcessEngineConfiguration engineConfiguration=ProcessEngineConfiguration.
createStandaloneProcessEngineConfiguration();
//设置数据库链接属性
engineConfiguration.setJdbcDriver("com.mysql.jdbc.Driver");
engineConfiguration.setJdbcUrl("jdbc:mysql://localhost:3306/activitiDB?createDatabaseIfNotExist=true"
+ "&useUnicode=true&characterEncoding=utf8");
engineConfiguration.setJdbcUsername("root");
engineConfiguration.setJdbcPassword("root");
// 设置建立表的策略 (当没有表时,自动建立表)
// public static final java.lang.String DB_SCHEMA_UPDATE_FALSE = "false";//不会自动建立表,没有表,则抛异常
// public static final java.lang.String DB_SCHEMA_UPDATE_CREATE_DROP = "create-drop";//先删除,再建立表
// public static final java.lang.String DB_SCHEMA_UPDATE_TRUE = "true";//假如没有表,则自动建立
engineConfiguration.setDatabaseSchemaUpdate("true");
//经过ProcessEngineConfiguration对象建立 ProcessEngine 对象
ProcessEngine processEngine = engineConfiguration.buildProcessEngine();
System.out.println("流程引擎建立成功!");
}
复制代码
Activiti也能够经过配置文件来配置数据库的信息,加载配置文件从而获得工做流引擎
/**2. 经过加载 activiti.cfg.xml 获取 流程引擎 和自动建立数据库及表 * ProcessEngineConfiguration engineConfiguration= ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml"); //从类加载路径中查找资源 activiti.cfg.xm文件名能够自定义 ProcessEngine processEngine = engineConfiguration.buildProcessEngine(); System.out.println("使用配置文件Activiti.cfg.xml获取流程引擎"); */
复制代码
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">
<!-- 配置 ProcessEngineConfiguration -->
<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/activitiDB?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf8"></property>
<property name="jdbcUsername" value="root"></property>
<property name="jdbcPassword" value="root"></property>
<!-- 配置建立表策略 :没有表时,自动建立 -->
<property name="databaseSchemaUpdate" value="true"></property>
</bean>
</beans>
复制代码
上面的那种加载配置文件方式,配置文件的名字是能够自定义的,若是咱们配置文件的名字默认就是activiti.cfg.xml
的话,也是放在类路径下,咱们就可使用默认的方式来进行加载了!
@Test
public void createActivitiEngine(){
/** * 3. 经过ProcessEngines 来获取默认的流程引擎 */
// 默认会加载类路径下的 activiti.cfg.xml
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
System.out.println("经过ProcessEngines 来获取流程引擎");
}
复制代码
定义工做流就须要咱们刚才下载的插件了,咱们是使用图形的方式来定义工做流的....
在每一个流程中,咱们均可以指定对应的处理人是谁,交由谁处理
咱们上面已经定义了工做流了,工做流引擎咱们也已经拿到了,接下来就是把工做流部署到工做流引擎中了
@Test
public void deploy() {
//获取仓库服务 :管理流程定义
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()//建立一个部署的构建器
.addClasspathResource("LeaveActiviti.bpmn")//从类路径中添加资源,一次只能添加一个资源
.name("请求单流程")//设置部署的名称
.category("办公类别")//设置部署的类别
.deploy();
System.out.println("部署的id"+deploy.getId());
System.out.println("部署的名称"+deploy.getName());
}
复制代码
相对应的数据库表就会插入数据、涉及到的数据库表后面会详细说明。如今咱们只要了解到,咱们工做流引擎执行操做会有数据库表记录
指定指定工做流就是咱们定义时工做流程表的id
@Test
public void startProcess(){
//指定执行咱们刚才部署的工做流程
String processDefiKey="leaveBill";
//取运行时服务
RuntimeService runtimeService = processEngine.getRuntimeService();
//取得流程实例
ProcessInstance pi = runtimeService.startProcessInstanceByKey(processDefiKey);//经过流程定义的key 来执行流程
System.out.println("流程实例id:"+pi.getId());//流程实例id
System.out.println("流程定义id:"+pi.getProcessDefinitionId());//输出流程定义的id
}
复制代码
刚才咱们已经开始了工做流了,随后工做流应该去到了申请请假的流程,申请请假的处理人是钟福成,咱们能够查询出对应的信息:
//查询任务
@Test
public void queryTask(){
//任务的办理人
String assignee="钟福成";
//取得任务服务
TaskService taskService = processEngine.getTaskService();
//建立一个任务查询对象
TaskQuery taskQuery = taskService.createTaskQuery();
//办理人的任务列表
List<Task> list = taskQuery.taskAssignee(assignee)//指定办理人
.list();
//遍历任务列表
if(list!=null&&list.size()>0){
for(Task task:list){
System.out.println("任务的办理人:"+task.getAssignee());
System.out.println("任务的id:"+task.getId());
System.out.println("任务的名称:"+task.getName());
}
}
}
复制代码
咱们如今处理流程去到“申请请假”中,处理人是钟福成...接着就是钟福成去处理任务,根据任务的id使得流程继续往下走
任务的id刚才咱们已经查询出来了【上面】,咱们若是是在web端操做数据的话,那么只要传递过去就好了!
//完成任务
@Test
public void compileTask(){
String taskId="304";
//taskId:任务id
processEngine.getTaskService().complete(taskId);
System.out.println("当前任务执行完毕");
}
复制代码
当咱们处理完该任务的时候,就到了批准【班主任】任务了,咱们查询一下是否是如咱们想象的效果:
咱们按照定义的工做流程图一步一步往下走,最终把流程走完
管理流程定义主要涉及到如下的4张表:
-- 流程部署相关的表
SELECT * FROM act_ge_bytearray # 通用字节资源表
SELECT * FROM act_ge_property # 通用属性表,能够生成部署id
SELECT * FROM act_re_deployment #部署表
SELECT * FROM act_re_procdef # 流程定义表
复制代码
在Eclipse中Activiti插件会自动生成一个BPMN与之对应的PNG图片,是须要经过加载PNG图片的
@Test
public void deploy() {
//获取仓库服务 :管理流程定义
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()//建立一个部署的构建器
.addClasspathResource("LeaveActiviti.bpmn")//从类路径中添加资源,一次只能添加一个资源
.name("请求单流程")//设置部署的名称
.category("办公类别")//设置部署的类别
.deploy();
System.out.println("部署的id"+deploy.getId());
System.out.println("部署的名称"+deploy.getName());
}
复制代码
而咱们的Intellij idea插件不会自动生成PNG图片,可是咱们在加载BPMN文件的时候,好像会自动插入PNG图片,数据库是有对应的记录的【咱们是没有手动加载PNG图片资源的】
咱们查看一下
//查看bpmn 资源图片
@Test
public void viewImage() throws Exception{
String deploymentId="201";
String imageName=null;
//取得某个部署的资源的名称 deploymentId
List<String> resourceNames = processEngine.getRepositoryService().getDeploymentResourceNames(deploymentId);
// buybill.bpmn buybill.png
if(resourceNames!=null&&resourceNames.size()>0){
for(String temp :resourceNames){
if(temp.indexOf(".png")>0){
imageName=temp;
}
}
}
/** * 读取资源 * deploymentId:部署的id * resourceName:资源的文件名 */
InputStream resourceAsStream = processEngine.getRepositoryService()
.getResourceAsStream(deploymentId, imageName);
//把文件输入流写入到文件中
File file=new File("d:/"+imageName);
FileUtils.copyInputStreamToFile(resourceAsStream, file);
}
复制代码
惋惜的是,查看出来的图片的中文数据会乱码...
咱们当时候查询流程定义是经过咱们设置流程图的id来查看的....其实咱们能够经过其余的属性来查询...而且能够查询出更加详细的数据
//查看流程定义
@Test
public void queryProcessDefination(){
String processDefiKey="buyBill";//流程定义key
//获取流程定义列表
List<ProcessDefinition> list = processEngine.getRepositoryService().createProcessDefinitionQuery()
//查询 ,比如where
// .processDefinitionId(proDefiId) //流程定义id
// 流程定义id : buyBill:2:704 组成 : proDefikey(流程定义key)+version(版本)+自动生成id
.processDefinitionKey(processDefiKey)//流程定义key 由bpmn 的 process 的 id属性决定
// .processDefinitionName(name)//流程定义名称 由bpmn 的 process 的 name属性决定
// .processDefinitionVersion(version)//流程定义的版本
.latestVersion()//最新版本
//排序
.orderByProcessDefinitionVersion().desc()//按版本的降序排序
//结果
// .count()//统计结果
// .listPage(arg0, arg1)//分页查询
.list();
//遍历结果
if(list!=null&&list.size()>0){
for(ProcessDefinition temp:list){
System.out.print("流程定义的id: "+temp.getId());
System.out.print("流程定义的key: "+temp.getKey());
System.out.print("流程定义的版本: "+temp.getVersion());
System.out.print("流程定义部署的id: "+temp.getDeploymentId());
System.out.println("流程定义的名称: "+temp.getName());
}
}
}
复制代码
咱们还能够加载的是ZIP类型的资源数据
//部署流程定义,资源来自zip格式
@Test
public void deployProcessDefiByZip(){
InputStream in=getClass().getClassLoader().getResourceAsStream("BuyBill.zip");
Deployment deploy = processEngine.getRepositoryService()
.createDeployment()
.name("采购流程")
.addZipInputStream(new ZipInputStream(in))
.deploy();
System.out.println("部署名称:"+deploy.getName());
System.out.println("部署id:"+deploy.getId());
}
复制代码
//删除流程定义
@Test
public void deleteProcessDefi(){
//经过部署id来删除流程定义
String deploymentId="101";
processEngine.getRepositoryService().deleteDeployment(deploymentId);
}
复制代码
再次查询的时候,已经没有101这个流程定义的数据了。
流程实例与任务执行的经常使用表有如下几个:
-- 流程实例与任务
SELECT * FROM act_ru_execution # 流程执行对象信息
SELECT * FROM act_ru_task # 正在运行的任务表
SELECT * FROM act_hi_procinst # 历史流程实例表
SELECT * FROM act_hi_taskinst # 历史流程任务表
复制代码
这里就简单简述一下流程实例与流程对象的区别:
@Test
public void startProcess(){
String processDefiKey="leaveActiviti";//bpmn 的 process id属性
ProcessInstance pi = processEngine.getRuntimeService()
.startProcessInstanceByKey(processDefiKey);
System.out.println("流程执行对象的id:"+pi.getId());//Execution 对象
System.out.println("流程实例的id:"+pi.getProcessInstanceId());//ProcessInstance 对象
System.out.println("流程定义的id:"+pi.getProcessDefinitionId());//默认执行的是最新版本的流程定义
}
复制代码
//查询正在运行任务
@Test
public void queryTask(){
//取得任务服务
TaskService taskService = processEngine.getTaskService();
//建立一个任务查询对象
TaskQuery taskQuery = taskService.createTaskQuery();
//办理人的任务列表
List<Task> list = taskQuery.list();
//遍历任务列表
if(list!=null&&list.size()>0){
for(Task task:list){
System.out.println("任务的办理人:"+task.getAssignee());
System.out.println("任务的id:"+task.getId());
System.out.println("任务的名称:"+task.getName());
}
}
}
复制代码
查询SELECT * FROM act_ru_task 表
有的时候,咱们须要判断它是在该流程,仍是该流程已经结束了。咱们能够根据获取出来的对象是否为空来进行判断
//获取流程实例的状态
@Test
public void getProcessInstanceState(){
String processInstanceId="605";
ProcessInstance pi = processEngine.getRuntimeService()
.createProcessInstanceQuery()
.processInstanceId(processInstanceId)
.singleResult();//返回的数据要么是单行,要么是空 ,其余状况报错
//判断流程实例的状态
if(pi!=null){
System.out.println("该流程实例"+processInstanceId+"正在运行... "+"当前活动的任务:"+pi.getActivityId());
}else{
System.out.println("当前的流程实例"+processInstanceId+" 已经结束!");
}
}
复制代码
//查看历史执行流程实例信息
@Test
public void queryHistoryProcInst(){
List<HistoricProcessInstance> list = processEngine.getHistoryService()
.createHistoricProcessInstanceQuery()
.list();
if(list!=null&&list.size()>0){
for(HistoricProcessInstance temp:list){
System.out.println("历史流程实例id:"+temp.getId());
System.out.println("历史流程定义的id:"+temp.getProcessDefinitionId());
System.out.println("历史流程实例开始时间--结束时间:"+temp.getStartTime()+"-->"+temp.getEndTime());
}
}
}
复制代码
查询表:
@Test
public void queryHistoryTask(){
String processInstanceId="605";
List<HistoricTaskInstance> list = processEngine.getHistoryService()
.createHistoricTaskInstanceQuery()
.processInstanceId(processInstanceId)
.list();
if(list!=null&&list.size()>0){
for(HistoricTaskInstance temp:list){
System.out.print("历史流程实例任务id:"+temp.getId());
System.out.print("历史流程定义的id:"+temp.getProcessDefinitionId());
System.out.print("历史流程实例任务名称:"+temp.getName());
System.out.println("历史流程实例任务处理人:"+temp.getAssignee());
}
}
}
复制代码
给予对应的实例id就能够查询出执行到哪一个任务了...
根据任务的id,就能够把该任务执行了。
@Test
public void compileTask(){
String taskId="608";
//taskId:任务id
processEngine.getTaskService().complete(taskId);
System.out.println("当前任务执行完毕");
}
复制代码
流程变量涉及到的数据库表:
act_ru_variable:正在执行的流程变量表
act_hi_varinst:流程变量历史表
复制代码
流程变量在工做流中扮演着一个很是重要的角色。例如:请假流程中有请假天数、请假缘由等一些参数都为流程变量的范围**。流程变量的做用域范围是只对应一个流程实例**。也就是说各个流程实例的流程变量是不相互影响的。流程实例结束完成之后流程变量还保存在数据库中(存放到流程变量的历史表中)。
咱们有两种服务能够设置流程变量,TaskService【任务服务】和RuntimeService【运行时服务】
场景
做用:
若是咱们使用JavaBean来做为流程的变量,那么咱们须要将JavaBean实现Serializable接口。
Javabean类型设置获取流程变量,除了须要这个javabean实现了Serializable接口外,还要求流程变量对象的属性不能发生变化,不然抛出异常。解决方案,固定序列化ID
//模拟流程变量设置
@Test
public void getAndSetProcessVariable(){
//有两种服务能够设置流程变量
// TaskService taskService = processEngine.getTaskService();
// RuntimeService runtimeService = processEngine.getRuntimeService();
/**1.经过 runtimeService 来设置流程变量 * executionId: 执行对象 * variableName:变量名 * values:变量值 */
// runtimeService.setVariable(executionId, variableName, values);
// runtimeService.setVariableLocal(executionId, variableName, values);
//设置本执行对象的变量 ,该变量的做用域只在当前的execution对象
// runtimeService.setVariables(executionId, variables);
//能够设置多个变量 放在 Map<key,value> Map<String,Object>
/**2. 经过TaskService来设置流程变量 * taskId:任务id */
// taskService.setVariable(taskId, variableName, values);
// taskService.setVariableLocal(taskId, variableName, values);
//// 设置本执行对象的变量 ,该变量的做用域只在当前的execution对象
// taskService.setVariables(taskId, variables); //设置的是Map<key,values>
/**3. 当流程开始执行的时候,设置变量参数 * processDefiKey: 流程定义的key * variables: 设置多个变量 Map<key,values> */
// processEngine.getRuntimeService()
// .startProcessInstanceByKey(processDefiKey, variables)
/**4. 当任务完成时候,能够设置流程变量 * taskId:任务id * variables: 设置多个变量 Map<key,values> */
// processEngine.getTaskService().complete(taskId, variables);
/** 5. 经过RuntimeService取变量值 * exxcutionId: 执行对象 * */
// runtimeService.getVariable(executionId, variableName);//取变量
// runtimeService.getVariableLocal(executionId, variableName);//取本执行对象的某个变量
// runtimeService.getVariables(variablesName);//取当前执行对象的全部变量
/** 6. 经过TaskService取变量值 * TaskId: 执行对象 * */
// taskService.getVariable(taskId, variableName);//取变量
// taskService.getVariableLocal(taskId, variableName);//取本执行对象的某个变量
// taskService.getVariables(taskId);//取当前执行对象的全部变量
}
复制代码
//设置流程变量值
@Test
public void setVariable(){
String taskId="1804";//任务id
//采用TaskService来设置流程变量
//1. 第一次设置流程变量
// TaskService taskService = processEngine.getTaskService();
// taskService.setVariable(taskId, "cost", 1000);//设置单一的变量,做用域在整个流程实例
// taskService.setVariable(taskId, "申请时间", new Date());
// taskService.setVariableLocal(taskId, "申请人", "何某某");//该变量只有在本任务中是有效的
//2. 在不一样的任务中设置变量
// TaskService taskService = processEngine.getTaskService();
// taskService.setVariable(taskId, "cost", 5000);//设置单一的变量,做用域在整个流程实例
// taskService.setVariable(taskId, "申请时间", new Date());
// taskService.setVariableLocal(taskId, "申请人", "李某某");//该变量只有在本任务中是有效的
/** * 3. 变量支持的类型 * - 简单的类型 :String 、boolean、Integer、double、date * - 自定义对象bean */
TaskService taskService = processEngine.getTaskService();
//传递的一个自定义bean对象
AppayBillBean appayBillBean=new AppayBillBean();
appayBillBean.setId(1);
appayBillBean.setCost(300);
appayBillBean.setDate(new Date());
appayBillBean.setAppayPerson("何某某");
taskService.setVariable(taskId, "appayBillBean", appayBillBean);
System.out.println("设置成功!");
}
复制代码
//查询流程变量
@Test
public void getVariable(){
String taskId="1804";//任务id
// TaskService taskService = processEngine.getTaskService();
// Integer cost=(Integer) taskService.getVariable(taskId, "cost");//取变量
// Date date=(Date) taskService.getVariable(taskId, "申请时间");//取本任务中的变量
//// Date date=(Date) taskService.getVariableLocal(taskId, "申请时间");//取本任务中的变量
// String appayPerson=(String) taskService.getVariableLocal(taskId, "申请人");//取本任务中的变量
//// String appayPerson=(String) taskService.getVariable(taskId, "申请人");//取本任务中的变量
//
// System.out.println("金额:"+cost);
// System.out.println("申请时间:"+date);
// System.out.println("申请人:"+appayPerson);
//读取实现序列化的对象变量数据
TaskService taskService = processEngine.getTaskService();
AppayBillBean appayBillBean=(AppayBillBean) taskService.getVariable(taskId, "appayBillBean");
System.out.println(appayBillBean.getCost());
System.out.println(appayBillBean.getAppayPerson());
}
复制代码
public class AppayBillBean implements Serializable{
private Integer id;
private Integer cost;//金额
private String appayPerson;//申请人
private Date date;//申请日期
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getCost() {
return cost;
}
public void setCost(Integer cost) {
this.cost = cost;
}
public String getAppayPerson() {
return appayPerson;
}
public void setAppayPerson(String appayPerson) {
this.appayPerson = appayPerson;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
复制代码
上面咱们已将学过了流程变量了,能够在【任务服务、运行时服务、流程开始、完成某个任务时设置流程变量】,而咱们的链接就是流程变量的实际应用了....
咱们并非全部的流程都是按一条的路径来走的,咱们有的时候会根据条件来走不一样的路。固然了,最终该流程是会一步步走完....
例子:
重要的信息交由老板来处理,不重要的信息交由经理来处理
表达式的结果必须是布尔型
#{variable=='value'}
我在任务完成时设置流程变量为不重要,那么跳到下一个流程时就是经理来进行处理
当我设置为重要的时候,那么就是交由老板来处理
上面咱们使用连线的时候用了两个条件 : 要么条件是“重要”,要么条件是“不重要”....若是有另外一种状况呢???就是用户把条件输入错了,写成“不知道重不重要”,那么咱们的流程怎么走???岂不是奔溃了???
所以,咱们要有一条默认的路来走,就是当该变量不符合任何的条件时,咱们也有一条默认的路
值得注意的是:若是是在Eclipse中使用插件的BPMN流程图,若是使用了排他网关,那么在Idea下是解析不了的...
解决:
咱们只要从新定义BPMN流程图的排他网关就好了,idea中的Activiti插件是不用制定默认流程的,只要咱们不设置条件,那就是默认的链接线
public class ExclusiveGetWay {
private ProcessEngine processEngine = ProcessEngines
.getDefaultProcessEngine();
// 部署流程定义,资源来在bpmn格式
@Test
public void deployProcessDefi() {
Deployment deploy = processEngine.getRepositoryService()
.createDeployment().name("排他网关流程")
.addClasspathResource("ExclusiveGateway.bpmn")
.deploy();
System.out.println("部署名称:" + deploy.getName());
System.out.println("部署id:" + deploy.getId());
}
// 执行流程,开始跑流程
@Test
public void startProcess() {
String processDefiKey = "bankBill";// bpmn 的 process id属性
ProcessInstance pi = processEngine.getRuntimeService()
.startProcessInstanceByKey(processDefiKey);
System.out.println("流程执行对象的id:" + pi.getId());// Execution 对象
System.out.println("流程实例的id:" + pi.getProcessInstanceId());// ProcessInstance
// 对象
System.out.println("流程定义的id:" + pi.getProcessDefinitionId());// 默认执行的是最新版本的流程定义
}
// 查询正在运行任务
@Test
public void queryTask() {
// 取得任务服务
TaskService taskService = processEngine.getTaskService();
// 建立一个任务查询对象
TaskQuery taskQuery = taskService.createTaskQuery();
// 办理人的任务列表
List<Task> list = taskQuery.list();
// 遍历任务列表
if (list != null && list.size() > 0) {
for (Task task : list) {
System.out.println("任务的办理人:" + task.getAssignee());
System.out.println("任务的id:" + task.getId());
System.out.println("任务的名称:" + task.getName());
}
}
}
// 完成任务
@Test
public void compileTask() {
String taskId = "2404";
Map<String,Object> params=new HashMap<String, Object>();
params.put("visitor", 6);
// taskId:任务id
processEngine.getTaskService().complete(taskId, params);
// processEngine.getTaskService().complete(taskId);
System.out.println("当前任务执行完毕");
}
}
复制代码
咱们指定的值并非VIP也不是后台,那么就会自动去普通窗口中处理
并行网关:
等待活动:
用户任务:
咱们在快速入门的例子中,是在定义流程图中硬性指定处理人,其实这么干是不够灵活的,咱们学了流程变量以后,咱们是能够灵活地指定处理人的....
@Test
public void deployProcessDefi() {
Deployment deploy = processEngine.getRepositoryService()
.createDeployment().name("用户任务指定流程")
.addClasspathResource("AppayBill.bpmn")
.deploy();
System.out.println("部署名称:" + deploy.getName());
System.out.println("部署id:" + deploy.getId());
}
// 执行流程,开始跑流程
@Test
public void startProcess() {
String processDefiKey = "appayBill";// bpmn 的 process id属性
Map<String,Object> params=new HashMap<String, Object>();
params.put("userID", "王某某");
ProcessInstance pi = processEngine.getRuntimeService()
.startProcessInstanceByKey(processDefiKey, params);
System.out.println("流程执行对象的id:" + pi.getId());// Execution 对象
System.out.println("流程实例的id:" + pi.getProcessInstanceId());// ProcessInstance
// 对象
System.out.println("流程定义的id:" + pi.getProcessDefinitionId());// 默认执行的是最新版本的流程定义
}
// 查询正在运行任务
@Test
public void queryTask() {
String assignee="王某某";//指定任务处理人
// 取得任务服务
TaskService taskService = processEngine.getTaskService();
// 建立一个任务查询对象
TaskQuery taskQuery = taskService.createTaskQuery();
// 办理人的任务列表
List<Task> list = taskQuery
.taskAssignee(assignee)
.list();
// 遍历任务列表
if (list != null && list.size() > 0) {
for (Task task : list) {
System.out.println("任务的办理人:" + task.getAssignee());
System.out.println("任务的id:" + task.getId());
System.out.println("任务的名称:" + task.getName());
}
}
}
复制代码
使用类指定:
组任务:
若是文章有错的地方欢迎指正,你们互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同窗,能够关注微信公众号:Java3y