- 浏览: 1015110 次
- 性别:
- 来自: 福州
最新评论
-
guanxin2012:
大神,您好。非常感谢您贡献了IKExpression。我们现在 ...
分享开源表达式解析器IK-Expression2.0 -
qqgigas:
LZ,public boolean createUser(LD ...
Sun Directory Server/LDAP学习笔记(二)——API说明及代码样例 -
gao_shengxian:
Hibernate: update T_GX_TEST set ...
优雅Java编程 之 使用Hibernate存储Oracle Spatial对象 -
a78113534:
感谢大神,在安卓里面调用成功了。
发布IK Expression开源表达式解析器 V2.1.0 -
majiedota:
加油
来自开源支持者的第一笔捐赠
相关资料:
《jBPM学习笔记(V3.2环境部署)》
《jBPM学习笔记(框架设计简介)》
背景
本片文章,我们将从业务流程的设计开始,通过带领大家完成一个完整工作流的程序设计,来学习jPDL的使用。
业务流程设计
这里我们实现一个相对简化的公司借款申请流程。流程图如下:
在jPDL中,与流程设计相关的文件有三个:processdefinition.xml、gdp.xml、processimage.jpg。其中processdefinition.xml是流程定义的描述文件;gpd.xml是对图形界面呈现的XML描述;而processimage.jpg则是对图形界面的快照。下面我们将展示本样例的流程定义文件。
流程定义描述
<?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.StartProcessActionHander"></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=">5000元总经理审批"></transition>
<transition to="财务拨款" name="<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>
判定结点的设计目标是根据上下文环境和程序逻辑,判定流程转向。通过指定一个实现DecisionHandlder接口的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/*</url-pattern>
</servlet-mapping>
</web-app>
2. 建立流程定义存储数据库表:
Demo中,我们使用的数据库是MySQL的,在E:\Java\tools\jbpm-jpdl-3.2.2\db\目录下有个jbpm.jpdl.mysql.sql数据库脚本文件。但我们不能直接导入该文件, 会提示有错误, 应为该文件的SQL语句末尾少了分号,在批量执行时,MySQL报错。需要在每一行SQL的末尾添加一个分号,这样就可以用source命令导入了。
3. 配置Hibernate.cfg.xml
由于jBPM的数据库持久化是依靠Hibernate进行的,因此需要配置Hibernate.cfg.xml使其适应我们的MySQL环境
<!-- hibernate dialect -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/linly</property>
<property name="hibernate.connection.username">linly</property>
<property name="hibernate.connection.password">coffee</property>
<property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
4. Import需要的jar包
这里的jar包包括三部分:jbpm的核心包;Hibernate及其支撑包;MySQL的JDBC驱动包。
到此,我们的配置工作完成,这是实现jBPM流程部署服务端的最小化应用配置。
流程控制及API使用
样例程序中的Handler接口实现
下面,根据上述的接口分类,列出样例程序中的类名及相应的功能说明,具体可参考源代码。
动作处理接口(ActioinHandler)
这里要提到一个很重要的区别,就是作用于Node上的ActoinHandler和作用于Transition上的ActoinHandler是有不同的。区别在于,Node上的ActoinHandler在结束业务逻辑处理后,必须调用executionContext.leaveNode();或executionContext.leaveNode(transition)来保证流程向下执行;而作用于Transition上的则不需要。
判定处理接口(DecisionHandlder)
委派处理接口(AssignmentHandler)
流程测试剖析
本章节,我们将给大家剖析两个流程测试类。一个是简单的基于内存模型的流程测试FirstFlowProcessTest;一个是更贴近实用的,基于MySQL数据库操作的标准测试案例。通过对这两个测试例程的分析,来直观的学习如何通过Java API操作jPDL。
简单流程测试案例
测试案例类:FirstFlowProcessTest.java
该案例是在没有数据库支持的情况下,对报销流程进行运行测试,测试逻辑如下:
1. 加载流程定义
在没有数据库存储的情况下,流程定义通过ProcessDefinition类直接从processdefinition.xml文件中解析加载。
2. 实例化流程对象
在获得流程定义的实例后,可以用它生成流程实例,使用如下的语句:
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. 员工发起借款申请
在借款流程发起后,流程进入了申请单填写阶段。这个阶段是个人工的任务,需要用户的介入。因此,对于要借款的用户而言,首先是获取填写申请单的任务实例:
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. 部门领导审批申请
这里,流程进入了部门经理审批阶段。由于没有数据库支持,我们只能采取遍历任务列表,并比对委派者ID的方式来确定委派给部门经理的任务实例。(在后面的基于数据库的标准案例中,我们会看到如果根据用户的ID来获取分配给指定用户的任务)
ti.getActorId().equals("DepartmentManager") // 比对任务的委派人。
ti.getToken().getNode().getLeavingTransitions();//获取任务在当前节点上的所有转向。
这里我们要特别指出的是ti.end("部门经理审批通过")和ti.end("部门经理驳回")这实际上调用token.signal(transition);来完成任务的转向,从而使流程继续。
5. 总经理审批申请
此步代码同“部门经理审批”代码相似,不作更多说明。
标准流程测试案例
该案例模拟了标准运行环境中,基于关系型数据库的jBPM系统是如何执行流程的。
测试案例类:FirstFlowProcessDBTest.java
相对于简单流程测试案例,标准流程的业务是相同的。它们的不同点在于:简单流程通过XML载入流程定义,并使用类的全局变量来保存流程实例的引用;而标准流程则是通过数据库载入流程定义,并使用数据库的会话来维护流程的运行。
1. 从数据库载入流程定义
2. 新建流程实例,并存入数据库持久化
设置实例的上下文变量,激活实例执行进程。
保存实例到数据库,持久化实例。
3. 从数据库获取属于指定操作者的任务集
注意,在每次的JbpmContext对象使用完毕后,一定要执行jbpmContext.close(),其本质是要释放数据库的操作连接。
(全文完)
什么叫“流定义”啊?!
这个完全是看业务设计的需要咯,没有一定由什么时候来指定执行者的。jBPM都可以支持的
《jBPM学习笔记(V3.2环境部署)》
《jBPM学习笔记(框架设计简介)》
背景
本片文章,我们将从业务流程的设计开始,通过带领大家完成一个完整工作流的程序设计,来学习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.StartProcessActionHander"></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=">5000元总经理审批"></transition>
<transition to="财务拨款" name="<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>
判定结点的设计目标是根据上下文环境和程序逻辑,判定流程转向。通过指定一个实现DecisionHandlder接口的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/*</url-pattern>
</servlet-mapping>
</web-app>
2. 建立流程定义存储数据库表:
Demo中,我们使用的数据库是MySQL的,在E:\Java\tools\jbpm-jpdl-3.2.2\db\目录下有个jbpm.jpdl.mysql.sql数据库脚本文件。但我们不能直接导入该文件, 会提示有错误, 应为该文件的SQL语句末尾少了分号,在批量执行时,MySQL报错。需要在每一行SQL的末尾添加一个分号,这样就可以用source命令导入了。
3. 配置Hibernate.cfg.xml
由于jBPM的数据库持久化是依靠Hibernate进行的,因此需要配置Hibernate.cfg.xml使其适应我们的MySQL环境
引用
<!-- hibernate dialect -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/linly</property>
<property name="hibernate.connection.username">linly</property>
<property name="hibernate.connection.password">coffee</property>
<property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
4. Import需要的jar包
这里的jar包包括三部分:jbpm的核心包;Hibernate及其支撑包;MySQL的JDBC驱动包。
到此,我们的配置工作完成,这是实现jBPM流程部署服务端的最小化应用配置。
流程控制及API使用
样例程序中的Handler接口实现
下面,根据上述的接口分类,列出样例程序中的类名及相应的功能说明,具体可参考源代码。
动作处理接口(ActioinHandler)
这里要提到一个很重要的区别,就是作用于Node上的ActoinHandler和作用于Transition上的ActoinHandler是有不同的。区别在于,Node上的ActoinHandler在结束业务逻辑处理后,必须调用executionContext.leaveNode();或executionContext.leaveNode(transition)来保证流程向下执行;而作用于Transition上的则不需要。
判定处理接口(DecisionHandlder)
委派处理接口(AssignmentHandler)
流程测试剖析
本章节,我们将给大家剖析两个流程测试类。一个是简单的基于内存模型的流程测试FirstFlowProcessTest;一个是更贴近实用的,基于MySQL数据库操作的标准测试案例。通过对这两个测试例程的分析,来直观的学习如何通过Java API操作jPDL。
简单流程测试案例
测试案例类:FirstFlowProcessTest.java
public class FirstFlowProcessTest extends TestCase { ProcessDefinition pdf ; ProcessInstance pi; public void test4000YuanApplication() throws Exception { deployProcessDefinition(); createProcessInstance("linly"); submitApplication(4000); approveByManager(true); checkTasks(); } public void test6000YuanApplication() throws Exception { deployProcessDefinition(); createProcessInstance("linly"); submitApplication(6000); approveByManager(true); approveByPresident(true); checkTasks(); } public void test7000YuanApplication() throws Exception { deployProcessDefinition(); createProcessInstance("linly"); submitApplication(7000); approveByManager(true); approveByPresident(false); checkTasks(); } /** * 部署流程定义 * @throws Exception */ 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(); } /** * 填写提交申请单 * @param money */ 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(); } /** * 部门经理审批 * @param pass */ @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; } } } /** * 总经理审批 * @param pass */ @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. 加载流程定义
ProcessDefinition.parseXmlResource("firstflow/processdefinition.xml")代码说明:
在没有数据库存储的情况下,流程定义通过ProcessDefinition类直接从processdefinition.xml文件中解析加载。
2. 实例化流程对象
//生成实例 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. 员工发起借款申请
/** * 填写提交申请单 * @param money */ 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. 部门领导审批申请
/** * 部门经理审批 * @param pass */ @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. 总经理审批申请
/** * 总经理审批 * @param pass */ @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
public class FirstFlowProcessDBTest { /* * 初始化jBPM配置 * 包含对Hibernate的数据库初始化 */ 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(); } } /** * 填写提交申请单 * @param money */ @SuppressWarnings("unchecked") protected void submitApplication(String actorId , int money){ System.out.println("==FirstFlowProcessTest.submitApplication()=="); JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); try { /* *根据操作者ID,获取属于该操作者的任务集 */ 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(); } } /** * 部门经理审批 * @param pass */ @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(); } } /** * 总经理审批 * @param pass */ @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. 从数据库载入流程定义
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();从jBPM配置环境中获取jBPM上下文实例,jbpmContext是对jbpm持久层操作API及上下文环境的封装,它根据jBPM的配置文件生成。
GraphSession graphSession = jbpmContext.getGraphSession();生成对流程图操作的持久层会话
ProcessDefinition pdf = graphSession.findLatestProcessDefinition("simple");从数据库获取命名为“simple”的流程定义。
2. 新建流程实例,并存入数据库持久化
ProcessInstance pi = pdf.createProcessInstance();根据流程定义生成实例。
pi.getContextInstance().createVariable("initiator", user); pi.signal();
设置实例的上下文变量,激活实例执行进程。
jbpmContext.save(pi);
保存实例到数据库,持久化实例。
3. 从数据库获取属于指定操作者的任务集
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对象,从数据库获取指定操作者的任务集合:
List<TaskInstance> taskInstances = jbpmContext.getTaskList("DepartmentManager");
注意,在每次的JbpmContext对象使用完毕后,一定要执行jbpmContext.close(),其本质是要释放数据库的操作连接。
(全文完)
- FirstFlow样例代码.rar (85.9 KB)
- 描述: jBPM Eclipse源码工程包(由于附件大小限制,去掉了lib中的jar包) 修订过的 MySQL建库脚本
- 下载次数: 6307
评论
29 楼
linliangyi2007
2008-09-05
引用
楼主我有个问题,如果填写借款金额以后,等待manage审批,但流定义可以在manage审批之前可以修改,这个流程怎么定义啊?
什么叫“流定义”啊?!
28 楼
lottons
2008-09-04
太好了,正在学习!
27 楼
cdtpf
2008-09-03
楼主我有个问题,如果填写借款金额以后,等待manage审批,但流定义可以在manage审批之前可以修改,这个流程怎么定义啊?
26 楼
linliangyi2007
2008-08-26
引用
谢谢楼主的讲解,我这里有个疑问,为什么在经理审批的时候才指定经理,而不是在申请的时候就指定审批的经理,这样经理上线以后才能知道自己有那个Task.
这个完全是看业务设计的需要咯,没有一定由什么时候来指定执行者的。jBPM都可以支持的
25 楼
cdtpf
2008-08-25
谢谢楼主的讲解,我这里有个疑问,为什么在经理审批的时候才指定经理,而不是在申请的时候就指定审批的经理,这样经理上线以后才能知道自己有那个Task.
24 楼
yirentianran
2008-08-13
good job.
23 楼
ethanwei
2008-08-13
谢谢分享,我在学习中遇到点问题,进行标准测试时报下面的错误,请帮助解答一下
ti.actor = DepartmentManager
Exception in thread "main" org.jbpm.JbpmException: task node does not have leaving transition '部门经理审批通过'
at org.jbpm.taskmgmt.exe.TaskInstance.end(TaskInstance.java:419)
at com.firstflow.FirstFlowProcessDBTest.approveByManager(FirstFlowProcessDBTest.java:140)
at com.firstflow.FirstFlowProcessDBTest.test6000YuanApplication(FirstFlowProcessDBTest.java:47)
at com.firstflow.FirstFlowProcessDBTest.main(FirstFlowProcessDBTest.java:33)
ti.actor = DepartmentManager
Exception in thread "main" org.jbpm.JbpmException: task node does not have leaving transition '部门经理审批通过'
at org.jbpm.taskmgmt.exe.TaskInstance.end(TaskInstance.java:419)
at com.firstflow.FirstFlowProcessDBTest.approveByManager(FirstFlowProcessDBTest.java:140)
at com.firstflow.FirstFlowProcessDBTest.test6000YuanApplication(FirstFlowProcessDBTest.java:47)
at com.firstflow.FirstFlowProcessDBTest.main(FirstFlowProcessDBTest.java:33)
22 楼
luozhiguo999
2008-07-18
[align=center][/align][size=xx-small][/size][color=orange][/color][url][/url]
引用
引用
[u][/u][/i][b][/b][i]- TaskNode
21 楼
kevindurant
2008-07-08
你牛 顶....LZ写得非常好
20 楼
burtonny
2008-06-23
19 楼
sgwood
2008-06-10
林兄,我的运行十分正常,但就发现有DB测试打印任务这个方法时总是内容为空,奇怪了!
问题是在:
List<TaskInstance> coll = jbpmContext.getTaskMgmtSession().findTaskInstancesByProcessInstance(pi);
System.out.println("coll size:"+coll.size()); //为什么这里总是size为0
问题是在:
List<TaskInstance> coll = jbpmContext.getTaskMgmtSession().findTaskInstancesByProcessInstance(pi);
System.out.println("coll size:"+coll.size()); //为什么这里总是size为0
18 楼
ewenxj1314
2008-05-24
随便写的一个简单的deployProcess方法:
public void deployProcess() {
jbpmContext = jbpmConfiguration.createJbpmContext();
try {
ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(
"<process-definition name='hello world'>" +
" <start-state name='start'>" +
" <transition to='s' />" +
" </start-state>" +
" <state name='s'>" +
" <transition to='end' />" +
" </state>" +
" <end-state name='end' />" +
"</process-definition>"
);
jbpmContext.deployProcessDefinition(processDefinition);
} finally {
jbpmContext.close();
}
}
public void deployProcess() {
jbpmContext = jbpmConfiguration.createJbpmContext();
try {
ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(
"<process-definition name='hello world'>" +
" <start-state name='start'>" +
" <transition to='s' />" +
" </start-state>" +
" <state name='s'>" +
" <transition to='end' />" +
" </state>" +
" <end-state name='end' />" +
"</process-definition>"
);
jbpmContext.deployProcessDefinition(processDefinition);
} finally {
jbpmContext.close();
}
}
17 楼
mysyche
2008-05-20
问题已经搞清了。是我的代码失误:ProcessDefinition.parseXmlString("firstflow/processdefinition.xml");
应该是ProcessDefinition.parseXmlResource("firstflow/processdefinition.xml");
小小的失误竟然浪费2个小时。当时心里清楚是要用parseXmlResource。可就是用parseXmlString。。。。。。 教训呀!!!!
应该是ProcessDefinition.parseXmlResource("firstflow/processdefinition.xml");
小小的失误竟然浪费2个小时。当时心里清楚是要用parseXmlResource。可就是用parseXmlString。。。。。。 教训呀!!!!
16 楼
mysyche
2008-05-20
纠正说明:jbmp3.2自带的dom4j已经是1.6的了。
15 楼
mysyche
2008-05-20
先谢谢,linliangyi2007 的贡献!我在部署中出现了一个问题:我把流程持久化到数据时,有异常:
org.dom4j.DocumentException: Error on line 1 of document : Content is not allowed in prolog. Nested exception: Content is not allowed in prolog.
对这个异常在网上找到资料是 processdefinition.xml 的utf-8的编码引起,是dom4j.jar的问题,jbmp3.2自带的是1.4,我重新下载了个dom4j-1.6.1.jar,替换原来 的dom4j.jar。但部署时还是出现上述异常问题。
我的持久化代码:
/**
* deploy persistent
*/
public void testDeployProcessDefinition() {
ProcessDefinition processDefinition = ProcessDefinition.parseXmlString("firstflow/processdefinition.xml");
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
jbpmContext.deployProcessDefinition(processDefinition);
} finally {
jbpmContext.close();
}
}
备注说明:processdefinition.xml 还是linliangyi2007 贡献的中原文件。没有任何改动 。
由于是初次学习jbpm,不知道哪位朋友,遇到过这个问题,请多指教。
org.dom4j.DocumentException: Error on line 1 of document : Content is not allowed in prolog. Nested exception: Content is not allowed in prolog.
对这个异常在网上找到资料是 processdefinition.xml 的utf-8的编码引起,是dom4j.jar的问题,jbmp3.2自带的是1.4,我重新下载了个dom4j-1.6.1.jar,替换原来 的dom4j.jar。但部署时还是出现上述异常问题。
我的持久化代码:
/**
* deploy persistent
*/
public void testDeployProcessDefinition() {
ProcessDefinition processDefinition = ProcessDefinition.parseXmlString("firstflow/processdefinition.xml");
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
jbpmContext.deployProcessDefinition(processDefinition);
} finally {
jbpmContext.close();
}
}
备注说明:processdefinition.xml 还是linliangyi2007 贡献的中原文件。没有任何改动 。
由于是初次学习jbpm,不知道哪位朋友,遇到过这个问题,请多指教。
14 楼
lingyifei117
2008-05-20
不错,学习中。。。
收藏!!
收藏!!
13 楼
mysyche
2008-05-16
谢谢共享!正在要学习的东西!!
12 楼
uniquejava
2008-04-29
在点击deploy process archive的时候报错
2008-4-29 16:13:00 org.apache.catalina.core.StandardWrapperValve invoke
严重: Servlet.service() for servlet GDP Deployer Servlet threw exception
org.hibernate.exception.DataException: could not insert: [org.jbpm.graph.def.ProcessDefinition]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:77)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:40)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2158)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2638)
at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:48)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:298)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:535)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:523)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:519)
at org.jbpm.db.GraphSession.deployProcessDefinition(GraphSession.java:77)
at org.jbpm.JbpmContext.deployProcessDefinition(JbpmContext.java:173)
at org.jbpm.web.ProcessUploadServlet.handleRequest(ProcessUploadServlet.java:91)
at org.jbpm.web.ProcessUploadServlet.service(ProcessUploadServlet.java:56)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:261)
at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:852)
at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:584)
at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1508)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.sql.SQLException: Data too long for column 'ISTERMINATIONIMPLICIT_' at row 1
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2001)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1168)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1279)
at com.mysql.jdbc.Connection.execSQL(Connection.java:2281)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1825)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1667)
at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:73)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:33)
... 33 more
2008-4-29 16:13:00 org.apache.catalina.core.StandardWrapperValve invoke
严重: Servlet.service() for servlet GDP Deployer Servlet threw exception
org.hibernate.exception.DataException: could not insert: [org.jbpm.graph.def.ProcessDefinition]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:77)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:40)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2158)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2638)
at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:48)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:298)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:535)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:523)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:519)
at org.jbpm.db.GraphSession.deployProcessDefinition(GraphSession.java:77)
at org.jbpm.JbpmContext.deployProcessDefinition(JbpmContext.java:173)
at org.jbpm.web.ProcessUploadServlet.handleRequest(ProcessUploadServlet.java:91)
at org.jbpm.web.ProcessUploadServlet.service(ProcessUploadServlet.java:56)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:261)
at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:852)
at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:584)
at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1508)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.sql.SQLException: Data too long for column 'ISTERMINATIONIMPLICIT_' at row 1
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2001)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1168)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1279)
at com.mysql.jdbc.Connection.execSQL(Connection.java:2281)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1825)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1667)
at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:73)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:33)
... 33 more
11 楼
uniquejava
2008-04-29
简单流程测试通过了,
换成数据库标准测试跑不起来,老报下面的错误?怎么办,帮忙看看,谢谢!
[main] INFO HbmBinder : Mapping collection: org.jbpm.taskmgmt.exe.SwimlaneInstance.pooledActors -> JBPM_POOLEDACTOR
[main] INFO HbmBinder : Mapping collection: org.jbpm.logging.log.CompositeLog.children -> JBPM_LOG
[main] INFO HbmBinder : Mapping collection: org.jbpm.graph.action.Script.variableAccesses -> JBPM_VARIABLEACCESS
[main] INFO HbmBinder : Mapping collection: org.jbpm.taskmgmt.def.TaskMgmtDefinition.swimlanes -> JBPM_SWIMLANE
[main] INFO HbmBinder : Mapping collection: org.jbpm.taskmgmt.def.TaskMgmtDefinition.tasks -> JBPM_TASK
[main] INFO C3P0ConnectionProvider : C3P0 using driver: com.mysql.jdbc.Driver at URL: jdbc:mysql://localhost:3306/j322demo?useUnicode=true&characterEncoding=utf-8
[main] INFO C3P0ConnectionProvider : Connection properties: {user=root, password=****}
[main] INFO C3P0ConnectionProvider : autocommit mode: false
[main] INFO MLog : MLog clients using log4j logging.
[main] INFO C3P0Registry : Initializing c3p0-0.9.0 [built 11-July-2005 00:43:29 -0400; debug? true; trace: 10]
[main] INFO PoolBackedDataSource : Initializing c3p0 pool... com.mchange.v2.c3p0.PoolBackedDataSource@5e13ad [ connectionPoolDataSource -> com.mchange.v2.c3p0.WrapperConnectionPoolDataSource@1309e87 [ acquireIncrement -> 1, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1309e87, idleConnectionTestPeriod -> 0, initialPoolSize -> 2, maxIdleTime -> 0, maxPoolSize -> 50, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 2, nestedDataSource -> com.mchange.v2.c3p0.DriverManagerDataSource@2bc3f5 [ description -> null, driverClass -> null, factoryClassLocation -> null, identityToken -> 2bc3f5, jdbcUrl -> jdbc:mysql://localhost:3306/j322demo?useUnicode=true&characterEncoding=utf-8, properties -> {user=******, password=******} ], preferredTestQuery -> null, propertyCycle -> 300, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, usesTraditionalReflectiveProxies -> false ], factoryClassLocation -> null, identityToken -> 5e13ad, numHelperThreads -> 3 ]
[main] INFO SettingsFactory : RDBMS: MySQL, version: 5.0.18-nt
[main] INFO SettingsFactory : JDBC driver: MySQL-AB JDBC Driver, version: mysql-connector-java-3.0.17-ga ( $Date: 2005/04/06 14:12:56 $, $Revision: 1.27.2.47 $ )
[main] INFO Dialect : Using dialect: org.hibernate.dialect.MySQLDialect
[main] INFO TransactionFactoryFactory : Using default transaction strategy (direct JDBC transactions)
[main] INFO TransactionManagerLookupFactory : No TransactionManagerLookup configured (in JTA environment, use of read-write or transactional second-level cache is not recommended)
[main] INFO SettingsFactory : Automatic flush during beforeCompletion(): disabled
[main] INFO SettingsFactory : Automatic session close at end of transaction: disabled
[main] INFO SettingsFactory : JDBC batch size: 15
[main] INFO SettingsFactory : JDBC batch updates for versioned data: disabled
[main] INFO SettingsFactory : Scrollable result sets: enabled
[main] INFO SettingsFactory : JDBC3 getGeneratedKeys(): enabled
[main] INFO SettingsFactory : Connection release mode: auto
[main] INFO SettingsFactory : Maximum outer join fetch depth: 2
[main] INFO SettingsFactory : Default batch fetch size: 1
[main] INFO SettingsFactory : Generate SQL with comments: disabled
[main] INFO SettingsFactory : Order SQL updates by primary key: disabled
[main] INFO SettingsFactory : Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory
[main] INFO ASTQueryTranslatorFactory : Using ASTQueryTranslatorFactory
[main] INFO SettingsFactory : Query language substitutions: {}
[main] INFO SettingsFactory : Second-level cache: enabled
[main] INFO SettingsFactory : Query cache: disabled
[main] INFO SettingsFactory : Cache provider: org.hibernate.cache.HashtableCacheProvider
[main] INFO SettingsFactory : Optimize cache for minimal puts: disabled
[main] INFO SettingsFactory : Structured second-level cache entries: disabled
[main] INFO SettingsFactory : Statistics: disabled
[main] INFO SettingsFactory : Deleted entity synthetic identifier rollback: disabled
[main] INFO SettingsFactory : Default entity-mode: pojo
[main] INFO SessionFactoryImpl : building session factory
[main] INFO SessionFactoryObjectFactory : Not binding factory to JNDI, no JNDI name configured
[main] WARN JDBCExceptionReporter : SQL Error: 1406, SQLState: 22001
[main] ERROR JDBCExceptionReporter : Data too long for column 'ISABLETOREACTIVATEPARENT_' at row 1
[main] ERROR AssertionFailure : an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
org.hibernate.AssertionFailure: null id in org.jbpm.graph.exe.ProcessInstance entry (don't flush the Session after an exception occurs)
at org.hibernate.event.def.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:48)
at org.hibernate.event.def.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:150)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:106)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:195)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:76)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:985)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:333)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at org.jbpm.persistence.db.DbPersistenceService.commit(DbPersistenceService.java:256)
at org.jbpm.persistence.db.DbPersistenceService.close(DbPersistenceService.java:214)
at org.jbpm.svc.Services.close(Services.java:225)
at org.jbpm.JbpmContext.close(JbpmContext.java:139)
at com.sample.FirstFlowProcessDBTest.createProcessInstance(FirstFlowProcessDBTest.java:75)
at com.sample.FirstFlowProcessDBTest.test4000YuanApplication(FirstFlowProcessDBTest.java:26)
at com.sample.FirstFlowProcessDBTest.main(FirstFlowProcessDBTest.java:21)
[main] ERROR DbPersistenceService : hibernate commit failed
换成数据库标准测试跑不起来,老报下面的错误?怎么办,帮忙看看,谢谢!
[main] INFO HbmBinder : Mapping collection: org.jbpm.taskmgmt.exe.SwimlaneInstance.pooledActors -> JBPM_POOLEDACTOR
[main] INFO HbmBinder : Mapping collection: org.jbpm.logging.log.CompositeLog.children -> JBPM_LOG
[main] INFO HbmBinder : Mapping collection: org.jbpm.graph.action.Script.variableAccesses -> JBPM_VARIABLEACCESS
[main] INFO HbmBinder : Mapping collection: org.jbpm.taskmgmt.def.TaskMgmtDefinition.swimlanes -> JBPM_SWIMLANE
[main] INFO HbmBinder : Mapping collection: org.jbpm.taskmgmt.def.TaskMgmtDefinition.tasks -> JBPM_TASK
[main] INFO C3P0ConnectionProvider : C3P0 using driver: com.mysql.jdbc.Driver at URL: jdbc:mysql://localhost:3306/j322demo?useUnicode=true&characterEncoding=utf-8
[main] INFO C3P0ConnectionProvider : Connection properties: {user=root, password=****}
[main] INFO C3P0ConnectionProvider : autocommit mode: false
[main] INFO MLog : MLog clients using log4j logging.
[main] INFO C3P0Registry : Initializing c3p0-0.9.0 [built 11-July-2005 00:43:29 -0400; debug? true; trace: 10]
[main] INFO PoolBackedDataSource : Initializing c3p0 pool... com.mchange.v2.c3p0.PoolBackedDataSource@5e13ad [ connectionPoolDataSource -> com.mchange.v2.c3p0.WrapperConnectionPoolDataSource@1309e87 [ acquireIncrement -> 1, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1309e87, idleConnectionTestPeriod -> 0, initialPoolSize -> 2, maxIdleTime -> 0, maxPoolSize -> 50, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 2, nestedDataSource -> com.mchange.v2.c3p0.DriverManagerDataSource@2bc3f5 [ description -> null, driverClass -> null, factoryClassLocation -> null, identityToken -> 2bc3f5, jdbcUrl -> jdbc:mysql://localhost:3306/j322demo?useUnicode=true&characterEncoding=utf-8, properties -> {user=******, password=******} ], preferredTestQuery -> null, propertyCycle -> 300, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, usesTraditionalReflectiveProxies -> false ], factoryClassLocation -> null, identityToken -> 5e13ad, numHelperThreads -> 3 ]
[main] INFO SettingsFactory : RDBMS: MySQL, version: 5.0.18-nt
[main] INFO SettingsFactory : JDBC driver: MySQL-AB JDBC Driver, version: mysql-connector-java-3.0.17-ga ( $Date: 2005/04/06 14:12:56 $, $Revision: 1.27.2.47 $ )
[main] INFO Dialect : Using dialect: org.hibernate.dialect.MySQLDialect
[main] INFO TransactionFactoryFactory : Using default transaction strategy (direct JDBC transactions)
[main] INFO TransactionManagerLookupFactory : No TransactionManagerLookup configured (in JTA environment, use of read-write or transactional second-level cache is not recommended)
[main] INFO SettingsFactory : Automatic flush during beforeCompletion(): disabled
[main] INFO SettingsFactory : Automatic session close at end of transaction: disabled
[main] INFO SettingsFactory : JDBC batch size: 15
[main] INFO SettingsFactory : JDBC batch updates for versioned data: disabled
[main] INFO SettingsFactory : Scrollable result sets: enabled
[main] INFO SettingsFactory : JDBC3 getGeneratedKeys(): enabled
[main] INFO SettingsFactory : Connection release mode: auto
[main] INFO SettingsFactory : Maximum outer join fetch depth: 2
[main] INFO SettingsFactory : Default batch fetch size: 1
[main] INFO SettingsFactory : Generate SQL with comments: disabled
[main] INFO SettingsFactory : Order SQL updates by primary key: disabled
[main] INFO SettingsFactory : Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory
[main] INFO ASTQueryTranslatorFactory : Using ASTQueryTranslatorFactory
[main] INFO SettingsFactory : Query language substitutions: {}
[main] INFO SettingsFactory : Second-level cache: enabled
[main] INFO SettingsFactory : Query cache: disabled
[main] INFO SettingsFactory : Cache provider: org.hibernate.cache.HashtableCacheProvider
[main] INFO SettingsFactory : Optimize cache for minimal puts: disabled
[main] INFO SettingsFactory : Structured second-level cache entries: disabled
[main] INFO SettingsFactory : Statistics: disabled
[main] INFO SettingsFactory : Deleted entity synthetic identifier rollback: disabled
[main] INFO SettingsFactory : Default entity-mode: pojo
[main] INFO SessionFactoryImpl : building session factory
[main] INFO SessionFactoryObjectFactory : Not binding factory to JNDI, no JNDI name configured
[main] WARN JDBCExceptionReporter : SQL Error: 1406, SQLState: 22001
[main] ERROR JDBCExceptionReporter : Data too long for column 'ISABLETOREACTIVATEPARENT_' at row 1
[main] ERROR AssertionFailure : an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
org.hibernate.AssertionFailure: null id in org.jbpm.graph.exe.ProcessInstance entry (don't flush the Session after an exception occurs)
at org.hibernate.event.def.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:48)
at org.hibernate.event.def.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:150)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:106)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:195)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:76)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:985)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:333)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at org.jbpm.persistence.db.DbPersistenceService.commit(DbPersistenceService.java:256)
at org.jbpm.persistence.db.DbPersistenceService.close(DbPersistenceService.java:214)
at org.jbpm.svc.Services.close(Services.java:225)
at org.jbpm.JbpmContext.close(JbpmContext.java:139)
at com.sample.FirstFlowProcessDBTest.createProcessInstance(FirstFlowProcessDBTest.java:75)
at com.sample.FirstFlowProcessDBTest.test4000YuanApplication(FirstFlowProcessDBTest.java:26)
at com.sample.FirstFlowProcessDBTest.main(FirstFlowProcessDBTest.java:21)
[main] ERROR DbPersistenceService : hibernate commit failed
10 楼
wjl1174
2008-04-17
部门经理是如何确定申请是哪个人提交的呢
发表评论
-
来自开源支持者的第一笔捐赠
2013-01-09 21:15 58022013年1月9号,一个平凡而又不平常的日子! IK中文分词 ... -
发布 IK Analyzer 2012 FF 版本
2012-10-23 17:50 25165首先感谢大家对IK分词器的关注。 最近一段时间正式公司事务最 ... -
发布 IK Analyzer 2012 版本
2012-03-08 11:23 36268新版本改进: 支持分词歧义处理 支持数量词合并 词典支持中英 ... -
CSDN发生严重用户账号泄密事件
2011-12-21 19:21 2573之前有在CSDN注册过的兄弟们,注意了。。。 如果你的邮箱, ... -
一个隐形的java int溢出
2011-08-30 09:44 7569故事的背景: 笔者最近在做一个类SNS的项目,其中 ... -
雷军 :互联网创业的葵花宝典
2011-05-04 10:35 3602博主评: 这片博客很短 ... -
Luci-mint站内搜索实测
2011-04-02 16:18 4162关于Luci-mint 服务器硬 ... -
发布 IK Analyzer 3.2.8 for Lucene3.X
2011-03-04 17:49 14282IK Analyzer 3.2.8版本修订 ... -
TIPS - XML CDATA中的非法字符处理
2011-02-17 15:03 3332XML解析过程中,常遇见CDATA中存在非法字符,尤其在火星文 ... -
对Cassandra的初体验
2010-10-13 17:58 9178作为“云计算”时代的架构设计人员而言,不懂K-V库会被 ... -
Spring + iBatis 的多库横向切分简易解决思路
2010-10-11 13:43 94311.引言 笔者最近在做一个互联网的“类SNS”应用,应用 ... -
发布 IK Analyzer 3.2.5 稳定版 for Lucene3.0
2010-09-08 14:43 5845新版本IKAnnlyzer3.2.8已发布! 地址: http ... -
关于Lucene3.0.1 QueryParser的一个错误
2010-05-21 21:33 2146表达式1: 引用 id:"1231231" ... -
发布 IK Analyzer 3.2.3 稳定版 for Lucene3.0
2010-05-15 14:13 6752IK Analyzer 3.2.3版本修订 在3.2.0版 ... -
windows平台上的nginx使用
2010-01-28 17:13 3417转载自:http://nginx.org/en/docs/wi ... -
发布IKAnnlyzer3.2.0稳定版 for Lucene3.0
2009-12-07 09:27 9616最新3.2.5版本已经推出,http://linliangyi ... -
在Tomcat下以JNDI方式发布JbossCache
2009-12-04 10:57 3863前言: 看过JbossCache的开发手册,发现在Jb ... -
Spring AOP小例子
2009-11-16 10:35 3412PS: 要注明一下,这个是转载滴,之前漏了说鸟,汗死 这里给 ... -
ActiveMQ 5.X 与 Tomcat 集成一(JNDI部署)
2009-11-10 15:15 5657原文地址:http://activemq.apache.org ... -
发布IKAnalyzer中文分词器V3.1.6GA
2009-11-08 23:10 11874IKAnalyzer3.2.0稳定版已经发布,支持Lucene ...
相关推荐
在《jBPM-jPDL学习笔记——流程设计与控制》这篇博文中,作者主要介绍了如何使用jPDL进行流程设计和控制,包括以下几个关键知识点: 1. **jPDL介绍**: jPDL是jBPM的核心组成部分,它定义了流程实例的行为。通过...
jBPM-jPDL学习笔记——流程设计与控制.doc JBPM4.4之HelloWorld示例.doc jbpm4.4会签实例.doc jbpm4.4安装配置step by step.doc jbpm4自带数据库分析.doc jBPM_4教程PPT.pdf JBPM与SSH架构融合.doc 工作流模型...
通过jBPM-jPDL学习笔记,你可以系统地学习如何使用jPDL设计和实施业务流程,掌握jbpm的核心概念和技术。无论是对于开发人员还是业务分析师,这份资料都将极大地提升你在工作流管理领域的专业技能。
在安装配置方面,"jBPM-jPDL学习笔记—框架设计简介.doc"和"jBPM-JPDL v3.2环境部署——发布到Tomcat + MySQL.doc"将是你的重要参考资料。这两个文档详细介绍了如何搭建jBPM开发环境,包括下载和安装jBPM工具,配置...
#### 三、JBPM学习笔记系列 **1.1 Ant构建与数据库环境配置** - 重点介绍了如何使用Ant进行构建和部署,以及如何配置数据库环境,为后续的流程定义和执行打下基础。 **1.2 MyEclipse整合JBPM配置** - 讲述了...