前言
在前面的博客中讲到了JBPM4.4与SSH的集成,今天就来讲一下JBPM3在项目中是如何使用的(jbpm3和4的使用流程是一致的,不一样就是实现而已)。
正题
1.需求简介
今天要讲解的是根据OA系统中的动态表单那部分,我们先定义流程,然后对该流程定义动态表单(模板),之后新建公文,公文需要绑定流程。
2.流程介绍
我们看一下下面的图来了解下整体流程:
1).web.xml(建表)
从上图我们可以看到配置文件的关联关系,需要在web.xml中配置spring和struts,然后spring中配置jbpm。这样一启动服务我们就可以创建jbpm所需要的表。
2).部署流程
表创建完成后,我们需要定义并部署流程,将定义好的流程配置文件上传并部署(该项目中有上传流程文件功能,即将流程内容以二进制的形式保存入数据库)。
由于业务需要,我们可以给流程绑定动态表单,即给流程绑定一个模板(这个动态表单不是必须的,需要根据业务需求确定)。
3).绑定实例
新建公文信息,先选择一个流程,然后就可以加载相应的模板,填完信息后即可保存公文信息并且生成该公文的流程实例信息。
3.核心代码
其实要想在我们项目中进行流程操作,主要就是需要封装一个关于流程操作的类,之后在需要用到的地方进行调用即可。
1)比如我们这里面的流程核心操作类是WorkflowManagerImpl.java:
package com.bjsxt.oa.managers.impl; import java.io.ByteArrayInputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.jbpm.JbpmConfiguration; import org.jbpm.JbpmContext; import org.jbpm.graph.def.ProcessDefinition; import org.jbpm.graph.def.Transition; import org.jbpm.graph.exe.ProcessInstance; import org.jbpm.taskmgmt.exe.TaskInstance; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import com.bjsxt.oa.managers.WorkflowManager; import com.bjsxt.oa.model.Document; import com.bjsxt.oa.model.Workflow; public class WorkflowManagerImpl extends HibernateDaoSupport implements WorkflowManager { private JbpmConfiguration jbpmConfiguration; public long addProcessInstance(String workflowName, int documentId) { JbpmContext context = getContext(); //从JBPM中加载流程定义 ProcessDefinition definition = context.getGraphSession().findLatestProcessDefinition(workflowName); ProcessInstance instance = new ProcessInstance(definition); //将公文标识绑定到流程实例 instance.getContextInstance().createVariable("document", documentId); //存储流程实例的信息 context.save(instance); return instance.getId(); } public void delProcessInstance(long processInstanceId) { JbpmContext context = getContext(); //删除流程实例 context.getGraphSession().deleteProcessInstance(processInstanceId); } public void delWorkflow(int workflowId) { //在OA中删除流程的定义 Workflow workflow = (Workflow)getHibernateTemplate().load(Workflow.class, workflowId); getHibernateTemplate().delete(workflow); //在JBPM中删除流程定义 //JBPM对流程定义按版本进行管理,所以在同一个时刻,可能存在同一个流程定义的多个不同的版本 //如果需要对其删除,则应该删除所有的版本 //查找对应流程定义的所有版本 List defs = getContext().getGraphSession().findAllProcessDefinitionVersions(workflow.getName()); for (Iterator iter = defs.iterator(); iter.hasNext();) { ProcessDefinition def = (ProcessDefinition) iter.next(); getContext().getGraphSession().deleteProcessDefinition(def); } } public void deployProcessDefinition(byte[] processDefinition, byte[] processImage) { //通过byte[]创建ProcessDefinition对象 ProcessDefinition def = ProcessDefinition.parseXmlInputStream( new ByteArrayInputStream(processDefinition)); //将流程定义文件部署到JBPM getContext().deployProcessDefinition(def); //首先查找一下Workflow对象是否已经存在 Workflow workflow = (Workflow)getSession() .createQuery("select w from Workflow w where w.name = ? ") .setParameter(0, def.getName()) .uniqueResult(); //如果流程尚未存在,则创建 if(workflow == null){ workflow = new Workflow(); workflow.setName(def.getName()); workflow.setProcessDefinition(processDefinition); workflow.setProcessImage(processImage); getHibernateTemplate().save(workflow); return; } //如果流程已经存在,则更新 workflow.setName(def.getName()); workflow.setProcessDefinition(processDefinition); workflow.setProcessImage(processImage); getHibernateTemplate().update(workflow); } public Workflow findWorkflow(int workflowId) { return (Workflow)getHibernateTemplate().load(Workflow.class, workflowId); } public String flowToNextStep(String username, long processInstanceId, String transitionName) { JbpmContext context = getContext(); String status = null; ProcessInstance instance = context.getProcessInstance(processInstanceId); //当前节点 String currentNodeName = instance.getRootToken().getNode().getName(); //起始节点 String startNodeName = instance.getProcessDefinition().getStartState().getName(); //如果是在起始节点,因为起始节点不会跟任何人相关联(即不会将任务分配给任何人) if(currentNodeName.equals(startNodeName)){ //需要使用流程实例的signal()方法来触发流程向下一步流动! instance.getRootToken().signal(transitionName); }else{ //首先找出用户的当前任务 List tasks = context.getTaskMgmtSession().findTaskInstances(username); for (Iterator iter = tasks.iterator(); iter.hasNext();) { TaskInstance taskInstance = (TaskInstance) iter.next(); if(taskInstance.getProcessInstance().getId() == processInstanceId){ //这就是当前文档对应的任务,需要结束这个任务,从而触发流程向下一步骤移动! taskInstance.end(transitionName); break; } } } //将公文当前所处节点作为状态信息返回 status = instance.getRootToken().getNode().getName(); //判断当前的状态是否已经结束! if(instance.hasEnded()){ status = Document.STATUS_END; } return status; } public List searchAllWorkflows() { return getHibernateTemplate().find("from Workflow"); } public List searchApprovingDocuments(String username) { JbpmContext context = getContext(); List docIds = new ArrayList(); //首先获得流转到用户的任务列表 List tasks = context.getTaskMgmtSession().findTaskInstances(username); for (Iterator iter = tasks.iterator(); iter.hasNext();) { TaskInstance taskInstance = (TaskInstance) iter.next(); //任务实例是否正在等待审批,如果不是,则忽略(即不应该被列到待审批列表中!) if(!taskInstance.isSignalling()){ continue; } //根据其对应的流程实例,获得公文标识 Integer docId = (Integer)taskInstance.getProcessInstance().getContextInstance().getVariable("document"); docIds.add(docId); } return docIds; } //下一步都有哪些流向? public List searchNextTransitions(String username,long processInstanceId) { JbpmContext context = getContext(); List transitions = new ArrayList(); //根据流程实例标识查找流程实例 ProcessInstance instance = context.getProcessInstance(processInstanceId); // //根据流程实例,获得当前的节点,从而得到在当前节点下有哪些流向 // List nextSteps = instance.getRootToken().getNode().getLeavingTransitions(); //当前节点 String currentNodeName = instance.getRootToken().getNode().getName(); //起始节点 String startNodeName = instance.getProcessDefinition().getStartState().getName(); Collection nextSteps = null; //如果是在起始节点,因为起始节点不会跟任何人相关联(即不会将任务分配给任何人) if(currentNodeName.equals(startNodeName)){ //需要使用流程实例的signal()方法来触发流程向下一步流动! nextSteps = instance.getRootToken().getAvailableTransitions(); }else{ //首先找出用户的当前任务 List tasks = context.getTaskMgmtSession().findTaskInstances(username); for (Iterator iter = tasks.iterator(); iter.hasNext();) { TaskInstance taskInstance = (TaskInstance) iter.next(); if(taskInstance.getProcessInstance().getId() == processInstanceId){ nextSteps = taskInstance.getAvailableTransitions(); break; } } } for (Iterator iter = nextSteps.iterator(); iter.hasNext();) { Transition transition = (Transition) iter.next(); transitions.add(transition.getName()); } return transitions; } /** * 获取JbpmContext对象,需要将JbpmContext的session设置为当前的session对象 * @return */ private JbpmContext getContext(){ JbpmContext context = jbpmConfiguration.createJbpmContext(); context.setSession(getSession()); return context; } public void setJbpmConfiguration(JbpmConfiguration jbpmConfiguration) { this.jbpmConfiguration = jbpmConfiguration; } }
2)然后我们部署流程的时候只需要再上传流程的那个action中调用workflowManager中的部署流程的方法即可:
//添加流程定义 publicActionForward add(ActionMapping mapping, ActionForm form, HttpServletRequestrequest, HttpServletResponse response) throws Exception { WorkflowActionFormwaf = (WorkflowActionForm)form; //TODO做一些判断,判断上传的文件是否为空,决定是否抛出异常,等等!! //部署流程 workflowManager.deployProcessDefinition( waf.getProcessDefinition().getFileData(), waf.getProcessImage().getFileData() ); returnmapping.findForward("add_success"); }
3)绑定实例的时候一样,我们需要在添加公文的DocumentManagerImpl.java类里面调用workflowManager的生成流程实例信息:
//添加公文 publicvoid addDocument(Document document, int workflowId, int userId) { //保存公文信息 document.setWorkflow((Workflow)getHibernateTemplate().load(Workflow.class,workflowId)); document.setCreator((User)getHibernateTemplate().load(User.class,userId)); document.setStatus(Document.STATUS_NEW); document.setCreateTime(newDate()); getHibernateTemplate().save(document); //添加流程实例 longprocessInstanceId =workflowManager.addProcessInstance(document.getWorkflow().getName(),document.getId()); //绑定流程实例的标识到公文对象 document.setProcessInstanceId(processInstanceId); getHibernateTemplate().update(document); }
4.小结
要想把工作流嵌入到项目中,就要把它的各个流程步骤添加进去,即建表——部署流程——创建实例——流程流转。重要的是要知道这几个步骤跟你的项目是如何协同合作的。