jBPM 笔记
(一)
早就听说工作流管理系统jBPM了,以前公司在项目中也用到过工作流,不过那里都是公司自己实现的简单的工作流管理,这次的项目会用到jBPM于是开始找资料学习,决定做个笔记加深记忆.
说到jBPM也就顺便吧工作流基本概念了解了一下:
工作流(Workflow),是对工作流程及其各操作步骤之间业务规则的抽象、概括、描述。
工作流建模,即将工作流程中的工作如何前后组织在一起的逻辑和规则在计算机中以恰当的模型进行表示并对其实施计算。
工作流要解决的主要问题是:为实现某个业务目标,在多个参与者之间,利用计算机,按某种预定规则自动传递文档、信息或者任务。
工作流管理系统(Workflow Management System, WfMS)的主要功能是通过计算机技术的支持去定义、执行和管理工作流,协调工作流执行过程中工作之间以及群体成员之间的信息交互。工作流需要依靠工作流管理系统来实现。
工作流属于计算机支持的协同工作(Computer Supported Cooperative Work,CSCW)的一部分。后者是普遍地研究一个群体如何在计算机的帮助下实现协同工作的。
首先要下载jBPM包以及相关内容。
当然.要先确定你的电脑中已经安装了Java开发环境。
到 http://sourceforge.net/project/showfiles.php?group_id=70542 页面下载。公司要使用jBPM3的版本。于由从列表中选择 f) jBPM jPDL 3 来下载.直接下载
jbpm-installer-3.2.6.SP1.jar 按提示一步一步安装就行了.
安装完以后,jBPM的目录下有config,database,designer,docs,examples,lib,src,Uninstaller几个目录.
其中,config目录中存放着jBPM要用到的配置文件的模板,用的时候copy来改改就好.
database目录中存放着jBPM要用到的数据库表的创建脚本.
designer目录中存放着流程设计器的eclipse插件.
lib目录中存放着jBPM的支持包
其它的就是文档和源码示例等等.
eclipse的安装以及jBPM的eclipse插件的安装就不多说了.
例子也不介绍了.直接自己动手做吧:
在eclipse中新建一个项目
在项目的Build Path中加入jBPM 目录中 lib子目录下的所有jar文件.
另外还要加一个jta.jar 不然会报一个 java.lang.NoClassDefFoundErr:javax/transaction/Synchronization异常.
从config子目录中拷贝一个hibernate配置文件.要根据你使用的数据库来选择,我测试时使用的是mysql数据库.就拷贝了hibernate.cfg.mysql.xml文件到项目的src下.
改名为hibernate.cfg.xml,修改其内容,与电脑上的数据库相符,新建一个数据库jbpmtest用来测试.再将数据库的JDBC Driver包引入项目path中.
为了可以看到log信息.创建一个log4j的配置文件.可以参考 log4j 基本配置文件(log4j.properties) 也可以直接copy examples目录下的log4j.xml,是xml格式的.
修改一下,让调试信息输出到控制台.
接下来就先创建一个过程定义(ProcessDefinition).
在项目的src目录上点右键->新建->其它,找到jBoss JBPM 中的 process definition 下一步.输入一个名字.这个名字是过程的名字.以后可以用来在数据库中查找.
确定后,会在src目录中创建一个以过程名字用名的目录.并在目录中生成processdefinition.xml,并且右边窗口出现了设计器.在设计器窗口的左边是工具箱,右边是绘图区.
我们先在工具箱中拖出一个Start和一个End,为了测试效果.再拖一个State出来放到Start和End中间,然后用Transition线,将它们按照Start->State1->End的顺序联接起来.
保存后,一个简单的不能再简单的流程图就设计好了.可以点设计器下面的Source,查看源码.很简单的源码,要注意的是其中的name项,有兴趣可以修改一下.下面就写点代码来测试一下吧.
在src下创建一个类.在其main方法中写入以下代码:
//实例化默认Configuration
JbpmConfiguration jc = JbpmConfiguration.getInstance();
//创建Context
JbpmContext context = jc.createJbpmContext();
//加载本地过程定义文件(processDefinition)myprocess就是之前起的过程名
ProcessDefinition pd = ProcessDefinition.parseXmlResource("myprocess/processdefinition.xml");
//将过程定义文件持久化至数据库
context.deployProcessDefinition(pd);
//关闭Context-事务提交
context.close();
运行之.运行结束后,可以在数据库jbpmtest的jbpm_processefinition表中看到一条数据.这就是我们刚才定义的过程.并且在jbpm_node表中也生成了node的记录.
接着做下一步测试.将main方法中的代码改为:
//实例化默认Configuration
JbpmConfiguration jc = JbpmConfiguration.getInstance();
//创建Context
JbpmContext context = jc.createJbpmContext();
//从数据库加载过程定义,使用的就是定义过程时起好的名字.
ProcessDefinition pd = context.getGraphSession().findLatestProcessDefinition("myprocess");
//用过程定义创建一个过程实例 jBPM 会自动向数据库插入实例记录
ProcessInstance instance = pd.createProcessInstance();
System.out.println("----------Node State:" + instance.getRootToken().getNode().getName());
//关闭Context-事务提交
context.close();
要对以上代码说明一下.jBPM管理的过程定义(processDefinition)及过程实例(ProcessInstance)的关系,就好像木工图纸与木工工匠的关系一样.图纸上只是说明了一件家具如何去制做,但是真正做家具的是工匠.
jBPM中也一样.过程定义(processDefinition)只是一个模板,工作流真正管理的是过程实例(ProcessInstance)的状态.
当我们得到一个过程实例(ProcessInstance)的时候.可以显示一下它的NodeName.(Token与Node在之后说明)我们发现结果就是我们在画流程定义图时.Start结点的名称,如果你没有修改的话,它应该是start-state1.
这时再看数据库的jbpm_ProcessInstance表中就有了一条记录.其ID应该是1.如果不是,记下这个ID.我们下一步测试要用到它.同时,jbpm_token表中也有了一条记录,token的作用就是标识一下实例运行到过程中的哪一个结点了,
其Node字段指出现在token所指向的Node,node就是结点.Start是Node,end也是Node,State也是一个Node.现在的token指向的是StartNode的ID.可以与jbpm_node表中的start结点对照一下.
接下来我们让这个实例走到下一个结点,将main方法中的代码改为:
//实例化默认Configuration
JbpmConfiguration jc = JbpmConfiguration.getInstance();
//创建Context
JbpmContext context = jc.createJbpmContext();
//加载过程实例.
ProcessInstance instance = context.getGraphSession().getProcessInstance(1);
//发送信号,使Token指向下一步
instance.signal();
System.out.println("----------Node State:" + instance.getRootToken().getNode().getName());
//关闭Context-事务提交
context.close();
这时看到输出的结果已经变成state结点的名称.没有修改的话应该是State1.查看数据库表jbpm_token中的记录,刚才的token的node字段已经更新了,对应了jbpm_node表中state1结点的ID.
ProcessInstance instance = context.getGraphSession().getProcessInstance(1);其中的1就是我们刚才在表中查到的实例ID号.
instance.signal();是为了向token发送一个信号,通知token向下一结点移动.
接下来再改:
//实例化默认Configuration
JbpmConfiguration jc = JbpmConfiguration.getInstance();
//创建Context
JbpmContext context = jc.createJbpmContext();
//加载过程实例.
ProcessInstance instance = context.getGraphSession().getProcessInstance(1);
//发送信号,使Token指向下一步
if(!instance.hasEnded()){
instance.signal();
}
System.out.println("----------Node State:" + instance.getRootToken().getNode().getName());
//关闭Context-事务提交
context.close();
这时输出结果已经变为end结点的name了.再看jbpm_token表和jbpm_ProcessInstance表.end字段已经有了时间.这时说明我们的这个流程实例已经走到结束结点了.
if(!instance.hasEnded())是为了判断一下实例是否已经结束,如果结束了还要发信号的话,会报异常.以上就是简单的jBPM测试,之后再做一个与业务相关的测试.