工作流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。

时间: 2024-07-31 23:34:38

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

通达OA 在工作流中直接查询表单内容的开发尝试

一个朋友提出要在工作里直接查询表单内容的需求,原来他们把工作流当做业务系统来用,也算把工作流用到极致了.为了实现像软件里直接的查询功能,他想在办理工作流的时候直接能查询到表单里面的内容. 通过研究通达工作流数据库,找到新版本的工作流现在把数据完全单独存放在一个表中,每个流程有一个单独的数据表. 通过将相关数据整合查询,达到了预期的查询目的,鉴于通达OA原有程序很难修改,这里单独做了一个办理及办结工作的界面,待办工作可以直接点击"主办"来进行相应查询.办理完毕的流程则只能查看表单结果.

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

一.前言 前面Activiti工作流的学习,说明了Activiti的基本应用,在我们开发中可以根据实际的业务参考Activiti的API去更好的理解以及巩固.我们实际的开发中我们基本上都使用spring框架进行开发,现在来说明一下Activiti工作流与spring集成,Activiti工作流与spring集成还算比较简单,可以参考Activiti的API来进行整合. 二.Activiti常用的表 ---------------------------------------------部署对象

向军2017年最新laravel开发宝典 laravel结合vue与接口开发webapp实战视频教程

课程介绍:Laravel是一套简洁.优雅的PHP Web开发框架(PHP Web Framework).它不仅可以让我们从面条一样杂乱的代码中解脱出来,还可以帮我们构建一个完美的网络APP,而且每行代码都可以简洁.富于表达力.在Laravel中已经具有了一套高级的PHP ActiveRecord实现 -- Eloquent ORM.它能方便的将"约束(constraints)"应用到关系的双方,这样你就具有了对数据的完全控制,而且享受到ActiveRecord的所有便利.Eloquen

JEPLUS工作流之流程事件——JEPLUS软件快速开发平台

JEPLUS工作流之流程事件 当我们遇到业务流程复杂的情况,简单赋值跟显隐已解决不了我们实际的需求,需要流程事件来处理数据,流程事件是流程在流转每一个动作的时候触发.事件可赋值,可指定java的service方法,获取动态的人员也可指定后台方法来动态拼装获取,这篇文章我来介绍下怎么实现流程事件. 一.效果展示 二.实现步骤 1.首先流程事件是需要我们在后台操作的,这里需要我们平台的类生成器来生成一个类 在这里保存时会提示一个选择,我们需要选择为--流程事件 2.重启服务并刷新之后我们就可以看到我

JEPLUS工作流之分支聚合——JEPLUS软件快速开发平台

JEPLUS工作流之分支聚合 今天给大家介绍的是分支聚合流程,在选择分支时候需要指定该节点的下面分支的节点,然后分支的线路同时在进行处理,当全部处理完毕后到达聚合集合,自动流转到聚合节点的后置节点. 一.效果展示 二.实现步骤 1.创建流程--工作流引擎创建工作流 创建流程并给对应的标签命名 连接每个流程并给流程配置合适的处理人员 将完成标签设置来源分支,点击完成标签,点击来源分支框,选择分支标签 在最后一步就是点击表单内容的功能配置,启用工作流 原文地址:http://blog.51cto.c

Activiti工作流从入门到入土:工作流简介

文章源码托管:https://github.com/OUYANGSIHAI/Activiti-learninig欢迎 star !!! 一.activiti介绍 Activiti5是由Alfresco软件在2010年5月17日发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理.工作流.服务协作等领域的一个开源的.灵活的.易扩展的可执行流程语言框架.Activiti基于Apache许可的开源BPM平台,创始人Tom Baeyens是JBoss jBPM的项目架构师,它特色是提供了eclips

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

IOS开发,从应用跳转到用浏览器打开网页: [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://www.oatos.com/bbs/"]]; 用一个Button覆盖整个cell,添加动作 cell.accessoryType = UITableViewCellAccessoryNone; UIButton *btn = [[UIButton alloc] initWithFrame:CGRec

Getting Real 开发宝典

   此书是管理者.程序员或设计师必学的宝典.它以更小的规模,更快的速度,更高的质量来完成软件开发,使产品更简单.粗暴(精致).      近百条精炼总结,不要奢望一次全部记住或理解,只要能理解或做到其中几条对你的收获都是巨大的.37 signals真是一个让人非常尊敬和佩服的团队.感谢它们提供给我们这么实用的经验(里面有很多敏捷开发的精髓).非常推荐与开发有关的同志阅读它.  Getting Real 除掉...  花费数月,甚至数年的进度表 不切实际的功能规格文档 可伸缩性的争论 又臭又长的

iOS开发宝典:String用法大全

本文转载至 http://mobile.51cto.com/iphone-395171.htm 新手们还在等什么?这是一本属于你的iOS开发"字典",在这里你可以查到字符串.数组.字典的各式各样的用法与详述. AD:干货来了,不要等!WOT2015 北京站演讲PPT开放下载! 一.NSString 创建字符串.  NSString *astring = @"This is a String!"; 创建空字符串,给予赋值.  NSString *astring = [