天天看點

JBPM筆記-基礎範例

1、節點含義

<?xml version="1.0" encoding="UTF-8"?>

<process-definition
  xmlns="urn:jbpm.org:jpdl-3.2"  name="example001">
   <start-state name="start">
      <transition name="" to="state1"></transition>
   </start-state>
  
   <state name="state1">
      <transition name="" to="node1"></transition>
   </state>
   
   <node name="node1">
      <transition name="" to="state2"></transition>
   </node>
   
   <state name="state2">
      <transition name="" to="task1"></transition>
   </state>
   
   <task-node name="task1">
      <transition name="tobf" to="end1"></transition>
   </task-node>
    <end-state name="end1"></end-state>
</process-definition>
           
JbpmContext jbpmContext = getJbpmContext();
		GraphSession graphSession=jbpmContext.getGraphSession();
		ProcessDefinition processDefinition = graphSession.findLatestProcessDefinition(processName);
		ProcessInstance processInstance = new ProcessInstance(processDefinition);
		Token token = processInstance.getRootToken();
		token.signal();
		logger.info("NodeName:"+token.getNode().getName());
		token.signal();
		logger.info("NodeName:"+token.getNode().getName());
		token.signal();
		logger.info("NodeName:"+token.getNode().getName());	
           

顯示結果如下:

NodeName:state1

NodeName:state2

NodeName:end1

總結:

node、state、task節點分别為node、等待節點、任務節點。

進過node、task-node不需要singal就往下走,是以沒有顯示他們的名稱,state節點必須singal才往下走。

二、ActionHandler、設定工作參與者以及擷取工作路由

<?xml version="1.0" encoding="UTF-8"?>

<process-definition
  xmlns="urn:jbpm.org:jpdl-3.2"  name="example002">
   <start-state name="start">
      <transition name="" to="state1"></transition>
   </start-state>
  
   <state name="state1">
      <transition name="" to="node1"></transition>
   </state>
   
   <node name="node1">
      <action class="jbpm.java.handler.example.TestAction"></action>
      <transition name="" to="state2"></transition>
   </node>
   
   <state name="state2">
      <transition name="" to="task1"></transition>
   </state>
   
   <task-node name="task1">
       <task>
         <assignment actor-id="#{user}"></assignment>
      </task>
      <transition name="tobf" to="end1"></transition>
   </task-node>
    <end-state name="end1"></end-state>
</process-definition>
           

TestAction.java

public class TestAction implements ActionHandler {
	private static final long serialVersionUID = 1196655833977006482L;

	@Override
	public void execute(ExecutionContext executionContext) throws Exception {
		System.out.println("通過Action類來解決問題!!!");
	}

}
           
JbpmContext jbpmContext = getJbpmContext();
		GraphSession graphSession=jbpmContext.getGraphSession();
		ProcessDefinition processDefinition = graphSession.findLatestProcessDefinition(processName);
		ProcessInstance processInstance = new ProcessInstance(processDefinition);
		processInstance.getContextInstance().setVariable("user", "使用者");
		Token token = processInstance.getRootToken();
		token.signal();
		logger.info("NodeName:"+token.getNode().getName());
		token.signal();
		logger.info("NodeName:"+token.getNode().getName());
		token.signal();
		logger.info("NodeName:"+token.getNode().getName());	
		token.signal();
		logger.info("NodeName:"+token.getNode().getName());		
		
		TaskInstance ti = (TaskInstance)processInstance.getTaskMgmtInstance().getTaskInstances().iterator().next();
		System.out.println("現在工作的參與者是"+ti.getActorId());
		//擷取該工作的路由
		List<Transition> tns = ti.getTask().getTaskNode().getLeavingTransitions();
		for(Transition tn : tns) {
			System.out.println("該工作的所有路由"+tn.getName());
		}
           

輸出結果:

NodeName:state1

通過Action類來解決問題!!!

NodeName:node1

NodeName:state2

NodeName:task1

現在工作的參與者是使用者

該工作的所有路由tobf

三、beanShell腳本、Assignment應用

<?xml version="1.0" encoding="UTF-8"?>

<process-definition
  xmlns="urn:jbpm.org:jpdl-3.2"  name="example003">
	<start-state name="start">
		<transition name="" to="task1"></transition>
	</start-state>
   
	<task-node name="task1">
		<task>
                      <assignment class="jbpm.java.handler.example.TestAssignment"></assignment>
			<assignment actor-id="使用者001"/>
		</task>
		<event type="node-enter">
			<script>
				print("目前節點對象的ID:"+token.getId());
				contextInstance = executionContext.getContextInstance();
				print("流程變量param的值:"+contextInstance.getVariable("param"));
				print("直接擷取變量值:"+param); 
			</script>
		</event>
		<transition name="" to="end1"></transition>
	</task-node>
   
	<end-state name="end1"></end-state>
   
</process-definition>
           

TestAssignment.java

public class TestAssignment implements AssignmentHandler{

	private static final long serialVersionUID = 1443420479356838909L;

	@Override
	public void assign(Assignable assignable, ExecutionContext executionContext) throws Exception {
		assignable.setActorId("使用者001");
	}

}
           
JbpmContext jbpmContext = getJbpmContext();
		GraphSession graphSession=jbpmContext.getGraphSession();
		ProcessDefinition processDefinition = graphSession.findLatestProcessDefinition(processName);
		ProcessInstance processInstance = new ProcessInstance(processDefinition);
		ContextInstance contextInstance = processInstance.getContextInstance();
		contextInstance.setVariable("param", "參數param值");
		Token token = processInstance.getRootToken();
		token.signal();
		logger.info("NodeName:"+token.getNode().getName());
		token.signal();
		logger.info("NodeName:"+token.getNode().getName());	
           

結果如下:

目前節點對象的ID:23

流程變量param的值:param的值

直接擷取變量值:param的值

 NodeName:task1

NodeName:end1

現在工作的參與者是使用者001

四、fork join 節點

discriminator = true 經過一個節點,則結束。  一般開發不使用。

預設情況下join會等到所有從fork上生成的子token都到達join節點時,才會繼續向下。

<?xml version="1.0" encoding="UTF-8"?>

<process-definition xmlns="urn:jbpm.org:jpdl-3.2"  name="example004">
  
   <start-state name="start">
      <transition name="" to="fork1"></transition>
   </start-state>
   
   <fork name="fork1">
      <script>
         <variable name="transNames" access="write"></variable>
         <expression>
            transNames = new ArrayList();
            if(param>100){
               transNames.add("tr1");
               transNames.add("tr2");
            }else{
               transNames.add("tr3");
               transNames.add("tr4");
            }
         </expression>
      </script>
      <transition name="tr1" to="node1"></transition>
      <transition name="tr2" to="node2"></transition>
      <transition name="tr3" to="node3"></transition>
      <transition name="tr4" to="node4"></transition>
   </fork>
   
   
   <node name="node1">
      <event type="node-enter">
         <script>
            print("進入第一個節點");
         </script>
      </event>
      <transition name="" to="join1"></transition>
   </node>
   
   <node name="node2">
      <event type="node-enter">
         <script>
            print("進入第二個節點");
         </script>
      </event>
      <transition name="" to="join1"></transition>
   </node>
   
   <node name="node3">
      <event type="node-enter">
         <script>
            print("進入第三個節點");
         </script>
      </event>
      <transition name="" to="join1"></transition>
   </node>
   
   
   <node name="node4">
      <event type="node-enter">
         <script>
            print("進入第四個節點");
         </script>
      </event>
      <transition name="" to="join1"></transition>
   </node> 
   
   <join name="join1">
      <transition name="" to="end1"></transition>
   </join>
   
   
   <end-state name="end1">
      <event type="node-enter">
         <script>
          print("結束操作");
        </script>
      </event>
   </end-state>
</process-definition>
           
JbpmContext jbpmContext = getJbpmContext();
		GraphSession graphSession=jbpmContext.getGraphSession();
		ProcessDefinition processDefinition = graphSession.findLatestProcessDefinition(processName);
		ProcessInstance processInstance = new ProcessInstance(processDefinition);
		processInstance.getContextInstance().setVariable("param", new Integer(11));
		Token token = processInstance.getRootToken();
		token.signal();
		logger.info("NodeName:"+token.getNode().getName());
           

結果如下:

進入第三個節點

進入第四個節點

結束操作

NodeName:end1

四、Decision節點  

定義流程走向節點,在本節點上添加多個Transtion,和Fork相反,隻能在多個Transition内選擇一個。

A:未指定decision線路。

<?xml version="1.0" encoding="UTF-8"?>

<process-definition xmlns="urn:jbpm.org:jpdl-3.2"  name="example005">


	<start-state name="start">
      <transition name="" to="decision1"></transition>
   </start-state>
   <decision name="decision1">
      <transition name="tr1" to="node1"></transition>
      <transition name="tr2" to="node2"></transition>
      <transition name="tr3" to="node3"></transition>
   </decision>
   <node name="node1">
     <event type="node-enter">
        <script>
          print("進入第一個節點");
        </script>
     </event>
      <transition name="" to="end1"></transition>
   </node>
   <node name="node2">
   <event type="node-enter">
        <script>
          print("進入第二個節點");
        </script>
     </event>
      <transition name="" to="end1"></transition>
   </node>
   <node name="node3">
   <event type="node-enter">
        <script>
          print("進入第三個節點");
        </script>
     </event>
      <transition name="" to="end1"></transition>
   </node>
   <end-state name="end1">
      <event type="node-enter">
         <script>
          print("結束操作");
        </script>
      </event>
   </end-state>
</process-definition>
           
String processName = (String)Persistence.getVariable("processName");
		logger.info("processName:"+processName);
		JbpmContext jbpmContext = getJbpmContext();
		GraphSession graphSession=jbpmContext.getGraphSession();
		ProcessDefinition processDefinition = graphSession.findLatestProcessDefinition(processName);
		ProcessInstance processInstance = new ProcessInstance(processDefinition);
		Token token = processInstance.getRootToken();
		token.signal();
		logger.info("NodeName:"+token.getNode().getName());
           

隻要經過一個節點,就可以繼續向下流轉。沒指定預設進入第一個。

結果如下:

進入第一個節點

結束操作

NodeName:end1

end

B:通過表達式變量程式内指定方式指定decision線路

<?xml version="1.0" encoding="UTF-8"?>

<process-definition xmlns="urn:jbpm.org:jpdl-3.2"  name="example005">


	<start-state name="start">
      <transition name="" to="decision1"></transition>
   </start-state>
   <decision name="decision1" expression="#{tname}">
      <transition name="tr1" to="node1"></transition>
      <transition name="tr2" to="node2"></transition>
      <transition name="tr3" to="node3"></transition>
   </decision>
   <node name="node1">
     <event type="node-enter">
        <script>
          print("進入第一個節點");
        </script>
     </event>
      <transition name="" to="end1"></transition>
   </node>
   <node name="node2">
   <event type="node-enter">
        <script>
          print("進入第二個節點");
        </script>
     </event>
      <transition name="" to="end1"></transition>
   </node>
   <node name="node3">
   <event type="node-enter">
        <script>
          print("進入第三個節點");
        </script>
     </event>
      <transition name="" to="end1"></transition>
   </node>
   <end-state name="end1">
      <event type="node-enter">
         <script>
          print("結束操作");
        </script>
      </event>
   </end-state>
</process-definition>
           
JbpmContext jbpmContext = getJbpmContext();
		GraphSession graphSession=jbpmContext.getGraphSession();
		ProcessDefinition processDefinition = graphSession.findLatestProcessDefinition(processName);
		ProcessInstance processInstance = new ProcessInstance(processDefinition);
		processInstance.getContextInstance().setVariable("tname", "tr2");
		Token token = processInstance.getRootToken();
		token.signal();
		logger.info("NodeName:"+token.getNode().getName());
           

結果:

進入第二個節點

結束操作

NodeName:end1

end

C:通過DecisionHandler方式指定decision線路

<?xml version="1.0" encoding="UTF-8"?>

<process-definition xmlns="urn:jbpm.org:jpdl-3.2"  name="example005">


	<start-state name="start">
      <transition name="" to="decision1"></transition>
   </start-state>
   <decision name="decision1">
      <handler class="jbpm.java.handler.example.TestDecision"/>
      <transition name="tr1" to="node1"></transition>
      <transition name="tr2" to="node2"></transition>
      <transition name="tr3" to="node3"></transition>
   </decision>
   <node name="node1">
     <event type="node-enter">
        <script>
          print("進入第一個節點");
        </script>
     </event>
      <transition name="" to="end1"></transition>
   </node>
   <node name="node2">
   <event type="node-enter">
        <script>
          print("進入第二個節點");
        </script>
     </event>
      <transition name="" to="end1"></transition>
   </node>
   <node name="node3">
   <event type="node-enter">
        <script>
          print("進入第三個節點");
        </script>
     </event>
      <transition name="" to="end1"></transition>
   </node>
   <end-state name="end1">
      <event type="node-enter">
         <script>
          print("結束操作");
        </script>
      </event>
   </end-state>
</process-definition>
           

TestDecision.java

public class TestDecision implements DecisionHandler {
	private static final long serialVersionUID = -9083605280987838663L;

	@Override
	public String decide(ExecutionContext executionContext) throws Exception {
		return "tr3";
	}
}
           
JbpmContext jbpmContext = getJbpmContext();
		GraphSession graphSession=jbpmContext.getGraphSession();
		ProcessDefinition processDefinition = graphSession.findLatestProcessDefinition(processName);
		ProcessInstance processInstance = new ProcessInstance(processDefinition);
		Token token = processInstance.getRootToken();
		token.signal();
		logger.info("NodeName:"+token.getNode().getName());
           

結果:

進入第三個節點

結束操作

NodeName:end1

end

五、根據參與者actor-id取到對應任務、根據任務ID取得執行個體

<?xml version="1.0" encoding="UTF-8"?>

<process-definition xmlns="urn:jbpm.org:jpdl-3.2"  name="example008">

	<start-state name="start">
      <transition name="" to="task1"></transition>
   </start-state>
   <task-node name="task1">
      <event type="task-create">
        <script>
          print("觸發了task-create事件");
        </script>
      </event>
      <event type="task-start">
        <script>
          print("觸發了task-start事件");
        </script>
      </event>
      <event type="task-assign">
        <script>
          print("觸發了task-assign事件");
        </script>
      </event>
      <event type="task-end">
        <script>
          print("觸發了task-end事件");
        </script>
      </event>
      <task>
         <assignment actor-id="admin001"></assignment>
      </task>
      <transition name="" to="end1"></transition>
   </task-node>
   
   <end-state name="end1"></end-state>
</process-definition>
           
JbpmContext jbpmContext = getJbpmContext();
		GraphSession graphSession=jbpmContext.getGraphSession();
		ProcessDefinition processDefinition = graphSession.findLatestProcessDefinition(processName);
		ProcessInstance processInstance = new ProcessInstance(processDefinition);
		Token token = processInstance.getRootToken();
		token.signal();
		logger.info("NodeName:"+token.getNode().getName());
		//根據參與者actor-id取到對應任務
		List<TaskInstance> taskInstance = jbpmContext.getTaskMgmtSession().findTaskInstances("admin001");
		for(TaskInstance ti : taskInstance){
			logger.info("actor-id:"+ti.getName());
		}
           

輸出結果:

觸發了task-create事件

觸發了task-assign事件

NodeName:task1

actor-id:task1

JbpmContext jbpmContext = getJbpmContext();
		GraphSession graphSession=jbpmContext.getGraphSession();
		ProcessDefinition processDefinition = graphSession.findLatestProcessDefinition(processName);
		ProcessInstance processInstance = new ProcessInstance(processDefinition);
		Token token = processInstance.getRootToken();
		token.signal();
		logger.info("NodeName:"+token.getNode().getName());
		
		//根據任務ID取得執行個體
		TaskInstance taskInstance = jbpmContext.loadTaskInstance(taskInstanceId);
		logger.info("actor-id:"+taskInstance.getName());/
           

輸出結果如下:

觸發了task-create事件

觸發了task-assign事件

NodeName:task1

actor-id:task1

六、Swimlane方式

用于處理一個流程中多個任務節點由同一個人或者角色來完成。

<?xml version="1.0" encoding="UTF-8"?>

<process-definition xmlns="urn:jbpm.org:jpdl-3.2"  name="example009">

	<swimlane name="user">
		<assignment actor-id="#{userId}"></assignment>
	</swimlane>
	
	<start-state name="start">
      <transition name="" to="task1"></transition>
   </start-state>
   <task-node name="task1">
      <event type="task-create">
        <script>
          print("觸發了task-create事件");
        </script>
      </event>
      <event type="task-start">
        <script>
          print("觸發了task-start事件");
        </script>
      </event>
      <event type="task-assign">
        <script>
          print("觸發了task-assign事件");
        </script>
      </event>
      <event type="task-end">
        <script>
          print("觸發了task-end事件");
        </script>
      </event>
      <task swimlane="user"/>
      
      <transition name="" to="end1"></transition>
   </task-node>
   
   <end-state name="end1"></end-state>
</process-definition>
           
JbpmContext jbpmContext = getJbpmContext();
		GraphSession graphSession=jbpmContext.getGraphSession();
		ProcessDefinition processDefinition = graphSession.findLatestProcessDefinition(processName);
		ProcessInstance processInstance = new ProcessInstance(processDefinition);
		processInstance.getContextInstance().setVariable("userId", "admin002");
		Token token = processInstance.getRootToken();
		token.signal();
		logger.info("NodeName:"+token.getNode().getName());
		
		List<TaskInstance> taskInstance = jbpmContext.getTaskMgmtSession().findTaskInstances("admin002");
		for(TaskInstance ti : taskInstance){
			logger.info("actor-id:"+ti.getName());
		}
           

輸出結果:

觸發了task-create事件

觸發了task-assign事件

NodeName:task1

actor-id:task1

七、pooled-actors方式 

一個任務直接配置設定給多個參與者,多個參與者用逗号隔開。

例如:送出給一個部門,該部門的人都能看到,其中一個人處理就可以了。

這種方式隻能靜态配置設定,不能動态配置設定。是以适用範圍有限。

<?xml version="1.0" encoding="UTF-8"?>

<process-definition xmlns="urn:jbpm.org:jpdl-3.2"  name="example010">


	
	<start-state name="start">
      <transition name="" to="task1"></transition>
   </start-state>
   <task-node name="task1">
      <event type="task-create">
        <script>
          print("觸發了task-create事件");
        </script>
      </event>
      <event type="task-start">
        <script>
          print("觸發了task-start事件");
        </script>
      </event>
      <event type="task-assign">
        <script>
          print("觸發了task-assign事件");
        </script>
      </event>
      <event type="task-end">
        <script>
          print("觸發了task-end事件");
        </script>
      </event>
      <task>
      	<assignment pooled-actors="admin001,admin002,admin003"></assignment>
      </task>
      
      <transition name="" to="end1"></transition>
   </task-node>
   
   <end-state name="end1"></end-state>
</process-definition>
           
JbpmContext jbpmContext = getJbpmContext();
		GraphSession graphSession=jbpmContext.getGraphSession();
		ProcessDefinition processDefinition = graphSession.findLatestProcessDefinition(processName);
		ProcessInstance processInstance = new ProcessInstance(processDefinition);

		Token token = processInstance.getRootToken();
		token.signal();
		logger.info("NodeName:"+token.getNode().getName());
		
		List<TaskInstance> taskInstance = jbpmContext.getTaskMgmtSession().findPooledTaskInstances("admin001");
		for(TaskInstance ti : taskInstance){
			logger.info("pooled-actors:"+ti.getName());
		}
           

輸出結果如下:

觸發了task-create事件

NodeName:task1

pooled-actors:task1

七、發送mail提醒

A、建立郵件服務。

下載下傳james-2.3.2,解壓。進入dos指令行模式,進入C:\james-2.3.2\bin,執行run.bat

JBPM筆記-基礎範例

例圖所示郵件伺服器啟動完畢,請不要關閉dos視窗。

pop3,smtp,等資訊顯示如上。

再打開新的dos視窗。

JBPM筆記-基礎範例

輸入telnet localhost 4555

JBPM筆記-基礎範例

提示輸入使用者名密碼:都是root

之後輸入help,可以看到指令幫助。

輸入 adduser   adminsender   123456   

新增一個使用者以及密碼。新增完畢之後即可關閉此視窗,或者輸入quit退出。

B、程式配置。

把jbpm-jpdl-3.2.3中的兩個jar檔案activation.jar、mail.jar放置工程中。

<?xml version="1.0" encoding="UTF-8"?>

<process-definition  xmlns=""  name="example011">


	<start-state name="start-state1">
		<transition to="task-node1"></transition>
	</start-state>


	<task-node name="task-node1">
		<task name="notifyTask" notify="true">
			<assignment actor-id="adminsender"></assignment>
		</task>
		<transition to="end-state1"></transition>
	</task-node>


	<end-state name="end-state1"></end-state>


</process-definition>
           

或者使用下面流程檔案:

<?xml version="1.0" encoding="UTF-8"?>

<process-definition  xmlns=""  name="example012">


	<start-state name="start-state1">
		<transition to="task-node1"></transition>
	</start-state>


	<task-node name="task-node1">
		<task name="notifyTask">
			<assignment actor-id="adminsender"/>
			<event type="task-assign">
				<mail template="task-assign"/>
			</event>
		</task>
		<transition to="end-state1"></transition>
	</task-node>


	<end-state name="end-state1"></end-state>


</process-definition>
           

注意 xmlns="" ,裡面暫時為空。不能放入urn:jbpm.org:jpdl-3.2,否則會在部署的時候提示org.jbpm.jpdl.JpdlException: [[ERROR] line 12: cvc-complex-type.3.2.2: Attribute 'notify' is not allowed to appear in element 'task'.]

原因暫時不清數,不過去掉,即可正常部署。

建立MailResolver.java檔案

package jbpm.java.mail;

import org.jbpm.mail.AddressResolver;

public class MailResolver implements AddressResolver{

	private static final long serialVersionUID = 3634448991562190346L;

	@Override
	public Object resolveAddress(String actorId) {
		if(actorId.equals("adminsender")){
			return "[email protected]";
		}else{
			return "[email protected]";
		}
	}

}
           

修改jbpm.cfg.xml,加入如下内容:

<string name="resource.mail.templates" value="jbpm.mail.templates.xml"/>
  <string name="jbpm.mail.smtp.host" value="localhost"/>
  <string name="jbpm.mail.smtp.port" value="25"/>
  <bean name="jbpm.mail.address.resolver" class="jbpm.java.mail.MailResolver" singleton="true"/>
  <string name="jbpm.mail.from.address" value="[email protected]"/>
  <string name="jbpm.mail.smtp.auth" value="true"/>
           

部署xml檔案。執行

JbpmContext jbpmContext = getJbpmContext();
		GraphSession graphSession=jbpmContext.getGraphSession();
		ProcessDefinition processDefinition = graphSession.findLatestProcessDefinition(processName);
		ProcessInstance processInstance = new ProcessInstance(processDefinition);
		Token token = processInstance.getRootToken();
		token.signal();
		logger.info("NodeName:"+token.getNode().getName());
           

提示

java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream錯誤。

主要原因是javax.mail和javax.activation這兩個包已經在javaEE5當中屬于基礎包了,但是裡面的方法與現在jbpm提供的的mail.jar和activation.jar有一些出入

X:/Program Files/MyEclipse 6.5/myeclipse/eclipse/plugins/com.genuitec.eclipse.j2eedt.core_6.5.0.zmyeclipse650200806/data/libraryset/EE_5

這個路徑裡,可以看到javaee.jar,用rar把這個檔案打開,然後進到javax檔案夾裡,删除mail.jar和activation.jar。注意備份。

之後執行,則通過。

八、任務排程