Jbpm 流程节点

1、Node节点
Node节点是一个自动完成节点,如果没有在Node节点上定义Action,流程达到Node节点后不会停留,而是继续往下执行到Node节点的下一个节点。利用之前的Helloworld例子,我们在Node节点上加上一个Action(Action的执行是在node-enter之后node-leave之前)
Xml代码 复制代码 收藏代码
  1. <nodename="node1">
  2. <actionclass="com.royzhou.action.NodeAction"></action>
  3. <transitionto="state1"></transition>
  4. </node>
	<node name="node1">
		<action class="com.royzhou.action.NodeAction"></action>
		<transition to="state1"></transition>
	</node>

Action类如下:
Java代码 复制代码 收藏代码
  1. packagecom.royzhou.action;
  2. importorg.jbpm.graph.def.ActionHandler;
  3. importorg.jbpm.graph.exe.ExecutionContext;
  4. publicclassNodeActionimplementsActionHandler{
  5. publicvoidexecute(ExecutionContextexecutionContext)throwsException{
  6. System.out.println("nodeaction……………………");
  7. }
  8. }
package com.royzhou.action;

import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;

public class NodeAction implements ActionHandler {
	public void execute(ExecutionContext executionContext) throws Exception {
		System.out.println("node action……………………");
	}
}

测试类如下:
Java代码 复制代码 收藏代码
  1. packagecom.royzhou.test;
  2. importjava.io.FileInputStream;
  3. importjava.io.FileNotFoundException;
  4. importjava.util.zip.ZipInputStream;
  5. importorg.jbpm.JbpmConfiguration;
  6. importorg.jbpm.JbpmContext;
  7. importorg.jbpm.graph.def.ProcessDefinition;
  8. importorg.jbpm.graph.exe.ProcessInstance;
  9. importorg.jbpm.graph.exe.Token;
  10. publicclassHelloWorldDB{
  11. publicstaticvoiddeploy()throwsFileNotFoundException{
  12. JbpmConfigurationjbpmConfiguration=JbpmConfiguration.getInstance();
  13. JbpmContextjbpmContext=jbpmConfiguration.createJbpmContext();
  14. try{
  15. FileInputStreamfis=newFileInputStream("F:/workspace/jbpm-test/src/main/jpdl/helloworld/helloworld.zip");
  16. ZipInputStreamzis=newZipInputStream(fis);
  17. ProcessDefinitionprocessDefinition=ProcessDefinition.parseParZipInputStream(zis);
  18. jbpmContext.deployProcessDefinition(processDefinition);
  19. fis.close();
  20. zis.close();
  21. }catch(Exceptione){
  22. e.printStackTrace();
  23. }finally{
  24. jbpmContext.close();
  25. }
  26. }
  27. publicstaticvoidmain(String[]args)throwsFileNotFoundException{
  28. HelloWorldDB.deploy();
  29. JbpmConfigurationjbpmConfiguration=JbpmConfiguration.getInstance();
  30. JbpmContextjbpmContext=jbpmConfiguration.createJbpmContext();
  31. jbpmContext.setActorId("royzhou");
  32. //获取最新版本的流程定义对象
  33. ProcessDefinitionprocessDefinition=jbpmContext.getGraphSession().findLatestProcessDefinition("helloworld");
  34. ProcessInstanceprocessInstance=newProcessInstance(processDefinition);
  35. //得到流程令牌
  36. Tokentoken=processInstance.getRootToken();
  37. //打印流程当前所处节点
  38. System.out.println("1:流程现在所处节点:"+token.getNode().getName());
  39. //触发流程流转到下一个节点Node
  40. token.signal();
  41. /**
  42. *注意因为Node节点设置Action
  43. *所以流程会停留在Node节点
  44. */
  45. System.out.println("2:流程现在所处节点:"+token.getNode().getName());
  46. //触发流程流转到下一个节点State
  47. token.signal();
  48. System.out.println("3:流程现在所处节点:"+token.getNode().getName());
  49. token.signal();
  50. System.out.println("4:流程现在所处节点:"+token.getNode().getName());
  51. System.out.println("流程状态是否结束:"+token.getProcessInstance().hasEnded());
  52. jbpmContext.close();
  53. }
  54. }
package com.royzhou.test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.zip.ZipInputStream;

import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;

public class HelloWorldDB {
	public static void deploy() throws FileNotFoundException {
		JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
		JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
		try {
			FileInputStream fis = new FileInputStream("F:/workspace/jbpm-test/src/main/jpdl/helloworld/helloworld.zip ");
			ZipInputStream zis = new ZipInputStream(fis);
			ProcessDefinition processDefinition = ProcessDefinition.parseParZipInputStream(zis);
			jbpmContext.deployProcessDefinition(processDefinition);
			fis.close();
			zis.close();
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			jbpmContext.close();
		}
	}
	
	public static void main(String[] args) throws FileNotFoundException {
		HelloWorldDB.deploy();
		JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
		JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
		jbpmContext.setActorId("royzhou");
		//获取最新版本的流程定义对象
		ProcessDefinition processDefinition = jbpmContext.getGraphSession().findLatestProcessDefinition("helloworld");
		ProcessInstance processInstance = new ProcessInstance(processDefinition);
		//得到流程令牌
		Token token = processInstance.getRootToken();
		
		//打印流程当前所处节点
		System.out.println("1:流程现在所处节点:" + token.getNode().getName());
		
		//触发流程流转到下一个节点Node
		token.signal();
		
		/**
		 * 注意因为Node节点设置Action
		 * 所以流程会停留在Node节点
		 */
		System.out.println("2:流程现在所处节点:" + token.getNode().getName());
		
		//触发流程流转到下一个节点State
		token.signal();
		System.out.println("3:流程现在所处节点:" + token.getNode().getName());
token.signal();
		System.out.println("4:流程现在所处节点:" + token.getNode().getName());
		System.out.println("流程状态是否结束:" + token.getProcessInstance().hasEnded());
		jbpmContext.close();
	}
}

测试结果如下:(验证了在Node上设置Action的时候,流程处于等待状态)
1:流程现在所处节点:start-state1
node action……………………
2:流程现在所处节点:node1
3:流程现在所处节点:state1
4:流程现在所处节点:end-state1
流程状态是否结束:true

2、State节点
State节点属性类似Node,不过当流程流转到State节点时就会停下来,直到外部向其发送流转的命令,如signal().

3、Task-Node
Task Node节点在Jbpm中是很重要的一个节点,可以用来添加任务,产生任务实例。一个Task Node 可以定义多个Task,为Task分配执行人等等。下面我们通过一个例子来解释Task Node。
Xml代码 复制代码 收藏代码
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <process-definitionxmlns="urn:jbpm.org:jpdl-3.2"name="tasknode">
  3. <start-statename="start-state1">
  4. <transitionto="task-node1"></transition>
  5. </start-state>
  6. <task-nodename="task-node1">
  7. <taskname="mytask">
  8. <assignmentactor-id="royzhou"></assignment>
  9. </task>
  10. <transitionto="end-state1"></transition>
  11. </task-node>
  12. <end-statename="end-state1"></end-state>
  13. </process-definition>
	<?xml version="1.0" encoding="UTF-8"?>

<process-definition  xmlns="urn:jbpm.org:jpdl-3.2"  name="tasknode">
	<start-state name="start-state1">
		<transition to="task-node1"></transition>
	</start-state>
	<task-node name="task-node1">
		<task name="mytask">
			<assignment actor-id="royzhou"></assignment>
		</task>
		<transition to="end-state1"></transition>
	</task-node>
	<end-state name="end-state1"></end-state>
</process-definition>

上面流程文件定义了一个Task Node ,在Task Node下面定义了一个Task节点,分配给了royzhou这个人(实际开发中的任务分配会更加复杂)
接下来我们开始写测试类:
Java代码 复制代码 收藏代码
  1. packagecom.royzhou.test;
  2. importjava.io.FileInputStream;
  3. importjava.io.FileNotFoundException;
  4. importjava.util.zip.ZipInputStream;
  5. importorg.jbpm.JbpmConfiguration;
  6. importorg.jbpm.JbpmContext;
  7. importorg.jbpm.graph.def.ProcessDefinition;
  8. importorg.jbpm.graph.exe.ProcessInstance;
  9. importorg.jbpm.graph.exe.Token;
  10. publicclassTaskNode{
  11. publicstaticvoiddeploy()throwsFileNotFoundException{
  12. JbpmConfigurationjbpmConfiguration=JbpmConfiguration.getInstance();
  13. JbpmContextjbpmContext=jbpmConfiguration.createJbpmContext();
  14. try{
  15. FileInputStreamfis=newFileInputStream("F:/workspace/jbpm-test/src/main/jpdl/tasknode/tasknode.zip");
  16. ZipInputStreamzis=newZipInputStream(fis);
  17. ProcessDefinitionprocessDefinition=ProcessDefinition.parseParZipInputStream(zis);
  18. jbpmContext.deployProcessDefinition(processDefinition);
  19. fis.close();
  20. zis.close();
  21. }catch(Exceptione){
  22. e.printStackTrace();
  23. }finally{
  24. jbpmContext.close();
  25. }
  26. }
  27. publicstaticvoidmain(String[]args)throwsFileNotFoundException{
  28. TaskNode.deploy();
  29. JbpmConfigurationjbpmConfiguration=JbpmConfiguration.getInstance();
  30. JbpmContextjbpmContext=jbpmConfiguration.createJbpmContext();
  31. ProcessDefinitionprocessDefinition=jbpmContext.getGraphSession().findLatestProcessDefinition("tasknode");
  32. ProcessInstanceprocessInstance=newProcessInstance(processDefinition);
  33. Tokentoken=processInstance.getRootToken();
  34. token.signal();
  35. System.out.println("流程现在所处节点:"+token.getNode().getName());
  36. jbpmContext.close();
  37. }
  38. }
	package com.royzhou.test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.zip.ZipInputStream;

import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;

public class TaskNode {
	
	public static void deploy() throws FileNotFoundException {
		JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
		JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
		try {
			FileInputStream fis = new FileInputStream("F:/workspace/jbpm-test/src/main/jpdl/tasknode/tasknode.zip");
			ZipInputStream zis = new ZipInputStream(fis);
			ProcessDefinition processDefinition = ProcessDefinition.parseParZipInputStream(zis);
			jbpmContext.deployProcessDefinition(processDefinition);
			fis.close();
			zis.close();
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			jbpmContext.close();
		}
	}
	
	public static void main(String[] args) throws FileNotFoundException {
		TaskNode.deploy();
		JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
		JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
		ProcessDefinition processDefinition = jbpmContext.getGraphSession().findLatestProcessDefinition("tasknode");
		ProcessInstance processInstance = new ProcessInstance(processDefinition);
		Token token = processInstance.getRootToken();
		token.signal();
		System.out.println("流程现在所处节点:" + token.getNode().getName());
		jbpmContext.close();
	}
}

后台打印结果:
流程现在所处节点:task-node1
查看jbpm_taskinstance表看到一个名叫mytask的任务,指定给了royzhou说明我们的任务创建成功了。
Task Node有几个比较重要的属性:
Signal:
last:最后一个完成之后继续往下流转,如果没有任务被创建直接流转到下一节点
last-wait:最后一个完成之后继续往下流转,如果没有任务被创建处于等待状态
first:只要有一个完成就继续往下流转,如果没有任务被创建直接流转下一个节点
first-wait:只要一个完成就继续往下流转,如果没有任务被创建则处于等待状态
never:必须显示调用processInstance.signal()才继续流转
unsynchronized:不停留,直接流转到下个节点

task-creates:流程流转到这个节点上时是不是自动创建任务,默认是true。通过设置为false,配合其他事件我们可以实现会签的功能。

4、Start节点
Start节点在每个流程中有且只能有一个。Start中可以配置Task,但是 配置在Start节点中的task不会调用任务分配机制。这点是不同于Task Node的。。。。

5、fork和join节点
二者是成对出现的。Fork节点可以将流程拆分成多条并行也就是将Token拆分成多个子Token,到join节点的时候再汇聚成一个Token继续往下执行
一般来说,在经过fork节点之后,必须等待每个子token都走完才会通过join节点继续往下走,但是我们可以通过修改join节点的discriminator属性来,设置为true之后只要有一个子token到达join节点,就会往下流转。不过这样做产生的一个影响就是其他没有结束的子token上的任务实例依然存在且处于等待状态,任务参与者仍然可以处理这些任务。因此,在设置join节点的discriminator为true时,我们还需要手动结束掉其他分支上的任务实例。
在fork节点中,我们可以设定条件来选择只走满足条件的分支。主要是通过之前提到的beanshell脚本来实现。举例说明一下这个实现:
流程定义由一个start节点,一个end节点,一对fork/join节点以及分支中的四个node节点组成,流程定义的xml文件如下:
Xml代码 复制代码 收藏代码
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <process-definitionxmlns="urn:jbpm.org:jpdl-3.2"name="forkjoin">
  3. <start-statename="start-state1">
  4. <transitionto="fork1"></transition>
  5. </start-state>
  6. <forkname="fork1">
  7. <script>
  8. <variablename="forkTransition"access="write"></variable>
  9. <expression>
  10. forkTransition=newArrayList();
  11. if(param&gt;1000){
  12. forkTransition.add("tonode1");
  13. forkTransition.add("tonode2");
  14. }else{
  15. forkTransition.add("tonode3");
  16. forkTransition.add("tonode4");
  17. }
  18. </expression>
  19. </script>
  20. <transitionto="node1"name="tonode1"></transition>
  21. <transitionto="node2"name="tonode2"></transition>
  22. <transitionto="node3"name="tonode3"></transition>
  23. <transitionto="node4"name="tonode4"></transition>
  24. </fork>
  25. <joinname="join1">
  26. <transitionto="end-state1"></transition>
  27. </join>
  28. <nodename="node1">
  29. <eventtype="node-enter">
  30. <script>
  31. print(&quot;node1enter&quot;);
  32. </script>
  33. </event>
  34. <transitionto="join1"></transition>
  35. </node>
  36. <nodename="node2">
  37. <eventtype="node-enter">
  38. <script>
  39. print(&quot;node2enter&quot;);
  40. </script>
  41. </event>
  42. <transitionto="join1"></transition>
  43. </node>
  44. <nodename="node3">
  45. <eventtype="node-enter">
  46. <script>
  47. print(&quot;node3enter&quot;);
  48. </script>
  49. </event>
  50. <transitionto="join1"></transition>
  51. </node>
  52. <nodename="node4">
  53. <eventtype="node-enter">
  54. <script>
  55. print(&quot;node4enter&quot;);
  56. </script>
  57. </event>
  58. <transitionto="join1"></transition>
  59. </node>
  60. <end-statename="end-state1"></end-state>
  61. </process-definition>
<?xml version="1.0" encoding="UTF-8"?>
<process-definition  xmlns="urn:jbpm.org:jpdl-3.2"  name="forkjoin">
	<start-state name="start-state1">
		<transition to="fork1"></transition>
	</start-state>
	<fork name="fork1">
		<script>
			<variable name="forkTransition" access="write"></variable>
			<expression>
				forkTransition = new ArrayList();
				if(param &gt; 1000) {
					forkTransition.add("to node1");
					forkTransition.add("to node2");
				} else {
					forkTransition.add("to node3");
					forkTransition.add("to node4");
				}
			</expression>
		</script>
		<transition to="node1" name="to node1"></transition>
		<transition to="node2" name="to node2"></transition>
		<transition to="node3" name="to node3"></transition>
		<transition to="node4" name="to node4"></transition>
	</fork>
	<join name="join1">
		<transition to="end-state1"></transition>
	</join>
	<node name="node1">
		<event type="node-enter">
			<script>
				print(&quot;node1 enter&quot;);
			</script>
		</event>
		<transition to="join1"></transition>
	</node>
	<node name="node2">
		<event type="node-enter">
			<script>
				print(&quot;node2 enter&quot;);
			</script>
		</event>
		<transition to="join1"></transition>
	</node>
	<node name="node3">
		<event type="node-enter">
			<script>
				print(&quot;node3 enter&quot;);
			</script>
		</event>
		<transition to="join1"></transition>
	</node>
	<node name="node4">
		<event type="node-enter">
			<script>
				print(&quot;node4 enter&quot;);
			</script>
		</event>
		<transition to="join1"></transition>
	</node>
	<end-state name="end-state1"></end-state>
</process-definition>

默认情况下,当流程进入fork节点之后会分成四个分支,分别经过Node节点。在上面定义文件中我们在fork节点下做了判断,如果流程变量param>1000的时候走分支1和分支2,如果小于则走分支3和分支4。
Xml代码 复制代码 收藏代码
  1. <script>
  2. <variablename="forkTransition"access="write"></variable>
  3. <expression>
  4. forkTransition=newArrayList();
  5. if(param&gt;1000){
  6. forkTransition.add("tonode1");
  7. forkTransition.add("tonode2");
  8. }else{
  9. forkTransition.add("tonode3");
  10. forkTransition.add("tonode4");
  11. }
  12. </expression>
  13. </script>
<script>
			<variable name="forkTransition" access="write"></variable>
			<expression>
				forkTransition = new ArrayList();
				if(param &gt; 1000) {
					forkTransition.add("to node1");
					forkTransition.add("to node2");
				} else {
					forkTransition.add("to node3");
					forkTransition.add("to node4");
				}
			</expression>
		</script>

注意这里的forkTransition必须是集合类型,它存放的是流程经过fork之后生成的分支名称。access属性设置为write表示是写入流程实例对应的Fork节点,才能生成我们指定的分支。在Expression标签下是我们做的逻辑处理,通过流程变量param来判断Fork节点具体要生成那些分支。
默认我们不为Fork节点添加script,流程到Fork节点时将生成所有transition。一旦设置了script,还必须设置一个变量,如上面的forkTransition写回流程变量中生成具体的分支。

测试类如下:(为方便测试没有将流程发布到数据库,下面测试例子也是采用相同做法)
Java代码 复制代码 收藏代码
  1. packagecom.royzhou.test;
  2. importorg.jbpm.graph.def.ProcessDefinition;
  3. importorg.jbpm.graph.exe.ProcessInstance;
  4. importorg.jbpm.graph.exe.Token;
  5. publicclassForkJoin{
  6. publicstaticvoidmain(String[]args){
  7. ProcessDefinitionprocessDefinition=ProcessDefinition.parseXmlResource("forkjoin/processDefinition.xml");
  8. ProcessInstanceprocessInstance=newProcessInstance(processDefinition);
  9. processInstance.getContextInstance().setVariable("param",10);
  10. Tokentoken=processInstance.getRootToken();
  11. token.signal();
  12. }
  13. }
package com.royzhou.test;

import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;

public class ForkJoin {
	
	public static void main(String[] args) {
		ProcessDefinition processDefinition = ProcessDefinition.parseXmlResource("forkjoin/processDefinition.xml");
		ProcessInstance processInstance = new ProcessInstance(processDefinition);
		processInstance.getContextInstance().setVariable("param", 10);
		Token token = processInstance.getRootToken();
		token.signal();
	}
}

执行成功之后后台输出:
node3 enter
node4 enter

修改我们的param改为2000再次执行,后台变为:
node1 enter
node2 enter

6、Decision节点
Decision节点是判断节点,当流程到达decision节点之后会有多个路由选择,我们可以在这个节点上定义handler或者是使用脚本等等来决定流程走向。Decision节点不同于Fork节点,它只能选择多个Transition中的其中一个,而Fork节点是并行的。
举例说明一下:
流程定义由一个start节点,一个end节点,一个Decision节点以及分支中的3个node节点组成,在Decision我们设置了delegation,使用实现DecisionHandler接口的类SelectNode来判断流程走向,它返回的结果是其中分支的名称,流程定义的xml文件如下:
Xml代码 复制代码 收藏代码
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <process-definitionxmlns="urn:jbpm.org:jpdl-3.2"name="decision">
  3. <start-statename="start-state1">
  4. <transitionto="decision1"></transition>
  5. </start-state>
  6. <decisionname="decision1">
  7. <handlerclass="com.royzhou.action.SelectNode"></handler>
  8. <transitionto="node1"name="tonode1"></transition>
  9. <transitionto="node2"name="tonode2"></transition>
  10. <transitionto="node3"name="tonode3"></transition>
  11. </decision>
  12. <nodename="node1">
  13. <script>
  14. print(&quot;node1enter&quot;)
  15. </script>
  16. </node>
  17. <nodename="node2">
  18. <script>
  19. print(&quot;node2enter&quot;)
  20. </script>
  21. <transitionto="end-state1"></transition>
  22. </node>
  23. <nodename="node3">
  24. <script>
  25. print(&quot;node3enter&quot;)
  26. </script>
  27. </node>
  28. <end-statename="end-state1"></end-state>
  29. </process-definition>
	<?xml version="1.0" encoding="UTF-8"?>
<process-definition  xmlns="urn:jbpm.org:jpdl-3.2"  name="decision">
	<start-state name="start-state1">
		<transition to="decision1"></transition>
	</start-state>
	<decision name="decision1">
		<handler class="com.royzhou.action.SelectNode"></handler>
		<transition to="node1" name="to node1"></transition>
		<transition to="node2" name="to node2"></transition>
		<transition to="node3" name="to node3"></transition>
	</decision>
	<node name="node1">
		<script>
			print(&quot;node1 enter&quot;)
		</script>
	</node>
	<node name="node2">
		<script>
			print(&quot;node2 enter&quot;)
		</script>
		<transition to="end-state1"></transition>
	</node>
	<node name="node3">
		<script>
			print(&quot;node3 enter&quot;)
		</script>
	</node>
	<end-state name="end-state1"></end-state>
</process-definition>

SelectNode类:(必须实现DecisionHandler接口并重写decide方法,返回值是要走的transition的名称)
Java代码 复制代码 收藏代码
  1. packagecom.royzhou.action;
  2. importorg.jbpm.graph.exe.ExecutionContext;
  3. importorg.jbpm.graph.node.DecisionHandler;
  4. //实现DecisionHandler接口
  5. publicclassSelectNodeimplementsDecisionHandler{
  6. publicStringdecide(ExecutionContextexecutionContext)throwsException{
  7. //通过流程变量来判断要走哪个transition
  8. StringwhichWay=executionContext.getVariable("whichWay").toString();
  9. returnwhichWay;
  10. }
  11. }
package com.royzhou.action;

import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.node.DecisionHandler;
//实现DecisionHandler接口
public class SelectNode implements DecisionHandler {
	public String decide(ExecutionContext executionContext) throws Exception {
		//通过流程变量来判断要走哪个transition
		String whichWay = executionContext.getVariable("whichWay").toString();
		return whichWay;
	}
}

测试类:
Java代码 复制代码 收藏代码
  1. packagecom.royzhou.test;
  2. importorg.jbpm.graph.def.ProcessDefinition;
  3. importorg.jbpm.graph.exe.ProcessInstance;
  4. importorg.jbpm.graph.exe.Token;
  5. publicclassDecision{
  6. publicstaticvoidmain(String[]args){
  7. ProcessDefinitionprocessDefinition=ProcessDefinition.parseXmlResource("decision/processDefinition.xml");
  8. ProcessInstanceprocessInstance=newProcessInstance(processDefinition);
  9. processInstance.getContextInstance().setVariable("whichWay","tonode2");
  10. Tokentoken=processInstance.getRootToken();
  11. token.signal();
  12. }
  13. }
package com.royzhou.test;

import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;

public class Decision {
	
	public static void main(String[] args) {
		ProcessDefinition processDefinition = ProcessDefinition.parseXmlResource("decision/processDefinition.xml");
		ProcessInstance processInstance = new ProcessInstance(processDefinition);
		processInstance.getContextInstance().setVariable("whichWay", "to node2");
		Token token = processInstance.getRootToken();
		token.signal();
	}
}

运行测试类,后台打印出 :
node2 enter
修改流程变量whichWay为to node1 重新运行,后台打印出:
node1 enter
说明我们的decision节点正确处理了其走向。

除了使用delegation,我们也可以在流程文件中直接定义decision节点的expression属性,如下所示:
Xml代码 复制代码 收藏代码
  1. <decisionname="decision1"expression="#{whichWay}">
  2. <!--
  3. <handlerclass="com.royzhou.action.SelectNode"></handler>
  4. -->
  5. <transitionto="node1"name="tonode1"></transition>
  6. <transitionto="node2"name="tonode2"></transition>
  7. <transitionto="node3"name="tonode3"></transition>
  8. </decision>
	<decision name="decision1" expression="#{whichWay}">
		<!-- 
		<handler class="com.royzhou.action.SelectNode"></handler>
		 -->
		<transition to="node1" name="to node1"></transition>
		<transition to="node2" name="to node2"></transition>
		<transition to="node3" name="to node3"></transition>
	</decision>

这里采用的是JPDL表达式来指定流程走向,JPDL表达式是一种类似EL表达式的语言。
上面expression表示从流程变量中获取whichWay这个变量作为我们流程走向的选择。

重新运行我们的测试类。发现结果与上面一种做法相同。

此外我们还可以直接在transition节点下定义condition标签,配合JPDL表达式来作为我们的判断依据
Xml代码 复制代码 收藏代码
  1. <decisionname="decision1">
  2. <transitionto="node1"name="tonode1">
  3. <conditionexpression="#{whichWay=='tonode1'}"></condition>
  4. </transition>
  5. <transitionto="node2"name="tonode2">
  6. <conditionexpression="#{whichWay=='tonode2'}"></condition>
  7. </transition>
  8. <transitionto="node3"name="tonode3">
  9. <conditionexpression="#{whichWay=='tonode3'}"></condition>
  10. </transition>
  11. </decision>
<decision name="decision1">
		<transition to="node1" name="to node1">
			<condition expression="#{whichWay == 'to node1'}"></condition>
		</transition>
		<transition to="node2" name="to node2">
			<condition expression="#{whichWay == 'to node2'}"></condition>
		</transition>
		<transition to="node3" name="to node3">
			<condition expression="#{whichWay == 'to node3'}"></condition>
		</transition>
	</decision>

再次运行测试程序发现结果仍然一致。

由此可见 Decision节点支持我们使用delegation、condition以及expression三种方式来指定流程走向。

7、Process State节点
子流程节点可以简化我们的复杂流程。主流程与子流程之间可以共享变量。如果使用子流程,在主流程发布之前必须先发布子流程。
举例说明一下主流程与子流程及其变量共享:
主流程定义文件mainprocess/processdefinition.xml
Xml代码 复制代码 收藏代码
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <process-definitionxmlns="urn:jbpm.org:jpdl-3.2"name="mainprocess">
  3. <start-statename="start-state1">
  4. <transitionto="task-node1"></transition>
  5. </start-state>
  6. <task-nodename="task-node1">
  7. <eventtype="node-enter">
  8. <script>
  9. print(&quot;maintasknode1enter&quot;)
  10. </script>
  11. </event>
  12. <taskname="maintask1">
  13. <assignmentactor-id="maintask1"></assignment>
  14. </task>
  15. <transitionto="process-state1"></transition>
  16. </task-node>
  17. <process-statename="process-state1">
  18. <sub-processname="subprocess"/>
  19. <variablename="mainParam"access="read"></variable>
  20. <variablename="subParam"access="write"></variable>
  21. <transitionto="task-node2"></transition>
  22. </process-state>
  23. <task-nodename="task-node2">
  24. <eventtype="node-enter">
  25. <script>
  26. print(&quot;maintasknode2enter&quot;)
  27. </script>
  28. </event>
  29. <taskname="maintask2">
  30. <assignmentactor-id="maintask2"></assignment>
  31. </task>
  32. <transitionto="end-state1"></transition>
  33. </task-node>
  34. <end-statename="end-state1"></end-state>
  35. </process-definition>
<?xml version="1.0" encoding="UTF-8"?>
<process-definition  xmlns="urn:jbpm.org:jpdl-3.2"  name="mainprocess">
	<start-state name="start-state1">
		<transition to="task-node1"></transition>
	</start-state>
	<task-node name="task-node1">
		<event type="node-enter">
			<script>
				print(&quot;main task node1 enter&quot;)
			</script>
		</event>
		<task name="maintask1">
			<assignment actor-id="maintask1"></assignment>
		</task>
		<transition to="process-state1"></transition>
	</task-node>
	<process-state name="process-state1">
		<sub-process name="subprocess"/>
		<variable name="mainParam" access="read"></variable>
		<variable name="subParam" access="write"></variable>
		<transition to="task-node2"></transition>
	</process-state>
	<task-node name="task-node2">
		<event type="node-enter">
			<script>
				print(&quot;main task node2 enter&quot;)
			</script>
		</event>
		<task name="maintask2">
			<assignment actor-id="maintask2"></assignment>
		</task>
		<transition to="end-state1"></transition>
	</task-node>
	<end-state name="end-state1"></end-state>
</process-definition>

主流程中设置了process-state节点,其sub-process 的name属性表示子流程的名称,
<variable name="mainParam" access="read"></variable>表示从主流程读取mainParam变量
<variable name="subParam" access="write"></variable>表示子流程将变量subParam写回主流程中。

子流程定义文件:subprocess/processdefinition.xml
Xml代码 复制代码 收藏代码
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <process-definitionxmlns="urn:jbpm.org:jpdl-3.2"name="subprocess">
  3. <start-statename="start-state1">
  4. <transitionto="task-node1"></transition>
  5. </start-state>
  6. <task-nodename="task-node1">
  7. <eventtype="node-enter">
  8. <script>
  9. print(&quot;subtasknode1enter&quot;)
  10. </script>
  11. </event>
  12. <taskname="subtask1">
  13. <assignmentactor-id="subtask1"></assignment>
  14. </task>
  15. <eventtype="node-enter">
  16. <script>
  17. print(&quot;subtasknode1enter&quot;)
  18. </script>
  19. </event>
  20. <transitionto="end-state1"></transition>
  21. </task-node>
  22. <end-statename="end-state1"></end-state>
  23. </process-definition>
<?xml version="1.0" encoding="UTF-8"?>
<process-definition  xmlns="urn:jbpm.org:jpdl-3.2"  name="subprocess">
	<start-state name="start-state1">
		<transition to="task-node1"></transition>
	</start-state>
	<task-node name="task-node1">
		<event type="node-enter">
			<script>
				print(&quot;sub task node1 enter&quot;)
			</script>
		</event>
		<task name="subtask1">
			<assignment actor-id="subtask1"></assignment>
		</task>
		<event type="node-enter">
			<script>
				print(&quot;sub task node1 enter&quot;)
			</script>
		</event>
		<transition to="end-state1"></transition>
	</task-node>
	<end-state name="end-state1"></end-state>
</process-definition>

测试类:
Java代码 复制代码 收藏代码
  1. packagecom.royzhou.test;
  2. importjava.io.FileNotFoundException;
  3. importorg.jbpm.JbpmConfiguration;
  4. importorg.jbpm.JbpmContext;
  5. importorg.jbpm.graph.def.ProcessDefinition;
  6. importorg.jbpm.graph.exe.ProcessInstance;
  7. importorg.jbpm.graph.exe.Token;
  8. importorg.jbpm.taskmgmt.exe.TaskInstance;
  9. publicclassSubProcess{
  10. publicstaticvoidinit(){
  11. JbpmConfigurationjbpmConfiguration=JbpmConfiguration.getInstance();
  12. jbpmConfiguration.createSchema();
  13. }
  14. publicstaticvoiddeploySub()throwsFileNotFoundException{
  15. JbpmConfigurationjbpmConfiguration=JbpmConfiguration.getInstance();
  16. JbpmContextjbpmContext=jbpmConfiguration.createJbpmContext();
  17. try{
  18. ProcessDefinitionsubProcessDefinition=ProcessDefinition.parseXmlResource("subprocess/processDefinition.xml");
  19. jbpmContext.deployProcessDefinition(subProcessDefinition);
  20. }catch(Exceptione){
  21. e.printStackTrace();
  22. }finally{
  23. jbpmContext.close();
  24. }
  25. }
  26. publicstaticvoiddeployMain()throwsFileNotFoundException{
  27. JbpmConfigurationjbpmConfiguration=JbpmConfiguration.getInstance();
  28. JbpmContextjbpmContext=jbpmConfiguration.createJbpmContext();
  29. try{
  30. ProcessDefinitionmainProcessDefinition=ProcessDefinition.parseXmlResource("mainprocess/processDefinition.xml");
  31. jbpmContext.deployProcessDefinition(mainProcessDefinition);
  32. }catch(Exceptione){
  33. e.printStackTrace();
  34. }finally{
  35. jbpmContext.close();
  36. }
  37. }
  38. publicstaticvoidstartProcess(){
  39. JbpmConfigurationjbpmConfiguration=JbpmConfiguration.getInstance();
  40. JbpmContextjbpmContext=jbpmConfiguration.createJbpmContext();
  41. try{
  42. ProcessDefinitionprocessDefinition=jbpmContext.getGraphSession().findLatestProcessDefinition("mainprocess");
  43. ProcessInstanceprocessInstance=newProcessInstance(processDefinition);
  44. Tokentoken=processInstance.getRootToken();
  45. token.signal();
  46. }catch(Exceptione){
  47. e.printStackTrace();
  48. }finally{
  49. jbpmContext.close();
  50. }
  51. }
  52. publicstaticvoidstartMainTask1(){
  53. JbpmConfigurationjbpmConfiguration=JbpmConfiguration.getInstance();
  54. JbpmContextjbpmContext=jbpmConfiguration.createJbpmContext();
  55. try{
  56. //主流程maintask1
  57. TaskInstancemainTaskInstance1=jbpmContext.loadTaskInstance(1L);
  58. //设置主流程变量
  59. mainTaskInstance1.getContextInstance().setVariable("mainParam","主流程设置的变量");
  60. mainTaskInstance1.end();
  61. }catch(Exceptione){
  62. e.printStackTrace();
  63. }finally{
  64. jbpmContext.close();
  65. }
  66. }
  67. publicstaticvoidstartSubTask1(){
  68. JbpmConfigurationjbpmConfiguration=JbpmConfiguration.getInstance();
  69. JbpmContextjbpmContext=jbpmConfiguration.createJbpmContext();
  70. try{
  71. //子流程subtask1
  72. TaskInstancesubTaskInstance1=jbpmContext.loadTaskInstance(2L);
  73. //获取主流程变量
  74. System.out.println(subTaskInstance1.getName()+"子流程读取主流程变量,mainParam的值是:"+subTaskInstance1.getContextInstance().getVariable("mainParam").toString());
  75. //设置子流程变量
  76. subTaskInstance1.getContextInstance().setVariable("subParam","子流程设置的变量");
  77. subTaskInstance1.end();
  78. }catch(Exceptione){
  79. e.printStackTrace();
  80. }finally{
  81. jbpmContext.close();
  82. }
  83. }
  84. publicstaticvoidstartMainTask2(){
  85. JbpmConfigurationjbpmConfiguration=JbpmConfiguration.getInstance();
  86. JbpmContextjbpmContext=jbpmConfiguration.createJbpmContext();
  87. try{
  88. TaskInstancemainTaskInstance2=jbpmContext.loadTaskInstance(3L);
  89. //读取子流程变量
  90. System.out.println(mainTaskInstance2.getName()+"主流程读取子流程变量,subParam的值是:"+mainTaskInstance2.getContextInstance().getVariable("subParam").toString());
  91. mainTaskInstance2.end();
  92. }catch(Exceptione){
  93. e.printStackTrace();
  94. }finally{
  95. jbpmContext.close();
  96. }
  97. }
  98. publicstaticvoidmain(String[]args)throwsFileNotFoundException{
  99. //数据库清理
  100. SubProcess.init();
  101. //发布流程,必须先发布子流程再发布主流程
  102. SubProcess.deploySub();
  103. SubProcess.deployMain();
  104. SubProcess.startProcess();
  105. SubProcess.startMainTask1();
  106. SubProcess.startSubTask1();
  107. SubProcess.startMainTask2();
  108. }
  109. }
package com.royzhou.test;

import java.io.FileNotFoundException;

import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;
import org.jbpm.taskmgmt.exe.TaskInstance;

public class SubProcess {
	
	public static void init() {
		JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
		jbpmConfiguration.createSchema();
	}
	
	public static void deploySub() throws FileNotFoundException {
		JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
		JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
		try {
			ProcessDefinition subProcessDefinition = ProcessDefinition.parseXmlResource("subprocess/processDefinition.xml");
			jbpmContext.deployProcessDefinition(subProcessDefinition);
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			jbpmContext.close();
		}
	}
	
	public static void deployMain() throws FileNotFoundException {
		JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
		JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
		try {
			ProcessDefinition mainProcessDefinition = ProcessDefinition.parseXmlResource("mainprocess/processDefinition.xml");
			jbpmContext.deployProcessDefinition(mainProcessDefinition);
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			jbpmContext.close();
		}
	}
	
	public static void startProcess() {
		JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
		JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
		try {
			ProcessDefinition processDefinition = jbpmContext.getGraphSession().findLatestProcessDefinition("mainprocess");
			ProcessInstance processInstance = new ProcessInstance(processDefinition);
			Token token = processInstance.getRootToken();
			token.signal();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			jbpmContext.close();
		}
	}
	
	public static void startMainTask1() {
		JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
		JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
		try {
			//主流程maintask1
			TaskInstance mainTaskInstance1 = jbpmContext.loadTaskInstance(1L);
			//设置主流程变量
			mainTaskInstance1.getContextInstance().setVariable("mainParam", "主流程设置的变量");
			mainTaskInstance1.end();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			jbpmContext.close();
		}
	}
	
	public static void startSubTask1() {
		JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
		JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
		try {
			//子流程subtask1
			TaskInstance subTaskInstance1 = jbpmContext.loadTaskInstance(2L);
			//获取主流程变量
			System.out.println(subTaskInstance1.getName() + "子流程读取主流程变量,mainParam的值是:" + subTaskInstance1.getContextInstance().getVariable("mainParam").toString());
			//设置子流程变量
			subTaskInstance1.getContextInstance().setVariable("subParam", "子流程设置的变量");
			subTaskInstance1.end();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			jbpmContext.close();
		}
	}
	
	public static void startMainTask2() {
		JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
		JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
		try {
			TaskInstance mainTaskInstance2 = jbpmContext.loadTaskInstance(3L);
			//读取子流程变量
			System.out.println(mainTaskInstance2.getName()+"主流程读取子流程变量,subParam的值是:" + mainTaskInstance2.getContextInstance().getVariable("subParam").toString());
			mainTaskInstance2.end();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			jbpmContext.close();
		}
	} 
	
	public static void main(String[] args) throws FileNotFoundException {
		//数据库清理
		SubProcess.init();
		//发布流程,必须先发布子流程再发布主流程
		SubProcess.deploySub();
		SubProcess.deployMain();
		SubProcess.startProcess();
		SubProcess.startMainTask1();
		SubProcess.startSubTask1();
		SubProcess.startMainTask2();
	}
}

运行上面程序,成功执行之后结果为:
main task node1 enter
sub task node1 enter
sub task node1 enter
subtask1子流程读取主流程变量,mainParam的值是:主流程设置的变量
main task node2 enter
maintask2主流程读取子流程变量,subParam的值是:子流程设置的变量

8、Mail Node 节点
该节点可以实现邮件的发送,具有通知提醒功能。
具体有两种配置方式:
通过mail node节点的template属性设置,采用此种方式需要修改jbpm.mail.template.xml文件里的模版,加上我们需要的模版,具体模版设置可参照里面已有模版。举例说明下:
流程模版文件:start -> mail node ->end
Xml代码 复制代码 收藏代码
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <process-definitionxmlns="urn:jbpm.org:jpdl-3.2"name="mail">
  3. <start-statename="start-state1">
  4. <transitionto="mail-node1"></transition>
  5. </start-state>
  6. <mail-nodename="mail-node1"template="test">
  7. <eventtype="node-enter">
  8. <script>
  9. print(&quot;entermailnode&quot;)
  10. </script>
  11. </event>
  12. <eventtype="node-leave">
  13. <script>
  14. print(&quot;leavemailnode&quot;)
  15. </script>
  16. </event>
  17. <transitionto="end-state1"></transition>
  18. </mail-node>
  19. <end-statename="end-state1"></end-state>
  20. </process-definition>
<?xml version="1.0" encoding="UTF-8"?>
<process-definition  xmlns="urn:jbpm.org:jpdl-3.2"  name="mail">
	<start-state name="start-state1">
		<transition to="mail-node1"></transition>
	</start-state>
	<mail-node name="mail-node1" template="test">
		<event type="node-enter">
			<script>
				print(&quot;enter mail node&quot;)
			</script>
		</event>
		<event type="node-leave">
			<script>
				print(&quot;leave mail node&quot;)
			</script>
		</event>
		<transition to="end-state1"></transition>
	</mail-node>
	<end-state name="end-state1"></end-state>
</process-definition>

我们使用的模版是test,但是jbpm.mail.template.xml没有,所以需要我们自己加:
Xml代码 复制代码 收藏代码
  1. <mail-templatename="test">
  2. <actors>#{actorId}</actors>
  3. <subject>mailnode节点测试</subject>
  4. <text><![CDATA[Hi#{actorId},
  5. 这是mailnode节点的测试内容。
  6. ]]></text>
  7. </mail-template>
<mail-template name="test">
		<actors>#{actorId}</actors>
		<subject>mail node 节点测试</subject>
		<text><![CDATA[Hi #{actorId},
		这是mail node节点的测试内容。
		]]></text>
	</mail-template>	

这个是我们自己定义的模版,其中actors标签表示的是收件人的地址,需要使用邮件解析类解析,邮件解析类是一个实现AddressResolver接口的类。并且需要在jbpm.cfg.xml中配置,告诉jbpm要使用这个类去解析获取发送邮件的地址。
Java代码 复制代码 收藏代码
  1. packagecom.royzhou.util;
  2. importorg.jbpm.mail.AddressResolver;
  3. publicclassMailAddressResolverimplementsAddressResolver{
  4. publicObjectresolveAddress(StringactorId){
  5. return"royzhou1985@foxmail.com";
  6. }
  7. }
package com.royzhou.util;

import org.jbpm.mail.AddressResolver;

public class MailAddressResolver implements AddressResolver {

	public Object resolveAddress(String actorId) {
		return "royzhou1985@foxmail.com";
	}
}

下面是jbpm.cfg.xml的配置内容。
Xml代码 复制代码 收藏代码
  1. <jbpm-configuration>
  2. <!--邮件解析类-->
  3. <beanname="jbpm.mail.address.resolver"
  4. class="com.royzhou.util.MailAddressResolver"singleton="true"/>
  5. <!--邮箱配置信息-->
  6. <stringname="resource.mail.properties"value="jbpm.mail.properties"/>
  7. <!--处理邮件发送的类-->
  8. <stringname="mail.class.name"value="com.royzhou.util.Mail"/>
  9. <!--发送人地址-->
  10. <stringname="jbpm.mail.from.address"value="test@163.com"></string>
  11. </jbpm-configuration>
<jbpm-configuration>
	<!-- 邮件解析类 -->
	<bean name="jbpm.mail.address.resolver"
		class="com.royzhou.util.MailAddressResolver" singleton="true" />
	<!-- 邮箱配置信息 -->
	<string name="resource.mail.properties" value="jbpm.mail.properties" />
	<!-- 处理邮件发送的类 -->
	<string name="mail.class.name" value="com.royzhou.util.Mail" />
	<!-- 发送人地址 -->
	<string name="jbpm.mail.from.address" value="test@163.com"></string>
</jbpm-configuration>


邮箱配置信息如下:
mail.smtp.host=smtp.163.com
mail.smtp.user=test
mail.smtp.password=test
mail.smtp.auth=true

配置中我们使用的是自己的邮件发送类,这是因为jbpm自己提供的邮件发送类没有提供身份认证,直接使用会报异常。
修改之后的邮件发送类如下:
Java代码 复制代码 收藏代码
  1. packagecom.royzhou.util;
  2. importjava.io.InputStream;
  3. importjava.io.Serializable;
  4. importjava.util.ArrayList;
  5. importjava.util.Arrays;
  6. importjava.util.Collection;
  7. importjava.util.Date;
  8. importjava.util.HashMap;
  9. importjava.util.Iterator;
  10. importjava.util.List;
  11. importjava.util.Map;
  12. importjava.util.Properties;
  13. importjava.util.StringTokenizer;
  14. importjavax.mail.Message;
  15. importjavax.mail.PasswordAuthentication;
  16. importjavax.mail.Session;
  17. importjavax.mail.Transport;
  18. importjavax.mail.internet.InternetAddress;
  19. importjavax.mail.internet.MimeMessage;
  20. importjavax.mail.Authenticator;
  21. importorg.apache.commons.logging.Log;
  22. importorg.apache.commons.logging.LogFactory;
  23. importorg.jbpm.JbpmConfiguration;
  24. importorg.jbpm.JbpmException;
  25. importorg.jbpm.graph.def.ActionHandler;
  26. importorg.jbpm.graph.exe.ExecutionContext;
  27. importorg.jbpm.jpdl.el.ELException;
  28. importorg.jbpm.jpdl.el.VariableResolver;
  29. importorg.jbpm.jpdl.el.impl.JbpmExpressionEvaluator;
  30. importorg.jbpm.mail.AddressResolver;
  31. importorg.jbpm.util.ClassLoaderUtil;
  32. importorg.jbpm.util.XmlUtil;
  33. publicclassMailimplementsActionHandler{
  34. privatestaticfinallongserialVersionUID=1L;
  35. Stringtemplate=null;
  36. Stringactors=null;
  37. Stringto=null;
  38. Stringbcc=null;
  39. StringbccActors=null;
  40. Stringsubject=null;
  41. Stringtext=null;
  42. ExecutionContextexecutionContext=null;
  43. publicMail(){
  44. }
  45. publicMail(Stringtemplate,
  46. Stringactors,
  47. Stringto,
  48. Stringsubject,
  49. Stringtext){
  50. this.template=template;
  51. this.actors=actors;
  52. this.to=to;
  53. this.subject=subject;
  54. this.text=text;
  55. }
  56. publicMail(Stringtemplate,
  57. Stringactors,
  58. Stringto,
  59. StringbccActors,
  60. Stringbcc,
  61. Stringsubject,
  62. Stringtext){
  63. this.template=template;
  64. this.actors=actors;
  65. this.to=to;
  66. this.bccActors=bccActors;
  67. this.bcc=bcc;
  68. this.subject=subject;
  69. this.text=text;
  70. }
  71. publicvoidexecute(ExecutionContextexecutionContext){
  72. this.executionContext=executionContext;
  73. send();
  74. }
  75. publicListgetRecipients(){
  76. Listrecipients=newArrayList();
  77. if(actors!=null){
  78. StringevaluatedActors=evaluate(actors);
  79. ListtokenizedActors=tokenize(evaluatedActors);
  80. if(tokenizedActors!=null){
  81. recipients.addAll(resolveAddresses(tokenizedActors));
  82. }
  83. }
  84. if(to!=null){
  85. StringresolvedTo=evaluate(to);
  86. recipients.addAll(tokenize(resolvedTo));
  87. }
  88. returnrecipients;
  89. }
  90. publicListgetBccRecipients(){
  91. Listrecipients=newArrayList();
  92. if(bccActors!=null){
  93. StringevaluatedActors=evaluate(bccActors);
  94. ListtokenizedActors=tokenize(evaluatedActors);
  95. if(tokenizedActors!=null){
  96. recipients.addAll(resolveAddresses(tokenizedActors));
  97. }
  98. }
  99. if(bcc!=null){
  100. StringresolvedTo=evaluate(to);
  101. recipients.addAll(tokenize(resolvedTo));
  102. }
  103. if(JbpmConfiguration.Configs.hasObject("jbpm.mail.bcc.address")){
  104. recipients.addAll(tokenize(
  105. JbpmConfiguration.Configs.getString("jbpm.mail.bcc.address")));
  106. }
  107. returnrecipients;
  108. }
  109. publicStringgetSubject(){
  110. if(subject==null)returnnull;
  111. returnevaluate(subject);
  112. }
  113. publicStringgetText(){
  114. if(text==null)returnnull;
  115. returnevaluate(text);
  116. }
  117. publicStringgetFromAddress(){
  118. if(JbpmConfiguration.Configs.hasObject("jbpm.mail.from.address")){
  119. returnJbpmConfiguration.Configs.getString("jbpm.mail.from.address");
  120. }
  121. return"jbpm@noreply";
  122. }
  123. publicvoidsend(){
  124. if(template!=null){
  125. Propertiesproperties=getMailTemplateProperties(template);
  126. if(actors==null){
  127. actors=properties.getProperty("actors");
  128. }
  129. if(to==null){
  130. to=properties.getProperty("to");
  131. }
  132. if(subject==null){
  133. subject=properties.getProperty("subject");
  134. }
  135. if(text==null){
  136. text=properties.getProperty("text");
  137. }
  138. if(bcc==null){
  139. bcc=properties.getProperty("bcc");
  140. }
  141. if(bccActors==null){
  142. bccActors=properties.getProperty("bccActors");
  143. }
  144. }
  145. send(getMailServerProperties(),
  146. getFromAddress(),
  147. getRecipients(),
  148. getBccRecipients(),
  149. getSubject(),
  150. getText());
  151. }
  152. publicstaticvoidsend(PropertiesmailServerProperties,StringfromAddress,Listrecipients,Stringsubject,Stringtext){
  153. send(mailServerProperties,fromAddress,recipients,null,subject,text);
  154. }
  155. publicstaticvoidsend(PropertiesmailServerProperties,StringfromAddress,Listrecipients,ListbccRecipients,Stringsubject,Stringtext){
  156. if((recipients==null)
  157. ||(recipients.isEmpty())
  158. ){
  159. log.debug("skippingmailbecausetherearenorecipients");
  160. return;
  161. }
  162. mailServerProperties.put("mail.smtp.auth","true");
  163. log.debug("sendingemailto'"+recipients+"'about'"+subject+"'");
  164. /**
  165. *添加认证类
  166. *royzhou2009.07.21
  167. */
  168. StringuserName=mailServerProperties.getProperty("mail.smtp.user").toString();
  169. Stringpassword=mailServerProperties.getProperty("mail.smtp.password").toString();
  170. MyAuthenticationmyAuthentication=newMyAuthentication(userName,password);
  171. Sessionsession=Session.getDefaultInstance(mailServerProperties,myAuthentication);
  172. MimeMessagemessage=newMimeMessage(session);
  173. try{
  174. if(fromAddress!=null){
  175. message.setFrom(newInternetAddress(fromAddress));
  176. }
  177. Iteratoriter=recipients.iterator();
  178. while(iter.hasNext()){
  179. InternetAddressrecipient=newInternetAddress((String)iter.next());
  180. message.addRecipient(Message.RecipientType.TO,recipient);
  181. }
  182. if(bccRecipients!=null){
  183. iter=bccRecipients.iterator();
  184. while(iter.hasNext()){
  185. InternetAddressrecipient=newInternetAddress((String)iter.next());
  186. message.addRecipient(Message.RecipientType.BCC,recipient);
  187. }
  188. }
  189. if(subject!=null){
  190. message.setSubject(subject);
  191. }
  192. if(text!=null){
  193. message.setText(text);
  194. }
  195. message.setSentDate(newDate());
  196. Transport.send(message);
  197. }catch(Exceptione){
  198. thrownewJbpmException("couldn'tsendemail",e);
  199. }
  200. }
  201. protectedListtokenize(Stringtext){
  202. if(text==null){
  203. returnnull;
  204. }
  205. Listlist=newArrayList();
  206. StringTokenizertokenizer=newStringTokenizer(text,";:");
  207. while(tokenizer.hasMoreTokens()){
  208. list.add(tokenizer.nextToken());
  209. }
  210. returnlist;
  211. }
  212. protectedCollectionresolveAddresses(ListactorIds){
  213. ListemailAddresses=newArrayList();
  214. Iteratoriter=actorIds.iterator();
  215. while(iter.hasNext()){
  216. StringactorId=(String)iter.next();
  217. AddressResolveraddressResolver=(AddressResolver)JbpmConfiguration.Configs.getObject("jbpm.mail.address.resolver");
  218. ObjectresolvedAddresses=addressResolver.resolveAddress(actorId);
  219. if(resolvedAddresses!=null){
  220. if(resolvedAddressesinstanceofString){
  221. emailAddresses.add((String)resolvedAddresses);
  222. }elseif(resolvedAddressesinstanceofCollection){
  223. emailAddresses.addAll((Collection)resolvedAddresses);
  224. }elseif(resolvedAddressesinstanceofString[]){
  225. emailAddresses.addAll(Arrays.asList((String[])resolvedAddresses));
  226. }else{
  227. thrownewJbpmException("Addressresolver'"+addressResolver+"'returned'"+resolvedAddresses.getClass().getName()+"'insteadofaString,CollectionorString-array:"+resolvedAddresses);
  228. }
  229. }
  230. }
  231. returnemailAddresses;
  232. }
  233. PropertiesgetMailServerProperties(){
  234. PropertiesmailServerProperties=newProperties();
  235. if(JbpmConfiguration.Configs.hasObject("resource.mail.properties")){
  236. StringmailServerPropertiesResource=JbpmConfiguration.Configs.getString("resource.mail.properties");
  237. try{
  238. InputStreammailServerStream=ClassLoaderUtil.getStream(mailServerPropertiesResource);
  239. mailServerProperties.load(mailServerStream);
  240. }catch(Exceptione){
  241. thrownewJbpmException("couldn'tgetconfigurationpropertiesforjbpmmailserverfromresource'"+mailServerPropertiesResource+"'",e);
  242. }
  243. }elseif(JbpmConfiguration.Configs.hasObject("jbpm.mail.smtp.host")){
  244. StringsmtpServer=JbpmConfiguration.Configs.getString("jbpm.mail.smtp.host");
  245. mailServerProperties.put("mail.smtp.host",smtpServer);
  246. }else{
  247. log.error("couldn'tgetmailproperties");
  248. }
  249. returnmailServerProperties;
  250. }
  251. staticMaptemplates=null;
  252. staticMaptemplateVariables=null;
  253. synchronizedPropertiesgetMailTemplateProperties(StringtemplateName){
  254. if(templates==null){
  255. templates=newHashMap();
  256. StringmailTemplatesResource=JbpmConfiguration.Configs.getString("resource.mail.templates");
  257. org.w3c.dom.ElementmailTemplatesElement=XmlUtil.parseXmlResource(mailTemplatesResource).getDocumentElement();
  258. ListmailTemplateElements=XmlUtil.elements(mailTemplatesElement,"mail-template");
  259. Iteratoriter=mailTemplateElements.iterator();
  260. while(iter.hasNext()){
  261. org.w3c.dom.ElementmailTemplateElement=(org.w3c.dom.Element)iter.next();
  262. PropertiestemplateProperties=newProperties();
  263. addTemplateProperty(mailTemplateElement,"actors",templateProperties);
  264. addTemplateProperty(mailTemplateElement,"to",templateProperties);
  265. addTemplateProperty(mailTemplateElement,"subject",templateProperties);
  266. addTemplateProperty(mailTemplateElement,"text",templateProperties);
  267. addTemplateProperty(mailTemplateElement,"bcc",templateProperties);
  268. addTemplateProperty(mailTemplateElement,"bccActors",templateProperties);
  269. templates.put(mailTemplateElement.getAttribute("name"),templateProperties);
  270. }
  271. templateVariables=newHashMap();
  272. ListvariableElements=XmlUtil.elements(mailTemplatesElement,"variable");
  273. iter=variableElements.iterator();
  274. while(iter.hasNext()){
  275. org.w3c.dom.ElementvariableElement=(org.w3c.dom.Element)iter.next();
  276. templateVariables.put(variableElement.getAttribute("name"),variableElement.getAttribute("value"));
  277. }
  278. }
  279. return(Properties)templates.get(templateName);
  280. }
  281. voidaddTemplateProperty(org.w3c.dom.ElementmailTemplateElement,Stringproperty,PropertiestemplateProperties){
  282. org.w3c.dom.Elementelement=XmlUtil.element(mailTemplateElement,property);
  283. if(element!=null){
  284. templateProperties.put(property,XmlUtil.getContentText(element));
  285. }
  286. }
  287. Stringevaluate(Stringexpression){
  288. if(expression==null){
  289. returnnull;
  290. }
  291. VariableResolvervariableResolver=JbpmExpressionEvaluator.getUsedVariableResolver();
  292. if(variableResolver!=null){
  293. variableResolver=newMailVariableResolver(templateVariables,variableResolver);
  294. }
  295. return(String)JbpmExpressionEvaluator.evaluate(expression,executionContext,variableResolver,null);
  296. }
  297. classMailVariableResolverimplementsVariableResolver,Serializable{
  298. privatestaticfinallongserialVersionUID=1L;
  299. MaptemplateVariables=null;
  300. VariableResolvervariableResolver=null;
  301. publicMailVariableResolver(MaptemplateVariables,VariableResolvervariableResolver){
  302. this.templateVariables=templateVariables;
  303. this.variableResolver=variableResolver;
  304. }
  305. publicObjectresolveVariable(StringpName)throwsELException{
  306. if((templateVariables!=null)
  307. &&(templateVariables.containsKey(pName))
  308. ){
  309. returntemplateVariables.get(pName);
  310. }
  311. returnvariableResolver.resolveVariable(pName);
  312. }
  313. }
  314. privatestaticLoglog=LogFactory.getLog(Mail.class);
  315. }
  316. /**
  317. *邮箱认证类
  318. *@authorroyzhou
  319. *2009.07.21
  320. */
  321. classMyAuthenticationextendsAuthenticator{
  322. privateStringuserName;
  323. privateStringpassword;
  324. publicMyAuthentication(StringuserName,Stringpassword){
  325. this.userName=userName;
  326. this.password=password;
  327. }
  328. protectedPasswordAuthenticationgetPasswordAuthentication(){
  329. returnnewPasswordAuthentication(userName,password);
  330. }
  331. }
package com.royzhou.util;

import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.Authenticator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmException;
import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.jpdl.el.ELException;
import org.jbpm.jpdl.el.VariableResolver;
import org.jbpm.jpdl.el.impl.JbpmExpressionEvaluator;
import org.jbpm.mail.AddressResolver;
import org.jbpm.util.ClassLoaderUtil;
import org.jbpm.util.XmlUtil;

public class Mail implements ActionHandler {

  private static final long serialVersionUID = 1L;
  
  String template = null;
  String actors = null;
  String to = null;
  String bcc = null;
  String bccActors = null;
  String subject = null;
  String text = null;
  
  ExecutionContext executionContext = null;
  
  public Mail() {
  }

  public Mail(String template,
              String actors,
              String to,
              String subject,
              String text) {
    this.template = template;
    this.actors = actors;
    this.to = to;
    this.subject = subject;
    this.text = text;
  }
  
  public Mail(String template,
      String actors,
      String to,
      String bccActors,
      String bcc,
      String subject,
      String text) {
    this.template = template;
    this.actors = actors;
    this.to = to;
    this.bccActors = bccActors;
    this.bcc = bcc;
    this.subject = subject;
    this.text = text;
  }  
  
  public void execute(ExecutionContext executionContext) {
    this.executionContext = executionContext;
    send();
  }

  public List getRecipients() {
    List recipients = new ArrayList();
    if (actors!=null) {
      String evaluatedActors = evaluate(actors);
      List tokenizedActors = tokenize(evaluatedActors);
      if (tokenizedActors!=null) {
        recipients.addAll(resolveAddresses(tokenizedActors));
      }
    }
    if (to!=null) {
      String resolvedTo = evaluate(to);
      recipients.addAll(tokenize(resolvedTo));
    }
    return recipients;
  }

  public List getBccRecipients() {
    List recipients = new ArrayList();
    if (bccActors!=null) {
      String evaluatedActors = evaluate(bccActors);
      List tokenizedActors = tokenize(evaluatedActors);
      if (tokenizedActors!=null) {
        recipients.addAll(resolveAddresses(tokenizedActors));
      }
    }
    if (bcc!=null) {
      String resolvedTo = evaluate(to);
      recipients.addAll(tokenize(resolvedTo));
    }
    if (JbpmConfiguration.Configs.hasObject("jbpm.mail.bcc.address")) {
      recipients.addAll(tokenize(
          JbpmConfiguration.Configs.getString("jbpm.mail.bcc.address")));
    }
    return recipients;
  }
  
  public String getSubject() {
    if (subject==null) return null;
    return evaluate(subject);
  }

  public String getText() {
    if (text==null) return null;
    return evaluate(text);
  }

  public String getFromAddress() {
    if (JbpmConfiguration.Configs.hasObject("jbpm.mail.from.address")) {
      return JbpmConfiguration.Configs.getString("jbpm.mail.from.address");
    } 
    return "jbpm@noreply";
  }

  public void send() {
    if (template!=null) {
      Properties properties = getMailTemplateProperties(template);
      if (actors==null) {
        actors = properties.getProperty("actors");
      }
      if (to==null) {
        to = properties.getProperty("to");
      }
      if (subject==null) {
        subject = properties.getProperty("subject");
      }
      if (text==null) {
        text = properties.getProperty("text");
      }
      if (bcc==null) {
        bcc = properties.getProperty("bcc");
      }
      if (bccActors==null) {
        bccActors = properties.getProperty("bccActors");
      }
    }
    
    send(getMailServerProperties(), 
            getFromAddress(), 
            getRecipients(), 
            getBccRecipients(),
            getSubject(), 
            getText());
  }
  
  public static void send(Properties mailServerProperties, String fromAddress, List recipients, String subject, String text) {
    send(mailServerProperties, fromAddress, recipients, null, subject, text);
  }
  
  public static void send(Properties mailServerProperties, String fromAddress, List recipients, List bccRecipients, String subject, String text) {
    if ( (recipients==null)
         || (recipients.isEmpty())
       ) {
      log.debug("skipping mail because there are no recipients");
      return;
    }
    mailServerProperties.put("mail.smtp.auth", "true");
    log.debug("sending email to '"+recipients+"' about '"+subject+"'");
    
    /**
     * 添加认证类
     * royzhou 2009.07.21
     */
    String userName = mailServerProperties.getProperty("mail.smtp.user").toString();
    String password = mailServerProperties.getProperty("mail.smtp.password").toString();
    MyAuthentication myAuthentication = new MyAuthentication(userName,password);
    Session session = Session.getDefaultInstance(mailServerProperties, myAuthentication);
    MimeMessage message = new MimeMessage(session);
    try {
      if (fromAddress!=null) {
        message.setFrom(new InternetAddress(fromAddress));
      }
      Iterator iter = recipients.iterator();
      while (iter.hasNext()) {
        InternetAddress recipient = new InternetAddress((String) iter.next());
        message.addRecipient(Message.RecipientType.TO, recipient);
      }
      if (bccRecipients!=null) {
        iter = bccRecipients.iterator();
        while (iter.hasNext()) {
          InternetAddress recipient = new InternetAddress((String) iter.next());
          message.addRecipient(Message.RecipientType.BCC, recipient);
        }        
      }
      if (subject!=null) {
        message.setSubject(subject);
      }
      if (text!=null) {
        message.setText(text);
      }
      message.setSentDate(new Date());
      
      Transport.send(message);
    } catch (Exception e) {
      throw new JbpmException("couldn't send email", e);
    }
  }

  protected List tokenize(String text) {
    if (text==null) {
      return null;
    }
    List list = new ArrayList();
    StringTokenizer tokenizer = new StringTokenizer(text, ";:");
    while (tokenizer.hasMoreTokens()) {
      list.add(tokenizer.nextToken());
    }
    return list;
  }

  protected Collection resolveAddresses(List actorIds) {
    List emailAddresses = new ArrayList();
    Iterator iter = actorIds.iterator();
    while (iter.hasNext()) {
      String actorId = (String) iter.next();
      AddressResolver addressResolver = (AddressResolver) JbpmConfiguration.Configs.getObject("jbpm.mail.address.resolver");
      Object resolvedAddresses = addressResolver.resolveAddress(actorId);
      if (resolvedAddresses!=null) {
        if (resolvedAddresses instanceof String) {
          emailAddresses.add((String)resolvedAddresses);
        } else if (resolvedAddresses instanceof Collection) {
          emailAddresses.addAll((Collection)resolvedAddresses);
        } else if (resolvedAddresses instanceof String[]) {
          emailAddresses.addAll(Arrays.asList((String[])resolvedAddresses));
        } else {
          throw new JbpmException("Address resolver '"+addressResolver+"' returned '"+resolvedAddresses.getClass().getName()+"' instead of a String, Collection or String-array: "+resolvedAddresses);
        }
      }
    }
    return emailAddresses;
  }

  Properties getMailServerProperties() {
    Properties mailServerProperties = new Properties();

    if (JbpmConfiguration.Configs.hasObject("resource.mail.properties")) {
      String mailServerPropertiesResource = JbpmConfiguration.Configs.getString("resource.mail.properties");
      try {
        InputStream mailServerStream = ClassLoaderUtil.getStream(mailServerPropertiesResource);
        mailServerProperties.load(mailServerStream);
      } catch (Exception e) {
        throw new JbpmException("couldn't get configuration properties for jbpm mail server from resource '"+mailServerPropertiesResource+"'", e);
      }
    
    } else if (JbpmConfiguration.Configs.hasObject("jbpm.mail.smtp.host")) {
      String smtpServer = JbpmConfiguration.Configs.getString("jbpm.mail.smtp.host");
      mailServerProperties.put("mail.smtp.host", smtpServer);
      
    } else {
      
      log.error("couldn't get mail properties");
    }

    return mailServerProperties;
  }

  static Map templates = null;
  static Map templateVariables = null;
  synchronized Properties getMailTemplateProperties(String templateName) {
    if (templates==null) {
      templates = new HashMap();
      String mailTemplatesResource = JbpmConfiguration.Configs.getString("resource.mail.templates");
      org.w3c.dom.Element mailTemplatesElement = XmlUtil.parseXmlResource(mailTemplatesResource).getDocumentElement();
      List mailTemplateElements = XmlUtil.elements(mailTemplatesElement, "mail-template");
      Iterator iter = mailTemplateElements.iterator();
      while (iter.hasNext()) {
        org.w3c.dom.Element mailTemplateElement = (org.w3c.dom.Element) iter.next();

        Properties templateProperties = new Properties();
        addTemplateProperty(mailTemplateElement, "actors", templateProperties);
        addTemplateProperty(mailTemplateElement, "to", templateProperties);
        addTemplateProperty(mailTemplateElement, "subject", templateProperties);
        addTemplateProperty(mailTemplateElement, "text", templateProperties);
        addTemplateProperty(mailTemplateElement, "bcc", templateProperties);
        addTemplateProperty(mailTemplateElement, "bccActors", templateProperties);

        templates.put(mailTemplateElement.getAttribute("name"), templateProperties);
      }

      templateVariables = new HashMap();
      List variableElements = XmlUtil.elements(mailTemplatesElement, "variable");
      iter = variableElements.iterator();
      while (iter.hasNext()) {
        org.w3c.dom.Element variableElement = (org.w3c.dom.Element) iter.next();
        templateVariables.put(variableElement.getAttribute("name"), variableElement.getAttribute("value"));
      }
    }
    return (Properties) templates.get(templateName);
  }

  void addTemplateProperty(org.w3c.dom.Element mailTemplateElement, String property, Properties templateProperties) {
    org.w3c.dom.Element element = XmlUtil.element(mailTemplateElement, property);
    if (element!=null) {
      templateProperties.put(property, XmlUtil.getContentText(element));
    }
  }
  
  String evaluate(String expression) {
    if (expression==null) {
      return null;
    }
    VariableResolver variableResolver = JbpmExpressionEvaluator.getUsedVariableResolver();
    if (variableResolver!=null) {
      variableResolver = new MailVariableResolver(templateVariables, variableResolver);
    }
    return (String) JbpmExpressionEvaluator.evaluate(expression, executionContext, variableResolver, null);
  }

  class MailVariableResolver implements VariableResolver, Serializable {
    private static final long serialVersionUID = 1L;
    Map templateVariables = null;
    VariableResolver variableResolver = null;

    public MailVariableResolver(Map templateVariables, VariableResolver variableResolver) {
      this.templateVariables = templateVariables;
      this.variableResolver = variableResolver;
    }

    public Object resolveVariable(String pName) throws ELException {
      if ( (templateVariables!=null)
           && (templateVariables.containsKey(pName))
         ){
        return templateVariables.get(pName);
      }
      return variableResolver.resolveVariable(pName);
    }
  }

  private static Log log = LogFactory.getLog(Mail.class);
}

/**
 * 邮箱认证类
 * @author royzhou
 * 2009.07.21
 */
class MyAuthentication extends Authenticator {
	private String userName;
	private String password;
	public MyAuthentication(String userName, String password) {
		this.userName = userName;
		this.password = password;
	}
	protected PasswordAuthentication getPasswordAuthentication() {
		return new PasswordAuthentication(userName,password);
	}
}


下面我们开始写我们的测试类:MailNode
Java代码 复制代码 收藏代码
  1. packagecom.royzhou.test;
  2. importorg.jbpm.graph.def.ProcessDefinition;
  3. importorg.jbpm.graph.exe.ProcessInstance;
  4. importorg.jbpm.graph.exe.Token;
  5. publicclassMailNode{
  6. publicstaticvoidmain(String[]args){
  7. ProcessDefinitionprocessDefinition=ProcessDefinition.parseXmlResource("mail/processDefinition.xml");
  8. ProcessInstanceprocessInstance=newProcessInstance(processDefinition);
  9. processInstance.getContextInstance().setVariable("actorId","royzhou");
  10. Tokentoken=processInstance.getRootToken();
  11. token.signal();
  12. System.out.println("end^^^^^^^^^^^^");
  13. }
  14. }
package com.royzhou.test;

import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;

public class MailNode {
	
	public static void main(String[] args) {
		ProcessDefinition processDefinition = ProcessDefinition.parseXmlResource("mail/processDefinition.xml");
		ProcessInstance processInstance = new ProcessInstance(processDefinition);
		processInstance.getContextInstance().setVariable("actorId", "royzhou");
		Token token = processInstance.getRootToken();
		token.signal();
		System.out.println("end^^^^^^^^^^^^");
	}
}

运行测试程序,后台打印:
enter mail node
test====test
leave mail node
end^^^^^^^^^^^^

打开你的收件箱发现邮件发送成功并且信息都是根据模版生成的。。


至此,我们将流程的节点基本上都过了一遍。。。。 笔记终于写完。。。累就一个字

明天出差。。。。
回来继续。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值