Jbpm4常用操作 一、ProcessEngine:流程引擎。是JBPM上层类,相当于Hibernate的SessionFactory级别。 //获得方式: ProcessEngine processEngine = Configuration.getProcessEngine(); /*Configuration类会读取classpath下的jbpm.cfg.xml文件进行流程引擎的加载。ProcessEngine是单例模式,即整个系统只会有一个processEngine实例。*/ 二、流程定义 1.部署流程定义 ProcessEngine processEngine = Configuration.getProcessEngine(); RepositoryService repositoryService = processEngine.getRepositoryService(); 例:布署文件中的流程 //布署当前目录下pd.jpdl.xml文件 String deploymentId = repositoryService.createDeployment() .addResourceFromClasspath("process.jpdl.xml").deploy(); /* deploymentId是发布的流程返回的ID号 */ 2.删除流程定义 类ProcessDefinition 包含如下属性: ID:流程定义ID号 DeploymentId:流程定义的布署ID号 Key:关键字 name:流程名 version:版本号 数据如下 ID Key 名称 版本 hello-1 hello hello 1 //获取类ProcessDefinition的属性ID String deploymentId = request.getParameter("deploymentId"); //根据流程ID获取流程定义实例 ProcessDefinition pd = repositoryService.createProcessDefinitionQuery() .processDefinitionId(deploymentId).uniqueResult(); //根据流程定义的布署ID号,删除该流程定义(根据流程定义的ID号级联删除) //注意:jbpm4是不允许直接根据流程定义的ID来直接删除流程定义的,因为还要删除其它配置数据 repositoryService.deleteDeploymentCascade(pd.getDeploymentId()); 3.获取全部流程定义 根据流程名获取所有流程定义 List<ProcessDefinition> processDefinitions = repositoryService .createProcessDefinitionQuery().orderAsc( ProcessDefinitionQuery.PROPERTY_NAME).list(); //还可以根据以下顺序进行排序 (org.jbpm.api.ProcessDefinitionQuery) public static final java.lang.String PROPERTY_DEPLOYMENT_TIMESTAMP "deployment.timestamp" public static final java.lang.String PROPERTY_ID "idProperty.stringValue" public static final java.lang.String PROPERTY_KEY "keyProperty.stringValue" public static final java.lang.String PROPERTY_NAME "idProperty.objectName" public static final java.lang.String PROPERTY_VERSION "versionProperty.longValue" 二、流程实例 1.启动一个流程实例 1.1根据key启动流程实例 //用户必须为新启动的流程实例分配一个key, 这个key是用户执行的时候定义的且唯一。通常在业务流程领域找到这种key。 比如,一个订单id或者一个保险单号。 ProcessInstance processInstance = executionService.startProcessInstanceByKey("ICL", "CL92837"); //key可以用来创建流程实例的id, 格式为{process-key}.{execution-id}。 所以上面的代码会创建一个id为 ICL.CL92837的流向 (execution)。 1.2 根据数据库主键启动流程实例 //如果没有提供用户定义的key,数据库就会把主键作为key。 这样可以使用如下方式获得id: ProcessInstance processInstance = executionService.startProcessInstanceByKey("ICL"); String pid = processInstance.getId(); //最好使用一个用户定义的key。提供给一个用户定义的key, 你可以组合流向的id,而不是执行一个基于流程变量的搜索 - 那种方式太消耗资源了。 1.3根据变量启动流程实例 //为一个新的流程实例启动时就提供一组对象参数。 将这些参数放在variables变量里, 然后可以在流程实例创建和启动时使用。 Map<String,Object> variables = new HashMap<String,Object>(); variables.put("customer", "John Doe"); variables.put("type", "Accident"); variables.put("amount", new Float(763.74)); ProcessInstance processInstance = executionService.startProcessInstanceByKey("ICL", variables); // //JBPM4.4支持变量历史 //变量可以被标记为作为历史记录保存。这意味着,当流程实例结束, 它的运行阶段的信息被删除,历史细节依然会被保存。 //通过公共 API ExecutionService启用变量的历史功能 void createVariable(String executionId, String name, Object value, boolean historyEnabled); void createVariables(String executionId, Map<String, ?> variables, boolean historyEnabled); //通过变量定义 <variable name="declaredVar" type="string" init-expr="testing declared variable" history="true"/> 2. 根据流程定义,查看流程实例 //根据类ProcessDefinition的属性ID,查看该流程的所有实例 String processDefinitionId = request.getParameter("processDefinitionId"); return executionService.createProcessInstanceQuery().processDefinitionId(processDefinitionId).list(); 3.执行实例 //根据类ProcessInstance的属性ID(流程实例ID),执行流程实例 String processInstanceId = request.getParameter("processInstanceId"); executionService.signalExecutionById(processInstanceId); 四.任务 //假设流程定义4-1如下: <process name="TaskAssignee"> <start> <transition to="review" /> </start> <task name="review" assignee="#{order.owner}"> <transition to="work" /> </task> <task name="review" assignee="de style="color: rgb(255, 102, 0);">johndoede>"> <transition to="wait" /> </task> <state name="wait"/> </process> assignee="johndoe" //表示任务会被分配给用户ID为"johndoe"的人。 assignee="#{order.owner}" //任务被分配给#{order.owner}。表示通过Order对的getOwner()方法会用来获得用户id,该用户负责完成这个任务。 public class Order implements Serializable { String owner; public Order(String owner) { this.owner = owner; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } } 1.获取任务列表 1.1根据用户ID获取任务列表 List<Task> taskList = taskService.findPersonalTasks("johndoe"); 1.2根据任务候选人或候选组获取任务列表 任务可能被分配给一组用户。 其中的一个用户应该接受这个任务并完成它。 candidate-groups:一个使用逗号分隔的组id列表。 所有组内的用户将会成为这个任务的候选人。 candidate-users:一个使用逗号分隔的用户id列表。 所有的用户将会成为这个任务的候选人。 例如: <task name="review" candidate-groups="sales-dept"> <transition to="wait" /> </task> 假设:sales-dept有两个成员:johndoe和joesmoe //这个任务被创建时,不显示在任何人的个人任务列表中。 下面的任务列表会是空的。 taskService.getAssignedTasks("johndoe"); taskService.getAssignedTasks("joesmoe"); 分组任务列表中,用户接口必须只接受对这些任务的“接受”操作。 taskService.takeTask(task.getDbid(), "johndoe"); 当一个用户接受了一个任务,这个任务的分配人就会变成当前用户。任务会从所有候选人的分组任务列表中消失,它会出现在用户的已分配列表中。 1.3在一个列表中显示该某人的所有任务 包括他的个人任务,候选任务,这时直接用jbpm4提供的api完成不了该功能要求。于是可以使用以下方式进行扩展: /** * 取得用户的对应的任务列表 * @param userId * @return */ public List<TaskImpl> getTasksByUserId(String userId){ AppUser user=(AppUser)getHibernateTemplate().load(AppUser.class, new Long(userId)); Iterator<AppRole> rolesIt=user.getRoles().iterator(); StringBuffer groupIds=new StringBuffer(); int i=0; while(rolesIt.hasNext()){ if(i>0)groupIds.append(","); groupIds.append("'"+rolesIt.next().getRoleId().toString()+"'"); } /** * select * from `jbpm4_task` task left join jbpm4_participation pt on task.`DBID_`=pt.`TASK_` where task.`ASSIGNEE_`='1' or ( pt.`TYPE_` = 'candidate' and (pt.`USERID_`='1') or pt.`GROUPID_`in ('1')) */ StringBuffer hqlSb=new StringBuffer(); hqlSb.append("select task from org.jbpm.pvm.internal.task.TaskImpl task left join task.participations pt where task.assignee=?"); hqlSb.append(" or (pt.type = 'candidate' and ((pt.userId=?)"); if(user.getRoles().size()>0){ hqlSb.append(" or (pt.groupId in ("+groupIds.toString()+"))"); } hqlSb.append("))"); hqlSb.append(" order by task.priority desc"); return findByHql(hqlSb.toString(), new Object[]{userId,userId}); } 2分配任务 如果在流程定义文件中将任务指定到了个人,则jbpm自动分配给个人。否则需要进行指定 2.1给用户组的用户分配任务 流程定义文件: <task name="review" candidate-groups="sales-dept"> <transition to="wait" /> </task> 假设:sales-dept有两个成员:johndoe和joesmoe 分组任务列表中,用户接口必须只接受对这些任务的“接受”操作。 taskService.takeTask(task.getDbid(), "johndoe"); 当一个用户接受了一个任务,这个任务的分配人就会变成当前用户。任务会从所有候选人的分组任务列表中消失,它会出现在用户的已分配列表中。 2.2任务分配处理器分配任务 一个AssignmentHandler可以通过编程方式来计算 一个任务的分配人和候选人。 public interface AssignmentHandler extends Serializable { void assign(Assignable assignable, OpenExecution execution) throws Exception; } Assignable是任务和泳道的通用接口。 所以任务分配处理器可以使用在任务, 也可以用在泳道中。 包含任务分配处理器的流程定义4-2如下: <process name="TaskAssignmentHandler" xmlns="http://jbpm.org/4.2/jpdl"> <start g="20,20,48,48"> <transition to="review" /> </start> <task name="review" g="96,16,127,52"> <assignment-handler class="org.jbpm.examples.task.assignmenthandler.AssignTask"> <field name="assignee"> <string value="johndoe" /> </field> </assignment-handler> <transition to="wait" /> </task> <state name="wait" g="255,16,88,52" /> </process> 类 AssignTask代码如下: public class AssignTask implements AssignmentHandler { String assignee; public void assign(Assignable assignable, OpenExecution execution) { assignable.setAssignee(assignee); } } 请注意,默认AssignmentHandler实现可以使用使用流程变量,任何其他Java API可以访问资源,像你的应用数据库来计算分配人和候选人用户和组。 启动一个TaskAssignmentHandler的新流程实例,会立即让新流程实例运行到任务节点。 一个新review任务被创建,在这个时候 AssignTask的分配处理器被调用。这将设置johndoe为分配人。 所以John Doe将在他自己的任务列表中找到这个任务。 2.3给泳道分配任务 任务泳道如下面的流程文件4-3: <process name="TaskSwimlane" xmlns="http://jbpm.org/4.2/jpdl"> <swimlane name="sales representative" candidate-groups="sales-dept" /> <start> <transition to="enter order data" /> </start> <task name="enter order data" swimlane="sales representative"> <transition to="calculate quote"/> </task> <task name="calculate quote" swimlane="sales representative"> </task> </process> 在这个例子中,我们在身份组件中 创建了下面的信息: identityService.createGroup("sales-dept"); identityService.createUser("johndoe", "johndoe", "John", "Doe"); identityService.createMembership("johndoe", "sales-dept"); 在启动一个新流程实例后,用户johndoe将成为 enter order data的一个候选人。还是像上一个流程候选人例子一样, John Doe可以像这样接收任务: taskService.takeTask(task.getDbid(), "johndoe"); 接收这个任务将让johndoe成为任务的负责人。 直到任务与泳道sales representative关联, 分配人johndoe也会关联到泳道中作为负责人。接下来,John Doe可以像下面这样完成任务: taskService.completeTask(taskDbid); 完成任务会将流程执行到下一个任务, 下一个任务是calculate quote。 这个任务也关联着泳道。因此, 任务会分配给johndoe。