微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

jbpm 入门实例4—— JBPM简单实例入门

1、新建项目

   菜单文件->新建->项目”,在弹出的对话框里,选中JBoss jbpm节点下的“ Process Project ”项。输入项目名:JbpmProject,项目建好后结构如图所示:

       

     

    这个项目和通常 Eclipse 的项目结构有点不同,不过  这是一个现在非常流行的项目结构, src/java 存放源文件 test/java 存放相应的 JUnit 单元测试代码

下面介绍一下各个文件

l         MessageActionHandler 自动生成一个 ActionHandler 。不想要可以删掉。

l         ehcache.xml  cache 配置文件,里面有很详解的英文说明。没有必要可以不用改它。

l         hibernate.cfg.xml   jBPM 是用 Hibernate 进行工作流的数据存储的,这个就是 Hibernate 配置文件。后面我们将讲到如何配置这个文件

l         jbpm.cfg.xml   jbpm 本身的配置文件。现在是空的,它用的是缺省配置,你想知道有哪些配置就去看这个文件E:/software/jbpm-starters-kit-3.1.2/jbpm/src/java.jbpm/org/jbpm/default.jbpm.cfg.xml

l         log4j.properties  这个是日志 API log4j 配置文件,用过 log4j 的都知道。

l         SimpleProcesstest.java  这个是对最重要的流程配置文件 processdeFinition.xml 单元测试代码。这里表扬一点, jBPM 的优良设计使得它的可测试性非常之高,喜欢写 t 单元测试的人有福了。

l         gpd.xml  用于生成流程图的定义文件。都是一些方框的坐标和长宽

l         processdeFinition.xml  这个是对最重要的流程配置文件,以后写流程要经常和它打交道。

l         processimage.jpg  一个流程图

2修改hibernate.cfg.cml配置文件

hibernate.cfg.xml 认设置是用 Hsql ,这是一个内存数据库,这种内存数据库用来代替项目实际所用的数据库来做单元测试挺不错的。

注:配置值可参考jbpm-starters-kit-3.1.2/jbpm-db 对应子目录下的 hibernate.properties 文件

一、网上朋友给我MysqLoracle的配置如下:

1 MysqL 的更改如下:

<property name="hibernate.dialect">org.hibernate.dialect.MysqLDialect</property>

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

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

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

<property name="hibernate.connection.password">123456</property>

 

2 Oracle 的更改如下:

<property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>

<property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>

<property name="hibernate.connection.url">jdbc:oracle:thin:@192.168.123.10:1521:wxxrDB</property>

<property name="hibernate.connection.username">chengang</property>

<property name="hibernate.connection.password">chengang</property>

 

如果你装了 Oracle 的客户端,并且 D:/oracle/ora92/network/ADMIN/tnsnames.ora 里做了如下的设置

WXXRDB_192.168.123.10 =

  (DESCRIPTION =

    (ADDRESS_LIST =

      (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.123.10)(PORT = 1521))

    )

    (CONNECT_DATA =

      (SID = wxxrDB)

      (SERVER = DEDICATED)

  )

Oracle hibernate.connection.url 项也可以设为: jdbc:oracle:oci:@WXXRDB_192.168.123.10

二、我的配置修改

 1sqlserver

<!-- hibernate dialect -->

    <property name="hibernate.dialect">org.hibernate.dialect.sqlServerDialect</property>

 

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

    <"hibernate.connection.driver_class">net.sourceforge.jtds.jdbc.Driver</property>

    <"hibernate.connection.url">jdbc:jtds:sqlserver://localhost:1433/jbpm</"hibernate.connection.username">sa</"hibernate.connection.password">admin</property>

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

3、完善库引用

主要是把你所用的数据库 JDBC 库引用进来,如果你是下载的jbpm-starters-kit-3.1.2可能还要 Hibernate hibernate3.jar 加入到项目的库引用中。

4、开始流程

这里是一个很简单的请假流程,请假人提交假单给经理审批,经理审批后结束。

1 、定义流程

流程的定义文件 processdeFinition.xml ,这个是一个关键文件 jBPM 的很大一部份内容都是关于它的。在这里我们把原来自动生成内容,稍做改动:

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

 

<process-deFinition

  xmlns="urn:jbpm.org:jpdl-3.2"

  name="helloworld">

  <!-- 申请 -->

   <start-state "request">

     <task>

          <controller>

                <variable "name"/>

                <"day"/>

                <"note"/>

          </controller>

     </task>

     流程转向 -->

      <transition "to_confirm" to="confirm">

         <action "requestAction" class="com.stt.jbpm.RequestAction">

            <reason>我要请假</reason>

         </action>

      </transition>

   </start-state>

   审批state "confirm">

      <"to_end" "end">

         <"finishAction" "com.stt.jbpm.ConfirmAction"/>

      </state>

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

</process-deFinition>

说明:

流程的名称改成了 helloworld 。(呵呵,也就是这里和 helloworld 有关了)

<controller> 标签定义了三个数据:姓名、请假天数、说明。

<transition> 标签定了 request 节点的一个流程转向,这里是转到 confirm 节点。

<action> 标签定义了流程由一个节点转到另一个节点时,所要执行的动作,动作封装在一个 ActionHandler 类中。比如这里当 request confirm 结点时将执行 RequestAction 类的 execute 方法

RequestAction下面还有一个 <reason> (请假理由),它对应于RequestAction 属性 String reason

5、编写 ActionHandler

    在上面 processdeFinition.xml 里我们定义了两个 ActionHandler RequestAction ConfirmAction 。其代码如下:

package com.stt.jbpm;

 

import org.jbpm.graph.def.ActionHandler;

import org.jbpm.graph.exe.ExecutionContext;

 

public class RequestAction implements ActionHandler {

    private static final long serialVersionUID = 1L;

   

    private String reason;

   

    @Override

    void execute(ExecutionContext context) throws Exception {

       context.getContextInstance().setvariable("note",reason);

    }

 

    public String getReason() {

       return reason;

    }

 

    void setReason(String reason) {

       this.reason = reason;

    }

 

}

说明: ExecutionContext 一个贯通流程的容器。它是个大宝箱,里面啥玩意都有,后面将更深入的提到。这里的 reasion 就是 processdeFinition.xml 中的我要请假

class ConfirmAction serialVersionUID = 1L;

   

    "准假");

    }

 

}

6、部署processdeFinition.xml

我们要把 processdeFinition.xml 的流程定义的数据部署到数据库中,因为 jBPM 在正式运行的时候不是去读 processdeFinition.xml 文件,而是去读数据库中的流程定义。    这里写了一个 JUnit 程序来部署 processdeFinition.xml ,当然你用普通的 Java Main 也可以。

import junit.framework.TestCase;

 

import org.jbpm.JbpmConfiguration;

import org.jbpm.JbpmContext;

import org.jbpm.graph.def.ProcessDeFinition;

 

/**

 * 流程部署

 * @author USER

 *

 */

class DeployProcesstest extends TestCase {

 

    /**

     方法执行完毕后,检查jbpm_processdeFinition表会多了一条记录

     @throws Exception

     */

    void testDeployProcess() throws Exception {

        //jbpm.cfg.xml取得jbpm的配置

       JbpmConfiguration config = JbpmConfiguration.getInstance();

       创建一个容器

       JbpmContext jbpmContext = config.createJbpmContext();

       processdiFinition.xml生成相对应的流程定义类ProcessDeFinition

       ProcessDeFinition processDeFinition = ProcessDeFinition.parseXmlResource("simple/processdeFinition.xml");

       

       利用容器的方法将流程定义数据部署到数据库

       jbpmContext.deployProcessDeFinition(processDeFinition);

       关闭jbpmContext

       jbpmContext.close();

    }

}

运行此程序,在控制台打印了一些日志,通过。如果出错,仔佃阅读出错信息以判断错误原因,并确定你按照前面两节:“修改 hibernate.cfg.xml ”和“完善库引用”的内容做好了设置。

报错:

14:44:50,921 [main] INFO  JpdlxmlReader : process xml @R_672_4045@ion: no swimlane or assignment specified for task '

<task xmlns="urn:jbpm.org:jpdl-3.2" blocking="false" signalling="true" priority="normal" notify="false">

          <!-- controller管理task变量 -->

          <controller config-type="field">

                <variable name="name" access="read,write"/>

                <variable name="day" access="read,write"/>

                <variable name="note" access="read,write"/>

          </controller>

     </task>'

14:44:55,765 [main] ERROR JDBCExceptionReporter : Table not found in statement [select top ? processdef0_.ID_ as ID1_0_,processdef0_.NAME_ as NAME3_0_,processdef0_.DESCRIPTION_ as DESCRIPT4_0_,processdef0_.VERSION_ as VERSION5_0_,processdef0_.ISTERMINATIONIMPLICIT_ as ISTERMIN6_0_,processdef0_.STARTSTATE_ as STARTSTATE7_0_ from JBPM_PROCESSDEFinitioN processdef0_ where processdef0_.NAME_=? order by processdef0_.VERSION_ desc]

14:44:55,765 [main] ERROR GraphSession : org.hibernate.exception.sqlGrammarException: Could not execute query

咋回事呢?查看hibernate.cfg.xml配置,原来中午修改的配置忘了保存。重新修改,再此运行,OK搞定。

到底成功了没呢?

7、从数据库中的查看部署效果

查询以下各表:

jbpm_processdeFinition

一个流程定义文件对应一条记录,可记录多个流程定义文件,可记录一个流程定义文件的对个版本。

jbpm_action

记录 ActionHandler 的对象实例(以名称为标识)

jbpm_delegation

记录了 ActionHandler 全类名,以便于用反射方式来加载

jbpm_envent

它的 transition 引用了 Jbpm_transition 表的 id ,再看其它字段,估计此表是表示流程转向事件的一个实例,或者是一个各表之间的联接表。

jbpm_node

流程结点

jbpm_transition

流程的转向定义

jbpm_variableaccess

流程中携带的变量。 ACCESS 字段是这些变量的读写权限

例如:查询 jbpm_processdeFinition 表,你会发现多了一条记录,查询结果如下:

字段名                      字段值

ID_                            1

CLASS_                         p

NAME_                          helloworld

DESCRIPTION_                   NULL 

VERSION_                       1 

ISTERMINATIONIMPLICIT_         0  

STARTSTATE_                    1                                                                 

表中各字段的作用由字段名也能知晓一二。其他表的查询下面寄不再一一列出。

select * from jbpm_processdeFinition

select * from jbpm_action

select * from jbpm_delegation

select * from jbpm_event

select * from jbpm_node

select * from jbpm_transition

select * from jbpm_variableaccess

可以看到数据库中文“我要请假”全部为“???”,这中文乱码该如何解决呢?下面我贴一下网上其他朋友的经验:

l         JBPMMysqL 4.0以下运行有问题,主要是select语句的问题。

l         JBPM 数据库认的字符段是255个字符,有时需要修改,比如存储文件的时候。JBPM数据库认的字段类型的定义有时候不一定适合需要,要手工进行修改

l         对于工作流定义文件-processdiFinition.xml中文问题解决方案如下:

1)       processdeFinition.xmlEncoding设定成”GBK“

@H_699_3502@<?xml version="1.0" encoding="GBK"@H_699_3502@?>

2)       对于MysqLhibernate相应的hibernate.connection.url设定成:jdbc:MysqL://localhost/test?useUnicode=true&characterEncoding=GBK

对于sqlserver设定为:

<property "hibernate.connection.url">jdbc:jtds:sqlserver://localhost:1433;SelectMethod=cursor;characterEncoding=GBK;DatabaseName=jbpm</property>

对于Oracle来讲,Hibernate使用的C3P0连接池有问题,可用最新的C3P0代替。

3)       文字显示的时候要用toGBK转换才能正确显示

        如果XML定义文件采用UTF8定义,显示时可不用做GBK转换。

*

 sqlSERVER 2005 中文乱码问题:

本人用的是sqlserver 2005,当保存到数据库中后,表中全部为乱码。按照上面的方法还是无法解决Hibernate配置文件里里关于解决乱码问题所采用的统一编码方式也尝试过,数据库里依然是“???”,究竟是哪里出了问题?

我想是不是数据库根本就无法保存中文,在数据库乱码字段中的值修改中文,输完后发现马上变成了“???”,嘿,还真是数据库本身出了问题。

由于在安装sqlserver 2005时帮助那些安装失败,所以只好查看机子上原来安装的sqlserver 2000中的帮助,输入“汉字”里面有一篇:使用 Unicode 数据

Unicode 规格通过采用两个字节编码每个字符使这个问题迎刃而解。转换最通用商业语言的单一规格具有足够多的 2 字节的模式 (65,536)。因为所有的 Unicode 系统均一致地采用同样的位模式来代表所有的字符,所以当从一个系统转到另一个系统时,将不会存在未正确转换字符的问题。通过在整个系统中使用 Unicode 数据类型,可尽量减少字符转换问题。

Microsoft sql Server 中,以下数据类型支持 Unicode 数据:

nchar   nvarchar  ntext

把乱码对应字段类型varchar(4000)改为nvarchar(4000)

再次在乱码字段输入中文,输完后发现正常,“???”没再回来。^_^

趁热打铁,运行程序,o(_)o…哈哈 ,ok!一切正常!

把原来的建表语句中的varchar全改为nvarchar,重新建。

8、开发客户端测试

本文不写 JSP ,而改采用 JUnit 的形式,输出则用 System.out.printlnimport org.jbpm.context.exe.ContextInstance;

import org.jbpm.graph.def.ProcessDeFinition;

import org.jbpm.graph.exe.ProcessInstance;

 

class ClientProcesstest extends TestCase {

    private JbpmConfiguration config = JbpmConfiguration.getInstance();

    private JbpmContext ctx = config.createJbpmContext();

    //helloworld对应于jbpm_processdeFinition表的name字段,也即processdeFinition.xmlname

    这个值得取比较耗时,实际项目里最好和"数据库JDBC连接一样,让它共享,不要频繁打开关闭

    private ProcessDeFinition processDeFinition = ctx.getGraphSession().findLatestProcessDeFinition("helloworld");

   

   

    测试方法入口

     void testNewRequest(){

       long id = newRequest();

       System.out.println("id="+id);

       checkNewRequest(id);

       confirmRequest(id);

       checkconfirmRequest(id);

       ctx.close();   容器

    }

 

    创建一个请假单

     @return  本次请假流程ID

     long newRequest() {

       创建一个新流程

       ProcessInstance pi = processDeFinition.createProcessInstance();

       取得流程的数据环境

       ContextInstance ci = pi.getContextInstance();

       创建一张请假单

       ci.setvariable("name",255); font-family: 宋体;">婷婷");

       ci.setvariable("day",2);

       请假申请结束,转到下一个流程节点

       pi.signal();

       return pi.getId();

    }

 

     

    检测请假单的数据

     @param id

     void checkNewRequest(long id) {

       数据库提取数据源

       ProcessInstance pi = ctx.loadProcessInstance(id);

       取得流程的数据环境

       ContextInstance ci = pi.getContextInstance();

       创建一张请假单

       assertEquals(",ci.getvariable("name"));

       assertEquals(Integer.valueOf(2),255); font-family: 'Courier New';" lang="EN-US">"day"));

       assertEquals(我要请假"note"));

      

       当前是结点为confirm

       assertEquals(pi.getRoottoken().getNode().getName(),255); font-family: 'Courier New';" lang="EN-US">"confirm");

       流程还未结束

       assertFalse(pi.hasEnded());

    }

 

    *  审批请假申请

     id

     void confirmRequest(取得流程的数据环境

       ContextInstance ci = pi.getContextInstance();

      

       假如,审批不通过

       ci.setvariable(不准请假");

       审批结束,到下一个流程结点

       pi.signal();

    }

 

    申请者取得最后审批结果

     void checkconfirmRequest(//ConfirmAction类在signal后执行,所以覆盖了经理的审批意见(注意这就是为何在此不会报错的原因)

       assertEquals(tvariable("note"));

       流程结束了

       assertTrue(pi.hasEnded());

    }

}

查看表JBPM_VARIABLEINSTANCE中将有三条记录分别是name的值为“婷婷”,day2note的值为“准假”。

JBPM_PROCESSINSTANCE添加了一条记录可知道该流程的开始日期(START_字段指定)和结束日期(END_字段指定)

这个简单的入门实例就到此结束。后面将开始一点点进入与业务相关的流程学习开发。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐