首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

【Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8调整例子】

2012-12-21 
【Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8整合例子】1.???????jbpm4.4?测试环境搭建2.???????Jbpm4

【Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8整合例子】

1.???????jbpm4.4?测试环境搭建

2.???????Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.?整合环境搭建

3.???????jbpm4.4?基础知识

4.???????整合过程中常见问题的解决

5.???????请假流程例子(?s2sh+jbpm?)

6.???????总结及参考文章

jbpm4.4?测试环境搭建

刚接触?jbpm?第一件事就是快速搭建环境,测试?jbpm?所给的例子。?Jbpm?是一个工作流引擎框架,如果没有javaEE?开发环境,?jbpm?也提供了安装脚本(?ant?),一键提供安装运行环境。同时也可以将?jbpm?整合到eclipse?或者?myeclipse?中。

?

快速搭建环境的步骤是:

1.???????安装?jbpm-myeclipse?插件,这个插件随?jbpm4.4?一起发布,位于?jbpm-4.4/install/src/gpd?目录下,这个安装好后,就可以在myeclipse?中编辑流程图了(可视化流程设计)

???在myeclipse->help->myeclipse configuration centre->software->add site->add from archive file?选择jbpm-4.4/install/src/gpd?下的jbpm-gpd-site.zip

安装这个插件应该注意断网,避免其到网上更新。同时注意:需要选择

【Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8调整例子】?双击每一项,确保每一项被加入到了

【Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8调整例子】

(说明:事实上不用选完,带source?的部件不用选择,为了省事就全部选择了)

?

提示:如果安装时不断网,jbpm?插件会自动到网上更新。同时会弹出一个错误窗口,安装速度异常缓慢。安装完成后,myeclipse?的references?菜单会变得面目全非。

2.???????搭建?jbpm?运行环境。

【Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8调整例子】

3?.然后配置jpdl?支持

【Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8调整例子】

4.?确定是否配置jbpm?正确

在myeclipse->new->other->

【Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8调整例子】

关于myeclipse?中配置jbpm?请参考jbpm?的帮助文档,文档给的是在eclipse?下配置jbpm?。

?

5.?测试运行环境:

新建一个?java?项目,将?jbpm-4.4/examples?下的?src?目录,?copy?到项目中。然后引入相关?jar?包,?jbpm.jar?和lib?下的所有包,先不考虑?jar?包选择问题。?Src?中包括了?jbpm?中的基本元素的使用。如?start?,?state?,?end?,sql?,?script?,?fork?,?join?等。然后跟着?jbpm?的帮助文档,一点一点的学习。

【Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8调整例子】

说说以上文件的作用:第一个是?jbpm?的配置文件,在这个文件又引入其他的文件,在被引入的文件有一个文件包含了

???????????<hibernate-configuration> <cfg resource="jbpm.hibernate.cfg.xml" />

???????????</hibernate-configuration> <hibernate-session-factory />

用于创建?hibernate?的?sessionfactory?并交给?jbpm?的?IOC?容器管理。

第二个文件是?hibernate?配置文件,里面包含了?jbpm?框架需要的表的?hbm.xml?配置文件。

?

?

?

Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.?整合环境搭建

我的开发环境:

tomcat6.0.28+mysql5.1.30+ Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8+myeclipse8.6+java jdk 6.0.23

在搭建环境之前,先认识一下?jbpm?。????JBPM?在管理流程时,是需要数据库表的支持的,因为底层的逻辑有那么复杂。默认下载下来的配置,使用的是(??

整合目标:将jbpm4?的IOC?移植到Spring?中,让spring?管理一个sessionfactory?,同时需要明确一点的是:jbpm4?对外提供服务是?ProcessEngine?。如:

????private?RepositoryService?repositoryService?;

????private?ExecutionService?executionService?;

????private?HistoryService?historyService?;

????private?TaskService?taskService?;

????private?IdentityService?identityService?;

上面这些服务就是通过?ProcessEngine?获得的。

Spring?配置文件:

<!--jbpm4.4?工作流???-->

????<?bean?id?=?"springHelper"?class?="org.jbpm.pvm.internal.processengine.SpringHelper"?>

???????<?property?name?=?"jbpmCfg"?value?=?"jbpm.cfg.xml"?/>

????</?bean?>

?

????<?bean?id?=?"sessionFactory"

???????class?=?"org.springframework.orm.hibernate3.LocalSessionFactoryBean"?>

???????<!--

???????????<property name="configLocation">

???????????<value>classpath:jbpm.hibernate.cfg.xml</value> </property>

???????-->

???????<?property?name?=?"dataSource"?ref?=?"dataSource"?/>

???????<?property?name?=?"hibernateProperties"?>

???????????<?props?>

??????????????<?prop?key?=?"hibernate.dialect"?>org.hibernate.dialect.MySQLInnoDBDialect?</?prop?>

??????????????<?prop?key?=?"hibernate.show_sql"?>?true?</?prop?>

??????????????<?prop?key?=?"hibernate.connection.pool_size"?>?1?</?prop?>

??????????????<?prop?key?=?"hibernate.format_sql"?>?true?</?prop?>

??????????????<?prop?key?=?"hibernate.hbm2ddl.auto"?>?update?</?prop?>

??????????????<!--

??????????????<prop key="hibernate.current_session_context_class">thread</prop>

??????????????-->

??????????????</?props?>

???????</?property?>

?

???????<?property?name?=?"mappingLocations"?>

???????????<?list?>

??????????????<?value?>?classpath:jbpm.execution.hbm.xml?</?value?>

??????????????<?value?>?classpath:jbpm.history.hbm.xml?</?value?>

??????????????<?value?>?classpath:jbpm.identity.hbm.xml?</?value?>

???????????????<?value?>?classpath:jbpm.repository.hbm.xml?</?value?>

??????????????<?value?>?classpath:jbpm.task.hbm.xml?</?value?>

???????????</?list?>

???????</?property?>

????</?bean?>

????<?bean

???????class?="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"?>

???????<?property?name?=?"locations"?value?=?"classpath:jdbc.properties"?></?property?>

????</?bean?>

?

????<?bean?id?=?"dataSource"

???????class?=?"org.springframework.jdbc.datasource.DriverManagerDataSource"?>

???????<?property?name?=?"driverClassName"?value?=?"${jdbc.driverClassName}"?/>

???????<?property?name?=?"url"?value?=?"${jdbc.url}"?/>

???????<?property?name?=?"username"?value?=?"${jdbc.username}"?/>

???????<?property?name?=?"password"?value?=?"${jdbc.password}"?/>

????</?bean?>

Jar?包选择:(没有选择,所以会有很多无用的)

【Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8调整例子】

【Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8调整例子】

【Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8调整例子】

?

基础知识:

在?jbpm4.4?目录?install/src/db/create?下有:

【Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8调整例子】

这些?sql?脚本所创建的表是?jbpm?能正常工作所必须的。我们可以直接运行这些?sql?在数据库建立起相关的表(共18?张,如下):

【Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8调整例子】

每张表对应的含义:

(?1?)?JBPM4_DEPLOYMENT

(?2?)?JBPM4_DEPLOYPROP

(?3?)?JBPM4_LOB?:存储?上传一个包含?png?和?jpdl.xml?的?zip?包?的相关数据?
jbpm4_deployment?表多了一条记录?
jbpm4_deployprop?表多了四条记录?,?对应?langid,pdid,pdkey,pdversion?
jbpm4_lob?表多了二条记录?,?保存流程图?png?图片和?jpdl.xml

(?4?)?JBPM4_HIST_PROCINST?与

(?5?)?JBPM4_HIST_ACTINST?分别存放的是?Process Instance?、?Activity Instance?的历史记

(?6?)?JBPM4_EXECUTION?主要是存放?JBPM4?的执行信息,?Execution?机制代替了?JBPM3?的?Token?机制(详细参阅?JBPM4?的?PVM?机制)。

(?7?)?JBPM4_TASK?存放需要人来完成的?Activities?,需要人来参与完成的?Activity?被称为?Task?。

(?8?)?JBPM4_PARTICIPATION?存放?Participation?的信息,?Participation?的种类有?Candidate?、?Client?、Owner?、?Replaced Assignee?和?Viewer?。而具体的?Participation?既可以是单一用户,也可以是用户组。

(?9?)?JBPM4_SWIMLANE?。?Swim Lane?是一种?Runtime Process Role?。通过?Swim Lane?,多个?Task?可以一次分配到同一?Actor?身上。

(?10?)?JBPM4_VARIABLE?存的是进行时的临时变量。

(?11?)?JBPM4_HIST_DETAIL?保存?Variable?的变更记录。

(?12?)?JBPM4_HIST_VAR?保存历史的变量。

(?13?)?JBPM4_HIST_TASKTask?的历史信息。

(?14?)?JBPM4_ID_GROUP

(?15?)?JBPM_ID_MEMBERSHIP

(?16?)?JBPM4_ID_USER?这三张表很常见了,基本的权限控制,关于用户认证方面建议还是自己开发一套,JBPM4?的功能太简单了,使用中有很多需要难以满足。

(?17?)?JBPM4_JOB?存放的是?Timer?的定义。

(?18?)?JBPM4_PROPERTY

你可以直接运行脚本,整合中有hibernate?,所以就用hibernate?自动创建。事实上jbpm?也是采用的hibernate?作为其持久化工具。

?

jbpm 4.4?中一些概念(?转自family168)

1,?流程定义(ProcessDefinition):?对整个流程步骤的描述.,?相当于我们在编程过程过程用到的类,?是个抽象的概念.

2.?流程实例(ProcessInstance)?代表着流程定义的特殊执行例子,?相当于我们常见的对象.?他是类的特殊化.

最典型的属性就是跟踪当前节点的指针.

3.?流程引擎(ProcessEngine),?服务接口可以从?ProcessEngine?中获得, 它是从?Configuration?构建的,?如下:

ProcessEngine processEngine = new Configuration()
????? .buildProcessEngine();

从流程引擎中可以获得如下的服务:

RepositoryService repositoryService = processEngine.getRepositoryService();
ExecutionService executionService = processEngine.getExecutionService();
TaskService taskService = processEngine.getTaskService();
HistoryService historyService = processEngine.getHistoryService();
ManagementService managementService = processEngine.getManagementService();

4.?部署流程(Deploying a process):

RepositoryService?包含了用来管理发布资源的所有方法,

如下可以发布流程定义.

String deploymentid = repositoryService.createDeployment()

????.addResourceFromClasspath("*.jpdl.xml")

????.deploy();

这个id?的格式是(key)-{version}.

5.?删除流程定义:

repositoryService.deleteDeployment(deploymentId);?可以用级联的方式,?也可以remove

?

6.?启动一个新的流程实例:

?

?

?

?

?

ProcessInstance processInstance = executionService.startProcessInstanceByKey("key");

?

如果启动指定版本的流程定义?,?用下面的方法?:

?

ProcessInstance processInstance =executionService.startProcessInstanceById("ID");

?

7.?使用变量

当一个新的流程实例启动时就会提供一组对象参数。 将这些参数放在variables?变量里, 然后可以在流程实例创建和启动时使用。

Map<String,Object> variables = new HashMap<String,Object>();

variables.put("customer", "John Doe");

variables.put("type", "Accident");

variables.put("amount", new Float(763.74));

?

ProcessInstance processInstance =

????executionService.startProcessInstanceByKey("ICL", variables);

8.?执行等待的流向:

当使用一个?state?活动时,执行(或流程实例) 会在到达state?的时候进行等待,

直到一个signal?(也叫外部触发器)出现。?signalExecution?方法可以被用作这种情况。

执行通过一个执行id?(字符串)来引用。

executionService.signalExecutionById(executionId);

9.TaskService?任务服务:

TaskService?的主要目的是提供对任务列表的访问途径。 例子代码会展示出如何为id?为?johndoe的

用户获得任务列表:

List<Task> taskList = taskService.findPersonalTasks("johndoe");

?

?

JBPM4 –ProcessEngine

在jBPM?内部通过各种服务相互作用。 服务接口可以从ProcessEngine?中获得, 它是从Configuration?构建的。

获得ProcessEngine?:?processEngine?=Configuration.getProcessEngine?();

?

JBPM4 – RepositoryService

RepositoryService?包含了用来管理发布资源的所有方法。

部署流程

String deploymentid = repositoryService.createDeployment()??
??? .addResourceFromClasspath("org/jbpm/examples/services/Order.jpdl.xml")??
??? .deploy();?

ZipInputStream zis =?new?ZipInputStream(?this?.getClass()

??????????????.getResourceAsStream(?"/com/jbpm/source/leave.zip"?));

//?发起流程,仅仅就是预定义任务,即在系统中创建一个流程,这是全局的,与具体的登陆?用户无关。然后,在启动流程时,才与登陆用户关联起来

String?did?=?repositoryService?.createDeployment()

??????????????.addResourcesFromZipInputStream(zis).deploy();?
通过上面的?addResourceFromClass?方法,流程定义?XML?的内容可以从文件,网址,字符串,输入流或?zip输入流中获得。

每次部署都包含了一系列资源。每个资源的内容都是一个字节数组。?jPDL?流程文件都是以?.jpdl.xml?作为扩展名的。其他资源是任务表单和?java?类。

部署时要用到一系列资源,默认会获得多种流程定义和其他的归档类型。?jPDL?发布器会自动识别后缀名是.jpdl.xml?的流程文件。

在部署过程中,会把一个?id?分配给流程定义。这个?id?的格式为?{key}-{version}?,?key?和?version?之间使用连字符连接。

如果没有提供?key?(指在流程定义文件中,对流程的定义),会在名字的基础自动生成。生成的?key?会把所有不是字母和数字的字符替换成下划线。

同一个名称只能关联到一个?key?,反之亦然。

如果没有为流程文件提供版本号,?jBPM?会自动为它分配一个版本号。请特别注意那些已经部署了的名字相同的流程文件的版本号。它会比已经部署的同一个?key?的流程定义里最大的版本号还大。没有部署相同?key?的流程定义的版本号会分配为?1?。

删除流程定义

删除一个流程定义会把它从数据库中删除。

repositoryService.deleteDeployment(deploymentId);?

如果在发布中的流程定义还存在活动的流程实例,这个方法就会抛出异常。

如果希望级联删除一个发布中流程定义的所有流程实例,可以使用?deleteDeploymentCascade?。

JBPM4 – TaskService

TaskService?的主要目的是提供对任务列表的访问途径。?例子代码会展示出如何为?id?为?johndoe?的用户获得任务列表

List<Task> taskList = taskService.findPersonalTasks("johndoe");?

一般来说,任务会对应一个表单,然后显示在一些用户接口中。?表单需要可以读写与任务相关的数据。

// read task variables??
Set<String> variableNames = taskService.getVariableNames(taskId);??
variables = taskService.getVariables(taskId, variableNames);?

// write task variables??
variables = new HashMap<String, Object>();??
variables.put("category", "small");??
variables.put("lires", 923874893);??
taskService.setVariables(taskId, variables);?


taskSerice?也用来完成任务。?
taskService.completeTask(taskId);??
taskService.completeTask(taskId, variables);??
taskService.completeTask(taskId, outcome);??
taskService.completeTask(taskId, outcome, variables);?

这些?API?允许提供一个变量?map?,它在任务完成之前作为流程变量添加到流程里。?它也可能提供一个?“?外出outcome”?,这会用来决定哪个外出转移会被选中。?逻辑如下所示:

如果一个任务拥有一个没用名称的外向转移:?
taskService.getOutcomes()?返回包含一个?null?值集合,。?
taskService.completeTask(taskId)?会使用这个外向转移。?
taskService.completeTask(taskId, null)?会使用这个外向转移。?
taskService.completeTask(taskId, "anyvalue")?会抛出一个异常。

如果一个任务拥有一个有名字的外向转移:?
taskService.getOutcomes()?返回包含这个转移名称的集合。?
taskService.completeTask(taskId)?会使用这个单独的外向转移。?
taskService.completeTask(taskId, null)?会抛出一个异常(因为这里没有无名称的转移)。?
taskService.completeTask(taskId, "anyvalue")?会抛出一个异常。?
taskService.completeTask(taskId, "myName")?会根据给定的名称使用转移。

如果一个任务拥有多个外向转移,其中一个转移没有名称,其他转移都有名称:?
taskService.getOutcomes()?返回包含一个?null?值和其他转移名称的集合。?
taskService.completeTask(taskId)?会使用没有名字的转移。?
taskService.completeTask(taskId, null)?会使用没有名字的转移。?
taskService.completeTask(taskId, "anyvalue")?会抛出异常。?
taskService.completeTask(taskId, "myName")?会使用名字为?'myName'?的转移。

如果一个任务拥有多个外向转移,每个转移都拥有唯一的名字:?
taskService.getOutcomes()?返回包含所有转移名称的集合。?
taskService.completeTask(taskId)?会抛出异常,因为这里没有无名称的转移。?
taskService.completeTask(taskId, null)?会抛出异常,因为这里没有无名称的转移。?
taskService.completeTask(taskId, "anyvalue")?会抛出异常。?
taskService.completeTask(taskId, "myName")?会使用名字为?'myName'?的转移。

任务可以拥有一批候选人。候选人可以是用户也可以是用户组。用户可以接收自己是候选人的任务。接收任务的意思是用户会被设置为被分配给任务的人。在那之后,其他用户就不能接收这个任务了。

人们不应该在任务做工作,除非他们被分配到这个任务上。用户界面应该显示表单,如果他们被分配到这个任务上,就允许用户完成任务。对于有了候选人,但是还没有分配的任务,唯一应该暴露的操作就是?“?接收任务?”?。

?

JBPM4 – ExecutionService

最新的流程实例?-- ByKey?
下面是为流程定义启动一个新的流程实例的最简单也是?最常用的方法:

ProcessInstance processInstance = executionService.startProcessInstanceByKey?("ICL");

上面?service?的方法会去查找?key?为?ICL?的最新版本的流程定义,?然后在最新的流程定义里启动流程实例。

当?key?为?ICL?的流程部署了一个新版本,?startProcessInstanceByKey?方法会自动切换到最新部署的版本。

原来已经启动的流程,还是按照启动时刻的版本执行。


指定流程版本?-- ById?
换句话说,你如果想根据特定的版本启动流程实例,?便可以使用流程定义的?id?启动流程实例。如下所示:

ProcessInstance processInstance = executionService.startProcessInstanceById?("ICL-1");


使用?key

我们可以为新启动的流程实例分配一个?key(?注意:?这个?key?不是?process?的?key?,而是启动的?instance?的key )?,这个?key?是用户执行的时候定义的,有时它会作为?“?业务?key”?引用。一个业务?key?必须在流程定义的所有版本范围内是唯一的。通常很容易在业务流程领域找到这种?key?。比如,一个订单?id?或者一个保险单号。?
ProcessInstance processInstance = executionService.startProcessInstanceByKey?("ICL", "CL92837");

// 2?个参数:?
//??第一个参数?processkey?,通过这个?key?启动?process?的一个实例?
//??第二个参数为这里所说的实例?key(instance key)

key?可以用来创建流程实例的?id?,格式为?{process-key}.{execution-id}?。所以上面的代码会创建一个?id为?ICL.CL92837?的流向(?execution?)。

如果没有提供用户定义的?key?,数据库就会把主键作为?key?。?这样可以使用如下方式获得?id?:?
ProcessInstance processInstance = executionService.startProcessInstanceByKey?("ICL");?
String pid = processInstance.getId();

最好使用一个用户定义的?key?。?特别在你的应用代码中,找到这样的?key?并不困难。提供给一个用户定义的key?,你可以组合流向的?id?,而不是执行一个基于流程变量的搜索?-?那种方式太消耗资源了。

使用变量

当一个新的流程实例启动时就会提供一组对象参数。?将这些参数放在?variables?变量里,?然后可以在流程实例创建和启动时使用。?
Map<String,Object> variables = new HashMap<String,Object>();?
variables.put("customer", "John Doe");?
variables.put("type", "Accident");?
variables.put("amount", new Float(763.74));

ProcessInstance processInstance = executionService.startProcessInstanceByKey?("ICL", variables);

启动?instance

启动?instance?,必须要知道?processdefinition?的信息:?processdefinition?可以通过?2?种方式获取:?
ByKey?:通过?ProcessKey?,启动该?Process?的最新版本?
ById?:???通过?Process?的?ID?,启动该?Process?的特定的版本

其他的参数,其余还可以在启动?Instance?的时候,给流程?2?个参数:?
InstanceKey?:这个?instanceKey?必须在整个流程定义的所有范围版本中唯一,如果用户不给于提供,系统也会自己生成;?
一个?Map<String, ?>?表:启动流程时候给予的变量信息

执行等待的流向

当使用一个?state?活动时,执行(或流程实例)会在到达?state?的时候进行等待,直到一个?signal?(也叫外部触发器)出现。?signalExecution?方法可以被用作这种情况。执行通过一个执行?id?(字符串)来引用。

在一些情况下,到达?state?的执行会是流程实例本身。但是这不是一直会出现的情况。在定时器和同步的情况,流程是执行树形的根节点。所以我们必须确认你的?signal?作用在正确的流程路径上。

获得正确的执行的比较好的方法是给?state?活动分配一个事件监听器,像这样:?
<state name="wait">??
? <on event="start">??
??? <event-listener />??
? </on>??
? ...??
</state>?

在事件监听器?StartExternalWork?中,你可以执行那些需要额外完成的部分。在这个事件监听器里,你也可以通过?execution.getId()?获得确切的流程?id?。那个流程?id?,在额外的工作完成后,你会需要它来提供给?signal操作的:

executionService.signalExecutionById?(executionId);?

这里有一个可选的(不是太推荐的)方式,来获得流程?id?,当流程到达?state?活动的时候。只可能通过这种方式获得执行?id?,如果你知道哪个?JBPM API?调用了之后,流程会进入?state?活动:

// assume that we know that after the next call??
// the process instance will arrive in state external work??
ProcessInstance processInstance = executionService.startProcessInstanceById(processDefinitionId);?

// or ProcessInstance processInstance =??
//? executionService.signalProcessInstanceById(executionId);??
Execution execution = processInstance.findActiveExecutionIn("external work");??
String executionId = execution.getId();?

?

JBPM4 – HistoryService

在流程实例执行的过程中,会不断触发事件。从那些事件中,运行和完成流程的历史信息会被收集到历史表中。

HistoryService?提供了?对那些信息的访问功能。

如果想查找某一特定流程定义的所有流程实例,?可以像这样操作:

List<HistoryProcessInstance> historyProcessInstances = historyService??
? .createHistoryProcessInstanceQuery()??
? .processDefinitionId("ICL-1")??
? .orderAsc(HistoryProcessInstanceQuery.PROPERTY_STARTTIME)??
? .list();?

单独的活动流程也可以作为?HistoryActivityInstance?保存到历史信息中。

List<HistoryActivityInstance> histActInsts = historyService??
??? .createHistoryActivityInstanceQuery()??
??? .processDefinitionId("ICL-1")??
??? .activityName("a")??
??? .list();?

也可以使用简易方法?avgDurationPerActivity?和?choiceDistribution?。可以通过?javadocs?获得这些方法的更多信息。

有时,我们需要获得指定流程实例已经过的节点的完整列表。下面的查询语句可以用来获得所有已经执行的节点列表:

List<HistoryActivityInstance> histActInsts = historyService??
??? .createHistoryActivityInstanceQuery()??
??? .processInstanceId("ICL.12345")??
??? .list();?

上面的查询与通过?execution id?查询有一些不同。有时?execution id?和流程实例?id?是不同的,?当一个节点中使用了定时器,?execution id?中就会使用额外的后缀,?这就会导致当我们通过?execution id?查询时,?这个节点不会出现在结果列表中。

?

整合过程中常见问题的解决

错误?1?:?java.lang.LinkageError: loader constraint violation: when resolving interface method "javax.servlet.jsp.JspApplicationContext.getExpressionFactory()Ljavax/el/ExpressionFactory;" the class loader (instance of org/apache/jasper/servlet/JasperLoader) of the current class, org/apache/jsp/index_jsp, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, javax/servlet/jsp/JspApplicationContext, have different Class objects for the type javax/el/ExpressionFactory used in the signature

错误的解决办法。(?Tomcat6.0.28?)

exception

javax.servlet.ServletException: java.lang.LinkageError: loader constraint violation: when resolving interface method "javax.servlet.jsp.JspApplicationContext.getExpressionFactory()Ljavax/el/ExpressionFactory;" the class loader (instance of org/apache/jasper/servlet/JasperLoader) of the current class, org/apache/jsp/OnDuty/wfmanage_jsp, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, javax/servlet/jsp/JspApplicationContext, have different Class objects for the type javax/el/ExpressionFactory used in the signature org.apache.jasper.servlet.JspServlet.service(JspServlet.java:275) javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

?

root cause

java.lang.LinkageError: loader constraint violation: when resolving interface method "javax.servlet.jsp.JspApplicationContext.getExpressionFactory()Ljavax/el/ExpressionFactory;" the class loader (instance of org/apache/jasper/servlet/JasperLoader) of the current class, org/apache/jsp/OnDuty/wfmanage_jsp, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, javax/servlet/jsp/JspApplicationContext, have different Class objects for the type javax/el/ExpressionFactory used in the signature org.apache.jsp.OnDuty.wfmanage_jsp._jspInit(wfmanage_jsp.java:27) org.apache.jasper.runtime.HttpJspBase.init(HttpJspBase.java:52) org.apache.jasper.servlet.JspServletWrapper.getServlet(JspServletWrapper.java:159) org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:329) org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342) org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267) javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

?

原因是项目中WEB-INF/lib?中的三个jar?包?(juel.jar, juel-engine.jar, juel-impl.jar?)和tomcat6?下lib?中jar?包(?el-api.jar?)?冲突

解决方法:?

方法一:换成tomcat5.5?一点问题也没有了(有新版本了还用老版本?)

?

方法二:将?juel.jar, juel-engine.jar, juel-impl.jar?这三个包复制到tomcat6?下lib?中,并删除原来的?el-api.jar?,切记要把WEB-INF/lib?中的juel.jar, juel-engine.jar, juel-impl.jar?删除。不然还是要冲突。

错误?2?:?org.jbpm.api.JbpmException: No unnamed transitions were found for the task '??'

如果一个任务拥有一个没用名称的外向转移:

taskService.getOutcomes()?返回包含一个?null?值集合,。?taskService.completeTask(taskId)?会使用这个外向转移。?taskService.completeTask(taskId, null)?会使用这个外向转移。taskService.completeTask(taskId, "anyvalue")?会抛出一个异常。

如果一个任务拥有一个有名字的外向转移:

gtaskService.getOutcomes()?返回包含这个转移名称的集合。?taskService.completeTask(taskId)?会使用这个单独的外向转移。?taskService.completeTask(taskId, null)?会抛出一个异常(因为这里没有无名称的转移)。?taskService.completeTask(taskId, "anyvalue")?会抛出一个异常。taskService.completeTask(taskId, "myName")?会根据给定的名称使用转移。

如果一个任务拥有多个外向转移,其中一个转移没有名称,其他转移都有名称:

taskService.getOutcomes()?返回包含一个?null?值和其他转移名称的集合。taskService.completeTask(taskId)?会使用没有名字的转移。?taskService.completeTask(taskId, null)?会使用没有名字的转移。?taskService.completeTask(taskId, "anyvalue")?会抛出异常。taskService.completeTask(taskId, "myName")?会使用名字为?'myName'?的转移。

如果一个任务拥有多个外向转移,每个转移都拥有唯一的名字:

taskService.getOutcomes()?返回包含所有转移名称的集合。?taskService.completeTask(taskId)?会抛出异常,因为这里没有无名称的转移。?taskService.completeTask(taskId, null)?会抛出异常,因为这里没有无名称的转移。?taskService.completeTask(taskId, "anyvalue")?会抛出异常。taskService.completeTask(taskId, "myName")?会使用名字为?'myName'?的转移。

?

解决方案:

?

根据以上分析,可得到解决方案:

?

1?、只拥有一个外向转移时(对应上文所述?1?、?2?情况):

?

Map map = new HashMap();

map.put("",……?)?//?各种参数

taskService.setVariables(taskId,map);

taskService.completeTask(taskId);

?

3?、拥有多个外向转移时(上文?3?、?4?种情况):

Map map = new HashMap();

map.put("",……?)?//?各种参数

taskService.setVariables(taskId,map);

?

//?如想转移至有名称的外向转移:

taskService.completeTask(taskId,"?外向转移名称?");

?

//?如想转移至无名称的外向转移:

taskService.completeTask(taskId);

错误3?:*.jpdl.xml?中文乱码问题。

在myeclipse?的配置文件myeclipse.ini?中加入:

-DFile.encoding=UTF-8

?

请假流程例子(?s2sh+jbpm?)

【Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8调整例子】

?

流程图:

【Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8调整例子】

?

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

?

<?process?name?=?"leave"?xmlns?=?"http://jbpm.org/4.4/jpdl"?>

???<?start?g?=?"214,37,48,48"?name?=?"start1"?>

??????<?transition?g?=?"-47,-17"?name?=?"to?申请?"?to?=?"?申请?"?/>

???</?start?>

???<?task?assignee?=?"#{owner}"?form?=?"request.html"?g?=?"192,126,92,52"?name?=?"?申请?">

??????<?transition?g?=?"-71,-17"?name?=?"to?经理审批?"?to?=?"?经理审批?"?/>

???</?task?>

???<?task?assignee?=?"manager"?form?=?"manager.html"?g?=?"194,241,92,52"?name?=?"?经理审批?"?>

??????<?transition?g?=?"-29,-14"?name?=?"?批准?"?to?=?"exclusive1"?/>

??????<?transition?g?=?"105,267;103,152:-47,-17"?name?=?"?驳回?"?to?=?"?申请?"?/>

???</?task?>

???<?decision?expr?=?"#{day > 3 ? '?老板审批?' : '?结束?'}"?g?=?"218,342,48,48"?name?="exclusive1"?>

??????<?transition?g?=?"415,367:-47,-17"?name?=?"?老板审批?"?to?=?"?老板审批?"?/>

??????<?transition?g?=?"-31,-16"?name?=?"?结束?"?to?=?"end1"?/>

???</?decision?>

???<?end?g?=?"219,499,48,48"?name?=?"end1"?/>

???<?task?assignee?=?"boss"?form?=?"boss.html"?g?=?"370,408,92,52"?name?=?"?老板审批?"?>

??????<?transition?g?=?"415,524:-91,-18"?name?=?"?结束?"?to?=?"end1"?/>

???</?task?>

</?process?>

步骤:

发布流程:将画好的流程图,发布到jbpm?框架中(放到jbpm?数据库中),这个流程是全局的,与用户无关。发布流程后会返回一个流程id?,我们会用流程id?得到?ProcessDefinition?流程定义。?发布方法如下:

public?void?deploy() {

???????// repositoryService.createDeployment().addResourceFromClasspath(

???????// "/com?/jbpm?/source/leave.jpdl.xml").deploy();

???????ZipInputStream zis =?new?ZipInputStream(?this?.getClass()

??????????????.getResourceAsStream(?"/com/jbpm/source/leave.zip"?));

???????//?发起流程,仅仅就是预定义任务,即在系统中创建一个流程,这是全局的,与具体的登陆?用户无关。然后,在启动流程时,才与登陆用户关联起来

???????String?did?=?repositoryService?.createDeployment()

??????????????.addResourcesFromZipInputStream(zis).deploy();

????}

启动流程:流程定义好后,并不能用,我们需要将其实例化,实例化流程将关联用户,同时将实例写入数据库中。启动流程方法如下:

public?void?start(String?id, Map<String?, Object> map) {

???????executionService?.startProcessInstanceById(id, map);

????}

流程一旦启动就通过start?节点,流到下一个任务节点。

获取待办任务列表:不同的用户登录后通过如下方式获得自己的待办任务

????public?List<Task> getTasks(String roleName) {

???????return?taskService?.findPersonalTasks(roleName);

????}

在流程中每一个任务节点都关联了一个?action?请求,用于处理待办任务的视图(?view?)

不多说了,哥就相信源码:?http://download.csdn.net/source/3223403

总结及参考文章:

参考文章:http://www.blogjava.net/paulwong/archive/2009/09/07/294114.html

http://zjkilly.iteye.com/blog/738426

http://fish119.iteye.com/blog/779379

?

http://alimama.iteye.com/blog/567651

其他参考资料:?family168?网,?http://code.google.com/p/family168/downloads/list

?

控制流程活动:

【Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8调整例子】

原子活动:

【Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8调整例子】

?

?

转自:http://blog.csdn.net/centre10/article/details/6361104

热点排行