JBPM4

一、 JBPM4的结构特点
1.嵌入式的工作流引擎,不需要依赖特定的中间件或服务器,减少了硬件和软件的绑定,完全支持嵌入式应用的
  业务流程开发框架,可以在事务处理、数据持久化等各个方面与业务应用程序进行灵活的集成。
2.可拔插的体系架构,采用模块化的架构设计,采用了IOC的设计理念,各模块之间可以比较方便地解除耦合或
  替换不同的实现,例如持久化、事务处理、身份认证、日志服务等,都由可选模块实现。
3. 易扩展的流程语言。


二、 Jbpm4的安装配置
1.下载地址:http://sourceforge.net/projects/jbpm/
2.解压资源包,进入目录install,在控制台下运行脚本:ant demo.setup.tomcat。会执行如下操作:
   1)下载安装Tomcat.
   2)安装HSQLDB,并创建数据表结构。
   3)启动Tomcat,创建examples.bar业务流程归档,并发布到JBPM数据库中,初始化相关用户和组。
   4)下载安装Eclipse,并启动Eclipse.
   5)安装JBPM Web控制台。
   6)安装Signavio Web 设计器。
3.在Eclipse中安装GPD插件,利用eclipse的软件升级指定GPD安装文件,文件为
  下载资源包中install/src/gpd/jbpm-gpd-site.zip。
4.添加jbdl4 Schema检验,在eclipse中配置schema,指定jbpm4安装目录下src文件夹中jpdl.xsd文件。
  步骤为:Window->Preferences->XML->XML CataLog->Add->File System。


三、 Jbpm流程API
1.流程相关概念
  流程定义:对业务过程步骤的描述,表现为若干"活动"节点通过"转移"线条串联。
  流程实例:表示流程定义在运行时特有的执行例程。
  流程执行:流程实例在其生命周期中,指向当前执行活动的指针。


2.流程的6个Service API,可通过流程引擎对象的接口方法获取。
   ProcessEngine processEngine = Configuration.getProcessEngine(); 
   1)RepositoryService,流程资源服务的接口。提供对流程定义的部署、查询、删除等操作。
   2)ExecutionService,流程执行服务的接口。提供启动流程实例、“执行”推进、设置流程变量等操作。
   3)TaskService,人工任务服务的接口。提供对任务的创建、提交、查询、保存、删除等操作。
   4)HistoryService,流程历史服务的接口。提供对流程历史库中历史流程实例、历史活动实例等记录的查询操作。
   5)IdentityService,身份认证服务的接口。提供对流程用户、用户组以及组成员关系的相关服务。
   6)ManagementService,流程管理控制服务的接口。提供异步工作(Job)相关的执行和查询操作。

 

3.流程的布署和删除
   1)流程的布署  

Java代码 复制代码  收藏代码
  1. String deploymentId = repositoryService.createDeployment()   
  2. .addResourceFromClasspath("org/jbpm/examples/task/assignee/process.jpdl.xml") .deploy();  
  3.  // 可多次调用addResourceFromClasspath方法部署其它流程定义  
String deploymentId = repositoryService.createDeployment() 
.addResourceFromClasspath("org/jbpm/examples/task/assignee/process.jpdl.xml") .deploy();
 // 可多次调用addResourceFromClasspath方法部署其它流程定义

  

  2)流程的删除

Java代码 复制代码  收藏代码
  1. repositoryService.deleteDeploymentCascade(deploymentId);   
repositoryService.deleteDeploymentCascade(deploymentId);

  

 4.发起流程实例
  1)流程Key 

Java代码 复制代码  收藏代码
  1. ProcessInstance processInstance = executionService.startProcessInstanceByKey("ICL");  
ProcessInstance processInstance = executionService.startProcessInstanceByKey("ICL");

 

  2)流程Id

Java代码 复制代码  收藏代码
  1. ProcessInstance processInstance = executionService.startProcessInstanceByKey("ICL-1");  
ProcessInstance processInstance = executionService.startProcessInstanceByKey("ICL-1");

 

  3)根据业务键指定流程实例ID

Java代码 复制代码  收藏代码
  1. ProcessInstance processInstance = executionService.startProcessInstanceByKey ("ICL",“Order09278”);  
ProcessInstance processInstance = executionService.startProcessInstanceByKey ("ICL",“Order09278”);

 

  4)传入流程变量

Java代码 复制代码  收藏代码
  1. ProcessInstance processInstance = executionService.startProcessInstanceByKey ("ICL", variablesMap);  
ProcessInstance processInstance = executionService.startProcessInstanceByKey ("ICL", variablesMap);

  

5.唤醒等待状态的执行

Java代码 复制代码  收藏代码
  1. executionService.signalExecutionById(executionId);  
executionService.signalExecutionById(executionId);

  

6.获得用户的任务列表

Java代码 复制代码  收藏代码
  1. List<Task> taskList = taskService.findPersonalTasks("johndoe");  
List<Task> taskList = taskService.findPersonalTasks("johndoe");

 

 

7.任务的完成提交
  1)将用户界面的任务表单内容存入任务

Java代码 复制代码  收藏代码
  1. taskService.setVariables(taskId,variablesMap);  
taskService.setVariables(taskId,variablesMap);

 

   2)根据任务ID完成任务

Java代码 复制代码  收藏代码
  1. taskService.completeTask(taskId);  
taskService.completeTask(taskId);

 

   3)根据任务ID完成任务,同时设入变量

Java代码 复制代码  收藏代码
  1. taskService.completeTask(taskId, variablesMap);  
taskService.completeTask(taskId, variablesMap);

 

   4)根据任务ID完成任务,并指定下一步的转移路径

Java代码 复制代码  收藏代码
  1. taskService.completeTask(taskId, outcome);  
taskService.completeTask(taskId, outcome);

 

 

8.流程历史实例获取
  1)获得流程定义的所有历史流程实例,返回结果按开始时间排序 

Java代码 复制代码  收藏代码
  1. List<HistoryProcessInstance> historyProcessInstances = historyService  
  2.  .createHistoryProcessInstanceQuery() .processDefinitionId("ICL-1")   
  3. .orderAsc(HistoryProcessInstanceQuery.PROPERTY_STARTTIME).list();  
List<HistoryProcessInstance> historyProcessInstances = historyService
 .createHistoryProcessInstanceQuery() .processDefinitionId("ICL-1") 
.orderAsc(HistoryProcessInstanceQuery.PROPERTY_STARTTIME).list();

 

   2)获得流程的历史活动实例,可指定具体名称的活动实例 

Java代码 复制代码  收藏代码
  1. List<HistoryActivityInstance> historyActivityInstances = historyService  
  2.  .createHistoryActivityInstanceQuery().processDefinitionId("ICL-1").list();  
List<HistoryActivityInstance> historyActivityInstances = historyService
 .createHistoryActivityInstanceQuery().processDefinitionId("ICL-1").list();

  

 9.查询结果分页
  1)流程实例查询分页

Java代码 复制代码  收藏代码
  1. List<ProcessInstance> results = executionService.createProcessInstanceQuery()  
  2.  .processDefinitionId("ICL-1").page(050).list();  
List<ProcessInstance> results = executionService.createProcessInstanceQuery()
 .processDefinitionId("ICL-1").page(0, 50).list();

 

   2)流程任务查询的分页

Java代码 复制代码  收藏代码
  1. List<Task> myTasks = taskService.createTaskQuery()  
  2. .processInstanceId("ICL.Order09278") .assignee("Alex")  
  3. .page(1020).list();  
List<Task> myTasks = taskService.createTaskQuery()
.processInstanceId("ICL.Order09278") .assignee("Alex")
.page(10, 20).list();

  

四、 流程定义

  

1.流程控制活动
  1)start,开始活动
  2)state,状态活动
  3)decision,判断活动
  4)fork,分支活动
  5)join,聚合活动
  6)end,结束活动

 

 


2.State活动

JBPM4

Jpdl定义:

Xml代码 复制代码  收藏代码
  1. <state name="wait for response">   
  2. <transition name="accept" to="submit document" />   
  3. <transition name="reject" to="try again"/>  
  4.  </state>  
  5.  <state name="submit document"/>   
  6. <state name="try again"/>  
<state name="wait for response"> 
<transition name="accept" to="submit document" /> 
<transition name="reject" to="try again"/>
 </state>
 <state name="submit document"/> 
<state name="try again"/>

  

// 获取流程实例ID

Java代码 复制代码  收藏代码
  1. String executionId = processInstance.findActiveExecutionIn("wait for response").getId();  
  2.  // 触发accept流向   
  3. processInstance = executionService.signalExecutionById(executionId, "accept");   
String executionId = processInstance.findActiveExecutionIn("wait for response").getId();
 // 触发accept流向 
processInstance = executionService.signalExecutionById(executionId, "accept");

  

3.decision活动
   1)使用condition元素判断decision活动 

JBPM4

Jpdl:

Xml代码 复制代码  收藏代码
  1. <!-- decision 中会运行并判断每一个transition 里的判断条件。   
  2. 当遇到一个嵌套条件是true 或者没有设置判断条件的转移,  
  3. 那么转移就会被运行 -->   
  4. <decision name="evaluate document" >   
  5. <transition to="submit document" >   
  6. <condition expr="#{content==’good’}" />   
  7. </transition>   
  8. <transition to="try again">   
  9. <condition expr="#{content==’bad’}" />   
  10. </transition>   
  11. <transition to="give up"/>   
  12. </decision>   
  13. <state name="submit document"/>   
  14. <state name="try again"/>   
  15. <state name="give up"/>  
<!-- decision 中会运行并判断每一个transition 里的判断条件。 
当遇到一个嵌套条件是true 或者没有设置判断条件的转移,
那么转移就会被运行 --> 
<decision name="evaluate document" > 
<transition to="submit document" > 
<condition expr="#{content==’good’}" /> 
</transition> 
<transition to="try again"> 
<condition expr="#{content==’bad’}" /> 
</transition> 
<transition to="give up"/> 
</decision> 
<state name="submit document"/> 
<state name="try again"/> 
<state name="give up"/>

  

Java代码 复制代码  收藏代码
  1. Map<String, Object> variables = new HashMap<String, Object>(); variables.put("content""good");  
  2.  // 由于传入变量为good,流向了submit document活动   
  3. ProcessInstance processInstance = executionService  
  4.  .startProcessInstanceByKey("DecisionConditions", variables);   
Map<String, Object> variables = new HashMap<String, Object>(); variables.put("content", "good");
 // 由于传入变量为good,流向了submit document活动 
ProcessInstance processInstance = executionService
 .startProcessInstanceByKey("DecisionConditions", variables);

 

  2)使用decision的expr属性判断decision活动。

Xml代码 复制代码  收藏代码
  1. <!--可选择的状态结点,expr指定将被运行的指定脚本 -->  
  2.  <decision name="evaluate document" expr="#{content}" >  
  3.  <transition name="good" to="submit document"/>  
  4.  <transition name="bad" to="try again"/>   
  5. <transition name="ugly" to="give up"/>   
  6. </decision>  
<!--可选择的状态结点,expr指定将被运行的指定脚本 -->
 <decision name="evaluate document" expr="#{content}" >
 <transition name="good" to="submit document"/>
 <transition name="bad" to="try again"/> 
<transition name="ugly" to="give up"/> 
</decision>

 

 流程执行操作同上面condition元素的操作。


  3)使用decision活动的handler元素判断decision活动。

Xml代码 复制代码  收藏代码
  1. <!-- decision handler决定处理器继承了DecisionHandler 接口的java 类,   
  2. 决定处理器负责选择向外转移 -->   
  3. <decision name="evaluate document" g="96,102,48,48">   
  4. <handler class="org.jbpm.examples.decision.handler.ContentEvaluation"/>  
  5.  <transition name="good" to="submit document"/>   
  6. <transition name="bad" to="try again"/>   
  7. <transition name="ugly" to="give up"/>   
  8. </decision>  
<!-- decision handler决定处理器继承了DecisionHandler 接口的java 类, 
决定处理器负责选择向外转移 --> 
<decision name="evaluate document" g="96,102,48,48"> 
<handler class="org.jbpm.examples.decision.handler.ContentEvaluation"/>
 <transition name="good" to="submit document"/> 
<transition name="bad" to="try again"/> 
<transition name="ugly" to="give up"/> 
</decision>

    ContentEvaluation类如下:

Java代码 复制代码  收藏代码
  1. public class ContentEvaluation implements DecisionHandler {   
  2. public String decide(OpenExecution execution) {  
  3.  String content = (String) execution.getVariable("content");   
  4. return content; }   
  5. }  
public class ContentEvaluation implements DecisionHandler { 
public String decide(OpenExecution execution) {
 String content = (String) execution.getVariable("content"); 
return content; } 
}

 

 流程执行操作同上面condition元素的操作。 

   Decision活动和state活动都可以实现条件流转,但二者的主要区别如下:
     如果decision活动定义的流转条件没有任何一个得到满足,那么流程实例将无法进行下去,抛出异常。
     而state活动在没有条件满足的条件下将流向state活动定义的第一条流出转移,从而往下流转。
     因此decision活动具有更加严格的条件判断特性。

 

4.fork-join活动

JBPM4

Jpdl:

Xml代码 复制代码  收藏代码
  1. <!-- fork活动在此产生3个并行分支,这些流程分支可以同步执行。 -->  
  2.  <fork name="fork">   
  3. <transition to="send invoice"/>   
  4. <transition to="load truck"/>   
  5. <transition to="print shipping documents"/>   
  6. </fork>   
  7. <state name="send invoice">   
  8. <transition to="final join"/>   
  9. </state>   
  10. <state name="load truck">   
  11. <transition to="shipping join"/>   
  12. </state>   
  13. <state name="print shipping documents">  
  14.  <transition g="378,213:" to="shipping join"/>  
  15.  </state>   
  16. <!--join活动为流程的合并,load truck和print shipping documents在此聚合 -->  
  17.  <join name="shipping join">  
  18.  <transition to="drive truck to destination"/>  
  19.  </join>  
  20.  <state name="drive truck to destination">   
  21. <transition to="final join"/>   
  22. </state>  
  23.  <!-- drive truck to destination活动和send invoice活动在此完成最终的聚合 -->   
  24. <join name="final join">  
  25.  <transition to="end"/>  
  26.  </join>  
<!-- fork活动在此产生3个并行分支,这些流程分支可以同步执行。 -->
 <fork name="fork"> 
<transition to="send invoice"/> 
<transition to="load truck"/> 
<transition to="print shipping documents"/> 
</fork> 
<state name="send invoice"> 
<transition to="final join"/> 
</state> 
<state name="load truck"> 
<transition to="shipping join"/> 
</state> 
<state name="print shipping documents">
 <transition g="378,213:" to="shipping join"/>
 </state> 
<!--join活动为流程的合并,load truck和print shipping documents在此聚合 -->
 <join name="shipping join">
 <transition to="drive truck to destination"/>
 </join>
 <state name="drive truck to destination"> 
<transition to="final join"/> 
</state>
 <!-- drive truck to destination活动和send invoice活动在此完成最终的聚合 --> 
<join name="final join">
 <transition to="end"/>
 </join>

 

Fork活动可以使流程在一条主干上出现并行的分支,join活动则可以使流程的并行分支聚合成一条主干。
部分执行测试代码如下:

Java代码 复制代码  收藏代码
  1. ProcessInstance processInstance = executionService  
  2. .startProcessInstanceByKey("ConcurrencyGraphBased");  
  3. // 当前活动为产生的3个分支活动  
  4. assertNotNull(processInstance.findActiveExecutionIn("send invoice"));  
  5. assertNotNull(processInstance.findActiveExecutionIn("load truck"));  
  6. assertNotNull(processInstance.findActiveExecutionIn("print shipping documents"));  
  7. // 执行send invoice活动,流程会在聚合活动上等待其它分支的到来  
  8. String sendInvoiceExecutionId = processInstance  
  9.     .findActiveExecutionIn("send invoice").getId();  
  10. processInstance = executionService.signalExecutionById(sendInvoiceExecutionId); 


 5.task人工任务活动
   1)、使用task活动的assignee属性进行任务分配

 

 

Xml代码 复制代码  收藏代码
  1. <task name="review" assignee="#{order.owner}">   
  2. <transition to="wait" />   
  3. </task>  
<task name="review" assignee="#{order.owner}"> 
<transition to="wait" /> 
</task>

 

   Assignee属性默认会被作为EL表达式来执行,任务被分配给#{order.owner}。

  

Java代码 复制代码  收藏代码
  1. Map<String, Object> variables = new HashMap<String, Object>();   
  2. variables.put("order"new Order("johndoe"));   
  3. //当一个新流程实例会被创建, 把order 作为一个流程变量分配给它   
  4. ProcessInstance processInstance = executionService   
  5. .startProcessInstanceByKey("TaskAssignee", variables);   
  6. //获取johndoe的任务列表   
  7. List<Task> taskList = taskService.findPersonalTasks("johndoe");   
Map<String, Object> variables = new HashMap<String, Object>(); 
variables.put("order", new Order("johndoe")); 
//当一个新流程实例会被创建, 把order 作为一个流程变量分配给它 
ProcessInstance processInstance = executionService 
.startProcessInstanceByKey("TaskAssignee", variables); 
//获取johndoe的任务列表 
List<Task> taskList = taskService.findPersonalTasks("johndoe");

 

   2)任务侯选者(candidate-groups,candidate-users)
      candidate-groups:一个使用逗号分隔的组id 列表,所有组内的用户将会成为这个任务的 候选人。
      candidate-users: 一个使用逗号分隔的用户id 列表,所有的用户将会成为这个任务的候选人。

 

Xml代码 复制代码  收藏代码
  1. <task name="review" candidate-groups="sales-dept>   
  2. <transition to="wait" />  
  3.  </task>  
<task name="review" candidate-groups="sales-dept> 
<transition to="wait" />
 </task>

 

   部分事例代码如下:

 

Java代码 复制代码  收藏代码
  1. // 创建sales-dept组   
  2. dept = identityService.createGroup("sales-dept");   
  3. // 创建用户johndoe,并加入sales-dept组  
  4.  identityService.createUser("johndoe""John""Doe");   
  5. identityService.createMembership("johndoe", dept, "developer");  
  6.  // 创建用户joesmoe,并加入sales-dept组   
  7. identityService.createUser("joesmoe""Joe""Smoe");   
  8. identityService.createMembership("joesmoe", dept, "developer");   
  9. //在流程创建后, 任务会出现在johndoe 和joesmoe 用户的分组任务列表中   
  10. List<Task> taskList = taskService.findGroupTasks("joesmoe");   
  11. List<Task> taskList = taskService.findGroupTasks("johndoe");   
  12. //候选人在处理任务之前,必须先接受任务,接受任务后,就会由任务的候选者变成   
  13. // 任务的分配者。同时,此任务会从所有候选者的任务列表中消失。   
  14. taskService.takeTask(task.getId(), "johndoe");  
// 创建sales-dept组 
dept = identityService.createGroup("sales-dept"); 
// 创建用户johndoe,并加入sales-dept组
 identityService.createUser("johndoe", "John", "Doe"); 
identityService.createMembership("johndoe", dept, "developer");
 // 创建用户joesmoe,并加入sales-dept组 
identityService.createUser("joesmoe", "Joe", "Smoe"); 
identityService.createMembership("joesmoe", dept, "developer"); 
//在流程创建后, 任务会出现在johndoe 和joesmoe 用户的分组任务列表中 
List<Task> taskList = taskService.findGroupTasks("joesmoe"); 
List<Task> taskList = taskService.findGroupTasks("johndoe"); 
//候选人在处理任务之前,必须先接受任务,接受任务后,就会由任务的候选者变成 
// 任务的分配者。同时,此任务会从所有候选者的任务列表中消失。 
taskService.takeTask(task.getId(), "johndoe");

 

 

   3)任务分配处理器(AssignmentHandler)

 

Xml代码 复制代码  收藏代码
  1. <task name="review">  
  2.  <!--assignment-handler 是任务元素的一个子元素,它指定用户代码对象 -->   
  3. <assignment-handler   
  4. class="org.jbpm.examples.task.assignmenthandler.AssignTask">   
  5. <field name="assignee">   
  6. <string value="johndoe" />   
  7. </field>   
  8. </assignment-handler>   
  9. <transition to="wait" />   
  10. </task>  
<task name="review">
 <!--assignment-handler 是任务元素的一个子元素,它指定用户代码对象 --> 
<assignment-handler 
class="org.jbpm.examples.task.assignmenthandler.AssignTask"> 
<field name="assignee"> 
<string value="johndoe" /> 
</field> 
</assignment-handler> 
<transition to="wait" /> 
</task>

 

   AssignTask类必须实现AssignmentHandler类,代码如下:

  

Java代码 复制代码  收藏代码
  1. //默认AssignmentHandler 实现可以使用使用流程变量   
  2. public class AssignTask implements AssignmentHandler {   
  3.      String assignee;  
  4.      public void assign(Assignable assignable, OpenExecution execution) {   
  5.        assignable.setAssignee(assignee);  
  6.      }  
  7.  }  
//默认AssignmentHandler 实现可以使用使用流程变量 
public class AssignTask implements AssignmentHandler { 
     String assignee;
     public void assign(Assignable assignable, OpenExecution execution) { 
       assignable.setAssignee(assignee);
     }
 }

  

   4)任务泳道(Swimlanes)
     泳道可以理解为流程定义的”全局用户组”,也可以被当作一个流程规则。流程定义中的多个任务需要被分配或候选给
      同一个群用户,统一将这个“同一群用户”定义为“一个泳道”。

 

Xml代码 复制代码  收藏代码
  1. <!—-在这里定义泳道,属全局用户组-->   
  2. <swimlane name="sales representative" candidate-groups="sales-dept" />   
  3. <!-- swimlane 引用一个定义在流程中的泳道 -->   
  4. <task name="enter order data" swimlane="sales representative">   
  5. <transition to="calculate quote"/>  
  6.  </task>   
  7. <task name="calculate quote" swimlane="sales representative">   
  8. </task>  
  9.   
  10.    
<!—-在这里定义泳道,属全局用户组--> 
<swimlane name="sales representative" candidate-groups="sales-dept" /> 
<!-- swimlane 引用一个定义在流程中的泳道 --> 
<task name="enter order data" swimlane="sales representative"> 
<transition to="calculate quote"/>
 </task> 
<task name="calculate quote" swimlane="sales representative"> 
</task>

 

   泳道中的用户组中的用户在接受任务后成为任务的分配者,同时泳道也会发生变化,接收任务者在流程实例中会被固化为分配者。

Java代码 复制代码  收藏代码
  1. taskService.takeTask(taskId, "johndoe");  
  2.  assertEquals(0, taskService.findGroupTasks("johndoe").size());   
  3. taskList = taskService.findPersonalTasks("johndoe");   
  4. assertEquals(1, taskList.size());   
taskService.takeTask(taskId, "johndoe");
 assertEquals(0, taskService.findGroupTasks("johndoe").size()); 
taskList = taskService.findPersonalTasks("johndoe"); 
assertEquals(1, taskList.size());

  

6.子流程活动(sub-process)


   1)父子流程间的数据交换(parameter-in,parameter-out)
       父流程SubProcessDocument定义JPDL:

Xml代码 复制代码  收藏代码
  1. <process name="SubProcessDocument" xmlns="http://jbpm.org/4.4/jpdl">   
  2. <start>   
  3. <transition to="review" />   
  4. </start>   
  5. <sub-process name="review" sub-process-key="SubProcessReview">   
  6. <parameter-in var="document" subvar="document" />   
  7. <parameter-out var="reviewResult" subvar="result" />   
  8. <transition to="wait" />  
  9.  </sub-process>   
  10. <state name="wait"/>   
  11. </process>  
<process name="SubProcessDocument" xmlns="http://jbpm.org/4.4/jpdl"> 
<start> 
<transition to="review" /> 
</start> 
<sub-process name="review" sub-process-key="SubProcessReview"> 
<parameter-in var="document" subvar="document" /> 
<parameter-out var="reviewResult" subvar="result" /> 
<transition to="wait" />
 </sub-process> 
<state name="wait"/> 
</process>

 

    子流程SubProcessReview定义JPDL:

Xml代码 复制代码  收藏代码
  1. <process name="SubProcessReview" xmlns="http://jbpm.org/4.4/jpdl">   
  2. <start>  
  3.  <transition to="get approval"/>   
  4. </start>  
  5.  <task name="get approval" assignee="johndoe">   
  6. <transition to="end"/>  
  7.  </task>   
  8. <end name="end"/>   
  9. </process>  
  10.    
<process name="SubProcessReview" xmlns="http://jbpm.org/4.4/jpdl"> 
<start>
 <transition to="get approval"/> 
</start>
 <task name="get approval" assignee="johndoe"> 
<transition to="end"/>
 </task> 
<end name="end"/> 
</process>
 

   流程变量是父子流程用来沟通的纽带。父流程在子流程启动时将自己的“父流程变量”输入子流程,
   反之,子流程在结束时可以将自己的“子流程变量”返回父流程,从而实现父子流程间的数据交换。
    部分事例代码如下:

Java代码 复制代码  收藏代码
  1. // 分别部署子流程跟父流程   
  2. String subProcessReviewDeploymentId = repositoryService.createDeployment()   
  3. .addResourceFromClasspath("org/jbpm/examples/subprocess/variables/SubProcessReview.jpdl.xml")  
  4.  .deploy();   
  5. String subProcessDocumentDeploymentId = repositoryService.createDeployment()   
  6. .addResourceFromClasspath("org/jbpm/examples/subprocess/variables/SubProcessDocument.jpdl.xml")   
  7. .deploy();   
  8. Map<String, Object> variables = new HashMap<String, Object>();   
  9. variables.put("document""This document describes how we can make more money...");   
  10. //设置父流程的变量document ProcessInstance processInstance = executionService  
  11.  .startProcessInstanceByKey("SubProcessDocument", variables);   
  12. List<Task> taskList = taskService.findPersonalTasks("johndoe"); Task task = taskList.get(0);  
  13.  // 父流程的变量document会被传入子流程,此处为获取子流程的变量document   
  14. String document = (String) taskService  
  15. .getVariable(task.getId(), "document");   
  16. variables = new HashMap<String, Object>();   
  17. variables.put("result""accept");   
  18. // 在子流程中设置流程变量result,该流程变量可在父流程中获取 taskService.setVariables(task.getId(), variables);  
  19.  taskService.completeTask(task.getId());  
  20.  processInstance = executionService.findProcessInstanceById(processInstance.getId());   
  21. // 在父流程中获取子流程中设置的流程变量result,名称为reviewResult   
  22. String result = (String) executionService  
  23. .getVariable(processInstance.getId(), "reviewResult");   
  24. assertEquals("accept", result);  
// 分别部署子流程跟父流程 
String subProcessReviewDeploymentId = repositoryService.createDeployment() 
.addResourceFromClasspath("org/jbpm/examples/subprocess/variables/SubProcessReview.jpdl.xml")
 .deploy(); 
String subProcessDocumentDeploymentId = repositoryService.createDeployment() 
.addResourceFromClasspath("org/jbpm/examples/subprocess/variables/SubProcessDocument.jpdl.xml") 
.deploy(); 
Map<String, Object> variables = new HashMap<String, Object>(); 
variables.put("document", "This document describes how we can make more money..."); 
//设置父流程的变量document ProcessInstance processInstance = executionService
 .startProcessInstanceByKey("SubProcessDocument", variables); 
List<Task> taskList = taskService.findPersonalTasks("johndoe"); Task task = taskList.get(0);
 // 父流程的变量document会被传入子流程,此处为获取子流程的变量document 
String document = (String) taskService
.getVariable(task.getId(), "document"); 
variables = new HashMap<String, Object>(); 
variables.put("result", "accept"); 
// 在子流程中设置流程变量result,该流程变量可在父流程中获取 taskService.setVariables(task.getId(), variables);
 taskService.completeTask(task.getId());
 processInstance = executionService.findProcessInstanceById(processInstance.getId()); 
// 在父流程中获取子流程中设置的流程变量result,名称为reviewResult 
String result = (String) executionService
.getVariable(processInstance.getId(), "reviewResult"); 
assertEquals("accept", result);

 

 

   2)通过outcome属性影响父流程的流程转移
      父流程SubProcessReview定义:

JBPM4

 

Xml代码 复制代码  收藏代码
  1. <!--父流程中的outcome属性引用名称为result的子流程变量  
  2.  <sub-process name="review" sub-process-key="SubProcessReview" outcome="#{result}">  
  3.  <!—如果result值等于ok,则流向此转移-->   
  4. <transition name="ok" to="next step" />   
  5. <transition name="nok" to="update" />   
  6. <transition name="reject" to="close" />   
  7. </sub-process>  
<!--父流程中的outcome属性引用名称为result的子流程变量
 <sub-process name="review" sub-process-key="SubProcessReview" outcome="#{result}">
 <!—如果result值等于ok,则流向此转移--> 
<transition name="ok" to="next step" /> 
<transition name="nok" to="update" /> 
<transition name="reject" to="close" /> 
</sub-process>

 

   子流程SubProcessReview定义:

Xml代码 复制代码  收藏代码
  1. <start>   
  2. <transition to="get approval"/>  
  3.  </start>   
  4. <task name="get approval" assignee="johndoe">   
  5. <transition to="end"/>   
  6. </task>   
  7. <end name="end" />  
<start> 
<transition to="get approval"/>
 </start> 
<task name="get approval" assignee="johndoe"> 
<transition to="end"/> 
</task> 
<end name="end" />

 

   部分事例代码如下:

Java代码 复制代码  收藏代码
  1. ProcessInstance processInstance = executionService   
  2. .startProcessInstanceByKey("SubProcessDocument");  
  3.  List<Task> taskList = taskService.findPersonalTasks("johndoe");   
  4. Task task = taskList.get(0);  
  5.  Map<String, Object> variables = new HashMap<String, Object>();   
  6. variables.put("result""ok");  
  7.  // 在子流程中设置流程变量result值为ok,这个ok值会被传递给outcome属性以决定父流程的走向。   
  8. taskService.setVariables(task.getId(), variables);   
  9. taskService.completeTask(task.getId());   
  10. processInstance = executionService.findProcessInstanceById  
  11. (processInstance.getId());   
  12. assertNotNull(processInstance.findActiveExecutionIn("next step"));   
ProcessInstance processInstance = executionService 
.startProcessInstanceByKey("SubProcessDocument");
 List<Task> taskList = taskService.findPersonalTasks("johndoe"); 
Task task = taskList.get(0);
 Map<String, Object> variables = new HashMap<String, Object>(); 
variables.put("result", "ok");
 // 在子流程中设置流程变量result值为ok,这个ok值会被传递给outcome属性以决定父流程的走向。 
taskService.setVariables(task.getId(), variables); 
taskService.completeTask(task.getId()); 
processInstance = executionService.findProcessInstanceById
(processInstance.getId()); 
assertNotNull(processInstance.findActiveExecutionIn("next step"));

 

    3)设置不同的子流程end活动名称自动关联父流程的流出转移

      父流程SubProcessReview定义:

Xml代码 复制代码  收藏代码
  1. <sub-process name="review" sub-process-key="SubProcessReview">   
  2. <transition name="ok" to="next step" />   
  3. <transition name="nok" to="update" />   
  4. <transition name="reject" to="close" />   
  5. </sub-process> <state name="next step" />   
  6. <state name="update" />   
  7. <state name="close" />   
<sub-process name="review" sub-process-key="SubProcessReview"> 
<transition name="ok" to="next step" /> 
<transition name="nok" to="update" /> 
<transition name="reject" to="close" /> 
</sub-process> <state name="next step" /> 
<state name="update" /> 
<state name="close" />

 

   子流程SubProcessReview定义:

Xml代码 复制代码  收藏代码
  1. <task assignee="johndoe" name="get approval">  
  2.  <transition name="ok" to="ok"/>   
  3. <transition name="nok" to="nok"/>  
  4.  <transition name="reject" to="state1"/>  
  5.  </task>  
  6.  <end name="ok"/>   
  7. <end name="nok"/>   
  8. <end name="reject"/>  
  9.  <state name="state1" >  
  10.  <transition name="to reject" to="reject"/>   
  11. </state>  
<task assignee="johndoe" name="get approval">
 <transition name="ok" to="ok"/> 
<transition name="nok" to="nok"/>
 <transition name="reject" to="state1"/>
 </task>
 <end name="ok"/> 
<end name="nok"/> 
<end name="reject"/>
 <state name="state1" >
 <transition name="to reject" to="reject"/> 
</state>

 

    部分事例代码如下:

Java代码 复制代码  收藏代码
  1. ProcessInstance processInstance = executionService   
  2. .startProcessInstanceByKey("SubProcessDocument");  
  3.  List<Task> taskList = taskService.findPersonalTasks("johndoe");   
  4. Task task = taskList.get(0);   
  5. //子流程活动结束于ok活动返回父流程实例,父流程会自动地通过名称为ok的转移,   
  6. //进入"next step活动" taskService.completeTask(task.getId(), "ok");   
  7. processInstance = executionService  
  8. .findProcessInstanceById(processInstance.getId());   
  9. assertNotNull(processInstance.findActiveExecutionIn("next step"));   
ProcessInstance processInstance = executionService 
.startProcessInstanceByKey("SubProcessDocument");
 List<Task> taskList = taskService.findPersonalTasks("johndoe"); 
Task task = taskList.get(0); 
//子流程活动结束于ok活动返回父流程实例,父流程会自动地通过名称为ok的转移, 
//进入"next step活动" taskService.completeTask(task.getId(), "ok"); 
processInstance = executionService
.findProcessInstanceById(processInstance.getId()); 
assertNotNull(processInstance.findActiveExecutionIn("next step"));

 

 

7.自定义活动
   如果有特殊而复杂的业务需求,与其生套JBPM本身提供的流转控制活动,不如自己实现一个自定义的活动使用。
Jpdl定义:

 

Xml代码 复制代码  收藏代码
  1. <!-- custom调用用户代码,实现一个自定义的活动行为 -->  
  2.  <custom name="print dots" class="org.jbpm.examples.custom.PrintDots"">   
  3. <transition to="end" />   
  4. </custom>  
<!-- custom调用用户代码,实现一个自定义的活动行为 -->
 <custom name="print dots" class="org.jbpm.examples.custom.PrintDots""> 
<transition to="end" /> 
</custom>

 

 自定义活动的类需实现ExternalActivityBehaviour接口

Java代码 复制代码  收藏代码
  1. public class PrintDots implements ExternalActivityBehaviour {   
  2. // 在流程实例进入到此活动时执行此方法   
  3. public void execute(ActivityExecution execution) {   
  4. // 执行自定义的处理逻辑   
  5. // 使流程陷入“等待”状态   
  6. execution.waitForSignal();  
  7.  }  
  8.  // 在流程实例得到执行信号离开此活动时执行此方法  
  9.  public void signal(ActivityExecution execution, String signalName,   Map<String, ?> parameters)  
  10.  { // 使流程实例进入下一步   
  11. execution.take(signalName);  
  12.  }   
  13. }  
public class PrintDots implements ExternalActivityBehaviour { 
// 在流程实例进入到此活动时执行此方法 
public void execute(ActivityExecution execution) { 
// 执行自定义的处理逻辑 
// 使流程陷入“等待”状态 
execution.waitForSignal();
 }
 // 在流程实例得到执行信号离开此活动时执行此方法
 public void signal(ActivityExecution execution, String signalName,   Map<String, ?> parameters)
 { // 使流程实例进入下一步 
execution.take(signalName);
 } 
}

 

 

8.自动活动
   自动活动是在执行过程中完全无须人工干预地编排好程序,jbpm在处理和执行这些自动活动时能把人工活动产生的数据
   通过流程变量等方式与之完美结合。
  1)java程序活动
  jpdl定义:

Xml代码 复制代码  收藏代码
  1. <!-- java 任务,流程处理的流向会执行 这个活动配置的方法  
  2.  class:完全类名   
  3. method:调用的方法名   
  4. var:返回值存储的 变量名 -->   
  5. <java name="greet" class="org.jbpm.examples.java.JohnDoe"   
  6. method="hello" var="answer" g="96,16,83,52">   
  7. <!--fileld:在方法调用之前给成员变量注入 配置值 -->   
  8. <field name="state">  
  9. <string value="fine"/>  
  10. </field>  
  11.  <!--arg:方法参数 -->   
  12. <arg><string value="Hi, how are you?"/></arg>   
  13. <transition to="shake hand" />   
  14. </java>  
  15.  <!--expr:这个表达式返回方法被调用 产生的目标对象 ,通过对象参数传入(new Hand()-->  
  16.  <java name="shake hand" expr="#{hand}"   
  17. method="shake" var="hand" g="215,17,99,52">   
  18. <!-- 通过表达式引用流程变量,为shake方法提供2个参数 -->   
  19. <arg><object expr="#{joesmoe.handshakes.force}"/></arg>   
  20. <arg><object expr="#{joesmoe.handshakes.duration}"/></arg>   
  21. <transition to="wait" /> </java>  
<!-- java 任务,流程处理的流向会执行 这个活动配置的方法
 class:完全类名 
method:调用的方法名 
var:返回值存储的 变量名 --> 
<java name="greet" class="org.jbpm.examples.java.JohnDoe" 
method="hello" var="answer" g="96,16,83,52"> 
<!--fileld:在方法调用之前给成员变量注入 配置值 --> 
<field name="state">
<string value="fine"/>
</field>
 <!--arg:方法参数 --> 
<arg><string value="Hi, how are you?"/></arg> 
<transition to="shake hand" /> 
</java>
 <!--expr:这个表达式返回方法被调用 产生的目标对象 ,通过对象参数传入(new Hand()-->
 <java name="shake hand" expr="#{hand}" 
method="shake" var="hand" g="215,17,99,52"> 
<!-- 通过表达式引用流程变量,为shake方法提供2个参数 --> 
<arg><object expr="#{joesmoe.handshakes.force}"/></arg> 
<arg><object expr="#{joesmoe.handshakes.duration}"/></arg> 
<transition to="wait" /> </java>

 

 JohnDoe事例代码如下:

Java代码 复制代码  收藏代码
  1. public class JohnDoe implements Serializable {    
  2.   String state;    
  3.   public String hello(String msg) {  
  4.     if ( (msg.indexOf("how are you?")!=-1)  
  5.        ) {  
  6.       return "I'm "+state+", thank you.";  
  7.     }  
  8.     return null;  
  9.   }  
  10. }  
public class JohnDoe implements Serializable {  
  String state;  
  public String hello(String msg) {
    if ( (msg.indexOf("how are you?")!=-1)
       ) {
      return "I'm "+state+", thank you.";
    }
    return null;
  }
}

 

 

 Hand事例代码如下:

Java代码 复制代码  收藏代码
  1. public class Hand implements Serializable {  
  2.   private boolean isShaken;  
  3.   public Hand shake(Integer force, Integer duration) {  
  4.     if (force>3 && duration>7) {  
  5.       isShaken = true;  
  6.     }      
  7.     return this;  
  8.   }  
  9.   public boolean isShaken() {  
  10.     return isShaken;  
  11.   }  
  12. }  
public class Hand implements Serializable {
  private boolean isShaken;
  public Hand shake(Integer force, Integer duration) {
    if (force>3 && duration>7) {
      isShaken = true;
    }    
    return this;
  }
  public boolean isShaken() {
    return isShaken;
  }
}

 

 JoeSmoe事例代码如下:

Java代码 复制代码  收藏代码
  1. public class JoeSmoe implements Serializable {  
  2.   public Map<String, Integer> getHandshakes() {  
  3.     Map<String, Integer> handshakes = new HashMap<String, Integer>();  
  4.     handshakes.put("force"5);  
  5.     handshakes.put("duration"12);  
  6.     return handshakes;  
  7.   }  
  8. }  
public class JoeSmoe implements Serializable {
  public Map<String, Integer> getHandshakes() {
    Map<String, Integer> handshakes = new HashMap<String, Integer>();
    handshakes.put("force", 5);
    handshakes.put("duration", 12);
    return handshakes;
  }
}

  测试代码如下:

 

Java代码 复制代码  收藏代码
  1. Map<String, Object> variables = new HashMap<String, Object>();  
  2.     variables.put("hand"new Hand());  
  3.     variables.put("joesmoe"new JoeSmoe());  
  4.       
  5.     ProcessInstance processInstance = executionService.startProcessInstanceByKey("Java", variables);  
  6.     String pid = processInstance.getId();  
  7.       
  8.     // 获取流程变量answer  
  9.     String answer = (String) executionService.getVariable(pid, "answer");  
  10.     assertEquals("I'm fine, thank you.", answer);  
  11.     // 获取流程变量hand  
  12.     Hand hand = (Hand) executionService.getVariable(pid, "hand");  
  13. assertTrue(hand.isShaken());

8、JBPM自动活动


2)script脚本活动

jpdl定义:

Xml代码 复制代码  收藏代码
  1. <!-- script 脚本活动会解析一个script 脚本。  
  2.     任何一种符合JSR-223 规范 的脚本引擎语言都可以在这里运行。  
  3.     expr:执行表达式的文本  
  4.     var:返回值存储的 变量名  
  5.   -->  
  6. <script name="invoke script"  
  7.       expr="Send packet to #{order.address}"  
  8.       var="text"  
  9.       g="96,16,104,52">  
  10. <transition to="wait" />  
  11. </script>  
<!-- script 脚本活动会解析一个script 脚本。
  	任何一种符合JSR-223 规范 的脚本引擎语言都可以在这里运行。
  	expr:执行表达式的文本
  	var:返回值存储的 变量名
  -->
<script name="invoke script"
      expr="Send packet to #{order.address}"
      var="text"
      g="96,16,104,52">
<transition to="wait" />
</script>

 

测试代码如下:

Java代码 复制代码  收藏代码
  1. Map<String, Object> variables = new HashMap<String, Object>();  
  2. variables.put("order"new Order("Berlin"));      
  3. Execution execution = executionService  
  4.     .startProcessInstanceByKey("ScriptExpression", variables);  
  5. String executionId = execution.getId();  
  6. String text = (String) executionService.getVariable(executionId, "text");  
  7. assertTextPresent("Send packet to Berlin", text);  
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("order", new Order("Berlin"));    
Execution execution = executionService
	.startProcessInstanceByKey("ScriptExpression", variables);
String executionId = execution.getId();
String text = (String) executionService.getVariable(executionId, "text");
assertTextPresent("Send packet to Berlin", text);

 

3)hql查询
jpdl定义:

Xml代码 复制代码  收藏代码
  1. <!-- 使用hql 活动,我们可以在database 中执行HQL query   
  2.     var:存储结果的变量名  
  3.     unique:值为true 是指从uniqueResult()方法中 获得hibernate query 的结果。  
  4.     默认值是false。 值为false 的话会使用list()方法得到结果。   
  5. -->  
  6. <hql name="get task names"  
  7.    var="tasknames with i"  
  8.    g="96,16,115,52">  
  9. <!--   
  10.     query:HQL query   
  11.     parameter:query 的参数  
  12. -->  
  13. <query>  
  14.   select task.name  
  15.   from org.jbpm.pvm.internal.task.TaskImpl as task  
  16.   where task.name like :taskName  
  17. </query>  
  18. <parameters>  
  19.   <string name="taskName" value="%i%" />  
  20. </parameters>  
  21. <transition to="count tasks" />  
  22. </hql>  
  23. <hql name="count tasks"  
  24.    var="tasks"  
  25.    unique="true"  
  26.    g="243,16,95,52">  
  27. <query>  
  28.   select count(*)  
  29.   from org.jbpm.pvm.internal.task.TaskImpl  
  30. </query>  
  31. <transition to="wait" />  
  32. </hql>  
<!-- 使用hql 活动,我们可以在database 中执行HQL query 
  	var:存储结果的变量名
  	unique:值为true 是指从uniqueResult()方法中 获得hibernate query 的结果。
  	默认值是false。 值为false 的话会使用list()方法得到结果。 
-->
<hql name="get task names"
   var="tasknames with i"
   g="96,16,115,52">
<!-- 
	query:HQL query 
	parameter:query 的参数
-->
<query>
  select task.name
  from org.jbpm.pvm.internal.task.TaskImpl as task
  where task.name like :taskName
</query>
<parameters>
  <string name="taskName" value="%i%" />
</parameters>
<transition to="count tasks" />
</hql>
<hql name="count tasks"
   var="tasks"
   unique="true"
   g="243,16,95,52">
<query>
  select count(*)
  from org.jbpm.pvm.internal.task.TaskImpl
</query>
<transition to="wait" />
</hql>

 测试事例代码如下:

Java代码 复制代码  收藏代码
  1. ProcessInstance processInstance = executionService.startProcessInstanceByKey("Hql");  
  2. String processInstanceId = processInstance.getId();  
  3. // 设定预期结果  
  4. Set<String> expectedTaskNames = new HashSet<String>();  
  5. expectedTaskNames.add("dishes");  
  6. expectedTaskNames.add("iron");  
  7. // 获取第一个hql活动的执行结果,流程变量"tasknames with i"  
  8. Collection<String> taskNames = (Collection<String>) executionService  
  9.                 .getVariable(processInstanceId, "tasknames with i");  
  10. taskNames = new HashSet<String>(taskNames);  
  11. assertEquals(expectedTaskNames, taskNames);  
  12. // 获取第二个hql活动的执行结果,流程数据库中共有3条记录  
  13. Object activities = executionService.getVariable(processInstanceId, "tasks");  
  14. assertEquals("3", activities.toString());  
ProcessInstance processInstance = executionService.startProcessInstanceByKey("Hql");
String processInstanceId = processInstance.getId();
// 设定预期结果
Set<String> expectedTaskNames = new HashSet<String>();
expectedTaskNames.add("dishes");
expectedTaskNames.add("iron");
// 获取第一个hql活动的执行结果,流程变量"tasknames with i"
Collection<String> taskNames = (Collection<String>) executionService
				.getVariable(processInstanceId, "tasknames with i");
taskNames = new HashSet<String>(taskNames);
assertEquals(expectedTaskNames, taskNames);
// 获取第二个hql活动的执行结果,流程数据库中共有3条记录
Object activities = executionService.getVariable(processInstanceId, "tasks");
assertEquals("3", activities.toString());

 

4)sql查询
jpdl定义:

Xml代码 复制代码  收藏代码
  1. <!--sql 活动和hql 活动十分相似, 唯一不同的地方就是 使用session.createSQLQuery(...) -->  
  2. <sql name="get task names"  
  3.       var="tasknames with i"  
  4.       g="96,16,126,52">  
  5. <query>  
  6.   select NAME_  
  7.   from JBPM4_TASK  
  8.   where NAME_ like :name  
  9. </query>  
  10. <parameters>  
  11.   <string name="name" value="%i%" />  
  12. </parameters>  
  13. <transition to="count tasks" />  
  14. </sql>  
  15.   
  16. <sql name="count tasks"  
  17.    var="tasks"  
  18.    unique="true"  
  19.    g="254,16,92,52">  
  20. <query>  
  21.   select count(*)  
  22.   from JBPM4_TASK  
  23. </query>  
  24. <transition to="wait" />  
  25. </sql>  
<!--sql 活动和hql 活动十分相似, 唯一不同的地方就是 使用session.createSQLQuery(...) -->
<sql name="get task names"
	  var="tasknames with i"
	  g="96,16,126,52">
<query>
  select NAME_
  from JBPM4_TASK
  where NAME_ like :name
</query>
<parameters>
  <string name="name" value="%i%" />
</parameters>
<transition to="count tasks" />
</sql>

<sql name="count tasks"
   var="tasks"
   unique="true"
   g="254,16,92,52">
<query>
  select count(*)
  from JBPM4_TASK
</query>
<transition to="wait" />
</sql>

 测试事例代码同Hql事例代码。

 

5) mail(邮件活动)

jpdl定义:

Xml代码 复制代码  收藏代码
  1. <!--  from:发件者列表  
  2.         to: 主要收件人列表  
  3.         cc:抄送收件人列表  
  4.         bcc: 密送收件人列表  
  5.         subject:这个元素的文字内容会成为消息的主题  
  6.         text:这个元素的文字内容会成为消息的文字内容  
  7.         html:这个元素的文字内容会成为消息的HTML 内容  
  8.         attachments:每个附件都会配置在单独的子元素中  
  9.    -->  
  10.   <mail g="99,25,115,45" language="juel" name="send rectify note">  
  11. <to addresses=" winston@minitrue"/>  
  12. <cc groups="innerparty" users="bb"/>  
  13. <bcc groups="thinkpol"/>  
  14. <subject>rectify ${newspaper}</subject>  
  15. <text>${newspaper} ${date} reporting bb dayorder doubleplusungood  
  16.   refs unpersons rewrite fullwise upsub antefiling</text>  
  17. <!--  
  18. <html><table><tr><td>${newspaper}</td><td>${date}</td>  
  19.   <td>reporting bb dayorder doubleplusungood  
  20.   refs unpersons rewrite fullwise upsub antefiling</td>  
  21.   </tr></table></html>  
  22. <attachments>  
  23.   <attachment url='http://www.george-orwell.org/1984/3.html' />  
  24.   <attachment resource='org/example/pic.jpg' />  
  25.   <attachment file='${user.home}/.face' />  
  26. </attachments>  
  27. -->  
  28. <transition to="wait"/>  
  29. </mail>  
<!--  from:发件者列表
		to: 主要收件人列表
		cc:抄送收件人列表
		bcc: 密送收件人列表
		subject:这个元素的文字内容会成为消息的主题
		text:这个元素的文字内容会成为消息的文字内容
		html:这个元素的文字内容会成为消息的HTML 内容
		attachments:每个附件都会配置在单独的子元素中
   -->
  <mail g="99,25,115,45" language="juel" name="send rectify note">
<to addresses=" winston@minitrue"/>
<cc groups="innerparty" users="bb"/>
<bcc groups="thinkpol"/>
<subject>rectify ${newspaper}</subject>
<text>${newspaper} ${date} reporting bb dayorder doubleplusungood
  refs unpersons rewrite fullwise upsub antefiling</text>
<!--
<html><table><tr><td>${newspaper}</td><td>${date}</td>
  <td>reporting bb dayorder doubleplusungood
  refs unpersons rewrite fullwise upsub antefiling</td>
  </tr></table></html>
<attachments>
  <attachment url='http://www.george-orwell.org/1984/3.html' />
  <attachment resource='org/example/pic.jpg' />
  <attachment file='${user.home}/.face' />
</attachments>
-->
<transition to="wait"/>
</mail>

 

9、事件
Jpdl定义:

Xml代码 复制代码  收藏代码
  1. <state name="wait" g="96,16,104,52">  
  2. <!-- event:事件名称(start或end)  
  3.         event-listener:一个事件监听器实现对象。  
  4.         start:活动开始时捕获  
  5.         end:活动结束时捕获  
  6. -->  
  7. <on event="start">  
  8. <event-listener class="org.jbpm.examples.eventlistener.LogListener">  
  9.   <field name="msg"><string value="start on activity wait"/></field>  
  10.     </event-listener>  
  11. </on>  
  12. <on event="end">  
  13.   <event-listener class="org.jbpm.examples.eventlistener.LogListener">  
  14. <field name="msg"><string value="end on activity wait"/></field>  
  15.   </event-listener>  
  16. </on>  
  17. <transition to="park">  
  18.   <event-listener class="org.jbpm.examples.eventlistener.LogListener">  
  19.      <field name="msg"><string value="take transition"/></field>  
  20.   </event-listener>  
  21. </transition>  
  22. </state>  
<state name="wait" g="96,16,104,52">
<!-- event:事件名称(start或end)
 	    event-listener:一个事件监听器实现对象。
 	    start:活动开始时捕获
 	    end:活动结束时捕获
-->
<on event="start">
<event-listener class="org.jbpm.examples.eventlistener.LogListener">
  <field name="msg"><string value="start on activity wait"/></field>
    </event-listener>
</on>
<on event="end">
  <event-listener class="org.jbpm.examples.eventlistener.LogListener">
<field name="msg"><string value="end on activity wait"/></field>
  </event-listener>
</on>
<transition to="park">
  <event-listener class="org.jbpm.examples.eventlistener.LogListener">
     <field name="msg"><string value="take transition"/></field>
  </event-listener>
</transition>
</state>

 监听器LogListener代码:

Java代码 复制代码  收藏代码
  1. public class LogListener implements EventListener {  
  2.   String msg;    
  3.   public void notify(EventListenerExecution execution) {  
  4.     List<String> logs = (List<String>) execution.getVariable("logs");  
  5. if (logs==null) {  
  6.   logs = new ArrayList<String>();  
  7.   execution.setVariable("logs", logs);  
  8. }      
  9. logs.add(msg);      
  10. execution.setVariable("logs", logs);  
  11.   }  
  12. }  
public class LogListener implements EventListener {
  String msg;  
  public void notify(EventListenerExecution execution) {
    List<String> logs = (List<String>) execution.getVariable("logs");
if (logs==null) {
  logs = new ArrayList<String>();
  execution.setVariable("logs", logs);
}    
logs.add(msg);    
execution.setVariable("logs", logs);
  }
}

 测试事例代码如下:

Java代码 复制代码  收藏代码
  1. ProcessInstance processInstance = executionService  
  2.         .startProcessInstanceByKey("EventListener");  
  3. Execution execution = processInstance.findActiveExecutionIn("wait");  
  4. executionService.signalExecutionById(execution.getId());  
  5. List<String> expectedLogs = new ArrayList<String>();  
  6. expectedLogs.add("start on process definition");  
  7. expectedLogs.add("start on activity wait");  
  8. expectedLogs.add("end on activity wait");  
  9. expectedLogs.add("take transition");  
  10. List<String> logs = (List<String>) executionService  
  11.             .getVariable(processInstance.getId(), "logs");      
  12. assertEquals(expectedLogs, logs);  
ProcessInstance processInstance = executionService
		.startProcessInstanceByKey("EventListener");
Execution execution = processInstance.findActiveExecutionIn("wait");
executionService.signalExecutionById(execution.getId());
List<String> expectedLogs = new ArrayList<String>();
expectedLogs.add("start on process definition");
expectedLogs.add("start on activity wait");
expectedLogs.add("end on activity wait");
expectedLogs.add("take transition");
List<String> logs = (List<String>) executionService
			.getVariable(processInstance.getId(), "logs");    
assertEquals(expectedLogs, logs);

 默认情况下,事件监听器只对当前订阅的元素所触发的事件起作用,即propagation=”false”,
但通过指定事件监听器的传播属性propagation=”enabled”或(propagation=”true”),
则该事件监听器可以对其监听元素的所有子元素起作用。

 

10. 异步执行
   1)几乎所有的活动都支持异步属性,流程一旦进入异步执行方式,一个异步消息会被作为当前事务的一部门发送出去,
       然后当前事务会立即自动提交。

    Jpdl定义:

Java代码 复制代码  收藏代码
  1. <!--  
  2. continue属性: sync (默认值) 作为当前事务的一部分,继续执行元素。   
  3.     async 使用一个异步调用(又名安全点)。当前事务被提交,元素在一个新事务中执行。  
  4.     事务性的异步消息被jBPM 用来 实现这个功能。  
  5. -->  
  6. <java name="generate pdf"  
  7.   continue="async"  
  8.   class="org.jbpm.examples.async.activity.Application"  
  9.   method="generatePdf"  
  10.   g="86,26,87,50">  
  11. <transition to="calculate primes"/>  
  12. </java>  
  13.   
  14. <java name="calculate primes"  
  15.   continue="async"  
  16.   class="org.jbpm.examples.async.activity.Application"  
  17.   method="calculatePrimes"  
  18.   g="203,26,98,50">  
  19. <transition to="end"/>  
  20. </java>  
<!--
continue属性: sync (默认值) 作为当前事务的一部分,继续执行元素。 
	async 使用一个异步调用(又名安全点)。当前事务被提交,元素在一个新事务中执行。
	事务性的异步消息被jBPM 用来 实现这个功能。
-->
<java name="generate pdf"
  continue="async"
  class="org.jbpm.examples.async.activity.Application"
  method="generatePdf"
  g="86,26,87,50">
<transition to="calculate primes"/>
</java>

<java name="calculate primes"
  continue="async"
  class="org.jbpm.examples.async.activity.Application"
  method="calculatePrimes"
  g="203,26,98,50">
<transition to="end"/>
</java>

Application事例代码如下: 

Java代码 复制代码  收藏代码
  1. public class Application implements Serializable {  
  2.   private static final long serialVersionUID = 1L;  
  3.   public void generatePdf() {  
  4.     // 此方法执行需要消耗较长时间  
  5.   }  
  6.   public void calculatePrimes() {  
  7.     // 此方法执行需要消耗较长时间  
  8.   }  
  9. }  
public class Application implements Serializable {
  private static final long serialVersionUID = 1L;
  public void generatePdf() {
    // 此方法执行需要消耗较长时间
  }
  public void calculatePrimes() {
	// 此方法执行需要消耗较长时间
  }
}

 测试事例代码如下:

Java代码 复制代码  收藏代码
  1. ProcessInstance processInstance = executionService  
  2.                 .startProcessInstanceByKey("AsyncActivity");  
  3. String processInstanceId = processInstance.getId();  
  4. // 流程实例处于异步执行状态  
  5. assertEquals(Execution.STATE_ASYNC, processInstance.getState());  
  6. // 获取流程实例异步消息队列中的第1条消息  
  7. Job job = managementService.createJobQuery()  
  8.   .processInstanceId(processInstanceId).uniqueResult();  
  9. // 手工执行异步消息  
  10. managementService.executeJob(job.getId());  
  11. processInstance = executionService.findProcessInstanceById(processInstanceId);  
  12. // 流程实例处于异步执行状态  
  13. assertEquals(Execution.STATE_ASYNC, processInstance.getState());  
  14. // 获取第2条消息(job)并执行之  
  15. job = managementService.createJobQuery()  
  16.       .processInstanceId(processInstanceId)  
  17.       .uniqueResult();  
  18. managementService.executeJob(job.getId());      
  19. assertNull(executionService.findProcessInstanceById(processInstanceId));  
ProcessInstance processInstance = executionService
				.startProcessInstanceByKey("AsyncActivity");
String processInstanceId = processInstance.getId();
// 流程实例处于异步执行状态
assertEquals(Execution.STATE_ASYNC, processInstance.getState());
// 获取流程实例异步消息队列中的第1条消息
Job job = managementService.createJobQuery()
  .processInstanceId(processInstanceId).uniqueResult();
// 手工执行异步消息
managementService.executeJob(job.getId());
processInstance = executionService.findProcessInstanceById(processInstanceId);
// 流程实例处于异步执行状态
assertEquals(Execution.STATE_ASYNC, processInstance.getState());
// 获取第2条消息(job)并执行之
job = managementService.createJobQuery()
      .processInstanceId(processInstanceId)
      .uniqueResult();
managementService.executeJob(job.getId());    
assertNull(executionService.findProcessInstanceById(processInstanceId));

 

   2)异步分支/聚合
    Jpdl定义:

Xml代码 复制代码  收藏代码
  1. <!--   
  2. exclusive 这个值被用来 将两个来自分支的异步调用的job 结果进行持久化。  
  3. 各自的事务会分别执行ship goods 和send bill, 然后这两个执行都会达到join 节点。   
  4. 在join 节点中,两个事务会同步到一个相同的执行上(在数据库总更新同一个执行),  
  5. 这可能导致一个潜在的乐观锁失败。-->  
  6. <fork g="99,68,80,40" name="fork">  
  7.    <!-- 并行的流程分支以独占方式异步执行 -->  
  8.   <on event="end" continue="exclusive" />  
  9.   <transition g="122,41:" to="ship goods"/>  
  10.   <transition g="123,142:" to="send bill"/>  
  11. </fork>  
  12.   
  13. <java class="org.jbpm.examples.async.fork.Application" g="159,17,98,50"  
  14.     method="shipGoods" name="ship goods">  
  15.    <transition g="297,42:" to="join"/>  
  16. </java>  
  17.   
  18. <java class="org.jbpm.examples.async.fork.Application" g="159,117,98,50"   
  19.      method="sendBill" name="send bill">  
  20. <transition g="297,141:" to="join"/>  
  21. </java>  
  22.   
  23. <join g="274,66,80,40" name="join">  
  24.   <transition to="end"/>  
  25. </join>  
<!-- 
exclusive 这个值被用来 将两个来自分支的异步调用的job 结果进行持久化。
各自的事务会分别执行ship goods 和send bill, 然后这两个执行都会达到join 节点。 
在join 节点中,两个事务会同步到一个相同的执行上(在数据库总更新同一个执行),
这可能导致一个潜在的乐观锁失败。-->
<fork g="99,68,80,40" name="fork">
   <!-- 并行的流程分支以独占方式异步执行 -->
  <on event="end" continue="exclusive" />
  <transition g="122,41:" to="ship goods"/>
  <transition g="123,142:" to="send bill"/>
</fork>

<java class="org.jbpm.examples.async.fork.Application" g="159,17,98,50"
	method="shipGoods" name="ship goods">
   <transition g="297,42:" to="join"/>
</java>

<java class="org.jbpm.examples.async.fork.Application" g="159,117,98,50" 
	 method="sendBill" name="send bill">
<transition g="297,141:" to="join"/>
</java>

<join g="274,66,80,40" name="join">
  <transition to="end"/>
</join>

 测试事例代码如下:

Java代码 复制代码  收藏代码
  1. ProcessInstance processInstance = executionService.startProcessInstanceByKey("AsyncFork");  
  2. String processInstanceId = processInstance.getId();  
  3. // 获取异步消息列表  
  4. List<Job> jobs = managementService.createJobQuery()  
  5.   .processInstanceId(processInstanceId).list();  
  6. //有两个分支,有2条异步消息  
  7. assertEquals(2, jobs.size());      
  8. Job job = jobs.get(0);  
  9. //手工执行第1条  
  10. managementService.executeJob(job.getId());      
  11. job = jobs.get(1);  
  12. //手工执行第2条  
  13. managementService.executeJob(job.getId());  
  14. Date endTime = historyService  
  15.   .createHistoryProcessInstanceQuery()  
  16.   .processInstanceId(processInstance.getId())  
  17.   .uniqueResult()  
  18.   .getEndTime();  
  19. // 流程已结束  
  20. assertNotNull(endTime);  
ProcessInstance processInstance = executionService.startProcessInstanceByKey("AsyncFork");
String processInstanceId = processInstance.getId();
// 获取异步消息列表
List<Job> jobs = managementService.createJobQuery()
  .processInstanceId(processInstanceId).list();
//有两个分支,有2条异步消息
assertEquals(2, jobs.size());    
Job job = jobs.get(0);
//手工执行第1条
managementService.executeJob(job.getId());    
job = jobs.get(1);
//手工执行第2条
managementService.executeJob(job.getId());
Date endTime = historyService
  .createHistoryProcessInstanceQuery()
  .processInstanceId(processInstance.getId())
  .uniqueResult()
  .getEndTime();
// 流程已结束
assertNotNull(endTime);

 

11. 流程变量
     1)流程变量与流程实例绑定, 可通过以下方法来操作流程变量:
     例:

Java代码 复制代码  收藏代码
  1. ProcessInstance   startProcessInstanceById   
  2.  (String processDefinitionId,Map<String,Object>variables);  
  3.   
  4. ProcessInstance   startProcessInstanceById  
  5. (String processDefinitionId,Map<String,Object>variables,String processInstanceKey);  
ProcessInstance   startProcessInstanceById 
 (String processDefinitionId,Map<String,Object>variables);

ProcessInstance   startProcessInstanceById
(String processDefinitionId,Map<String,Object>variables,String processInstanceKey);

    2)其它引擎服务中也存在类似的方法,例如TaskService也提供方法操作任务绑定的流程变量。

    3)通过流程变量控制流程的流向是正确的做法,但是不要被这种“方便”的机制诱惑而往流程实例里面放所有的东西,
        特别是与流转控制无关的业务数据。

 

五、 JBPM数据表

 

JBPM4_DEPLOYMENT: 流程定义的部署记录
JBPM4_DEPLOYPROP: 已部署的流程定义的具体属性
JBPM4_LOB:流程定义的相关资源,包括JPDL XML、图片、用户代码Java类等。
JBPM4_JOB:异步活动或定时执行的Job记录。
JBPM4_VARIABLE:流程实例的变量。
JBPM4_EXECUTION:流程实例及执行对象。
JBPM4_SWIMLANE:任务泳道。
JBPM4_PARTICIPATION:任务参与者,任务的相关用户,区别于任务的分配人。
JBPM4_TASK:流程实例的任务记录。
JBPM4_HIST_PROCINST:保存历史的流程实例记录。
JBPM4_HIST_ACTINST:保存历史的活动实例记录。
JBPM4_HIST_TASK:保存历史的任务实例记录。
JBPM4_HIST_VAR:保存历史的流程变量数据。
JBPM4_HIST_DETAIL:保存流程实例、活动实例、任务实例运行过程中历史明细数据。
JBPM4_ID_USER:保存用户记录。
JBPM4_ID_MEMBERSHIP:保存用户和用户组之间的关联关系。
JBPM4_ID_GROUP:保存用户组记录。

你可能感兴趣的:(JBPM4)