jbpm3

JBPM学习笔记  

2012-01-05 14:06:00|  分类: JBPM |字号 订阅
一、如何在MyEclipse中安装JBPM插件

1、环境
系统:Win7
MyEclipse版本:7.5/8.0
Jbpm版本:4.4
2、步骤
①到jboss官网下载JBPM4.4,网址:http://sourceforge.net/projects/jbpm/files/
②将下载的JBPM4压缩包解压,将%JBPM_HOME%\install\src\gpd\jbpm-gpd-site.zip文件解压。
③点击MyEclipse8菜单:help-->software updates-->Add /remove software... ,在弹出的Add/Remove Software窗口中,单击add-->add Local-->找到上面解压后的%JBPM_HOME%\install\src\gpd\jbpm-gpd-site文件夹,点打开。可以看到就能加载成功了。
④在接下来的窗口中勾选jbpm中除以Sources结尾外的选项,接着点下一步,一路点下去直到提醒你重启,则插件安装成功。





注意:是勾选以Sources结尾以外的选项,否则安装会报错。
如果第3步的最后一个环节处(单击add-->add Local)还有类似add Archive的选项,则第一步不需将jbpm-gpd-site.zip文件解压,通过Archive直接选择jbpm-gpd-site.zip文件即可。

3、jbpm插件成功安装后,新建工程有个"jboss jBPM",可以新建一个文件,画流程图。

4、画流程图时候,可能会出现二个问题:

问题一:打开"window-show view-properties"页面有错误,因为我需要在这个页面上修改流程图中属性。

解决方法:从网上下载"site-1.6.10.zip"包,然后解压,把"features目录和plugins目录copy到myeclipse安装目录\myPlugin(自己建立的目录)\svn下,解压之后其他文件不需要。在然后到myeclipse安装目录\dropins下增加一个文件svn.link,该文件内容如下:

path=myeclipse安装目录\\myPlugin\\Svn

再然后把myeclipse安装目录下\configuration中的org.eclipse.update目录删除,最后重启myeclipse,一切ok了。

问题二:jbpm的xml文件中文是乱码

在myeclipse目录下找到myeclipse.ini文件,在文件结尾增加一行代码:

-Dfile.encoding=UTF-8

然后重启myeclipse,一切ok了。

二、JBPM与Myeclipse集成

英文版:

A、安装Eclipse插件:Graphical Process Designer(GPD),该插件已经包含在软件包中${jbpm.home}/install/src/gpd/jbpm-gpd-site.zip

1. Help --> Install New Software...

2.Click Add...

3.In dialog Add Site dialog, click Archive...

4.Navigate to install/src/gpd/jbpm-gpd-site.zip and click 'Open'

5.Clicking OK in the Add Site dialog will bring you back to the dialog 'Install'

6.Select the jPDL 4 GPD Update Site that has appeared

7.Click Next... and then Finish

8.Approve the license

9.Restart eclipse when that is asked

B、为Eclipse配置jBPM Runtime

1.Click Window --> Preferences

2.Select JBoss jBPM --> jBPM 4 --> Runtime Locations

3.Click Add...

4.In the Add Location dialog, enter a name like e.g. jbpm-4.0 and then click Search...

5.In the Browse For Folder dialog, select your jbpm home directory and click OK

6.Click OK in the Add Location dialog

C、为Eclipse添加用户库jBPM

1.Click Window --> Preferences

2.Select Java --> Build Path --> User Libraries

3.Click New...

4.Type name jBPM Libraries

5.Click Add JARs...

6.Navigate to the 'lib' folder of your jBPM installation

7.Select all jar files and click Open

8.Select the jBPM Libraries entry

9.Click Add JARs... again

10.Select the jbpm.jar file in the root of your jBPM installation

11.Click Open

12.Select entry Source attachment under jbpm.jar

//下列步骤是附加源码,不是必须的。

Click Edit

In dialog Source Attachment Configuration, click External Folder...

Navigate to the src folder in your jBPM installation

Click Choose

Click OK twice to close all the open dialogs

D、为了便于手工编辑XML的流程文件,为Eclispe添加schema文件

1.Click Window --> Preferences

2.Select XML --> XML Catalog

3.Click 'Add...'

4.The 'Add XML Catalog Entry' dialog opens

5.Click the button with the map-icon next to location and select 'File System...'

6.In the dialog that opens, select file jpdl-4.0.xsd in the src directory of the jBPM installation root.

7.Click 'Open' and close all the dialogs

E、导入示例项目

1.Select File --> Import...

2.Select General --> Existing Projects into Workspace

3.Click Next

4.Click Browse... to select a root directory

5.Navigate to the jBPM root installation directory

6.Click OK

7.The examples project is automatically found and selected

8.Click Finish

至此,所有例子都可以作为测试运行,右击所选项目:'Run As' --> 'JUnit Test'.

中文版:

使用jbpm时,有一个东东叫做图形化流程设计器,即Graph Process Designer(GPD),是用户能够通过图形拖拽,属性设置等可视化的方式进行业务流程设计,建立并展现业务流程模型。这个模型在jbpm4中一般为.jpdl.xml文件,遵循jpdl规范,此文件即“流程定义”文件,在运行时由工作流引擎解释执行,生成“流程实例”。

下面我们看看怎样用eclipse集成GPD,由于jbpm4 gpd集成eclipse有版本的限制,即eclipse3.5.x,所以我一咬牙就下了个myeclipse8.5,对应的eclipse版本为Eclipse 3.5.2,最开始以为这个版本肯定很慢,等装了之后,发觉部署和启动,都比6.0快,还不错。

myeclipse8.5的软件更新和前几个版本不太相同,首先Help-->Myeclipse Configuration Center,进去之后,点击SoftWare,然后Add from Archive File,选择 ${jbpm.home}/install/src/gpd/jbpm-gpd-site.zip文件,取个名字如 jbpmgpd,展开节点,点击右键,Add to Profile(不要带source的),最后点击Apply change,此时打开 window-

perferences里面会有一个jbpmgpd的栏目,重启OK。(这几步骤容易出错,小心行事,我试了一下,最好先把jboss配置好,在点击apply change的时候看看个数是否正确)。

成功后,会在window-->Preferences中看到 JBoss jBPM这个栏目。然后选择Runtime Locations来配置运行环境,点击add,输入名称如jbpm4.4,然后选择jbpm安装目录,ok。之后回到Runtime Location 选择jbpm4.4,点击OK,配置完成。

接下来为你的工作空间定义一个jbpm用户库(User Libraries),它可以被用来饮用jBPM的所有依赖库文件。如果你新建一个jBPM工程,只需将这个jBPM用户库添加到build path下即可。

1,选择 window-->Preferences

2,选择java -Build Path-User Libraries选项,单击New,输入名称 jBPM Libraries.

3,单击add jars,找到jbpm安装目录下的lib目录。

4,选择lib目录下的所有jar文件,并单击open按钮。

5,选中刚才新建的jBPM Libraries,重新单击add jars,在jbpm的安装目录下选择jbpm.jar文件

6,单击open

7,在jbpm.jar下选中Sourceattachment。

8,单击edit,在Source Attachement Configuration对话框中,单击External Folder按钮。

9,找到jBPM安装目录下的src目录。

10,单击choose按钮,为jbpm.jar关联源代码。

11,单击两次ok按钮关闭所有对话框,搞定。

添加jpdl4 schema校验,就像刚才说的jpdl是jbpm独有的流程定义语言,它以xml文件的形式描述业务流程。由于jbpm官方提供的图形化流程设计器功能不全面,因此很多情况下我们需要直接编辑jpdl的xml源代码,所以,最好为jpdl xml指定Schema,这样,可以通过快捷键"Alt+/"快速呼出语法提示,并帮你校验jpdl的语法错误。

在Eclipse中配置此Schema的过程是:

1,选择window-preferences,选择xml-->xml CataLog.

2,单击add,单击File System,然后选择${jbpm.home}/src/jpdl.xsd文件,ok,配置完成。

上面的整完之后呢,我们现在亲自动手,弄个程序跑跑,瞧好了。

在Jbpm4的软件包中,含有丰富的范例流程和测试代码,下面就将这些范例导入你的Eclipse中,成为一个examples工程,供学习和研究,步骤如下

file-->import,然后选择${jbpm.home}下的examples,ok完成。

配置了jbpm4用户依赖库后,范例中所有的单元测试类(都继承了JbpmTestCase)都可以作为Junit test运行了,在各个测试类上选择 run as-->JUnit Test命令即可。

当然,万能的ant也可以来帮你发布程序。首先,选择window-->show view-->other-->Ant-->Ant命令,打开ant试图;然后,将范例工程中的ant构建文件build.xml,从包视图拖拽到ant视图,即可使用其中的ant构建任务(target),来发布范例流程到目标服务器上,关于部署流程的细节,以后再讲。

现在,我们将设计一个最简单的流程定义 "HelloAfei"。

如下:

新建jbpm4 Process Definition,然后可以通过如下方式拖拽:





 

 

http://fndcz.iteye.com/blog/114436

http://www.iteye.com/topic/212671

http://duyunfei.iteye.com/blog/857793

http://www.iteye.com/topic/854291

 

三、JBoss JBPM实践系列

(一) 安装配置(Tomcat6.0+MySQL5.0)

jBPM,全称是Java Business Process Management,是一种基于J2EE的轻量级工作流管理系统。jBPM是公开源代码项目,遵循Apache License。jBPM在2004年10月18日,发布了2.0版本,并在同一天加入了JBoss,成为了JBoss企业中间件平台的一个组成部分,它的名称也改成JBoss jBPM。

jBPM有两大特色,使他成为市场的一大亮点。其中最大的特色就是它的业务逻辑定义没有采用目前的一些规范,如WfMC´s XPDL, BPML, ebXML, BPEL4WS等,而是它自己定义的JBoss jBPM Process definition language (jPdl)。jPdl把一个业务逻辑流程看作是一个UML状态图,如果你不熟悉UML状态图,那初学计算机语言的流程图应该熟悉吧,表达的方式和意思大同小异。jPdl详细定义了这个状态图的每个部分,如起始、结束状态,状态之间的转换等;其另一大特色就是集成Hibernate,确切的说是绑定,使用Hibernate来管理数据库,这样jBPM只专注于他的业务流程控制。

从上面可以看出,jBPM是一个业务流程管理引擎,是一个工作流引擎。除此之外,它同时实现了对jPDL和对BPEL的支持。它整合了Hibernate技术处理数据库,创建了一系列的数据库表,持久化工作流引擎所需的状态。因此,jBPM支持所有Hibernate支持的数据库,能够把Java对象持久化到数据库中,把Hibernate支持的Java类的对象保存到数据库中!

你完全可以像用 Java 的类库一样使用JBoss jBPM,而且通过配置JBoss jBPM也可以被部署在其它J2EE应用服务器上和任何数据库上。

在本文中,我们首先来创建我们的JBoss jBPM运行开发环境。在开始之前,请准备一下软件产品:

·JDK 1.5 或者更高版本, 这里使用JDK 6u10b

·Apache Tomcat 5.5.x或更高版本,这里使用Tomcat 6.0.16

·MySQL 5.1 ,也可以选择其它Hiberante 支持的数据库,没有太大差别,这里使用MySQL 5.1

·Apache Ant 1.7.0

·JBPM-3.2.3

·Eclipse Europa(Eclipse V3.3) for JavaEE Developers或更高, 这里使用Eclipse V3.4

说明:JBoss jBPM的发布包中已经配置好了一套服务环境,是基于JBoss的。因为我们习惯了Tomcat 的小巧灵活,而且我们也不希望jBPM依赖JBoss。

1. 下载安装JDK,Tomcat, Ant, MySQL, 并设置相应的环境变量

此步骤不再熬述,具体请查阅官方文档

Jdk:http://java.sun.com/

Ant:http://ant.apache.org/

Tomcat:http://tomcat.apache.org/

Eclipse:http://www.eclipse.org/

2. 下载JBoss jBPM

JBoss jBPM 官方(http://www.jboss.org/jbossjbpm/)当前发布的版本为 3.2.3, 只需要下载jPDL Suite,下载后得到jbpm-jpdl-suite-3.2.3.zip,这个套件包含了所有的内容和资源,包括eclipse插件,示例,和流程管理控制应用。

解压jbpm-jpdl-suite-3.2.3.zip,这里解压后得到D:\jbpm-jpdl-3.2.3,其主要目录结构如下:

D:\jbpm-jpdl-3.2.3

--- db   这里都是些sql定义和数据文件,如果改用其它数据库,可以使用这些资源来创建,服务还是很周到的。顺便啰嗦一句,jBPM 默认使用的是内存数据库 hsqldb ,这个数据库还没研究过

--- deploy  用来部署你的应用的包和资源

--- designer  这里是Eclipse插件,这样你就可以在图形界面来定义你的业务流程,骨灰级人物没他也能过日子

--- doc  这里是jBPM相关组件的API 文档

--- examples  这里是些学习的例子

--- lib  jBPM 的类库

--- server  这里有一个JBoss 服务器,并且包含了本JBoss jBPM引擎,还部署了websale例子

--- src  这里是JBoss  jBPM的源代码

安装Eclipse及jBPM开发插件

Eclipse不是开发 jBPM 必须的工具,但它是对 jBPM 开发很有帮助的工具,特别是 jBPM 提供了一个 Eclipse 插件用来辅助开发 jBPM 。关于 Eclipse 的安装请参阅相关文档。本实验安装的是MyEclipse6.0集成Eclipse3.3。

安装完Eclipse安装jBPM的开发插件,步骤如下:

(1) 打开Eclipse选择菜单“Help->Software Updates->Find and Install”;

(2) 弹出窗口中选择“Search for new features to install”,然后点击“Next >”;如图





 

 

(3) 点击按扭“New Local Site…”选择插件目录,位于designer\ eclipse目录下,如:E:\Java\tools\jbpm-jpdl-3.2.2\designer\eclipse。选定后点“OK”,如图





 

 

(4) 选中“designer/eclipse”,然后点击“Finish”,如图





 

 

(5) 然后选择同意条款,按提示步骤安装就可以了。

到此为止需要的所有工具都安装好了。接下来先体验一下jBPM工作流。在 jbpm-jpdl-3.2.2的 server 目录是一个已经在JBoss中配置好的了 jBPM 示例,双击 server 目录下的 start.bat 文件,启动 JBoss 服务。打开网页: http://localhost:8080/ jbpm-console 得到如下页面:




 

这是一个流程控制管理平台,用右边的账号与密码就可以登录,这个控制台包括流程管理,可以部署流程、删除流程、查看流程图、管理流程实例等;还有任务管理,工作管理及用户与用户组管理。

完成上述操作后,就可以创建JBoss jBPM项目了。在Eclipse中进行如下操作: File => new => Project 在项目类型中有一个“JBoss jBPM”点击展开选择“Process Project”=>输入项目名称(这里为:firstflow)=>Finish

现在你可以开始你的JBoss jBPM之旅了。在刚才新建的项目firstflow已经提供了一个简单的流程定义例子,打开src/main/jpdl/simple/processdifinition.xml 在右边编辑区就可以看到该流程定义的图形界面,左边就是设计器了。所有的GUI 设计器都是一样的用法,拖过来就可以用了,如果你在JBuilder等做过GUI开发这个就非常简单了(这里本身就没什么难度),也可以在 source 中直接编写代码来定义你的流程; src/main/jpdl/simple 下的 gpd.xml是用来定位你的图形设计组件的布局定位的,你不用去理会它,另外在Eclipse 菜单 View 中 选择 Show Grid ,你的设计器就会显示定位网格了,这样可以把组件摆的更美观;src/main/jpdl/simple 下的 processimage.jpg 就是你画的流程定义的结果图片了。 可以看出,你的工作就仅仅操作processdifinition.xml 来定义你的流程。

有了例子事情就容易多了,假如我们要建立一个自己的流程,可以在Eclipse 项目树 src/main/jpdl 右键 New => Other => 找到JBoss jBPM  展开后选择 Process Difinition => Next => 输入 Process Name (这里假设为fisrtflow) => Finish . OK, 你现在可以定义自己的流程了。

流程定义完成后,你可以在src/test 创建单元测试来测试你的代码,有现成的例子这里不多说了。一切都完成后,你就可以部署你的流程了。

你可以在D:\jbpm-jpdl-3.2.2\examples 找到各种Demo,这些官方的例子要比其它的地方的东西正宗,请阅读:jbpm-jpdl-suite-3.2.2\jbpm-jpdl-3.2.2\examples\readme.html,仔细看看相信你会有所收获。

3. 配置数据库(此处以MySQL为例,其他数据库方法一致)

jBPM需要把初始化数据和工作流定义存储到数据库中,它定义了一套数据结构来存储这些数据,这也是该容器本身的特点。

在mysql 中创建一个数据库 jbpm ,(create database jbpm;),并创建用户jbossjbpm(密码:jbossjbpm)

说明:如果你嫌麻烦可以使用root账号和其密码,不过下面的设置请做相应的更改。在D:\jbpm-jpdl-3.2.3\db 找到jbpm.jpdl.mysql.sql, 该文件必须修改一下,以符合MySQL的语法结构。具体就是在每条语句的末尾增加一个分号";"你可以借助 UltrEdit, EditPlus等工具来做这些事情(注意替换时要注意匹配大小写,有写表的字段中包含CREATE字符),如果是第一次创建这些数据库表,要删除create语句上面的alter和drop(这些表还都不存在)。

4. 准备jBPM包

这是个jbpm-jpdl流程管理控制台,就像Tomcat有个单独的Administrator应用用来管理配置和部署一样的东东。有了他你可以在图形界面来操作控制你的应用。

打开命令行控制台,切换到D:\jbpm-jpdl-3.2.2\deploy 目录,执行以下命令:

ant customize.console.for.tomcat

注意:请确保你的ant安装配置妥当,可以在命令行输入:ant -version 来检测ant 是否正确安装。命令执行后能看到ant的版本信息即OK

ant customize.console.for.tomcat 执行成功后,会在D:\jbpm-jpdl-3.2.2\deploy 目录下生成customized和target目录,其中customized目录下的jbpm-console.war即是我们想要的war包。

我们需要修改jbpm-console.war/WEB-INF/classes/hibernate.cfg.xml 文件,以适应我们的资源属性的需要。修改后的结果如下:

Xml代码

1.<hibernate-configuration>

2.  <session-factory>

3.

4.    <!-- hibernate dialect -->

5.    <property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>

6.

7.    <!-- JDBC connection properties (begin) -->

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

9.    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/jbpm</property>

10.    <property name="hibernate.connection.username">jbossjbpm</property>

11.    <property name="hibernate.connection.password">jbossjbpm</property>

12.     <!-- JDBC connection properties (end) -->

13.

14.    <property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>

15.

16.    <!-- DataSource properties (begin) ==

17.    <property name="hibernate.connection.datasource">java:/JbpmDS</property>

18.    == DataSource properties (end) -->

19.    <property name="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>

20....

这里就是启用了更换了默认的数据属性,JDBC connection properties ,还有自己定义的数据名字和帐号,另外需要注意的是用

Xml代码

1.<property name="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>

代替JTATransactionFactory和CMTTransactionFactory,想用JTATransactionFactory或CMTTransactionFactory配置也可以,不过还没有研究过,有知道的朋友可以一起学习一下。

拷贝jboss-j2ee.jar包至jbpm-console.war/WEB-INF/lib 。发布包下(D:\jbpm-jpdl-3.2.2)很多地方都有这个包你可以找一下,比如 D:\jbpm-jpdl-3.2.2\server\client。

这里主要是用到了Java Transaction Architecture, 所以你可以用J2EE中的jta.jar包还替换jboss-j2ee.jar。jta相关信息请参考:http://java.sun.com/javaee/technologies/jta/index.jsp

拷贝commons-collections.jar 包至jbpm-console.war/WEB-INF/lib  。发布包下(D:\jbpm-jpdl-3.2.2)好几处都有这个包,比如 D:\jbpm-jpdl-3.2.2\server\server\jbpm\lib 。这个包是Apache Commons包,到处都找的的到。

拷贝jsf-api.jar和jsf-impl.jar包至jbpm-console.war/WEB-INF/lib ,你可以在D:\jbpm-jpdl-3.2.2\server\server\jbpm\deploy\jboss-web.deployer\jsf-libs种找到这两个包。

说明:因为jbpm-console是一个jsf应用,没这两个包,你访问时会报404或505错误。

拷贝MySQL JDBC驱动程序包至?TALINA_HOME%/lib(Tomcat 6)或?TALINA_HOME%/common/lib(Tomcat 5.5)

拷贝修改后的jbpm-console至?TALINA_HOME%/webapps

这样jBPM基本上配置完成,但是我们还不能访问他,还需要配置安全访问控制和初始的用户数据

5. 配置Tomcat 安全域

方法一:在?TALINA_HOME%/conf/Catalina/localhost 创建一个jbpm-console.xml 文件,内容如下:

Xml代码

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

<Context>

2.<Realm  className="org.apache.catalina.realm.JDBCRealm"

3.    driverName="com.mysql.jdbc.Driver"

4.    connectionURL="jdbc:mysql://localhost:3306/jbpm"

5.    connectionName="jbossjbpm"

6.    connectionPassword="jbossjbpm"

7.    userTable="JBPM_ID_USER u, JBPM_ID_MEMBERSHIP m, JBPM_ID_GROUP g"

8.    userNameCol="g.TYPE_ = 'security-role' AND m.GROUP_ = g.ID_ AND m.USER_ = u.ID_ AND u.NAME_"

9.    userCredCol="DISTINCT u.PASSWORD_"

10.    userRoleTable="JBPM_ID_USER u, JBPM_ID_MEMBERSHIP m, JBPM_ID_GROUP g"

11.    roleNameCol="g.NAME_" />

12.</Context>

方法二:修改 ?TALINA_HOME%/conf/tomcat-users.xml文件来设置安全域。为了不和tomcat已有的用户冲突,这里把 tomcat以前的登陆帐号username="admin" 修改为username="tadmin",修改后的文件如下:

Xml代码

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

2.

3.<tomcat-users>

4.

5.  <role rolename="user"/>

6.

7.  <role rolename="administrator"/>

8.

9.  <role rolename="manager"/>

10.

11.  <role rolename="sales"/>

12.

13.  <role rolename="hr"/>

14.

15.  <role rolename="admin"/>

16.

17.  <role rolename="participant"/>

18.

19.  <user username="user" password="user" roles="user,sales"/>

20.

21.  <user username="shipper" password="shipper" roles="user,hr"/>

22.

23.  <user username="manager" password="manager" roles="admin,hr,manager,user,sales"/>

24.

25.  <user username="tadmin" password="" roles="admin,manager"/>

26.  <user username="admin" password="admin" roles="admin,user,hr"/>

27.</tomcat-users>

6. 初始化数据

在MySQL jbpm数据库中插入以下数据

Sql代码

1.INSERT INTO JBPM_ID_GROUP VALUES(1,'G','sales','organisation',NULL);

2.

3.INSERT INTO JBPM_ID_GROUP VALUES(2,'G','admin','security-role',NULL);

4.

5.INSERT INTO JBPM_ID_GROUP VALUES(3,'G','user','security-role',NULL);

6.

7.INSERT INTO JBPM_ID_GROUP VALUES(4,'G','hr','organisation',NULL);

8.

9.INSERT INTO JBPM_ID_GROUP VALUES(5,'G','manager','security-role',NULL);

10.

11.INSERT INTO JBPM_ID_USER VALUES(1,'U','user','[email protected]','user');

12.

13.INSERT INTO JBPM_ID_USER VALUES(2,'U','manager','[email protected]','manager');

14.

15.INSERT INTO JBPM_ID_USER VALUES(3,'U','admin','[email protected]','admin');

16.

17.INSERT INTO JBPM_ID_USER VALUES(4,'U','shipper','[email protected]','shipper');

18.

19.INSERT INTO JBPM_ID_MEMBERSHIP VALUES(1,'M',NULL,NULL,2,4);

20.

21.INSERT INTO JBPM_ID_MEMBERSHIP VALUES(2,'M',NULL,NULL,3,4);

22.

23.INSERT INTO JBPM_ID_MEMBERSHIP VALUES(3,'M',NULL,NULL,4,4);

24.

25.INSERT INTO JBPM_ID_MEMBERSHIP VALUES(4,'M',NULL,NULL,4,3);

26.

27.INSERT INTO JBPM_ID_MEMBERSHIP VALUES(5,'M',NULL,NULL,1,3);

28.

29.INSERT INTO JBPM_ID_MEMBERSHIP VALUES(6,'M',NULL,NULL,2,3);

30.

31.INSERT INTO JBPM_ID_MEMBERSHIP VALUES(7,'M',NULL,NULL,3,3);

32.

33.INSERT INTO JBPM_ID_MEMBERSHIP VALUES(8,'M',NULL,NULL,3,2);

34.

35.INSERT INTO JBPM_ID_MEMBERSHIP VALUES(9,'M',NULL,NULL,2,2);

36.

37.INSERT INTO JBPM_ID_MEMBERSHIP VALUES(10,'M',NULL,NULL,2,5);

38.

39.INSERT INTO JBPM_ID_MEMBERSHIP VALUES(11,'M',NULL,'boss',2,1);

40.

41.INSERT INTO JBPM_ID_MEMBERSHIP VALUES(12,'M',NULL,NULL,1,1);

7. 启动Tomcat 服务,查看控制台的日志,排除错误,数据库错误和支持库不完整都可能导致错误。

在浏览器中输入:http://localhost:8080/jbpm-console  (注意这里的URL是你的tomcat的路径,依照具体的tomcat url输入) 能正常访问说明部署成功,你可以用页面上列出的用户和账号登陆进去体验一下。

8.打开网页:http://localhost:8080/jbpm-console 得到如下页面就说明已经部署成功:



 

用右边的manager账号登录,如下图:



点击“Deploy”转到部署流程页面,点击“浏览”按扭选择E:\Java\tools\jbpm-jpdl-3.2.2\examples\websale\target\websale.jpdl文件,名后点击“Deploy”按扭部署。

(二) 流程设计与部署

参考http://linliangyi2007.iteye.com/blog/176345

背景

本片文章,我们将从业务流程的设计开始,通过带领大家完成一个完整工作流的程序设计,来学习jPDL的使用。

业务流程设计

这里我们实现一个相对简化的公司借款申请流程。流程图如下:

 





 

在jPDL中,与流程设计相关的文件有三个:processdefinition.xml、gdp.xml、processimage.jpg。其中processdefinition.xml是流程定义的描述文件;gpd.xml是对图形界面呈现的XML描述;而processimage.jpg则是对图形界面的快照。下面我们将展示本样例的流程定义文件。

流程定义描述

processdefinition.xml文件

引用

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

<process-definition   xmlns ="urn:jbpm.org:jpdl-3.2"  name="simple">

<start-state name="开始">

<transition name="借款发起" to="填写借款申请">

<action name="Action_StartProcess" class="com.firstflow.action.StartProcessActionHandler"></action>

</transition>

</start-state>

<task-node name="填写借款申请">

<task name="Task_AssignToInitiator">

<assignment class="com.firstflow.task.NewApplicationAssignmentHandler"></assignment>

</task>

<transition to="部门经理审批" name="提交申请">

<action name="Action_SubmitApply" class="com.firstflow.action.SubmitApplyActionHandler"></action>

</transition>

</task-node>

<task-node name="部门经理审批">

<task name="Task_ManagerApprove">

<assignment class="com.firstflow.task.DepartmentManagerApproveAssignmentHandler"></assignment>

</task>

<transition to="金额判定" name="部门经理审批通过">

<action name="Task_ManagerApproved" class="com.firstflow.action.ManagerApprovedActionHandler"></action>

</transition>

<transition to="结束" name="部门经理驳回">

<action name="Action_ManagerDisapprove" class="com.firstflow.action.ManagerDisapproveActionHandler"></action>

</transition>

</task-node>

<node name="财务拨款">

<action name="Action_AccountantProcess" class="com.firstflow.action.AccountantProcessActoinHandler"></action>

<transition to="结束" name="邮件通知">

<action name="Action_Mail" class="com.firstflow.action.SendMailActionHandler"></action>

</transition>

</node>

<decision name="金额判定">

<handler class="com.firstflow.decision.MoneyCheckDecisionHandler"></handler>

<transition to="总经理审批" name="&gt;5000元总经理审批"></transition>

<transition to="财务拨款" name="&lt;5000元 财务拨款"></transition>

</decision>

<task-node name="总经理审批">

<task name="Task_PresidentApprove">

<assignment class="com.firstflow.task.PresidentApproveAssignmentHandler"></assignment>

</task>

<transition to="财务拨款" name="总经理审批通过">

<action name="Action_PresidentApproved" class="com.firstflow.action.PresidentApprovedActionHandler"></action>

</transition>

<transition to="结束" name="总经理驳回">

<action name="Action_PresidentDisapproved" class="com.firstflow.action.PresidentDisapprovedActionHandler"></action>

</transition>

</task-node>

<end-state name="结束"></end-state>

</process-definition>

在样例流程中,除了开始和结束结点外,我们定义了三种类型的结点:

任务结点<task-node>

任务结点是一个需要人工参与的结点类型。当流程进入结点时,会生成相应的任务实例(TaskInstatnce),并通过委派接口AssignmentHandler或jBPM表达式将任务委派给一个或多个特定的角色或参与者。结点自身进入等待状态,直到任务被参与者完成或者跳过,流程继续。

判定结点<decision>

判定结点的设计目标是根据上下文环境和程序逻辑,判定流程转向。通过指定一个实现DecisionHandler接口的Java委派类或jBPM表达式,来返回转向(transition)的字符窜类型的名称(可以是中文哦),来达到决定流程方向的功能。

普通结点<node>

普通结点也可以定义相应的处理任务,通过定义相应的ActioinHandler类。同任务结点不同的是,普通结点定义的任务是由流程自动执行的,无须人工干预。

三种结点都可定义结点事件(event):

node-enter,该事件在流程进入结点时触发

node-leave,该事件在流程离开节点是触发

可以在事件上挂接ActioinHandler接口的实现类来完成一些特定的功能。

三种节点都可以定义异步处理方式(async属性):

异步处理意味着每个结点的事务处理是通过消息机制分离的,不再同一线程中统一调用执行。而是由消息监听线程从消息队列中取得消息体来运行相应得程序。

此外我们定义了结点间的转向(transition),用来记录和处理状态的变迁。每个转向中,可以委派一个或多个的ActioinHandler接口实现类,负责处理节点变迁时的上下文状态变更及回调用户定义的处理程序。

流程的程序接口说明

动作处理接口(ActioinHandler)

接口方法:void execute( ExecutionContext executionContext ) throws Exception

该接口是jPDL中最常用的一个回调接口。从它的接口方法可以发现,它仅仅暴露了流程执行上下文变量ExecutionContext。用户程序通过ExecutionContext来了解流程的执行状态,并通过改变ExecutionContext中的属性值来影响流程的执行。

ActioinHandler接口可以在所有能包含事件(event)、动作(action)元素的地方被回调。

判定处理接口(DecisionHandlder)

接口方法:String decide(ExecutionContext executionContext) throws Exception

判定接口仅适用于判定节点(decision)中。从它的接口方法可以看出,方法要返回一个字符串型的结果,这个结果必须和判定节点拥有的转向(transition)集合中的一条转向名称相匹配。

在DecisionHandlder的接口方法中一样能访问到ExecutionContext变量,这为判定提供了执行上下文的根据。当然,如果有必要,用户也可以在该接口中改变ExecutionContext中的变量值。

委派处理接口(AssignmentHandler)

接口方法:void assign(Assignable assignable, ExecutionContext executionContext) throws Exception;

委派处理接口被用户任务元素(task)的委派(assignment)子元素中,它的职责很明确,就是将任务分配给指定的人员或角色。

在AssignmentHandler接口的方法中,Assignable变量通常指任务实例(TaskInstance)。通过将ExecutionContext和TaskInstance两个变量都暴露给接口方法,用户就可以根据流程上下文情况,来决定要将指定的任务分配个谁。

流程的部署

用户使用jPDL的流程设计器定义业务流程,当然,你也可以直接用文档编辑器直接编辑processdefinition.xml定义文件。定义文档是可以直接被ProcessDefinition类载入使用的,但在正式运行的系统中,流程定义信息更多是使用关系型数据库来存储。从流程定义文件将数据导入流程数据库的过程,我们称之为流程部署。

jPDL的流程部署文件包含processdefinition.xml的定义部分和Java处理器的代码部分,这些文件可以被一起打包成.jpdl的zip格式包而后上传服务器端。这个过程可以在流程设计器界面的“deployment”标签页中操作:




这里我们着重要讲述的是接受部署文件上载的服务器端配置。在jBPM3.2的包中带着一个jPDL的管理控制台web应用,默认名字为jbpm-console。该应用带有接受流程定义包部署的程序,但不是最小化的。实际上完成流程部署功能的,只是jbpm-jpdl.jar核心包中的一个servlet类:org.jbpm.web.ProcessUploadServlet . 完成这个Servlet的成功部署,需要以下工作:

1. 配置web.xml,将servlet配置成启动时加载,如下:

引用

<web-app>

<servlet>

<servlet-name>GDP Deployer Servlet</servlet-name>

<servlet-class>org.jbpm.web.ProcessUploadServlet</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>GDP Deployer Servlet</servlet-name>

<url-pattern>/upload

protected void deployProcessDefinition() throws Exception{

System.out.println("==FirstFlowProcessTest.deployProcessDefinition()==");

pdf = ProcessDefinition.parseXmlResource("firstflow/processdefinition.xml");

assertNotNull("Definition should not be null", pdf);

}

 

protected void createProcessInstance(String user){

System.out.println("==FirstFlowProcessTest.createProcessInstance()==");

assertNotNull("Definition should not be null", pdf);

//生成实例

pi = pdf.createProcessInstance();

assertNotNull("processInstance should not be null", pi);

//设置流程发起人

pi.getContextInstance().createVariable("initiator", user);

//触发流程转向

pi.signal();

}

 

protected void submitApplication(int money){

System.out.println("==FirstFlowProcessTest.submitApplication()==");

TaskInstance ti = (TaskInstance)pi.getTaskMgmtInstance().getTaskInstances().iterator() .next() ;

System.out.println("ti.actor = " + ti.getActorId());

ContextInstance ci = ti.getContextInstance();

ci.setVariable("money",new Integer(money));

ti.end();

}

 

@SuppressWarnings("unchecked")

protected void approveByManager(boolean pass){

System.out.println("==FirstFlowProcessTest.approveByManager()==");

Iterator<TaskInstance> it = pi.getTaskMgmtInstance().getTaskInstances().iterator();

for( ;it.hasNext(); ){

TaskInstance ti = it.next();

if(ti.getActorId().equals("DepartmentManager")){

List<Transition> transitions = ti.getToken().getNode().getLeavingTransitions();

for(Transition t : transitions){

System.out.println("----Transition" + t.getName());

}

assertEquals("DepartmentManager",ti.getActorId());

if(pass){

ti.end("部门经理审批通过");

}else{

ti.end("部门经理驳回");

}

return;

}

}

}

 

 

@SuppressWarnings("unchecked")

protected void approveByPresident(boolean pass){

System.out.println("==FirstFlowProcessTest.approveByPresident()==");

 

Iterator<TaskInstance> it = pi.getTaskMgmtInstance().getTaskInstances().iterator();

 

for( ;it.hasNext(); ){

 

TaskInstance ti = it.next();

 

if(ti.getActorId().equals("President")){

List<Transition> transitions = ti.getToken().getNode().getLeavingTransitions();

for(Transition t : transitions){

System.out.println("----Transition" + t.getName());

}

assertEquals("President",ti.getActorId());

if(pass){

ti.end("总经理审批通过");

}else{

ti.end("总经理驳回");

}

return;

}

}

}

 

@SuppressWarnings("unchecked")

protected void checkTasks(){

System.out.println("==FirstFlowProcessTest.checkTasks()==");

Collection<TaskInstance> coll = pi.getTaskMgmtInstance().getTaskInstances();

System.out.println("====Process has task:====");

for(TaskInstance ti : coll){

System.out.println("=="+ti.getName()+"==");

System.out.println("=="+ti.getActorId()+"==");

System.out.println("=="+ti.getVariables().toString() +"==");

}

System.out.println("====end====");

}

 

 

该案例是在没有数据库支持的情况下,对报销流程进行运行测试,测试逻辑如下:

 

1. 加载流程定义

Java代码

ProcessDefinition.parseXmlResource("firstflow/processdefinition.xml")

代码说明:

在没有数据库存储的情况下,流程定义通过ProcessDefinition类直接从processdefinition.xml文件中解析加载。

 

2. 实例化流程对象

Java代码

//生成实例

pi = pdf.createProcessInstance();

assertNotNull("processInstance should not be null", pi);

//设置流程发起人

pi.getContextInstance().createVariable("initiator", user);

//触发流程转向

pi.signal();

代码说明:

在获得流程定义的实例后,可以用它生成流程实例,使用如下的语句:

pi = pdf.createProcessInstance();

流程实例拥有自己的ContextInstance环境变量对象。它实际上是一个HashMap,以key-value方式记录了流程的上下文变量值,代码中的

pi.getContextInstance().createVariable("initiator", user);就是向环境变量中添加一个key为initiator的对象。

每个流程实例都拥有自己Token令牌对象,主流程有自己的RootToken,子流程也拥有自己的子Token。父流程的Token和子流程的Token相互关联,形成Token树。

Token对象表示流程运行的当前位置(运行到哪个节点了)。通过对Token对象的signal()方法调用,可以使流程向下运行。代码中的pi.signal();实际上是间接调用了pi.getRootToken().signal();它使得新建的流程继续向下个节点(即借款申请单填写)进发。

 

3. 员工发起借款申请

Java代码

 

protected void submitApplication(int money){

System.out.println("==FirstFlowProcessTest.submitApplication()==");

 

TaskInstance ti = (TaskInstance)pi.getTaskMgmtInstance().getTaskInstances().iterator() .next()

System.out.println("ti.actor = " + ti.getActorId());

ContextInstance ci = ti.getContextInstance();

ci.setVariable("money",new Integer(money));

ti.end();

代码说明:

在借款流程发起后,流程进入了申请单填写阶段。这个阶段是个人工的任务,需要用户的介入。因此,对于要借款的用户而言,首先是获取填写申请单的任务实例:

TaskInstance ti = (TaskInstance)pi.getTaskMgmtInstance().getTaskInstances().iterator() .next()

在这个测试类中,由于没有数据库。对流程实例的引用是依靠了类的全局标量pi。这里通过pi获取全部的任务列表。实际上有且仅有一个任务,就是我们刚刚发起的申请单填写任务。

接下来,我们获取流程的上下文变量,将申请借款的数额记录在上下文变量中ContextInstance ci = ti.getContextInstance();

ci.setVariable("money",new Integer(money));

最后,我们要结束当前任务,告诉流程继续下行,调用ti.end();这个方法的本质依然是调用了token.signal(),它选择了一个默认的transition进行转向。这里要说明的是signal方法有多态的实现signal(Transition  transition),是可以指定具体转向参数的。

 

4. 部门领导审批申请

Java代码

 

@SuppressWarnings("unchecked")

protected void approveByManager(boolean pass){

System.out.println("==FirstFlowProcessTest.approveByManager()==");

Iterator<TaskInstance> it = pi.getTaskMgmtInstance().getTaskInstances().iterator();

for( ;it.hasNext(); ){

TaskInstance ti = it.next();

if(ti.getActorId().equals("DepartmentManager")){

List<Transition> transitions = ti.getToken().getNode().getLeavingTransitions();

for(Transition t : transitions){

System.out.println("----Transition" + t.getName());

}

assertEquals("DepartmentManager",ti.getActorId());

if(pass){

ti.end("部门经理审批通过");

}else{

ti.end("部门经理驳回");

}

return;

}

}

}

代码说明:

这里,流程进入了部门经理审批阶段。由于没有数据库支持,我们只能采取遍历任务列表,并比对委派者ID的方式来确定委派给部门经理的任务实例。(在后面的基于数据库的标准案例中,我们会看到如果根据用户的ID来获取分配给指定用户的任务)

ti.getActorId().equals("DepartmentManager") // 比对任务的委派人。

ti.getToken().getNode().getLeavingTransitions();//获取任务在当前节点上的所有转向。

这里我们要特别指出的是ti.end("部门经理审批通过")和ti.end("部门经理驳回")这实际上调用token.signal(transition);来完成任务的转向,从而使流程继续。

 

5. 总经理审批申请

Java代码

 

@SuppressWarnings("unchecked")

protected void approveByPresident(boolean pass){

System.out.println("==FirstFlowProcessTest.approveByPresident()==");

Iterator<TaskInstance> it = pi.getTaskMgmtInstance().getTaskInstances().iterator();

 

for( ;it.hasNext(); ){

TaskInstance ti = it.next();

if(ti.getActorId().equals("President")){

List<Transition> transitions = ti.getToken().getNode().getLeavingTransitions();

for(Transition t : transitions){

System.out.println("----Transition" + t.getName());

}

assertEquals("President",ti.getActorId());

if(pass){

ti.end("总经理审批通过");

}else{

ti.end("总经理驳回");

}

return;

}

}

}

代码说明:

此步代码同“部门经理审批”代码相似,不作更多说明。

 

标准流程测试案例

 

该案例模拟了标准运行环境中,基于关系型数据库的jBPM系统是如何执行流程的。

测试案例类:FirstFlowProcessDBTest.java

Java代码

public class FirstFlowProcessDBTest {

 

static JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();

public static void main(String[] args){

FirstFlowProcessDBTest test = new FirstFlowProcessDBTest();

test.test4000YuanApplication();

test.test6000YuanApplication();

test.test7000YuanApplication();

}

 

public void test4000YuanApplication(){

ProcessInstance pi = createProcessInstance("linly");

submitApplication("linly" , 4000);

approveByManager(true);

checkTasks(pi);

}

public void test6000YuanApplication() {

ProcessInstance pi = createProcessInstance("linly");

submitApplication("linly" , 6000);

approveByManager(true);

approveByPresident(true);

checkTasks(pi);

}

public void test7000YuanApplication() {

ProcessInstance pi = createProcessInstance("linly");

submitApplication("linly" , 7000);

approveByManager(true);

approveByPresident(false);

checkTasks(pi);

}

 

protected ProcessInstance createProcessInstance(String user){

System.out.println("==FirstFlowProcessTest.createProcessInstance()==");

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();

try {

GraphSession graphSession = jbpmContext.getGraphSession();

 

ProcessDefinition pdf  = graphSession.findLatestProcessDefinition("simple");

//生成流程实例

ProcessInstance pi = pdf.createProcessInstance();

//设置流程发起人

pi.getContextInstance().createVariable("initiator", user);

//触发流程转向

pi.signal();

 

jbpmContext.save(pi);

return pi;

}finally{

jbpmContext.close();

}

}

 

 

@SuppressWarnings("unchecked")

protected void submitApplication(String actorId , int money){

System.out.println("==FirstFlowProcessTest.submitApplication()==");

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();

try {

 

List<TaskInstance> taskInstances = jbpmContext.getTaskList(actorId);

for(TaskInstance ti : taskInstances){

System.out.println("ti.name = " + ti.getName());

System.out.println("ti.actor = " + ti.getActorId());

ContextInstance ci = ti.getContextInstance();

ci.setVariable("money",new Integer(money));

ti.end();

}

}finally{

jbpmContext.close();

}

}

 

 

@SuppressWarnings("unchecked")

protected void approveByManager(boolean pass){

System.out.println("==FirstFlowProcessTest.approveByManager()==");

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();

try{

List<TaskInstance> taskInstances = jbpmContext.getTaskList("DepartmentManager");

for(TaskInstance ti : taskInstances){

System.out.println("ti.name = " + ti.getName());

System.out.println("ti.actor = " + ti.getActorId());

if(pass){

ti.end("部门经理审批通过");

}else{

ti.end("部门经理驳回");

}

}

}finally{

jbpmContext.close();

}

}

 

 

@SuppressWarnings("unchecked")

protected void approveByPresident(boolean pass){

System.out.println("==FirstFlowProcessTest.approveByPresident()==");

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();

try{

List<TaskInstance> taskInstances = jbpmContext.getTaskList("President");

for(TaskInstance ti : taskInstances){

System.out.println("ti.name = " + ti.getName());

System.out.println("ti.actor = " + ti.getActorId());

if(pass){

ti.end("总经理审批通过");

}else{

ti.end("总经理驳回");

}

}

}finally{

jbpmContext.close();

}

}

 

 

@SuppressWarnings("unchecked")

protected void checkTasks(ProcessInstance pi){

System.out.println("==FirstFlowProcessTest.checkTasks()==");

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();

try{

List<TaskInstance> coll = jbpmContext.getTaskMgmtSession().findTaskInstancesByProcessInstance(pi);

System.out.println("====Process has task:====");

for(TaskInstance ti : coll){

System.out.println("=="+ti.getName()+"==");

System.out.println("=="+ti.getActorId()+"==");

System.out.println("=="+ti.getVariables().toString() +"==");

}

System.out.println("====end====");

}finally{

jbpmContext.close();

}

}

}

 

相对于简单流程测试案例,标准流程的业务是相同的。它们的不同点在于:简单流程通过XML载入流程定义,并使用类的全局变量来保存流程实例的引用;而标准流程则是通过数据库载入流程定义,并使用数据库的会话来维护流程的运行。

 

1. 从数据库载入流程定义

Java代码

?   JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();

从jBPM配置环境中获取jBPM上下文实例,jbpmContext是对jbpm持久层操作API及上下文环境的封装,它根据jBPM的配置文件生成。

?

Java代码

GraphSession graphSession = jbpmContext.getGraphSession();

生成对流程图操作的持久层会话

?

Java代码

ProcessDefinition pdf  = graphSession.findLatestProcessDefinition("simple");

从数据库获取命名为“simple”的流程定义。

 

2. 新建流程实例,并存入数据库持久化

?

Java代码

ProcessInstance pi = pdf.createProcessInstance();

根据流程定义生成实例。

?

Java代码

pi.getContextInstance().createVariable("initiator", user);

pi.signal();

 

设置实例的上下文变量,激活实例执行进程。

?

Java代码

jbpmContext.save(pi);

 

保存实例到数据库,持久化实例。

 

3. 从数据库获取属于指定操作者的任务集

Java代码

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();

try{

List<TaskInstance> taskInstances = jbpmContext.getTaskList("DepartmentManager");

for(TaskInstance ti : taskInstances){

System.out.println("ti.name = " + ti.getName());

System.out.println("ti.actor = " + ti.getActorId());

if(pass){

ti.end("部门经理审批通过");

}else{

ti.end("部门经理驳回");

}

}

}finally{

jbpmContext.close();

}

通过JbpmContext对象,从数据库获取指定操作者的任务集合:

Java代码

List<TaskInstance> taskInstances = jbpmContext.getTaskList("DepartmentManager");

注意,在每次的JbpmContext对象使用完毕后,一定要执行jbpmContext.close(),其本质是要释放数据库的操作连接。





http://blog.163.com/magicc_love/blog/static/185853662201205260843/

猜你喜欢

转载自lixg425.iteye.com/blog/1925211