jbpm的使用

 

Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8 整合例子(附完整的请假流程例子)。javascript

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

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

3.       jbpm4.4 基础知识mysql

4.       整合过程当中常见问题的解决程序员

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

6.       总结及参考文章spring

jbpm4.4 测试环境搭建sql

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

 

快速搭建环境的步骤是:apache

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

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

双击每一项,确保每一项被加入到了

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

 

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

2.       搭建 jbpm 运行环境。

3 .而后配置jpdl 支持

4. 肯定是否配置jbpm 正确

在myeclipse->new->other->

关于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 的帮助文档,一点一点的学习。

说说以上文件的做用:第一个是 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 在管理流程时,是须要数据库表的支持的,由于底层的逻辑有那么复杂。默认下载下来的配置,使用的是( hsqldb )内存数据库。实际应用中,咱们就须要链接到咱们的数据库里来。因此要事先建好相关的表,相应的 sql 文件在 /jbpm-4.4/install/src/db 下,固然,你也可使用 hibernate hibernate.hbm2ddl.auto 自动建表,本人建议本身用建表语句,会少不少麻烦(本人在此处可没少碰麻烦)。 若是不结合其余的框架进行整个开发( 如:spring 、hibernate),JBPM4 也有本身的一套IOC 容器, 能后将本身的服务配置到IOC 容器中, 可以很容易的运行容器所配置的服务, 这样它也可以在代码中减小一陀一陀的工厂类等代码的调用, 下降了偶核性, 可是若是结合spring 框架来进行整个开发的话, 那么就有两个容器, 两个SessionFactory, 可是系统中只考虑一个容器来。对服务进行管理, 那么咱们就要将jbpm4 的服务移植到spring 的IOC 容器中, 让spring 来进行统一管理, 这样经过spring 的容器来管理服务、事务。

 

整合目标:将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 目录 install/src/db/create 下有:

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

每张表对应的含义:

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 class="org.jbpm.examples.StartExternalWork" /> 
  </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

 

流程图:

 

<? 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://zwllxs.iteye.com/blog/726303

 

 

 

总结及参考文章:

参考文章: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

 

控制流程活动:

原子活动:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted on 2011-07-24 16:20 SIMONE 阅读(15082) 评论(1)   编辑   收藏 所属分类: JAVA
 
相关文章
相关标签/搜索