JBPM学习(六):详解流程图
概念:
流程图的组成:
a. 活动 Activity / 节点 Node
b. 流转 Transition / 连线(单向箭头)
c. 事件
1.流转(Transition)
a) 一般情况一个活动中可以指定一个或多个Transition
i. 开始活动(Start)中只能有一个Transition。
ii. 结束活动(End)中没有Transition。
iii. 其他活动中有一条或多条Transition
b) 如果Transition只有一个,则可以不指定名称(名称是null);如果有多个,则要分别指定唯一的名称。
2.活动(Activity)
a) 流转控制活动(预定义活动)
i. start开始活动
代表流程的开始边界,一个流程有且只能有一个Start活动。开始活动只能指定一个Transition。在流程实例启动后,会 自动的使用这个唯一的Transition离开开始活动,到一下个活动。
ii. end/end-error/end-cancel(结束活动)
代表流程的结束边界,可以有多个,也可以没有。如果有多个,则到达任一个结束活动,整个流程就都结束了;如果没 有,则到达最后那个没有Transition的活动,流程就结束了。
iii. state状态活动
作用:等待。可以使用signal使其结束等待,并向后执行一步。
iv. task任务活动
-->个人任务的分配
1. 使用流程变量:assignee="#{manager}"
2. AssignmentHandler:assignable.setAssignee(userId); // 指定当前任务的办理人(分配任务)
a) 需要在.jbdl.xml的<task>元素中写
<assignment-handler class="cn.grace.AssignmentHandlerImpl"/>
b) 指定的AssignmentHandlerImpl类要实现AssignmentHandler接口
c) 在AssignmentHandlerImpl类中可以使用assignable.setAssignee(userId),分配个人任务。
3. TaskService.assignTask(taskId, userId)// 把指定的任务分配给指定的人
processEngine.getTaskService().assignTask(taskId, userId);
-->组任务的分配
1. 使用流程变量:assignee="#{userIdsString}" // 要是String型的变量,多个候选人之前用','隔开
2. AssignmentHandler:assignable.addCandidateUser(userId);// 添加组任务的候选人
a) 需要在.jbdl.xml的<task>元素中写
<assignment-handler class="cn.grace.GroupTaskAssignmentHandlerImpl"/>
b) 指定的AssignmentHandlerImpl类要实现AssignmentHandler接口
c) 在AssignmentHandlerImpl类中可以使用assignable.addCandidateUser(userId),添加组任务候选人。
3. TaskService.addTaskParticipatingUser(taskId,userId,Participation.CANDIDATE);//添加组任务的候选人
v. Decision判断活动
1. 使用expression,如:expr="#{'to state2'}"
2. 使用Handler,在Handler Class里配置指定的DecisionHandlerImpl类的路径
DecisionHandlerImpl.java
public class DecisionHandlerImpl implements DecisionHandler { // 计算离开当前节点用的Transition的名称并返回
@Override
public String decide(OpenExecution execution) {
System.out.println("DecisionHandlerImpl.decide()");
// 获取业务数据
Integer days = (Integer) execution.getVariable("请假天数");
// 选择Transition
if (days > 7) {
return "to 总经理审批";
} else {
return "to end1";
}
}
}
ProcessTest.java
@Test
public void test() {
// 1,部署流程定义
InputStream in = this.getClass().getResourceAsStream("test.jpdl.xml"); // 当前类所在包中的文件
processEngine.getRepositoryService()//
.createDeployment()//
.addResourceFromInputStream("test.jpdl.xml", in)//
.deploy(); // 2,启动流程实例
Map<String, Object> variables = new HashMap<String, Object>();
// variables.put("请假天数", 10);启动流程实例后,进行到to 总经理审批环节。
variables.put("请假天数", 3);//启动流程实例后,进行到to end1环节。
ProcessInstance pi = processEngine.getExecutionService().startProcessInstanceByKey("test", variables);
}
此时,如果variables.put("请假天数", 3);启动流程实例后,进行到to end1环节。
此时,如果variables.put("请假天数", 10);启动流程实例后,进行到to 总经理审批环节。
3. 如果同时配置了expression与Handler,则expression有效,忽略Handler。
vi. fork、join分支/聚合活动
public class ProcessTest { private ProcessEngine processEngine = Configuration.getProcessEngine(); @Test
public void test() {
// 1,部署流程定义
InputStream in = this.getClass().getResourceAsStream("test.jpdl.xml"); // 当前类所在包中的文件
processEngine.getRepositoryService()//
.createDeployment()//
.addResourceFromInputStream("test.jpdl.xml", in)//
.deploy(); // 2,启动流程实例
ProcessInstance pi = processEngine.getExecutionService().startProcessInstanceByKey("test");
System.out.println("processInstanceId = " + pi.getId());
System.out.println("当前正在执行的活动:" + pi.findActiveActivityNames());
}
}
输出结果为:
processInstanceId = test.330007
当前正在执行的活动:[汇款, 发货]
可以看出,汇款和发货同时执行中。并且,只有当2条路线都到join活动,流程才会继续往后执行。
b) 自定义活动(custom)
i. 在<custom>元素中指定class属性为指定的类ExternalActivityBehaviourImpl
ii. 这个类要实现ExternalActivityBehaviour接口,其中有两个方法:
1. execute(ActivityExecution):节点的功能代码
2. signal(ActivityExecution, String, Map):在当前节点等待时,外部发信号时的行为
3. 在execute()方法中,可以调用以下方法对流程进行控制
a) ActivityExecution.waitForSignal():在当前节点等待。
b) ActivityExecution.takeDefaultTransition():使用默认的Transition离开,当前节点中定义的第一个为默认的。
c) ActivityExecution.take(String transitionName):使用指定的Transition离开
d) ActivityExecution.end():结束流程实例
4. 也可以实现ActivityBehaviour接口,只有一个方法execute(ActivityExecution),这样就不能等待,否则signal时会有类转换异常。
public class ExternalActivityBehaviourImpl implements ExternalActivityBehaviour { // 到达这个活动时执行的方法
@Override
public void execute(ActivityExecution execution) throws Exception {
System.out.println("已发送信息.");//此处写自己要执行的事件 // 默认是执行完代码后离开当前活动,不会执行signal方法,也可以写如下代码
// execution.takeDefaultTransition(); // 离开当前活动 // // 使用指定名称的Transition离开当前活动
// execution.take(transitionName); // 执行完后不要离开,而是要等待外部调用signal()方法时才离开
execution.waitForSignal();
} // 调用signal()方法离开当前节点前执行的方法(如果在execute()中直接离开当前节点了,这个方法就不会被执行)
@Override
public void signal(ActivityExecution execution, String signalName, Map<String, ?> parameters) throws Exception {
System.out.println("ExternalActivityBehaviourImpl.signal()");
}
}
3.事件
a) 在根元素中,或在节点元素中,使用<on event="">元素指定事件,其中event属性代表事件的类型。
b) 在<on>中用子元素<event-listener class="EventListenerImpl" />,指定处理的类,要求指定的类要实现EventListener接口
c) 事件类型:
i. <on>元素放在根元素(<process>)中,可以指定event为start或end,表示流程的开始与结束。
ii. <on>元素放在节点元素中,可以指定event为start或end,表示节点的进入与离开
iii. 在Start节点中只有end事件,在End节点中只有start事件。
iv. 在<transition>元素中直接写<event-listener class="">,就是配置事件。(因为在这里只有一个事件,所以不用写on与类型)
v. 在<task>元素中还可以配置assign事件,是在分配任务时触发的。
<?xml version="1.0" encoding="UTF-8"?> <process name="test" xmlns="http://jbpm.org/4.4/jpdl"> <!-- 流程实例的启动事件 -->
<on event="start">
<event-listener class="cn.grace.EventListenerImpl"></event-listener>
</on>
<!-- 流程实例的结束事件 -->
<on event="end">
<event-listener class="cn.grace.EventListenerImpl"></event-listener>
</on> <start name="start1" g="86,69,7,1">
<!-- 开始活动中只有离开活动的事件 -->
<on event="end">
<event-listener class="cn.grace.EventListenerImpl"></event-listener>
</on>
<transition name="to task1" to="task1" g="-53,-17" />
</start> <task name="task1" g="61,171,92,52" assignee="张三">
<!-- 进入活动的事件 -->
<on event="start">
<event-listener class="cn.grace.EventListenerImpl"></event-listener>
</on>
<!--离开活动的事件 -->
<on event="end">
<event-listener class="cn.grace.EventListenerImpl"></event-listener>
</on>
<transition name="to end1" to="end1" g="-47,-17" />
</task> <end name="end1" g="86,272,48,48">
<!-- 结束活动中只有进入活动的事件 -->
<on event="start">
<event-listener class="cn.grace.EventListenerImpl"></event-listener>
</on>
</end>
</process>
根据上述.jpdl.xml和对应的.png图,启动流程实例会执行3次EventListenerImpl事件,结束流程实例也会执行3次EventListenerImpl事件。
JBPM学习(六):详解流程图的更多相关文章
- iPhone应用开发 UITableView学习点滴详解
iPhone应用开发 UITableView学习点滴详解是本文要介绍的内容,内容不多,主要是以代码实现UITableView的学习点滴,我们来看内容. -.建立 UITableView DataTab ...
- Eclipse IDE for C/C++ Developers和MinGW安装配置C/C++开发学习环境详解
Eclipse IDE for C/C++ Developers和MinGW安装配置C/C++开发学习环境详解 操作系统:Windows 7 JDK版本:1.6.0_33 Eclipse版本:Juno ...
- 框架基础学习之--详解web+maven+spring+mybatis+struts框架文件夹作用
详解web+maven+spring+mybatis+struts框架文件夹作用 1.程序名 2.Mybatis,mybatis是数据持久层,就是和对象类有关系的东西 3.存放java文件,xml,p ...
- css学习--inline-block详解及dispaly:inline inline-block block 三者区别精要概括
*知识储备: 内联元素:是不可以控制宽和高.margin等:并且在同一行显示,不换行. 块级元素:是可以控制宽和高.margin等,并且会换行. 1.inline-block 详解 (1)一句话就是在 ...
- mybatis 学习笔记 -详解mybatis 及实例demo
快速入门1 要点: 首先明白mybatis 是什么 这是一个持久层的框架.之前叫做ibatis.所以,在它的代码中出现ibatis这个词的时候,不要感到惊讶.不是写错了,它确实就是这个样子的. 首先, ...
- 这个贴子的内容值得好好学习--实例详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化
感觉要DJANGO用得好,ORM必须要学好,不管理是内置的,还是第三方的ORM. 最最后还是要到SQL.....:( 这一关,慢慢练啦.. 实例详解Django的 select_related 和 p ...
- JBPM工作流(七)——详解流程图
概念: 流程图的组成: a. 活动 Activity / 节点 Node b. 流转 Transition / 连线(单向箭头) c. 事件 1.流转(Transition) a) 一般情况一个活动中 ...
- ASP.NET Core MVC 源码学习:详解 Action 的激活
前言 在 上一篇 文章中,我们已经学习了 ASP.NET Core MVC 的启动流程,那么 MVC 在启动了之后,当请求到达过来的时候,它是怎么样处理的呢? 又是怎么样把我们的请求准确的传达到我们的 ...
- ASP.NET Core MVC 源码学习:详解 Action 的匹配
前言 在 上一篇 文章中,我们已经学习了 ASP.NET Core MVC 的启动流程,那么 MVC 在启动了之后,当请求到达过来的时候,它是怎么样处理的呢? 又是怎么样把我们的请求准确的传达到我们的 ...
随机推荐
- JS数据类型&&typeof&&其他
1. 5种基本数据类型: 1. String 2. Number 3. Boolean 4. Undefined 5. Null 2. 1种复杂数据类型:Object 3. 检测变量的数据类型:typ ...
- int([x[, base]]) : 将一个字符转换为int类型,base表示进制
int([x[, base]]) : 将一个字符转换为int类型,base表示进制 >>> int(-12) -12 >>> int(-12.00) -12 > ...
- Codeforces Round #209 (Div. 2)
A: 要么是两次要么4次,判断是否在边界: #include<cstdio> using namespace std; int main() { int n,m,x; ; scanf(&q ...
- asp.net DropDownList无刷新ajax二级联动实现详细过程
只适合新手制作DropDownList无刷新ajax二级联动效果: 数据库实现,添加两表如图:表1,pingpai,表2,type,具体数据库实现看自己的理解: //页面主要代码: <asp:S ...
- ALT+数字,可输入汉字或拉丁字母 good
各种编码查询表:http://bm.kdd.cc/ 输入 ALT + 50385 就出 难 字了,原因是它的十六进制ANSI编码是C4D1=50385 同理: 汉=BABA=47802字=D7D6=5 ...
- 让QT编译快一点(增加基础头文件)
姚冬,中老年程序员 进藤光.杨个毛.欧阳修 等人赞同 我是来反对楼上某些答案的.我曾经用MFC写了金山词霸(大约20多万行),又用Qt写了YY语音(大约100多万行),算是对两种框架都比较有经验.纠正 ...
- 如何迁移SharePoint 2010至新的站点
SharePoint使用非常方便,但是有一个问题获取会困扰大家,就是SharePoint的备份和迁移.下面我们来看一下如何把SharePoint迁移至别的SharePoint站点. 1. 使用网站集管 ...
- string.Split函数
正文 string str = "a---b---c"; string[] array = str.Split(new char[]{'-'}); 分割之后array中的元素为 分 ...
- bzoj3698
显然是有源有汇有下界最大流,不刷不知道,一刷吓一跳发现了我之前求有源有汇有下界最大流的错误,具体见我那篇介绍有下界的网络流的解题报告(bzoj2502),已经更正 ; type node=record ...
- hadoop的wordcount例子运行
可以通过一个简单的例子来说明MapReduce到底是什么: 我们要统计一个大文件中的各个单词出现的次数.由于文件太大.我们把这个文件切分成如果小文件,然后安排多个人去统计.这个过程就是”Map”.然后 ...