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

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 原文:工作流Jpbm4.4工作流知识点总结(工作流开发宝典)Jbpm工作流开发过程中的一些知识点总结,方便以后开发使用! 目录: 一、工作流框架的搭建 二、工作流框架的流程开发   1、管理流程定义     ①部署流程定义     ②查询流程定义     ③删除流程定义     ④...
原文: 工作流Jpbm4.4工作流知识点总结(工作流开发宝典)

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

目录:

一、工作流框架的搭建

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

  1、管理流程定义

    ①部署流程定义

    ②查询流程定义

    ③删除流程定义

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

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

  2、执行流程实例

    ①启动流程实例

    ②向后执行一步

    ③查询任务

    ④完成任务

    ⑤拾取任务

    ⑥获取流程中的变量

三、Jbpm和spring整合

 

 

第一章 工作流框架的搭建

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

1.1.1. 添加jBPM4.4jar

  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包中已包含mysqljdbc驱动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>(); // mapkey是流程定义的keymapvlaue是流程定义对象

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. 查询个人任务列表

方式1TaskService.findPersonalTasks(userId);

 

方式2List<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.4Spring整合(使用了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) 同一个SessionFactorySessionFactory 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

 

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

有三个解决办法:

1,方法一:在MyEclipsePreferences -> 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

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
7天前
|
XML 分布式计算 监控
Oozie工作流管理系统设计与实践:面试经验与必备知识点解析
【4月更文挑战第9天】本文详述了Oozie工作流管理系统的核心概念,包括安装配置、Workflow XML、Action、Coordinator和Bundle XML定义。此外,讨论了工作流设计实践,如监控调试、自动化运维,并对比了Oozie与其他工作流工具的差异。文中还分享了面试经验及解决实际项目挑战的方法,同时展望了Oozie的未来发展趋势。通过学习,读者能提升Oozie技术能力,为面试做好充分准备。
22 0
|
存储 开发工具 数据库
搭建zotero到obsidian的工作流
所谓“工欲善其事,必先利其器”(差生文具多),想要针对一个领域研究出成果,首先需要建立其对于这个领域完善的知识体系,即形成属于自己的知识库。现在有非常多的笔记软件,例如Notion、语雀、Obsidian等等,对于建立知识库非常有帮助,下面我就来谈谈我个人探索出来的一套从zotero管理文献,到阅读文献做笔记再到obsidian中形成阅读笔记的丝滑工作流。
1697 0
|
6天前
|
Prometheus 监控 数据可视化
面试分享:Airflow工作流调度系统架构与使用指南
【4月更文挑战第10天】Apache Airflow是关键的工作流调度系统,本文结合面试经验,深入探讨其核心架构和使用技巧。重点包括:1) Airflow的Scheduler、Web Server、Worker和Metadata Database组件;2) DAG、Task和Operator的概念;3) DAG编写、调度及错误处理策略;4) 监控与扩展性,如自定义Operator和最佳实践。通过学习,助你在面试中应对Airflow相关问题,并提升实际工作中的数据工程能力。
18 5
|
2月前
|
前端开发 测试技术 持续交付
如何打造高效的前端工作流
【2月更文挑战第8天】在现代 Web 开发中,前端工作流程变得越来越重要。好的工作流可以使开发人员更加高效地编写代码、测试和部署应用程序。本文将介绍一些使用先进的工具和技术来打造高效的前端工作流的方法。
46 6
|
11月前
snakerflow工作流实践分享
snakerflow工作流实践分享
195 0
|
运维 数据可视化 网络协议
金鱼哥RHCA回忆录:DO447构建高级作业工作流--创建工作流作业模板并启动工作流作业
第十章 构建高级作业工作流--创建工作流作业模板并启动工作流作业
99 0
金鱼哥RHCA回忆录:DO447构建高级作业工作流--创建工作流作业模板并启动工作流作业
|
存储 SQL XML
工作流引擎Activiti使用进阶!详细解析工作流框架中高级功能的使用示例
本篇文章介绍了Activiti的几个高级用例。主要包括监听流程解析,使用UUID生成器,多租户,执行自定义的SQL,实现流程引擎配置,安全的BPMN 2.0结构以及事件日志的使用。使用这些高级功能,可以使得集成工作流Activiti的项目具有更多的可操作性。
942 0
工作流引擎Activiti使用进阶!详细解析工作流框架中高级功能的使用示例
|
运维 Shell 调度
|
数据库
RoadFlow工作流使用快速入门
RoadFlow工作流使用快速入门
1834 0