原文:工作流Jpbm4.4工作流知识点总结(工作流开发宝典)

Jbpm工作流开发过程中的一些知识点总结,方便以后开发使用!

目录:

一、工作流框架的搭建

二、工作流框架的流程开发

  1、管理流程定义

    ①部署流程定义

    ②查询流程定义

    ③删除流程定义

    ④获取部署对象中的文件资源内容

    ⑤ 获取流程图中某活动的坐标

  2、执行流程实例

    ①启动流程实例

    ②向后执行一步

    ③查询任务

    ④完成任务

    ⑤拾取任务

    ⑥获取流程中的变量

三、Jbpm和spring整合

第一章 工作流框架的搭建

1.1. 准备jBPM4.4的开发环境

1.1.1. 添加jBPM4.4的jar包

  1. ${JBPM_HOME}/jbpm.jar(核心包)
  2. JBPM_HOME/lib/*.jar,不添加以下jar包:servlet-api.jar, junit.jar。其中junit.jar一定不要添加,因为是3.8.2版本,与我们使用的junit4有冲突。
  3. 所使用的数据库对应的驱动的jar包(第2步所添加的jar包中已包含mysql的jdbc驱动jar包)。
  4. 配置文件可以从JBPM_HOME/examples/src/中拷贝:
    jbpm.cfg.xml、
    logging.properties、//要注意版本的问题,接口和实现类要相同版本
    jbpm.hibernate.cfg.xml。
  5. 修改logging.properties中的日志输出级别为WARNING: java.util.logging.ConsoleHandler.level=WARNING
  6. 修改jbpm.hibernate.cfg.xml中的数据库连接信息。如果使用MySQL,使用的方言一定要是org.hibernate.dialect.MySQL5InnoDBDialect。
  7. 数据库连接编码一定要是UTF-8。否则可能会在部署含有中文字符的流程定义时会抛异常,说sql语法错误。

第二章 工作流框架的流程开发

1.1. 部署流程定义

注意区分Deployment与ProcessDefinition

1.1.1. 示例代码1:流程定义有关文件在classpath中

String deploymentId = processEngine.getRepositoryService()

.createDeployment()

.addResourceFromClasspath("process/test.jpdl.xml")

.addResourceFromClasspath("process/test.png")

.deploy();

1.1.2. 示例代码2:一次添加多个流程定义有关文件(要先打成zip包)

String deploymentId = processEngine.getRepositoryService()

.createDeployment()

.addResourcesFromZipInputStream(zipInputStream)

.deploy();

1.1.3. 说明

1, .addResourceFromClasspath(resource); 可以调用多次以添加多个文件。文件重复添加也不会报错。

2, .addResourceFromInputStream(resourceName, inputStream)添加一个文件(使用InputStream)

3, .addResourcesFromZipInputStream(zipInputStream)添加多个文件,里面也可以有文件夹。

4, 以上方法可以在一起调用。

1.2. 删除流程定义

1.2.1. 示例代码1:删除流程定义,如果有关联的流程实例信息则报错

repositoryService.deleteDeployment(deploymentId);

1.2.2. ?示例代码2:删除流程定义,并删除关联的流程实例与历史信息

repositoryService.deleteDeploymentCascade(deploymentId);

关联:关联的流程实例,就是流程定义中执行过的那些实例【已经放到了历史表中,级联删除的就是同时删除那些执行过了的实例】,

1.3. 查询流程定义

1.3.1. 相关查询API说明:ProcessDefinitionQuery

RepositoryService.createProcessDefinitionQuery()

1.3.2. 示例代码1:查询所有流程定义

// 1,构建查询

ProcessDefinitionQuery pdQuery = processEngine.getRepositoryService()

.createProcessDefinitionQuery()//

.orderAsc(ProcessDefinitionQuery.PROPERTY_NAME)//

.orderDesc(ProcessDefinitionQuery.PROPERTY_VERSION);

// 2,查询出总数量与数据列表

long count = pdQuery.count();

List<ProcessDefinition> list = pdQuery.page(0, 100).list();// 分页:取出前100条记录

// 3,显示结果

System.out.println(count);

for (ProcessDefinition pd : list) {

System.out.println("id=" + pd.getId()//

+ ",deploymentId=" + pd.getDeploymentId()//

+ ",name=" + pd.getName()//

+ ",version=" + pd.getVersion()//

+ ",key=" + pd.getKey()); //

}

1.3.3. 示例代码2:查询所有最新版本的流程定义列表

// 1,查询,按version升序排序,则最大版本排在最后面

List<ProcessDefinition> all = processEngine.getRepositoryService()//

.createProcessDefinitionQuery()//

.orderAsc(ProcessDefinitionQuery.PROPERTY_VERSION)

.list();

// 2,过滤出所有不同Key的最新版本(因为最大版本在最后面)

Map<String, ProcessDefinition> map = new HashMap<String, ProcessDefinition>(); // map的key是流程定义的key,map的vlaue是流程定义对象

for (ProcessDefinition pd : all) {

map.put(pd.getKey(), pd);

}

Collection<ProcessDefinition> result = map.values();

// 3,显示结果

for (ProcessDefinition pd : result) {

System.out.println("deploymentId=" + pd.getDeploymentId()//

+ ",\t id=" + pd.getId()// 流程定义的id,格式:{key}-{version}

+ ",\t name=" + pd.getName()

+ ",\t key=" + pd.getKey()

+ ",\t version=" + pd.getVersion());

}

1.4. 获取部署对象中的文件资源内容

// 资源的名称,就是 jbpm4_lob 表中的 NAME_ 列表值

String deploymentId = "90001";

String resourceName = "test.png";

InputStream in = processEngine.getRepositoryService()

.getResourceAsStream(deploymentId, resourceName);

1.5. 获取流程图中某活动的坐标

String processDefinitionId = "test-1"; // 流程定义的id

String activityName = "start1"; // 活动的名称

ActivityCoordinates c = processEngine.getRepositoryService()

.getActivityCoordinates(processDefinitionId, activityName);

System.out.println("x=" + c.getX()

+ ",y=" + c.getY()

+ ",width=" + c.getWidth()

+ ",height=" + c.getHeight());

2. 执行流程实例

2.1. 启动流程实例

说明:流程实例创建后,直接就到开始活动后的第一个活动,不会在开始活动停留。

2.1.1. 示例代码1:使用指定key的最新版本的流程定义启动流程实例

ProcessInstance pi = processEngine.getExecutionService()

.startProcessInstanceByKey(processDefinitionKey);

2.1.2. 示例代码2:使用指定key的最新版本的流程定义启动流程实例,并设置一些流程变量

// 准备流程变量

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

variables.put("申请人", "张三");

variables.put("报销金额", 1000.00);

// 启动流程实例,并设置一些流程变量

ProcessInstance pi = processEngine.getExecutionService()

.startProcessInstanceByKey(processDefinitionKey, variables);

2.2. 向后执行一步(Signal)

2.2.1. 示例代码1:向后执行一步,使用唯一的outcome离开活动

processEngine.getExecutionService().signalExecutionById(executionId);

2.2.2. 示例代码2:向后执行一步,使用唯一的outcome离开活动,并设置一些流程变量

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

variables.put("审批结果", "同意");

processEngine.getExecutionService()

.signalExecutionById(executionId, variables);

2.2.3. 示例代码3:向后执行一步,使用指定的outcome离开活动

String outcome= "to end1";

processEngine.getExecutionService()

.signalExecutionById(executionId, outcome);

2.2.4. 示例代码4:向后执行一步,使用指定的outcome离开活动,并设置一些流程变量

String outcome= "to end1";

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

variables.put("审批结果", "同意");

processEngine.getExecutionService()

.signalExecutionById(executionId, outcome, variables);

2.3. 查询任务

2.3.1. 查询个人任务列表

方式1:TaskService.findPersonalTasks(userId);

方式2:List<Task> list = taskService.createTaskQuery()

.assignee(userId)

.list();

// 显示任务信息

for (Task task : taskList) {

System.out.println("id=" + task.getId()// 任务的id

+ ",name=" + task.getName()// 任务的名称

+ ",assignee=" + task.getAssignee()// 任务的办理人

+ ",createTime=" + task.getCreateTime() // 任务的创建(生成)的时间

+ ",executionId=" + task.getExecutionId());// 任务所属流程实例的id

}

2.3.2. 查询组任务列表

方式1: taskService.findGroupTasks(userId);

方式2: List<Task> list = processEngine.getTaskService()//

.createTaskQuery()//

.candidate(userId)//

.list();

2.4. 完成任务

2.4.1. 正常完成任务(也可以同时设置一些流程变量)

String taskId = "420001";

processEngine.getTaskService().completeTask(taskId);

processEngine.getTaskService().completeTask(taskId, outcome);

processEngine.getTaskService().completeTask(taskId, outcome, variables);

2.4.2. 自行控制任务完成后是否可向后流转

String taskId = "420001";

// 1,设置为false代表:办理完任务后不向后移动(默认为true)

TaskImpl taskImpl = (TaskImpl) processEngine

.getTaskService().getTask(taskId);

taskImpl.setSignalling(false);

// 2,办理完任务

processEngine.getTaskService().completeTask(taskId);

2.5. 拾取任务

1, TaskService.takeTask(taskId, userId),拾取组任务到个人任务列表中,如果任务有assignee,则会抛异常。

2, processEngine.getTaskService().assignTask(taskId, userId),转交任务给其他人,(如果任务有assignee,则执行这个方法代表重新分配。也可以把assignee设为null表示组任务没有人办理了)

2.6. 设置与获取流程变量

2.6.1. 设置流程变量

2.6.1.1. 方式1:根据 executionId 设置或获取流程变量

ExecutionService.setVariable(executionId, name, value);

Object obj = executionService.getVariable(executionId, "请假人");

2.6.1.2. 方式2:根据 taskId 设置或获取流程变量

TaskService.setVariables(taskId, variables); // 一次设置多个变量

Object obj = executionService.getVariable(executionId, "请假人");

2.6.1.3. 流程变量所支持的值的类型(jBPM User Guide,7.2. Variable types)

7.2. Variable types

jBPM supports following Java types as process variables:

java.lang.String

java.lang.Long

java.lang.Double

java.util.Date

java.lang.Boolean

java.lang.Character

java.lang.Byte

java.lang.Short

java.lang.Integer

java.lang.Float

byte[] (byte array)

char[] (char array)

hibernate entity with a long id

hibernate entity with a string id

serializable

For persistence of these variable, the type of the variable is checked in the order of this list. The first match will determine how the variable is stored.

2.7. 直接结束流程实例(自己手工结束)

String processInstanceId =  "test.10001";

processEngine.getExecutionService()

.endProcessInstance(processInstanceId, ProcessInstance.STATE_ENDED);

第三章  jbpm与spring整合

1.1. 与Spring集成(jBPM4.4 Developers Guide, Chapter 17. Spring Integration)

1.1.1. 在jbpm.cfg.xml中

1,删除配置:<import resource="jbpm.tx.hibernate.cfg.xml" />

2,增加配置:<import resource="jbpm.tx.spring.cfg.xml" />

1.1.2. 在applicationContext.xml中配置

<!-- 配置ProcessEngine(整合jBPM4) -->

<!-- jbpmCfg是相对于classpath的相对路径,默认值为jbpm.cfg.xml -->

<bean id="springHelper"

class="org.jbpm.pvm.internal.processengine.SpringHelper">

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

</bean>

<bean id="processEngine" factory-bean="springHelper"

factory-method="createProcessEngine" />

1.1.3. 测试

@Test // 测试ProcessEngine

public void testProcessEngine() {

ProcessEngine processEngine = (ProcessEngine)ac.getBean("processEngine");

Assert.assertNotNull(processEngine);

}

1.1.4. 注意事项

如果做了JBPM4.4与Spring整合(使用了jbpm.tx.spring.cfg.xml),则在程序中就一定要使用Spring注入ProcessEngine,千万不能使用Configuration.getProcessEngine()生成ProcessEngine,因为这时内部的代码有以下逻辑:如果整合了Spring但没有ApplicationContext,就默认读取applicationContext.xml创建ApplicationContext实例并从中获取名为”ProcessEngine”的对象。而这时如果把pe = Configuration.getProcessEngine()写成某Spring中管理的bean的初始化代码,就会有无限循环,不停的创建ApplicationContext了!

1.2. 自行控制事务

1, 修改 jbpm.tx.hibernate.cfg.xml

a) 不让jBPM自行管理事务:去掉<standard-transaction-interceptor />

b) 让Jbpm使用SessionFactory.getCurrentSession():修改为 <hibernate-session current="true" />

2, 配置可以使用SessionFactory.getCurrentSession(),在jbpm.hibernate.cfg.xml 中配置:<property name="hibernate.current_session_context_class">thread</property>

3, 要使用同一个SessionFactory,且都要使用 SessionFactory.getCurrentSession() 获取 Session:

a) 同一个SessionFactory:SessionFactory sf = processEngine.get(SessionFactory.class)

b) 在 BaseDaoImpl 中增加:

  1. getSession() { return HibernateUtils.getSessionFactory().getCurrentSession(); }
  2. getProcessEngine(){ return org.jbpm.api.Configuration.getProcessEngine(); }

4, 统一的打开与提交或回滚事务:使用 OpenSessionInViewFilter 控制事务。

1.3. 启动Tomcat后,访问JSP时(使用的是MyEclipse自带的Tomcat,是6.0的版本),报错:   Caused by: java.lang.LinkageError: loader constraints violated when linking javax/el/ExpressionFactory class

at org.apache.jsp.WEB_002dINF.jsp.UserAction.loginUI_jsp._jspInit(loginUI_jsp.java:39)

at org.apache.jasper.runtime.HttpJspBase.init(HttpJspBase.java:52)

at org.apache.jasper.servlet.JspServletWrapper.getServlet(JspServletWrapper.java:159)

at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:329)

at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320)

at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266)

... 40 more

说明:原因是Jbpm的juel.jar, juel-engine.jar, juel-impl.jar包和Tomcat6.0中的el-api.jar包冲突了。

有三个解决办法:

1,方法一:在MyEclipse的Preferences -> MyEclipse -> Application Servers -> Tomcat -> .. -> Paths 中配置 Append to classpath,选中 juel.jar, juel-engine.jar, juel-impl.jar 这三个jar包就可以了。

2,方法二:将 juel.jar, juel-engine.jar, juel-impl.jar 这三个包复制到tomcat6下 lib/ 中,并删除原来的el-api.jar,

切记还要把工程中 WEB-INF\lib 下的 juel.jar, juel-engine.jar, juel-impl.jar 删除,不然还是要冲突。

3,方法三:换成tomcat5.5,就没有问题了。

1.4. 完成流程实例中的最后一个任务时报错(任务实例结束时),或删除流程定义级联删除流程实例时,报错如下:

com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`itcastoa_20100909/jbpm4_execution`, CONSTRAINT `FK_EXEC_INSTANCE` FOREIGN KEY (`INSTANCE_`) REFERENCES `jbpm4_execution` (`DBID_`))

解决办法:把方言设为 MySQL5InnoDBDialect,不能是 MySQLDialect。

工作流Jpbm4.4工作流知识点总结(工作流开发宝典)的更多相关文章

  1. Activiti工作流学习(三)Activiti工作流与spring集成

    一.前言 前面Activiti工作流的学习,说明了Activiti的基本应用,在我们开发中可以根据实际的业务参考Activiti的API去更好的理解以及巩固.我们实际的开发中我们基本上都使用sprin ...

  2. 通达OA 在工作流中直接查询表单内容的开发尝试(图文)

    一个朋友提出要在工作里直接查询表单内容的需求,原来他们把工作流当做业务系统来用.也算把工作流用到极致了.为了实现像软件里直接的查询功能,他想在办理工作流的时候直接能查询到表单里面的内容. 通过研究通达 ...

  3. WF工作流与管理类应用系统工作流需求实现的一些误区

             如今实现各种应用系统大家都知道工作流是一个非常重要的环节,不同的业务系统的工作流需求是需要找相应的工作流产品去实现的,因为不同工作流产品的架构细节也许会成为某类需求实现的瓶颈. WF ...

  4. java知识点总结--java开发环境搭建

    安装 JDK(Java Development Kit) 和开发工具 如:eclipse,myeclipse,idea等 配置系统环境变量 查看系统环境变量 1.通过 我的电脑--->“属性”- ...

  5. IOS开发,知识点小结,ios开发中经常使用的宏定义总结

    IOS开发,从应用跳转到用浏览器打开网页: [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http:// ...

  6. Getting Real 开发宝典

       此书是管理者.程序员或设计师必学的宝典.它以更小的规模,更快的速度,更高的质量来完成软件开发,使产品更简单.粗暴(精致).      近百条精炼总结,不要奢望一次全部记住或理解,只要能理解或做到 ...

  7. iOS开发宝典:String用法大全

    一.NSString 创建字符串.  NSString *astring = @"This is a String!"; 创建空字符串,给予赋值.  NSString *astri ...

  8. winform快速开发平台 -> 工作流组件(仿GooFlow)

    对于web方向的工作流,一直在用gooflow对于目前我的winform开发平台却没有较好的工作流组件.  针对目前的项目经验告诉我们.一个工作流控件是很必要的. 当然在winform方面的工作流第三 ...

  9. SharePoint 2013 开发——工作流架构

    博客地址:http://blog.csdn.net/FoxDave SharePoint 2013的工作流较之前有了不同,第一次真正地作为独立的服务的概念推出了.这意味着SharePoint工作流不再 ...

随机推荐

  1. iOS发展- backBarButtonItem 颜色/文字修改

    iOS7之后. 默认返回button字体颜色为蓝色, 在父母的陈列柜VC(老界面)的title 假设做出改变, 通过下面的方法可以: 1. 更改字体颜色 (1) 在plist里面, 加View con ...

  2. MFC9.0 Outlook控件的标题显示无法改动

    这是我在开发中遇到的问题,现记录下来,以便帮助你们. 不想看废话的能够仅仅看最后三行,但你会错过非常多. 俗话说的好啊,"Wise men learn by other men's mist ...

  3. RH133读书笔记(11)-Lab 11 System Rescue and Troubleshooting

    Lab 11 System Rescue and Troubleshooting Goal: To build skills in system rescue procedures. Estimate ...

  4. .Net程序猿乐Android发展---(10)框架布局FrameLayout

    帧布局FrameLayout中全部的控件都在界面的左上側,后绘制的空间会覆盖之前的控件.布局内控件以层叠方式显示,用在游戏开发方面可能多些. 1.层叠展示                 以下这个样例 ...

  5. 刷牙LeetCode思考

    时间已经到了不自觉地,3在五月中旬.今天正式LeetCode自由181刷牙的问题.感觉,以提高他们的算法非常有帮助. 第一个主要的深搜索,广泛搜索,DP他已经掌握7788.也有自己写的代码格公式,使用 ...

  6. Android Studio Debug

    小米4usb调试怎么打开?miui6进入开发者模式想要打开USB调试首先开启开发者模式.过去在MIUI V5版本时,小米手机开启开发者模式的方法是连续点击Anroid版本号.不过最新上市的小米4都搭载 ...

  7. USACO dualpal

    /* ID:kevin_s1 PROG:dualpal LANG:C++ */ #include <iostream> #include <cstdio> #include & ...

  8. linux 终端下敲ctrl-c时,到底发生了什么?(转)

    通过telnet登录到单板,然后按ctrl-c会发生什么情况,流程是怎么样的? 在分析之前,先介绍tty的相关知识.我们可以认为,所有跟输入输出相关的操作,最终都由tty来接管.举例来说,当我们敲 l ...

  9. (大数据工程师学习路径)第三步 Git Community Book----Git基本用法(上)

    一.git的初始化 1.Git 配置 使用Git的第一件事就是设置你的名字和email,这些就是你在提交commit时的签名. $ git config --global user.name &quo ...

  10. list-style-type 去除li 前面的标记(小黑点)

    list-style-type 设置标记的样式(或者隐藏标记) <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//E ...