`
infen
  • 浏览: 13725 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

跟我学JBPM4之State、Decision 、Task活动

    博客分类:
  • jBPM
阅读更多

本文转自<雪山飞鹄> http://www.blogjava.net/sxyx2008/archive/2010/09/29/333385.html

State、Decision 、Task活动详解:

State表示一个等待状态。当流程实例执行到state节点时会暂停下来(处于等待状态),流程的执行会在外部触发器被调用之前一直等待(会暂停)

Decision条件判断节点,表示在多条路径中选择一条。一个 decision 活动拥有很多个传出的转移。流程的执行到达一个 decision 活动时,会自动进行计算来决定采用哪个传出的转移(满足条件时,向下执行,没有符合条件时会停留在decision活动的上一个活动)

Task任务组件,主要用来为流程实例分配任务。通常与form表单相关联.(会暂停下来)

State节点示例

无分支的state节点

 

流程定义文件:

<?xml version="1.0" encoding="UTF-8"?>
<process name="demo" xmlns="http://jbpm.org/4.3/jpdl">
   <start g="134,113,48,48" name="start">
      <transition g="-53,-17" name="to state" to="state"/>
   </start>
   <state g="219,204,92,52" name="state">
      <transition g="-41,-17" name="to end" to="end"/>
   </state>
   <end g="329,301,48,48" name="end"/>
</process>


测试代码:

    

        ProcessInstance processInstance=executionService.startProcessInstanceByKey("demo");
        System.out.println("流程实例Id:"+processInstance.getId());
        System.out.println("流程定义Id:"+processInstance.getProcessDefinitionId());
        //判断当前是否位于start节点
        System.out.println("是否位于start节点:"+processInstance.isActive("start"));//false
        //判断当前是否位于state节点
        System.out.println("是否位于state节点:"+processInstance.isActive("state"));//true
        //判断流程是否结束
        System.out.println("判断流程是否结束:"+processInstance.isEnded());//false
        System.out.println("------------------------>使流程继续向下执行");
        //使流程继续向下执行
        //ProcessInstance instanceState=executionService.signalExecutionById(processInstance.getId());
        //此处也可以这么写
        ProcessInstance instanceState=executionService.signalExecutionById(processInstance.getId(),"to end");
        //to end为流程定义中用于连接state和end节点之间transition的name属性的值
        //判断当前是否位于state节点
        System.out.println("是否位于state节点:"+instanceState.isActive("state"));//false
        //判断流程是否结束
        System.out.println("判断流程是否结束:"+instanceState.isEnded());//true
 


执行结果:

 

流程实例Id:demo.7

流程定义Id:demo-1

是否位于start节点:false

是否位于state节点:true

判断流程是否结束:false

------------------------>使流程继续向下执行

是否位于state节点:false

判断流程是否结束:true

 


有分支的state节点:

 

注意:在此流程定义中在state节点后含有2个分支(2个transition 即to 400和to 200),那么在使流程实例从state节点向下执行的时候需要明确给出transition的方向name属性的值,否则流程实例会一直处于state节点

executionService.signalExecutionById(processInstance.getId(), "to 200");

流程定义文件:

<?xml version="1.0" encoding="UTF-8"?>
<process name="demo" xmlns="http://jbpm.org/4.3/jpdl">
   <start g="347,27,48,48" name="start">
      <transition g="-53,-17" name="to state" to="state"/>
   </start>
   <state g="329,132,92,52" name="state">
      <transition name="to 200" to="200" g="-41,-17"/>
      <transition name="to 400" to="400" g="-41,-17"/>
   </state>
   <end g="358,321,48,48" name="end"/>
   <state name="200" g="420,226,92,52">
      <transition name="to end" to="end" g="-41,-17"/>
   </state>
   <state name="400" g="266,225,92,52">
      <transition name="to end" to="end" g="-41,-17"/>
   </state>
</process>

 
测试代码:

        ProcessInstance processInstance=executionService.startProcessInstanceByKey("demo");
        System.out.println("------------------------>使流程继续向下执行");
        System.out.println("------------------------>使流程流向200");
        ProcessInstance processInstance200=executionService.signalExecutionById(processInstance.getId(), "to 200");
        System.out.println("当前流程是否位于200节点---->"+processInstance200.isActive("200"));//true
        System.out.println("当前流程是否结束---->"+processInstance200.isEnded());//false
        /*System.out.println("------------------------>使流程流向400");
        ProcessInstance processInstance400=executionService.signalExecutionById(processInstance.getId(), "to 400");
        System.out.println("当前流程是否位于400节点---->"+processInstance400.isActive("400"));
        System.out.println("当前流程是否结束---->"+processInstance400.isEnded());*/

 
 


执行结果:

 

------------------------>使流程继续向下执行

------------------------>使流程流向200

当前流程是否位于200节点---->true

当前流程是否结束---->false


流向400的自己测试

由于流程定义中200和400均为state节点,所以流程在流经200或400节点后仍会停留在该节点,以下代码完成流程实例从start->200->end这一过程

        ProcessInstance processInstance=executionService.startProcessInstanceByKey("demo");
        //查询该流程实例的活动节点
     System.out.println(processInstance.findActiveActivityNames());     //因为流程实例启动后,它会自动向下执行,直到遇到state或task等节点时暂停下来,在我们的流程定义文件中紧跟在start后的节点为state,所以流程实例会在state节点暂停下来
     Execution execution=processInstance.findActiveExecutionIn("state");//查询当前流程实例的当前节点
     ProcessInstance processInstance200=executionService.signalExecutionById(execution.getId(), "to 200");//此时流程流向200
        System.out.println("当前流程是否位于200节点---->"+processInstance200.isActive("200"));//true
        System.out.println("当前流程是否结束---->"+processInstance200.isEnded());//false
        //使流程继续向下执行(结束)
        System.out.println("-------使流程继续向下执行(结束)------->");
        //由于200节点后没有分支仅有end这一节点,所以200与end之间transition的name属性的值可以省略,当然加上更好
        ProcessInstance instance=executionService.signalExecutionById(processInstance200.getId());//流程执行到end,结束流程实例
        System.out.println("当前流程是否结束---->"+instance.isEnded());//true

  


执行结果:

 

[state]

当前流程是否位于200节点---->true

当前流程是否结束---->false

-------使流程继续向下执行(结束)------->

当前流程是否结束---->true

 


Decision节点示例

流程图:

 

流程定义:

在使用Decision时,一个Decision活动应配置为以下三种中的一种

decision 会检查每一个传出的转移里的内置条件。流程的执行会采用第一个内置条件为

true 或者没有设置内置条件的转移

第一种:使用Decision内置条件(返回true或false)

    即在流程定义中设置每一个transition的子节点condition,并为每一个condition填充expr属性

形如:

<condition expr="${coder=='200'}"></condition>

详细的流程定义

<?xml version="1.0" encoding="UTF-8"?>
<process name="decision" xmlns="http://jbpm.org/4.3/jpdl">
   <start g="61,51,48,48" name="开始">
      <transition g="-47,-17" name="to waite" to="waite"/>
   </start>
   <decision g="188,160,48,48" name="gowhere">
      <transition g="-41,-17" name="to 200" to="200">
       <condition expr="${coder=='200'}"></condition>
      </transition>
      <transition g="-41,-17" name="to 500" to="500">
       <condition expr="${coder=='500'}"></condition>
      </transition>
      <transition g="-41,-17" name="to 404" to="404">
       <condition expr="${coder=='404'}"></condition>
      </transition>
   </decision>
   <state g="386,143,92,52" name="200">
      <transition g="-47,-17" name="to 结束" to="结束"/>
   </state>
   <state g="296,261,92,52" name="500">
      <transition g="-47,-17" name="to 结束" to="结束"/>
   </state>
   <state g="197,389,92,52" name="404">
      <transition g="-47,-17" name="to 结束" to="结束"/>
   </state>
   <end g="498,407,48,48" name="结束"/>
   <state g="114,97,92,52" name="waite">
      <transition g="-65,-17" name="to gowhere" to="gowhere"/>
   </state>
</process>

  


观察红色标注的部分

测试代码:

  Map<String, String> map=new HashMap<String, String>();
        //coder为流程定义中表达式的名称
        map.put("coder", "200");
        ProcessInstance processInstance=executionService.startProcessInstanceByKey("decision",map);
        System.out.println("流程是否处于waite节点:"+processInstance.isActive("waite"));//true
        ProcessInstance processInstanceDecision=executionService.signalExecutionById(processInstance.getId());
        System.out.println("流程是否处于waite节点:"+processInstanceDecision.isActive("waite"));//false
        System.out.println("流程是否处于gowhere节点:"+processInstanceDecision.isActive("gowhere"));//false
        System.out.println("流程是否处于200节点:"+processInstanceDecision.isActive("200"));//true
        System.out.println("流程是否处于404节点:"+processInstanceDecision.isActive("404"));//false
        System.out.println("流程是否处于500节点:"+processInstanceDecision.isActive("500"));//false

  


代码说明:

在一开始定义了一个Map,在程序中手动为coder(详见流程定义中的condition的expr属性)赋值200,当流程实例启动时运行到decision时会自动计算每一个transition节点子节点condition里面的expr属性(详见流程定义中),如果某一内置条件(condition)执行为true,则就将流程执行到该节点。在使用此种方式时, condition的expr中设置的下一活动的活动名称(name),而不是transition的name属性.这里紧跟在decision活动后有三个活动200、404、500且三个活动名称依次为200、404、500,所以程序中为coder赋值200就表示将流程执行到200这个活动.

执行结果:

 

流程是否处于waite节点:true

流程是否处于waite节点:false

流程是否处于gowhere节点:false

流程是否处于200节点:true

流程是否处于404节点:false

流程是否处于500节点:false

 


第二种:为流程定义中decision活动设置expr属性,decision 表达式返回类型为字符串的向外转移的名字,使用此种方式不用再去为每一个transition设置condition子节点

形如:

<decision g="188,160,48,48" name="gowhere" expr="${towhere}">

这里towhere就表示流程流经decision活动后要流经的下一个transition的name属性的值

详细的流程定义文件:

<?xml version="1.0" encoding="UTF-8"?>
<process name="decision" xmlns="http://jbpm.org/4.3/jpdl">
   <start g="61,51,48,48" name="开始">
      <transition g="-47,-17" name="to waite" to="waite"/>
   </start>
   <decision g="188,160,48,48" name="gowhere" expr="${towhere}">
      <transition g="-41,-17" name="to 200" to="200">
      </transition>
      <transition g="-41,-17" name="to 500" to="500">
      </transition>
      <transition g="-41,-17" name="to 404" to="404">
      </transition>
   </decision>
   <state g="386,143,92,52" name="200">
      <transition g="-47,-17" name="to 结束" to="结束"/>
   </state>
   <state g="296,261,92,52" name="500">
      <transition g="-47,-17" name="to 结束" to="结束"/>
   </state>
   <state g="197,389,92,52" name="404">
      <transition g="-47,-17" name="to 结束" to="结束"/>
   </state>
   <end g="498,407,48,48" name="结束"/>
   <state g="114,97,92,52" name="waite">
      <transition g="-65,-17" name="to gowhere" to="gowhere"/>
   </state>
</process>

  


重点关注红色标注的地方

执行代码:

  Map<String, String> map=new HashMap<String, String>();
        // towhere为流程定义中表达式的名称
        map.put("towhere", "to 200");
        ProcessInstance processInstance=executionService.startProcessInstanceByKey("decision",map);
        System.out.println("流程是否处于waite节点:"+processInstance.isActive("waite"));//true
        ProcessInstance processInstanceDecision=executionService.signalExecutionById(processInstance.getId());
        System.out.println("流程是否处于waite节点:"+processInstanceDecision.isActive("waite"));//false
        System.out.println("流程是否处于gowhere节点:"+processInstanceDecision.isActive("gowhere"));//false
        System.out.println("流程是否处于200节点:"+processInstanceDecision.isActive("200"));//true
        System.out.println("流程是否处于404节点:"+processInstanceDecision.isActive("404"));//false
        System.out.println("流程是否处于500节点:"+processInstanceDecision.isActive("500"));//false

  


代码解释:

从流程图中我们可以看出decision后有三个transition,且每个transition的name属性的值依次为to 200、to 404、to 500.在代码中声明了一Map对象,并为该Map添加一个以towhere作为键to 200位置的元素,然后使流程向下执行.那么当流程实例流经decision活动时,会计算decision节点expr的值,从中选择下一个transition的名称,然后向下执行.

使用此种方式为decision节点设置expr属性,设置的是下一个transition的name属性,请与第一种情况加以区别(第一种情况设置的下一活动的name)

执行结果:

 

流程是否处于waite节点:true

流程是否处于waite节点:false

流程是否处于gowhere节点:false

流程是否处于200节点:true

流程是否处于404节点:false

流程是否处于500节点:false

 


第三种:为decision配置一个handler的类(在流程定义中在decision节点内部配置<handler/>子节点,并设置该元素的class属性为你自己的类)该类实现了org.jbpm.api.jpdl.DecisionHandler.你需要赋写

String decide(OpenExecution execution);方法即可,在该方法最终返回decision活动后的下一个transition的name属性的值

形如:

<handler class="com.jbpm.decision.handler.HandlerDecision"></handler>

这里class="com.jbpm.decision.handler.HandlerDecision"就表示实现了org.jbpm.api.jpdl.DecisionHandler的自定义类,你只需要赋写String decide(OpenExecution execution) 方法,在该方法最终返回decision活动后的下一个transition的name属性的值

详细的流程定义文件:

<?xml version="1.0" encoding="UTF-8"?>
<process name="decision" xmlns="http://jbpm.org/4.3/jpdl">
   <start g="61,51,48,48" name="开始">
      <transition g="-47,-17" name="to waite" to="waite"/>
   </start>
   <decision g="188,160,48,48" name="gowhere">
     <handler class="com.jbpm.decision.handler.HandlerDecision"></handler>
      <transition g="-41,-17" name="to 200" to="200">
      </transition>
      <transition g="-41,-17" name="to 500" to="500">
      </transition>
      <transition g="-41,-17" name="to 404" to="404">
      </transition>
   </decision>
   <state g="386,143,92,52" name="200">
      <transition g="-47,-17" name="to 结束" to="结束"/>
   </state>
   <state g="296,261,92,52" name="500">
      <transition g="-47,-17" name="to 结束" to="结束"/>
   </state>
   <state g="197,389,92,52" name="404">
      <transition g="-47,-17" name="to 结束" to="结束"/>
   </state>
   <end g="498,407,48,48" name="结束"/>
   <state g="114,97,92,52" name="waite">
      <transition g="-65,-17" name="to gowhere" to="gowhere"/>
   </state>
</process>

  


请关注红色标注部分:

测试代码:

  Map<String, String> map=new HashMap<String, String>();
        //towhere为流程定义中表达式的名称
        map.put("towhere", "执行到200这个活动");
        //map.put("towhere", "执行到404这个活动");
        //map.put("towhere", "执行到500这个活动");
        ProcessInstance processInstance=executionService.startProcessInstanceByKey("decision",map);
        System.out.println("流程是否处于waite节点:"+processInstance.isActive("waite"));//true
        ProcessInstance processInstanceDecision=executionService.signalExecutionById(processInstance.getId());
        System.out.println("流程是否处于waite节点:"+processInstanceDecision.isActive("waite"));//false
        System.out.println("流程是否处于gowhere节点:"+processInstanceDecision.isActive("gowhere"));//false
  System.out.println("流程是否处于200节点:"+processInstanceDecision.isActive("200"));//true
        System.out.println("流程是否处于404节点:"+processInstanceDecision.isActive("404"));//false
        System.out.println("流程是否处于500节点:"+processInstanceDecision.isActive("500"));//false

  


处理类:

  

package com.jbpm.decision.handler;
import org.jbpm.api.jpdl.DecisionHandler;
import org.jbpm.api.model.OpenExecution;

@SuppressWarnings("serial")
public class HandlerDecision implements DecisionHandler {
    @Override
    public String decide(OpenExecution execution) {
        String towhere=(String) execution.getVariable("towhere");
        String result = null;
        if("执行到200这个活动".equals(towhere)){
            result="to 200";
        }else if("执行到404这个活动".equals(towhere)){
            result="to 404";
        }else if("执行到500这个活动".equals(towhere)){
            result="to 500";
        }
        return result;
    }
}

 


代码解释:

在测试代码中同样创建了一个map对象,然后为该map对象添加了一个以towhere为键的值,并在流程实例向下执行的时候传递该map对象。

在HandlerDecision处理类中,通过execution.getVariable("towhere");获取towhere的value,然后依次判断,看是否与之前放进去的值匹配,若匹配的话就返回到一个你想使流程向那执行的transition的name属性的值.至此流程就会沿着这个值的方向向下执行.

执行结果:

 

流程是否处于waite节点:true

流程是否处于waite节点:false

流程是否处于gowhere节点:false

流程是否处于200节点:true

流程是否处于404节点:false

流程是否处于500节点:false

 


需要说明的是代码中为map对象设置的键值跟流程定义无任何关系,你可以任意设置,只要符合map的使用规律即成,完了在流程实例向下执行的时候顺带传递此map对象,最后在自定义的处理类中根据之前的设置的键来获取值,最终返回一个你期望到达的transition即可。

Task是一个任务活动,主要是在流程实例经过活动时为某一人或组指派任务(流程到达此活动时会暂停下来)

Task有一个可选的assignee属性

第一, assignee用来指示用户, 负责完成任务的人。分配人是一个任务中的字符串属性 引用一个用户。(直接指定一个字符串)

第二,这个属性默认会当做表达式来执行。(指定一个表达式,然后在代码里为该表达式赋值) 如:在这里任务被分配给#{order.owner}。这意味着首先使用order这个名字查找一个对象。 其中一个查找对象的地方是这个任务对应的流程变量。 然后getOwner()方法会用来 获得用户id, 引用的用户负责完成这个任务。

示例:

流程定义图

 

第一种情况:(直接指定一个字符串)

流程定义文件:

<?xml version="1.0" encoding="UTF-8"?>
<process name="task" xmlns="http://jbpm.org/4.3/jpdl">
   <start g="99,112,48,48" name="start">
      <transition g="-47,-17" name="to task" to="task"/>
   </start>
   <task g="155,221,92,52" name="task" assignee="lisi">
      <transition g="-41,-17" name="to end" to="end"/>
   </task>
   <end g="260,350,48,48" name="end"/>
</process>

  


关注红色部分

解释,在task中直接将任务指派给lisi

测试代码(查看lisi的任务列表)

  ProcessInstance processInstance=executionService.startProcessInstanceByKey("task");
        System.out.println("流程是否处于task节点:"+processInstance.isActive("task"));//true
        System.out.println("流程实例Id:"+processInstance.getId());
        List<Task> list=taskService.findPersonalTasks("lisi");
        for (Task task : list) {
            System.out.println("任务活动名称:"+task.getActivityName());
            System.out.println("流程实例Id:"+task.getExecutionId());
            System.out.println("任务活动Id:"+task.getId());
            System.out.println("任务活动创建时间:"+task.getCreateTime());
            System.out.println("任务活动进度:"+task.getProgress());
            System.out.println("任务活动分配给:"+task.getAssignee());
        }
 

 
代码解释:

使用taskService.findPersonalTasks("lisi");即可取得lisi的任务列表

执行结果:

 

流程是否处于task节点:true

流程实例Id:task.7

任务活动名称:task

流程实例Id:task.7

任务活动Id:8

任务活动创建时间:2010-09-29 11:54:34.25

任务活动进度:null

任务活动分配给:lisi

 


第二种情况:(为task指定一表达式)

流程定义文件:

<?xml version="1.0" encoding="UTF-8"?>
<process name="task" xmlns="http://jbpm.org/4.3/jpdl">
   <start g="99,112,48,48" name="start">
      <transition g="-47,-17" name="to task" to="task"/>
   </start>
   <task g="155,221,92,52" name="task" assignee="${taskAssignee}">
      <transition g="-41,-17" name="to end" to="end"/>
   </task>
   <end g="260,350,48,48" name="end"/>
</process>

  


关注红色部分

解释,在task中使用了表达式${taskAssignee},该值在程序执行时动态分配

测试代码(查看任务列表)

  Map<String,String> map=new HashMap<String, String>();
        map.put("taskAssignee", "lisi");
        ProcessInstance processInstance=executionService.startProcessInstanceByKey("task",map);
  System.out.println("流程是否处于task节点:"+processInstance.isActive("task"));//true
        System.out.println("流程实例Id:"+processInstance.getId());
        List<Task> list=taskService.findPersonalTasks("lisi");
        for (Task task : list) {
            System.out.println("任务活动名称:"+task.getActivityName());
            System.out.println("流程实例Id:"+task.getExecutionId());
            System.out.println("任务活动Id:"+task.getId());
            System.out.println("任务活动创建时间:"+task.getCreateTime());
            System.out.println("任务活动进度:"+task.getProgress());
            System.out.println("任务活动分配给:"+task.getAssignee());
        }

  


代码解释:

在程序一开始创建了一个map对象,并为该map添加一个元素,其键为流程定义中的taskAssignee,值任意分配,然后传递该map,最后查询任务列表

执行效果:

 

流程是否处于task节点?true

流程实例Id:task.7

任务活动名称:task

流程实例Id:task.7

任务活动Id:9

任务活动创建时间:2010-09-29 11:58:07.359

任务活动进度:null

任务活动分配给:lisi

 


最后说明一下,在jbpm中表达式$(),#()均可以成功解析

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics