活动 Activity
预先定义好的活动
Start 开始活动 代表流程的开始,有且仅有一个,向后只有一个transition,启动后自动离开,不能有其他的指向开始
End 结束活动 代表流程的结束,可以有多个(方便绘图)和没有,分end、cancel-end、error-end
State 状态活动 到达这儿等待直到发出信号,配合监听器去做一些事情后回来通知,他的作用就是等待
Decision 判断活动 根据一个流程变量判断走哪一条路【通过写一个类,实现DecisionHandler包装判断逻辑,传入上下文信息】
Decision节点中<handler class="cn.itcast.f_decision.DecisionHandlerImpl" />
Fork/Join 分支/聚合活动 有一个主Execution和分支Execution,可以看成主流程和子流程,通过pi.findActiveActivityNames()获取正在执行的活动,当所有的子执行完成后(join)才算完成。
Task 任务活动,表示由人完成的任务,关键在于指定assignee,不能像这样
固定死,使用EL表达式[废掉了作用域的概念],比如由经理完成,#{manager},机制就是获取流程变量看看是否匹配,比如张三请假需要上级王五来批,那么张三提交申请之后设置流程变量manager=王五,引擎就知道王五有一个任务了,代码为variables.put("manager","王经理");
指定个人任务的办理人的方式:
1,直接指定:assignee="张三"
2,使用变量:assignee="#{manager}",变量值是一个字符串
3,使用AssignmentHandler【和其他代码分离,可以灵活配置】,任务下面的子元素,类实现AssignmentHandler
assignable.setAssignee(userId); // 指定个人任务的办理人
4,直接指定任务的办理人,重新分配【最通用的方法,暴力执行,可以覆盖其他的】:
taskService.assignTask(taskId, userId);
// 直接指定任务的办理人
@Test
publicvoid testAssignTask() throws Exception {
StringtaskId = "300009";
StringuserId = "王经理";
processEngine.getTaskService().assignTask(taskId,userId);
}
一个任务可以多个人的其中一个人干。
1,组任务:一个任务,很多人都能看到(同一组的人)。
2,先把任务拾取过来,就变成了自己的个人任务[组任务查询就查不到了],别人就看不到了【组任务和个人任务都看不到】。
processEngine.getTaskService().takeTask(taskId,userId);
3,如果因事不能继续办理这个任务,可以选择:
a, 退回到组任务列表,让别人再去拾取与办理。
b, 直接把任务指定给某人。
String taskId = "310009";
// String userId = null; // 退回到组任务列表
String userId = "赵工程师";
processEngine.getTaskService().assignTask(taskId, userId);
组任务与组任务分配方式:
1, 直接指定【相当于硬编码,不灵活】:candidate-users="王工程师,李工程师,赵工程师",在查询的时候就不能使用findPersonalTasks
而要使用组任务查询
<task name="维修" g="55,187,92,52"candidate-users="王工程师,李工程师,赵工程师">
<transition name="to end1"to="end1" g="-47,-10"/>
</task>
//////////////////////////////////////////////////////////////////////////////////////////////////////
String userId = "王工程师";
//String userId = "赵工程师";
//查询
//List<Task> list =processEngine.getTaskService().findGroupTasks(userId);
//分页
List<Task>list = processEngine.getTaskService()//
.createTaskQuery()//
.candidate(userId)// 指定候选人,这是查询组任务
.page(0,100)// 分页
.list();
//////////////////////////////////////////////////////////////////////////////////////////////////////
2,使用变量:candidate-users="#{userIds}"变量值是一个字符串,多个人之间使用英文的逗号隔开。variables.put("userIds", "小A,小B,小C,小D");
3,使用AssignmentHandler
assignable.addCandidateUser("小A");// 添加一个候选人(组任务)
assignable.addCandidateUser("小B");// 添加一个候选人(组任务)
assignable.addCandidateUser("小C");// 添加一个候选人(组任务)
publicclass ProcessTest {
privatestatic ProcessEngine processEngine = Configuration.getProcessEngine();
@Test
publicvoid testProcess() throws Exception {
// 部署流程定义
InputStream in = this.getClass().getResourceAsStream("test.jpdl.xml");
String deploymentId = processEngine.getRepositoryService()//
.createDeployment()//
.addResourceFromInputStream("test.jpdl.xml", in)//
.deploy();
System.out.println("部署流程定义完毕:deploymentId = " + deploymentId);
// 启动流程实例
Map<String, Object> variables = new HashMap<String,Object>();
variables.put("manager", "王经理");
variables.put("userIds", "小A,小B,小C,小D");//这几个人是候选人
ProcessInstance pi = processEngine.getExecutionService().startProcessInstanceByKey("test",variables);
System.out.println("流程实例启动完毕:processInstanceId = " + pi.getId());
}
// 查询组任务列表
@Test
publicvoid testFindMyGroupTaskList() throws Exception {
String userId = "王工程师";
// String userId = "赵工程师";
// 查询
// List<Task> list =processEngine.getTaskService().findGroupTasks(userId);
// 分页
List<Task> list = processEngine.getTaskService()//
.createTaskQuery()//
.candidate(userId)// 指定候选人,这是查询组任务
.page(0, 100)// 分页
.list();
// 显示
System.out.println("====== 【" + userId + "】的个人任务列表 ======");
for (Task task : list) {
System.out.println("id=" + task.getId()//
+ ",name=" + task.getName()//
+ ",assignee=" + task.getAssignee()//
+ ",createTime=" + task.getCreateTime()//
+ ",executionId=" + task.getExecutionId());
}
}
// 拾取任务
@Test
publicvoid testTakeTask() throws Exception {
String taskId = "310009";
String userId = "王工程师";
processEngine.getTaskService().takeTask(taskId, userId);
}
// 查询个人任务列表
@Test
publicvoid testFindMyPersonalTaskList() throws Exception {
String userId = "王工程师";
// 查询
// List<Task> list =processEngine.getTaskService().findPersonalTasks(userId);
// 分页
List<Task> list = processEngine.getTaskService()//
.createTaskQuery()//
.assignee(userId)// 指定办理人条件
.page(0, 100)// 分页
.list();
// 显示
System.out.println("====== 【" + userId + "】的个人任务列表 ======");
for (Task task : list) {
System.out.println("id=" + task.getId()//
+ ",name=" + task.getName()//
+ ",assignee=" + task.getAssignee()//
+ ",createTime=" + task.getCreateTime()//
+ ",executionId=" + task.getExecutionId());
}
}
// 直接指定任务的办理人
@Test
publicvoid testAssignTask() throws Exception {
String taskId = "310009";
// String userId = null; // 退回到组任务列表
String userId = "赵工程师";
processEngine.getTaskService().assignTask(taskId, userId);
}
}
在完成任务的时候注意transition
@在网页中高亮正在执行的活动
1,获取当前正在执行的活动名称
processInstance.findActiveActivityNames()
2,获取活动对应的坐标
repositoryService.getActivityCoordinates(processDefinitionId,activityName)
3,获取流程图片
repositoryService().getResourceAsStream(deploymentId,resourceName);
在网页中使用css+div布局即可实现
<styletype="text/css">
.highlightBox{
/* 140,176,92,52*/
border: red 1px solid;
position:absolute;
top: 176px;
left: 140px;
width: 92px;
height: 52px;
}
</style>
</head>
<body style="background:url('test.png') no-repeat">
<div class="highlightBox" title="这个环节的信息..."></div>
</body>
自定义的活动【像sql、hql、jms、java活动都可以用custom活动来完成】
Custom + ..Class【短信,邮件】
自定义活动通过指定class,将要执行的东西封装到代码中,这个类实现ActivityBehivour接口,其他的所有的活动都实现这个接口,如StartActivity、EndActivity、TaskActivity等,当然我们一般用的时候实现ExternalActivityBehivour接口。
在<custom>元素中指定class属性为指定的类。
2,这个类要实现ExternalActivityBehaviour接口,其中有两个方法:
1,execute(ActivityExecution),节点的功能代码
2,signal(ActivityExecution, String,Map),在当前节点等待时,外部发信号时的行为
3,在execute()方法中,可以调用以下方法对流程进行控制
1,ActivityExecution.waitForSignal(),在当前节点等待。
2,ActivityExecution.takeDefaultTransition(),使用默认的Transition离开,当前节点中定义的第一个为默认的。
3,ActivityExecution.take(String transitionName),使用指定的Transition离开
4,ActivityExecution.end(),结束流程实例
1, 也可以实现ActivityBehaviour接口,只有一个方法execute(ActivityExecution),这样就不能等待,否则signal时会有类转换异常。
public class ExternalActivityBehaviourImplimplements ExternalActivityBehaviour {
//流程执行到本活动后,马上执行的代码
//默认是本方法执行完后就离开了
@Override
publicvoid execute(ActivityExecution execution) throws Exception {
System.out.println("--->ExternalActivityBehaviourImpl.execute()");
System.out.println("已经发送了通知.");
//// 默认的行为:使用默认的Transition离开本活动
//execution.takeDefaultTransition();
//// 使用指定名称的Transition离开本活动
//execution.take(transitionName);
//不离开在,而是在本活动上等待,直到外部调用signalExecution()时才离开
execution.waitForSignal();
}
//在本活动等待时,调用signalExecution()离开本活动之前所执行的代码。
//如果本活动不等待,在execute()中就离开了本活动,则本方法不会被执行。
@Override
publicvoid signal(ActivityExecution execution, String signalName, Map<String,?> parameters) throws Exception {
System.out.println("--->ExternalActivityBehaviourImpl.signal()");
}
}
publicclass ProcessTest {
privatestatic ProcessEngine processEngine = Configuration.getProcessEngine();
@Test
publicvoid testProcess() throws Exception {
// 部署流程定义
InputStream in = this.getClass().getResourceAsStream("test.jpdl.xml");
processEngine.getRepositoryService()//
.createDeployment()//
.addResourceFromInputStream("test.jpdl.xml", in)//
.deploy();
// 启动流程实例
processEngine.getExecutionService().startProcessInstanceByKey("test");
}
@Test
publicvoid testSignal() throws Exception {
String executionId = "test.340007";
processEngine.getExecutionService().signalExecutionById(executionId);
}
}
事件:
使用on节点指定,event=start、end这两个值,表示在开始和结束的时候通知,on如果放在process下面表示流程实例启动和结束的时候通知,如果放在其他活动里面表示这个活动执行和结束的时候通知。使用event-listener指定监听器,实现EventListener
而在边界start和end活动时,不能全指定start和end监听器,start中只能指定end监听器,end中只能指定start监听器,因为不能有其他活动指向start,结束了之后就没有其他的活动了。
<process name="test" xmlns="http://jbpm.org/4.4/jpdl">
<!-- 流程实例启动事件 -->
<on event="start">
<event-listener class="cn.itcast.j_event.EventListenerImpl"></event-listener>
</on>
<!-- 流程实例结束事件 -->
<on event="end">
<event-listener class="cn.itcast.j_event.EventListenerImpl"></event-listener>
</on>
<start name="start1" g="172,62,48,48">
<!-- 开始活动只有离开活动的事件 -->
<on event="end">
<event-listener class="cn.itcast.j_event.EventListenerImpl"></event-listener>
</on>
<transition name="to 审批" to="审批" g="-47,-17"/>
</start>
<task name="审批" g="162,169,92,52"assignee="王经理">
<!-- 进入活动的事件 -->
<on event="start">
<event-listener class="cn.itcast.j_event.EventListenerImpl"></event-listener>
</on>
<!-- 离开活动的事件 -->
<on event="end">
<event-listener class="cn.itcast.j_event.EventListenerImpl"></event-listener>
</on>
<transition name="to end1"to="end1" g="-47,-17"/>
</task>
<end name="end1" g="194,275,48,48">
<!-- 结束活动只有进入活动的事件 -->
<on event="start">
<event-listener class="cn.itcast.j_event.EventListenerImpl"></event-listener>
</on>
</end>
</process>
publicclass EventListenerImpl implements EventListener {
@Override
publicvoid notify(EventListenerExecution execution) throws Exception {
System.out.println("事件触发了:" + execution.getActivity());
}
}
publicclass ProcessTest {
privatestatic ProcessEngine processEngine = Configuration.getProcessEngine();
@Test
publicvoid testProcess() throws Exception {
// 部署流程定义
InputStream in = this.getClass().getResourceAsStream("test.jpdl.xml");
String deploymentId = processEngine.getRepositoryService()//
.createDeployment()//
.addResourceFromInputStream("test.jpdl.xml", in)//
.deploy();
System.out.println("部署流程定义完毕:deploymentId = " + deploymentId);
// 启动流程实例
ProcessInstance pi = processEngine.getExecutionService().startProcessInstanceByKey("test");
System.out.println("流程实例启动完毕:processInstanceId = " + pi.getId());
}
@Test
publicvoid testCompleteTask() throws Exception {
String taskId = "350008";
processEngine.getTaskService().completeTask(taskId);
}
}