业务流程包括三部分:

  1. 活动 Activity / 节点 Node (有很多种,不同的类型有不同的功能,必须要有一个Start Activity)
  2. 连线 Transition / 转移 (从一个Activity指向另一个Activity)
  3. 事件 Event

Transition

开始活动中有且只能有一个连线,并且一个流程实例启动后,会在开始活动之后的一个活动处停下,所以只能有一个开始活动和连线.结束活动不能有连线.其它的活动可以一个或多个连线.当有一个或多个连线的时候,必须使用指定的连线名称离开当前活动,不指定连线名称默认为null,最多只能有一个名称为null的连线名称.相应的语法为:

TaskService.completeTask(taskId, outcome);

指定的连线的名称一定要和流程图上的连线名称相同,包括空格.如果没有找到相应的连线,则会抛出异常。

jBPM4.4中有很多地方都要用到连线名称,其API中也有很多种叫法,比如outcome、signalName、transionName  都是表示Transition的名称.variables、parameters都是表示流程变量的集合Map。

Activity

活动分为两种:预定义活动和自定义活动. 预定义活动就是可以可以直接使用的活动.比如Start,End等.

下面就对几种常见的预定义活动进行说明:

开始活动/Start

表示流程的开始,一个流程图中有且只能有一个Start.而且Start必须要有且只能有一个Transition.不能有其他的Transition指向Start,流程实例启动后,会离开开始活动。

结束活动/End

代表流程的结束,一个流程图中可以有0个或多个End.比如:

如果没有End,则执行完没有Transition的活动后,流程就结束了。

如果有多个End,则执行到其中任意一个End,流程就结束了。

任务活动/Task

代表在这里需要有一个人来做事情,事情做完后流程才能继续向后执行。

指定任务办理人时,可以使用assignee属性来指定。

生成任务时,默认只有这个指定的人才能看到任务和办理这个任务。

判断活动/Decision

使用Decision时要指定一个DecisionHandler的实现类来处理.比如有这么一个流程实例:

如果不大于2000,则部门经理直接办理,超过2000就要找总经理.要进行这个逻辑判断就要使用Decision,建立一个类实现DecisionHandler接口:

@SuppressWarnings("serial")
public class DecisionHandlerImpl implements DecisionHandler { // 进行计算,得出并返回应使用的连线的名称
@Override
public String decide(OpenExecution execution) {
int money = (Integer) execution.getVariable("报销金额");
System.out.println("DecisionHandlerImpl.decide() ---> 报销金额=" + money); if (money > 2000) {
return "to 总经理审批";
} else {
return "to end1";
}
} }

我们说了流程变量的生命周期与流程实例的生命周期相同,金额由流程变量带过去.处理器类在Decision的Handler Class属性中指定。

分支/聚合 Fork/Join

Fork与Join要成对地使用.从一个Fork中分出的多个分支一定要再回到同一个Join中去.当流程执行到Fork中时,ProcessInstance会分成多个并行执行的子Execution,因为ProcessInstance继承自Execution,并且是个标记接口,所以说ProcessInstance只是一个概念,它是想表示整个Execution的执行,也就是主线的执行。

public interface ProcessInstance extends Execution {
}

跑题了,回来继续.当流程执行到Fork时,会分成多个并行执行的子Execution,当所有的分支都执行完到达Join的时候,流程才会继续向Join后执行:

上面这个流程实例就是指:当部门经理和总经理都同意的情况下,不管是谁先同意,就继续执行。

状态活动/State

状态活动可以这样理解:如果说Task是等待人来办理的话,那么State就是等待计算机来办理.因为State除了有一个Name的属性外,没有其他的属性了,而且流程执行到State这里会停住,直到你告诉它要继续的时候它才会往后执行.你唯一可以做的就是给它一个"信号".假设有这样一个流程实例:

有两个State,在流程实例启动的时候会遇到State1,然后停住,等待"信号",在上面的时候说过.outcome、signalName、transionName 都是表示Transition的名称.但是与其他活动的行为不同,其他的活动,比如Task,在没有找到相应的Transition时,会抛异常,而State则什么也不做:

// 让流程向后执行一步
@Test
public void singal() {
// 让指定的Execution离开当前所在的节点,继续向后执行
String executionId = "test.380007"; // 当只有一条Transition时,会使用这个Transition离开当前活动
// 如果有多条Transition,但没有指定要用哪一个,则不会离开节点,也不报错。
// processEngine.getExecutionService().signalExecutionById(executionId); // 当有多条Transition时,必须要指下要使用的Transition的名称。
processEngine.getExecutionService().signalExecutionById(executionId, "to state2");
}

上面预定义活动中可以做的任何事情,都可以通过自定义活动来完成。

自定义活动只有两个属性,一个Name,一个Class的全路径名,给它的类要实现ExternalActivityBehaviour接口,假设我要在这个活动中发送邮件,可以这样做:

@SuppressWarnings("serial")
public class ExternalActivityBehaviourImpl implements ExternalActivityBehaviour { // 当流程执到当前活动时要做的事。
@Override
public void execute(ActivityExecution execution) throws Exception {
// 通过流程变量获取要通知的人和要通知的信息
String subject = (String) execution.getVariable("subject");
String[] users = (String[]) execution.getVariable("users"); // 模拟进行通知
for (String user : users) {
System.out.println(user + ",今天下午5点有个会议,会议主题为:" + subject + "。");
} // 执行完后不要离开,等到调用singal方法时才离开。
// execution.waitForSignal(); // 使用指定名称的连线离开当前活动。
// execution.take(transitionName); // 使用默认的(配置中的第1个)Transition离开当前活动。
execution.takeDefaultTransition(); // 如果以上的方法都没有调用,默认是执行完后离开当前活动。
} // 在外部明确的调用signal方法真正离开当前活动之前要做的事
@Override
public void signal(ActivityExecution execution, String signalName, Map parameters) throws Exception {
System.out.println("---> ExternalActivityBehaviourImpl.signal()");
}
}

我们只需要在随意覆写execute()方法,就能做自己想做的事情.里面需要用到的数据还是要通过流程变量带过去。

Task的分配方式

方式一:

Task可以通过assignee属性设置办理人,是具体的某人,也可以指定一个流程变量,会使用计算出的结果(结果要是String类型)表示办理人.

方式二:

利用建立一个类实现AssignmentHandler接口,比如:

@SuppressWarnings("serial")
public class AssignmentHandlerImpl implements AssignmentHandler { @Override
public void assign(Assignable assignable, OpenExecution execution) throws Exception {
// 计算出任务的办理人(可能是获取流程变量,也可能是查询数据库,也可以是其他)
// execution.getVariable(key);
String userId = "赵六"; // 指定任务的办理人
assignable.setAssignee(userId); System.out.println("----> AssignmentHandlerImpl.assign()");
} }

把最后的结果(String类型)用setAssignee()方法设置办理人.这需要先在xml文件中加上assignment-handler标签,写上全类路径名:

<task name="task1" g="86,175,92,52">
<assignment-handler class="cn.zhangao.AssignmentHandlerImpl">assignment-handler>
<transition name="to end1" to="end1" g="-47,-17" />
task>

方式三:

直接在程序中指定,userId的类型为字符串:

processEngine.getTaskService().assignTask(taskId, userId);

这三种方式都只能分配给个人,下面三种方式可能分配给组:

方式一:

指定candidate-users属性,可以指定为具体的String(多个人之间用英文的逗号隔开),也可以指定一个流程变量,会使用计算出的结果(要是String类型,多个人之间用逗号隔开)表示候选人.

方式二:

实现AssignmentHandler接口,用assignable.addCandidateUser(userId)方法添加一个组成员(候选人)

方式三:

程序中指定:

processEngine.getTaskService().addTaskParticipatingUser(taskId, userId, Participation.CANDIDATE);

注意,组任务必须要查询组的任务列表才能看到:

// 查询某人的组任务列表(以组的名义去查询)
@Test
public void findGroupTasks() {
// String userId = "张3";
String userId = "王5"; // 查询
// List list = processEngine.getTaskService().findGroupTasks(userId);
List list = processEngine.getTaskService()//
.createTaskQuery()//
.candidate(userId)//
.list(); // 显示
System.out.println("=========== [" + userId + "]的组任务列表 ==========");
for (Task t : list) {
System.out.println("id=" + t.getId()//
+ ", name=" + t.getName()// 任务的名称
+ ", assignee=" + t.getAssignee()// 任务的办理人
+ ", createTime=" + t.getCreateTime() // 任务的创建时间
+ ", executionId=" + t.getExecutionId()); // 任务所属的Execution的id
}
}

在个人里面是看不到的,找到自己的组任务后,可以通过"拾取"任务把任务变为个人任务,这样自己就能办理了:

// 拾取任务
@Test
public void takeTask() {
String taskId = "450008";
String userId = "王5"; processEngine.getTaskService().takeTask(taskId, userId);
}

变为个人任务后,在组任务查询中就查不到了.

事件/Event

事件只能自己手动在xml文件中添加.

  1. 在根元素中,或在节点元素中,使用元素指定事件,其中event属性代表事件的类型。
  2. 在中用子元素,指定处理的类,要求指定的类要实现EventListener接口

事件类型:

  • 元素放在根元素()中,可以指定event为start或end,表示流程的开始与结束。
  • 元素放在节点元素中,可以指定event为start或end,表示节点的进入与离开
  • 在Start节点中只有end事件,在End节点中只有start事件。
  • 在元素中直接写,就是配置事件。(因为在这里只有一个事件,所以不用写on与类型)
  • 在元素中还可以配置assign事件,是在分配任务时触发的。

本文转自:http://blog.csdn.net/zhangao0086/article/details/6327406

JBPM表达业务流程(流程定义语言)的更多相关文章

  1. JBPM4.4_jBPM4.4的流程定义语言(设计流程)

    1. jBPM4.4的流程定义语言(设计流程) 1.1. process(流程) 是.jpdl.xml的根元素,可以指定的属性有: 属性名 作用说明 name 流程定义的名称,用于显示. key 流程 ...

  2. Activiti流程定义语言

    1.流程(process) bpmn文件一个流程的根元素.一个流程就代表一个工作流. 2.顺序流(sequenceFlow) 顺序流是连接两个流程节点的连线,代表一个节点的出口.流程执行完一个节点后, ...

  3. 实例演示使用RDIFramework.NET 框架的工作流组件进行业务流程的定义—请假申请流程-Web

    实例演示使用RDIFramework.NET 框架的工作流组件 进行业务流程的定义—请假申请流程-Web 参考文章: RDIFramework.NET — 基于.NET的快速信息化系统开发框架 — 系 ...

  4. jbpm部署流程定义到MySql报乱码解决方案

    问题起因: 我在使用ant将流程定义和流程相关资源部署到JBPM数据库中的时候,报了下面一个错误. 错误提示,大概是: 11:33:40,781 ERROR JDBCExceptionReporter ...

  5. jBPM学习之部署流程定义

    也许部署流程定义的方法有很多,这里选用的是用Java代码调用工作流引擎提供的部署服务API.在这之前,假设你的Eclipse已经安装好了GPD工作流画图工具,并且学会了画出最简单的HelloWorld ...

  6. JBPM学习(三):管理流程定义

    概念: ProcessDefinition,流程定义:一个流程的步骤说明,如一个请假流程.报销流程.是一个规则. ProcessDefinition,流程定义对象,是解析.jpdl.xml文件得到流程 ...

  7. JBPM工作流(四)——管理流程定义

    概念: ProcessDefinition,流程定义:一个流程的步骤说明,如一个请假流程.报销流程.是一个规则. ProcessDefinition,流程定义对象,是解析.jpdl.xml文件得到流程 ...

  8. JBPM4入门——5.流程定义的发布、查询、删除

    本博文只是简要对JBPM4进行介绍,如需更详细内容请自行google 链接: JBPM入门系列文章: JBPM4入门——1.jbpm简要介绍 JBPM4入门——2.在eclipse中安装绘制jbpm流 ...

  9. Activiti7流程定义

    一.什么是流程定义 流程定义是线下bpmn2.0标椎去描述业务流程,通常使用activiti-explorer(web控制台)或 activiti-eclipse-designer 插件对业务流程进行 ...

随机推荐

  1. css行内样式

    <title>归园田居</title> </head> <body> <h2>归园田居</h2> <p>种豆南山下, ...

  2. Tor

    参考: http://www.douban.com/group/topic/67555786/ http://blog.sina.com.cn/s/blog_72a7ac670101km46.html ...

  3. nested exception is org.xml.sax.SAXParseException; lineNumber: 8; columnNumber: 56; cvc-complex-type.2.4.c通配符的匹配很全面, 但无法找到元素 'dubbo:application' 的声明

    严重: Exception sending context initialized event to listener instance of class org.springframework.we ...

  4. Expected MultipartHttpServletRequest: is a MultipartResolver configured?

    2015-05-05 19:09:47.510::WARN: /purchase/long-term-contract/uploading.htmjava.lang.IllegalArgumentEx ...

  5. 66. 有序数组构造二叉搜索树[array to binary search tree]

    [本文链接] http://www.cnblogs.com/hellogiser/p/array-to-binary-search-tree.html [题目] 编写一个程序,把一个有序整数数组放到二 ...

  6. 如何利用phpize在生产环境中为php添加新的扩展php-bcmath

    在日常的开发当中,随着开发的功能越来越复杂.对运行环境的要求也就随着需求的变化需要不断地更新和变化.一个在线的生产系统不可能一开始就满足了所有的运行依赖,因此动态地添加依赖就显得比较必要了.如果你的应 ...

  7. Android 中“TabBar”的背景拉伸问题

    在最近的一个工程中,要求有一个在上方了tabbar,上面有并排的3个方形按钮,每个按钮都有背景图.问题来了,如何让图片在不同尺寸的屏幕上不失真呢?(由于我们的项目比较小,工时很短,不能为每一个屏幕尺寸 ...

  8. mybatis中的oracle和mysql分页

    这段时间一直在用mybatis+spring+springMVC的框架,总结点东西吧. mybatis的oracle分页写法: <?xml version="1.0" enc ...

  9. VS 高亮显示不带后缀的C++头文件

    工具-选项-文本编辑器-文件扩展名-勾选“将无扩展名文件映射到(M)” Microsoft Visual C++

  10. 面向服务的体系结构(SOA)——(2)ESB介绍及职责

    企业服务总线(Enterprise Service Bus)是SOA的基础设施,之所以这么说是因为要达到SOA的目标(增强灵活性)就必须有调用服务的方法,ESB的存在有效的保证了消费者能够调用供应者提 ...