JBPM业务流程管理框架详细解读

2015年11月24日 20:51:21 低调的洋仔 

 版权声明:本文为博主原创文章,未经博主允许不得转载。

1. 什么是JBPM4.4业务流程管理框架?

JBPM,全称是Java Business Process Management(业务流程管理),它是覆盖了业务流程管理、工作流、服务协作等领域的一个开源的、灵活的、易扩展的可执行流程语言框架。

相关概念:a: 从一个节点到另一个节点==>流转。b:程序预先设定的行为==>活动。

2. JBPM工作流的特点

2.1 直观描述业务流程

采用了自己定义的JPDL:业务流程被看成是UML状态图,详细定义状态图中每个部分,起始、结束每个状态以及状态之间的转换。通过流程图的方式来呈现、直观描述业务流程。如图所示:

2.2 使用Hibernate管理数据库

通过Hibernate管理数据库,JBPM就可以把数据的管理分离出去,自己专注于业务流程。

3 ProcessEngine的核心服务

RespositoryService:流程定义的服务接口:包括流程定义的部署、查询、删除等操作。

ExecutionService: 流程执行的服务接口:包括启动流程、实例推进、设置变量等操作。

ManagementService:Web管理控制台的服务接口,包括获得消息和计时器的操作。

HistoryService:历史库的服务接口:包括对流程实例、活动实例进行查询。某个流程定义中的所有的活动的平均持续        时间,某个流程定义中的某个活动实例的转移的执行次数等操作。

IdentityService:主要包括用户、组、成员关系等相关的操作

CommondService:command模式的服务接口,实际上将客户端请求全部封装在一个调用接口中,execute(Command      cmd),由这个接口去调用command接口的众多实现类。

4 怎么用JBMP?

4.1 所需环境与相关资源

1. jBPM requires a JDK (standard java) version 5 orhigher.

    http://java.sun.com/javase/downloads/index.jsp

2. jBPM下载地址:http://sourceforge.net/projects/jbpm/files/

3. Eclipse下载地址( Eclipse IDE for Java EE Developers (163 MB),Version:                  3.5):http://www.eclipse.org/downloads/download.php?    file=/technology/epp/downloads/release/galileo

4.2 安装说明

第一步:  

Help -->Install New Software...

  ClickAdd...

  In dialogAdd Site dialog, clickArchive...

  Navigate toinstall/src/gpd/jbpm-gpd-site.zip and click 'Open'

  ClickingOK in theAdd Site dialog will bring you back to the dialog 'Install'

  Select thejPDL 4 GPD Update Site that has appeared

  ClickNext... and thenFinish

  Approve the license

  Restart eclipse when that is asked

第二步:

流程定义文件的xsd文件的路径为:JBPM_HOME/src/jpdl-4.4.xsd。

添加到Eclipse中的方法为(jBPM4.4User Guide, 2.11.5. Adding jPDL 4 schema tothe catalog):

  ClickWindow -->Preferences

  SelectXML -->XML Catalog

  Click 'Add...'

  The 'Add XML Catalog Entry' dialog opens

  Click the button with the map-icon next to location and select 'FileSystem...'

  In the dialog that opens, select filejpdl-4.4.xsd in the src directoryof the jBPM installation root.

  Click 'Open' and close all the dialogs

第三步:添加jar包

1. JBPM解压目录下有一个重要的jar包:jbpm.jar。

2. JBPM/lib目录下的jar很多,不要添加的jar包:servlet-api.jar、junit.jar(尤其不要添加)。

3. 所使用的数据库对应的驱动的jar包在上面lib目录当中已经有了,所以不需要添加了。

第四步: 添加配置文件

1. 配置文件包括jbpm.cfg.xml和jbpm.hibernate.cfg.xml(解压包当中都有模板,直接拷贝即可)

2. jbpm.hibernate.cfg.xml中配置的是Hibernate的配置信息,包括数据库连接的必要信息等等

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

  2.  
  3. <jbpm-configuration>

  4.  
  5. <import resource="jbpm.default.cfg.xml" />

  6. <import resource="jbpm.businesscalendar.cfg.xml" />

  7. <import resource="jbpm.tx.hibernate.cfg.xml" />

  8. <import resource="jbpm.jpdl.cfg.xml" />

  9. <import resource="jbpm.bpmn.cfg.xml" />

  10. <import resource="jbpm.identity.cfg.xml" />

  11.  
  12. <!-- Job executor is excluded for running the example test cases. -->

  13. <!-- To enable timers and messages in production use, this should be included. -->

  14. <!--

  15. <import resource="jbpm.jobexecutor.cfg.xml" />

  16. -->

  17.  
  18. </jbpm-configuration>

jbpm.cfg.xml

 
  1. <?xml version="1.0" encoding="utf-8"?>

  2.  
  3. <!DOCTYPE hibernate-configuration PUBLIC

  4. "-//Hibernate/Hibernate Configuration DTD 3.0//EN"

  5. "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

  6.  
  7. <hibernate-configuration>

  8. <session-factory>

  9. <!-- 数据库信息 -->

  10. <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>

  11. <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

  12. <property name="hibernate.connection.url">jdbc:mysql:///jbpm4test</property>

  13. <property name="hibernate.connection.username">root</property>

  14. <property name="hibernate.connection.password">root</property>

  15.  
  16. <!-- 其他配置 -->

  17. <property name="hibernate.hbm2ddl.auto">update</property>

  18.  
  19. <!-- 导入映射文件 -->

  20. <mapping resource="jbpm.repository.hbm.xml" />

  21. <mapping resource="jbpm.execution.hbm.xml" />

  22. <mapping resource="jbpm.history.hbm.xml" />

  23. <mapping resource="jbpm.task.hbm.xml" />

  24. <mapping resource="jbpm.identity.hbm.xml" />

  25.  
  26. </session-factory>

  27. </hibernate-configuration>

jbpm.hibernate.cfg.xml

配置到此结束

4.3 JBPM工作流的使用

1. 创建jbpm的文件

2. 绘制工作流程图

绘制完成流程图之后,会相应的生成其xml中的代码(下面的代码便是自动生成的)

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

  2.  
  3. <process name="员工请假流程" xmlns="http://jbpm.org/4.4/jpdl">

  4. <start g="77,20,48,48" name="start1">

  5. <transition g="-71,-17" name="to 提交申请" to="提交申请"/>

  6. </start>

  7. <end g="77,352,48,48" name="end1"/>

  8. <task assignee="ww" g="55,268,92,52" name="总经理审批">

  9. <transition g="-47,-17" name="to end1" to="end1"/>

  10. </task>

  11. <task assignee="ls" g="55,184,92,52" name="部门经理审批">

  12. <transition g="-26,-8" name="同意" to="总经理审批"/>

  13. </task>

  14. <task assignee="#{applyInfo.applier.userName}" g="55,100,92,52" name="提交申请">

  15. <transition g="-96,-16" name="to 部门经理审批" to="部门经理审批"/>

  16. </task>

  17. </process>

保存之后相应的生成png格式的对应的图片。

4.4 JBPM工作流编程实例

4.4.1 JBPM建表

Hibernate会自动的帮我们把所需要的表建好。

 
  1. // 建表

  2. @Test

  3. public void createSchema() {

  4. new org.hibernate.cfg.Configuration()//

  5. .configure("jbpm.hibernate.cfg.xml")//

  6. .buildSessionFactory();

  7. }

4.4.2 创建ProcessEngine对象

processEngine对象十分的重要,他是使用JBPM各类接口的切入点。

1. 指定配置文件生成processEngine对象

 
  1. private static ProcessEngine processEngine = new Configuration()//

  2. .setResource("jbpm.cfg.xml")//

  3. .buildProcessEngine();

2. 使用默认的配置文件生成processEngine对象

private ProcessEngine processEngine = new Configuration().buildProcessEngine();


3. 通过默认的配置文件生成单例的processEngine对象

private ProcessEngine processEngine = Configuration.getProcessEngine();

4.4.3 部署流程定义

流程定义:是这一次流程的步骤的说明,是对工作流程的静态式的说明信息。

 
  1. <span style="white-space:pre"> </span>// 部署流程定义

  2. @Test

  3. public void deployProcessDefinition()

  4. {

  5. String reponseStr = processEngine.getRepositoryService()//

  6. .createDeployment()//

  7. .addResourceFromClasspath("test/test.jpdl.xml")//这里目录需要根据自己的目录确定

  8. .addResourceFromClasspath("test/test.png")//

  9. .deploy();

  10. System.out.println(reponseStr);// 10001

  11. }

4.4.4 启动流程实例

流程实例:代表工作流的一次执行,是一种动态的过程。

1. 需要获得流程实例对象的时候

 
  1. // 启动流程实例

  2. // jbpm4_execution

  3. @Test

  4. public void testStartProcessInstance() throws Exception {

  5. ProcessInstance <strong style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></strong><pre name="code" class="java" style="display: inline !important;">processInstance

= processEngine.getExecutionService().startProcessInstanceByKey("test");System.out.println("流程实例启动成功:id=" +

processInstance <strong style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></strong><pre name="code" class="java" style="display: inline !important;">.getId() //
 

+ ", state=" +

processInstance

.getState() // 状态+ ", processDefinitionId=" +

processInstance

.getProcessDefinitionId()); // 所使用的流程定义的ID}

 

2. 通过key获取并直接启动实例

 
  1. // 启动实例

  2. @Test

  3. public void startProcessInstance() {

  4. processEngine.getExecutionService().startProcessInstanceByKey("test");

  5. }

4.4.5 查看个人的任务列表

通过findPersonalTasks("person")可以获得具体的个人的任务列表

 
  1. // 查询任务列表

  2. @Test

  3. public void findTaskList() {

  4. List<Task> taskList = processEngine.getTaskService().findPersonalTasks("员工");

  5. System.out.println("个人任务列表");

  6. System.out.println(taskList);

  7. for(Task task : taskList)

  8. {

  9. System.out.println("id= " + task.getId() + ", name = " + task.getName() + ", assignee = " + task.getAssignee());

  10. }

  11. }

4.4.6 查询所有的流程定义

 
  1. // 查询所有

  2. @Test

  3. public void findAll() throws Exception {

  4. // 查询

  5. List<ProcessDefinition> list = processEngine.getRepositoryService()//

  6. .createProcessDefinitionQuery()//

  7. // 过滤条件

  8. // .processDefinitionKey("")//

  9. // .processDefinitionNameLike("%xx%")//

  10. // 排序条件

  11. // .orderAsc(ProcessDefinitionQuery.PROPERTY_KEY)//

  12. // .orderDesc(ProcessDefinitionQuery.PROPERTY_VERSION)//

  13. // 执行查询

  14. // .uniqueResult();

  15. // .count();

  16. // .page(firstResult, maxResults)//

  17. .list();

  18.  
  19. // 显示

  20. for (ProcessDefinition pd : list) {

  21. System.out.println("id=" + pd.getId()// 格式为:{key}-{version},用于唯一的标识一个流程定义

  22. + ", name=" + pd.getName()// 流程定义的名称,jpdl.xml中根元素的name属性的值

  23. + ", key=" + pd.getKey()// 流程定义的key,jpdl.xml中根元素的key属性的值,默认是name属性的值

  24. + ", version=" + pd.getVersion()// 自动生成的,同一个名称的第一个为1,以后的自动加1.

  25. + ", deploymentId=" + pd.getDeploymentId()); // 所属的部署对象

  26. }

  27. }

4.4.7 查询最新版的流程定义

 
  1. // 查询所有最新版本的流程定义

  2. @Test

  3. public void findAllLatestVersions() throws Exception {

  4. // 查询所有,让所有最大的版本都排到最后面

  5. List<ProcessDefinition> all = processEngine.getRepositoryService()//

  6. .createProcessDefinitionQuery()//

  7. .orderAsc(ProcessDefinitionQuery.PROPERTY_VERSION)//

  8. .list();

  9.  
  10. // 过滤出所有最新的版本

  11. Map<String, ProcessDefinition> map = new HashMap<String, ProcessDefinition>();

  12. for (ProcessDefinition pd : all) {

  13. map.put(pd.getKey(), pd);

  14. }

  15.  
  16. // 显示

  17. for (ProcessDefinition pd : map.values()) {

  18. System.out.println("id=" + pd.getId()// 格式为:{key}-{version},用于唯一的标识一个流程定义

  19. + ", name=" + pd.getName()// 流程定义的名称,jpdl.xml中根元素的name属性的值

  20. + ", key=" + pd.getKey()// 流程定义的key,jpdl.xml中根元素的key属性的值,默认是name属性的值

  21. + ", version=" + pd.getVersion()// 自动生成的,同一个名称的第一个为1,以后的自动加1.

  22. + ", deploymentId=" + pd.getDeploymentId()); // 所属的部署对象

  23. }

  24. }

4.4.8 删除流程定义

 
  1. // 删除

  2. @Test

  3. public void deleteById() throws Exception {

  4. String deploymentId = "80001";

  5.  
  6. // // 删除指定的部署对象(流程定义),如果有关联的执行信息,就会报错

  7. // processEngine.getRepositoryService().deleteDeployment(deploymentId);

  8.  
  9. // 删除指定的部署对象(流程定义),如果有关联的执行信息,会被同时删除

  10. processEngine.getRepositoryService().deleteDeploymentCascade(deploymentId);

  11. }

 
  1. // 删除指定key的所有版本的流程定义

  2. @Test

  3. public void deleteByKey() throws Exception {

  4. // 查询出指定key的所有版本的流程定义

  5. List<ProcessDefinition> list = processEngine.getRepositoryService()//

  6. .createProcessDefinitionQuery()//

  7. .processDefinitionKey("helloworld")//

  8. .list();

  9.  
  10. // 一一删除

  11. for (ProcessDefinition pd : list) {

  12. processEngine.getRepositoryService().deleteDeploymentCascade(pd.getDeploymentId());

  13. }

  14. }

4.4.9 查看流程图

 
  1. // 查看流程图(xxx.png)

  2. @Test

  3. public void getImageResource() throws Exception {

  4. String deploymentId = "50001";

  5. String resourceName = "helloworld/helloworld.png";

  6.  
  7. // 获取指定部署对象中的所有资源的名称

  8. Set<String> names = processEngine.getRepositoryService().getResourceNames(deploymentId);

  9. System.out.println("所有的资源名称:");

  10. for (String name : names) {

  11. System.out.println("\t" + name);

  12. }

  13.  
  14. // 获取指定部署对象中的指下资源的内容

  15. InputStream in = processEngine.getRepositoryService().getResourceAsStream(deploymentId, resourceName);

  16.  
  17. // 保存到c盘

  18. OutputStream out = new FileOutputStream("c:/process.png");

  19. for (int b = -1; (b = in.read()) != -1;) {

  20. out.write(b);

  21. }

  22. in.close();

  23. out.close();

  24. }

4.4.10 向后执行一步

 
  1. // 向后执行一步

  2. @Test

  3. public void testSignalExecution() throws Exception {

  4. String executionId = "test.130001";

  5. processEngine.getExecutionService().signalExecutionById(executionId);

  6.  
  7. // processEngine.getExecutionService().signalExecutionById(executionId, parametersMap); // 离开前先设置一些流程变量

  8. // processEngine.getExecutionService().signalExecutionById(executionId, signalName); // 使用指定名称的Transition离开本活动

  9. // processEngine.getExecutionService().signalExecutionById(executionId, signalName, parameters) // 离开前先设置一些流程变量,再使用指定名称的Transition离开本活动

  10.  
  11. }

4.4.11 办理任务

 
  1. // 办理任务

  2. @Test

  3. public void testCompleteTask() throws Exception {

  4. String taskId = "130002";

  5. processEngine.getTaskService().completeTask(taskId);

  6. }

4.4.12 设置流程变量

 
  1. // 设置流程变量

  2. @Test

  3. public void testSetVariable() throws Exception {

  4. String executionId = "test.150001";

  5. processEngine.getExecutionService().setVariable(executionId, "请假天数", 15);

  6. }

 
  1. // 获取流程变量

  2. @Test

  3. public void testGetVariable() throws Exception {

  4. String executionId = "test.150001";

  5. Integer days = (Integer) processEngine.getExecutionService().getVariable(executionId, "请假天数");

  6. System.out.println("请假天数 = " + days);

  7. }

 
  1. {

  2. ExecutionService executionService = processEngine.getExecutionService();

  3. TaskService taskService = processEngine.getTaskService();

  4.  
  5. // ============ 设置变量 ========================

  6. executionService.setVariable(executionId, name, value); // 设置一个变量

  7. executionService.setVariables(executionId, variablesMap); // 设置多个变量

  8. taskService.setVariables(taskId, variables); // 设置多个变量

  9.  
  10. executionService.startProcessInstanceByKey(processDefinitionKey, variablesMap); // 启动流程实例时,先设置一些变量

  11. taskService.completeTask(taskId, variablesMap); // 真正办理完任务前先设置一些变量

  12.  
  13.  
  14. // ============ 获取变量 ========================

  15. executionService.getVariable(executionId, variableName); // 获取一个变量

  16. executionService.getVariableNames(executionId); // 返回Set<String>,是所有变量的名称集合

  17. executionService.getVariables(executionId, variableNames); //获取多个变量,返回Map<String,Object>,表示指定名称的变量信息

  18.  
  19. taskService.getVariable(taskId, variableName);

  20. taskService.getVariableNames(taskId);

  21. taskService.getVariables(taskId, variableNames);

  22. }

4.4.13 流程执行

 
  1. @Test

  2. public void testProcess() throws Exception {

  3. // 部署流程定义

  4. InputStream in = this.getClass().getResourceAsStream("test.jpdl.xml");

  5. String deploymentId = processEngine.getRepositoryService()//

  6. .createDeployment()//

  7. .addResourceFromInputStream("test.jpdl.xml", in)//

  8. .deploy();

  9. System.out.println("部署流程定义完毕:deploymentId = " + deploymentId);

  10.  
  11. // 启动流程实例

  12. ProcessInstance pi = processEngine.getExecutionService().startProcessInstanceByKey("test");

  13. System.out.println("流程实例启动完毕:processInstanceId = " + pi.getId());

  14.  
  15. // 完成第一步“提交申请”的任务,要使用指定的Transition离开当前活动

  16. Task task = processEngine.getTaskService()//

  17. .createTaskQuery()// 获取本流程实例中当前情况下仅有的一个任务

  18. .processInstanceId(pi.getId())//

  19. .uniqueResult();

  20.  
  21. String transitionName1 = "to 部门经理审批";

  22. String transitionName2 = "to 总经理审批";

  23. processEngine.getTaskService().completeTask(task.getId(), transitionName2); // 使用指定名称的Transition离开本活动

  24. }

4.4.14 分配任务

 
  1. public class AssignmentHandlerImpl implements AssignmentHandler {

  2.  
  3. // 计算此任务的办理人,并分配任务

  4. @Override

  5. public void assign(Assignable assignable, OpenExecution execution) throws Exception {

  6. System.out.println("---> AssignmentHandlerImpl.assign()");

  7. // 计算办理人

  8. String userId = "李经理--";

  9.  
  10. // 分配个人任务

  11. assignable.setAssignee(userId); // 指定个人任务的办理人

  12.  
  13. // // 分配组任务

  14. // assignable.addCandidateUser("小A"); // 添加一个候选人(组任务)

  15. // assignable.addCandidateUser("小B"); // 添加一个候选人(组任务)

  16. // assignable.addCandidateUser("小C"); // 添加一个候选人(组任务)

  17. }

  18.  
  19. }

4.4.15 组任务与分配

 
  1. public class ProcessTest {

  2.  
  3. private static ProcessEngine processEngine = Configuration.getProcessEngine();

  4.  
  5. @Test

  6. public void testProcess() throws Exception {

  7. // 部署流程定义

  8. InputStream in = this.getClass().getResourceAsStream("test.jpdl.xml");

  9. String deploymentId = processEngine.getRepositoryService()//

  10. .createDeployment()//

  11. .addResourceFromInputStream("test.jpdl.xml", in)//

  12. .deploy();

  13. System.out.println("部署流程定义完毕:deploymentId = " + deploymentId);

  14.  
  15. // 启动流程实例

  16. Map<String, Object> variables = new HashMap<String, Object>();

  17. variables.put("manager", "王经理");

  18. variables.put("userIds", "小A,小B,小C,小D");

  19. ProcessInstance pi = processEngine.getExecutionService().startProcessInstanceByKey("test", variables);

  20. System.out.println("流程实例启动完毕:processInstanceId = " + pi.getId());

  21. }

  22.  
  23. // 查询组任务列表

  24. @Test

  25. public void testFindMyGroupTaskList() throws Exception {

  26. String userId = "王工程师";

  27. // String userId = "赵工程师";

  28. // 查询

  29. // List<Task> list = processEngine.getTaskService().findGroupTasks(userId);

  30. // 分页

  31. List<Task> list = processEngine.getTaskService()//

  32. .createTaskQuery()//

  33. .candidate(userId)// 指定候选人,这是查询组任务

  34. .page(0, 100)// 分页

  35. .list();

  36.  
  37. // 显示

  38. System.out.println("====== " + userId + "的个人任务列表 ======");

  39. for (Task task : list) {

  40. System.out.println("id=" + task.getId()//

  41. + ", name=" + task.getName()//

  42. + ", assignee=" + task.getAssignee()//

  43. + ", createTime=" + task.getCreateTime()//

  44. + ", executionId=" + task.getExecutionId());

  45. }

  46. }

  47.  
  48. // 拾取任务

  49. @Test

  50. public void testTakeTask() throws Exception {

  51. String taskId = "310009";

  52. String userId = "王工程师";

  53. processEngine.getTaskService().takeTask(taskId, userId);

  54. }

  55.  
  56. // 查询个人任务列表

  57. @Test

  58. public void testFindMyPersonalTaskList() throws Exception {

  59. String userId = "王工程师";

  60.  
  61. // 查询

  62. // List<Task> list = processEngine.getTaskService().findPersonalTasks(userId);

  63. // 分页

  64. List<Task> list = processEngine.getTaskService()//

  65. .createTaskQuery()//

  66. .assignee(userId)// 指定办理人条件

  67. .page(0, 100)// 分页

  68. .list();

  69.  
  70. // 显示

  71. System.out.println("====== " + userId + "的个人任务列表 ======");

  72. for (Task task : list) {

  73. System.out.println("id=" + task.getId()//

  74. + ", name=" + task.getName()//

  75. + ", assignee=" + task.getAssignee()//

  76. + ", createTime=" + task.getCreateTime()//

  77. + ", executionId=" + task.getExecutionId());

  78. }

  79. }

  80.  
  81. // 直接指定任务的办理人

  82. @Test

  83. public void testAssignTask() throws Exception {

  84. String taskId = "310009";

  85. // String userId = null; // 退回到组任务列表

  86. String userId = "赵工程师";

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

  88. }

  89.  
  90. }

猜你喜欢

转载自blog.csdn.net/syq8023/article/details/89851592