项目第八天和项目第九天 学习 JBPM 理论部分
项目第十天 权限管理模块
项目第十一天 项目第十二天 JBPM 应用
1. 工作流框架概述
1.1. 什么是工作流
工作流(Workflow),就是“业务过程的部分或整体在计算机应用环境下的自动化”
工作流技术 是 OA 系统中最关键的一环 !!!
简单的说,就是将工作的流程通过程序管理起来,以表单审核和任务办理为主体,实现办公自动化
工作流开发: 实现业务流程可定制化,将定制业务流程保存到工作流框架系统中,用户登录之后,询问工作流,哪个流程该我完成了,工作流返回需要用户办理任务节点, 用户选择对应任务进行办理,在办理任务后,流程会自动流行下一个节点 !
1.2. 通过工作流实例来了解工作流框架
通过 “演示程序” 了解工作流
1、 定制业务流程
MyProcessDesigner_流程设计器
完成流程图
点击保存按钮 , 生成holiday.zip 压缩包
---- process.jpdl.xml 流程描述文件
---- process.png 流程图片
2、 将业务流程发布 工作流系统中
使用 tomcat-6.0.14 运行 (配置 JAVA_HOME),自带 MyJbpm4-Console 工作流Demo
注意: 在运行项目之前,先配置项目 hibernate 配置文件
修改 jbpm.hibernate.cfg.xml
启动tomcat ,访问 http://localhost:8080/MyJbpm4-Console/
3、 使用 admin账户登陆 (无密码)
发布 holiday.zip
启动流程,流程停留到 员工请假申请 节点
4、 使用 员工 登陆
查看个人任务
5、 使用部门经理登陆
查看个人任务
6、 使用总经理登陆
查看个人任务
所有流程 基本办理模式都是相似的, 先登陆系统, 查询我的个人任务, 办理个人任务, 流程流转 !!
2. JBPM学习
2.1. 什么是JBPM ?
JBPM,全称是Java Business Process Management(业务流程管理)
是一款开源工作流框架
企业主流工作流产品: JBPM、OSWorkFlow、 OFBIZ、
OFBIZ 很多大公司在用 ,构建大中型企业级、跨平台、跨数据库、跨应用服务器的多层、分布式电子商务类WEB应用系统的框架。
企业主流JBPM版本, 3.x 、4.x
JBPM 从5.x 开始分流 ,原来JBPM开发团队,离开JBOSS公司 ,原开发团队写工作流框架叫做Activity (是对JBPM 延续 ,数据库技术使用 MyBatis )、JBOSS公司另外一个团队推出 JBPM5 (和 JBPM4没有任务关系 )
2.2. 下载JBPM开发包
http://sourceforge.net/projects/jbpm/files/
下载JBPM4.4
2.3. 安装JBPM流程设计器
安装Eclipse 的JBPM 流程设计器插件
—- 对eclipse内置插件有要求 ,有些myeclipse内部缺少需要插件
步骤一: 进行myeclipse 配置中心
步骤二: 进入SoftWare 管理界面
点击 Add site
找到 jbpm解压目录/install/src/gpd/ 插件的zip包
展开jbpm插件选项,将每一项右键添加 profile
最后点击下方 apply 8 changes 进行安装 ,安装后会重启MyEclipse
在新建中 出现
说明安装插件成功 !!!
2.4. 使用 JPDL流程设计器,设计流程
习惯性,在开发中设计流程图,新建 source forlder (jpdl/xml)
使用插件自带设计器 编写JBPM 流程
通过 properties 视图,修改图中节点属性
<process name="holiday" xmlns="http://jbpm.org/4.4/jpdl">
<start name="start1" g="211,21,48,48">
<transition name="to 员工请假申请" to="员工请假申请" g="-95,-17"/>
</start>
<end name="end1" g="206,288,48,48"/>
<task name="员工请假申请" g="188,105,92,52">
<transition name="to 部门经理审批" to="部门经理审批" g="-95,-17"/>
</task>
<task name="部门经理审批" g="192,192,92,52">
<transition name="to end1" to="end1" g="-47,-17"/>
</task>
</process>
需要为 流程设计器,设置schema 提示 , 选择jbpm解压目录/src/jpdl-4.4.xsd
2.5. 搭建JBPM开发环境
2.5.1. 在项目中导入JBPM的jar包
{JBPM_HOME}/jbpm.jar 开发jbpm核心jar 包
去掉 servlet-api、 junit、 slf4j-*
替换 slf4j 1.5.8的jar包
2.5.2. 配置文件导入
src/log4j.properties
将 JBPM_HOME/examples/src/ 下面文件复制到 src目录
jbpm.cfg.xml (JBPM框架核心配置文件)
jbpm.hibernate.cfg.xml (hibernate 配置文件、修改数据库连接参数)
修改 hibernate 连接参数时 ,改为mysql参数
<property name="hibernate.dialect">
org.hibernate.dialect.MySQL5InnoDBDialect
</property>
<property name="hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="hibernate.connection.url">
jdbc:mysql:///jbpm01
</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">abc</property>
<property name="hibernate.hbm2ddl.auto">update</property>
注意: 方言必须要用 org.hibernate.dialect.MySQL5InnoDBDialect,否则在流程结束时会报一个异常!
2.5.3. 编写程序,初始化JBPM数据表
// 1、 定义配置类,用来加载jbpm配置文件
Configuration configuration = new Configuration();
// 2、加载配置文件,初始化jbpm环境
configuration.buildProcessEngine();
创建18张数据表
参加 : 资料/ JBPM4.4数据表结构说明.rtf 文档
3. JBPM工作流操作— 流程定义管理
目的: 将设计好业务流程,部署到JBPM工作流引擎中!
3.1. 设计流程图
JBPM流程设计,分为线上设计器 和 线下设计器两种
很多企业开发中,公司都会定制自己的线上设计器 ,打开一个网页,在网页上直接设计JBPM业务流程,通过保存按钮,直接将设计好流程部署系统中!
MyEclipse 安装GPD插件,属于线下设计器 ,需要将设计好流程通过文件上传的方式,发布到JBPM系统中
生成 jpdl/xml文件(流程描述文件)、 png流程图 两个文件
3.2. 将设计好流程部署到JBPM系统中
JBPM程序开发步骤:
步骤一: 获得流程引擎对象 ProcessEngine
// 步骤一: 获得流程引擎
ProcessEngine processEngine =
new Configuration().buildProcessEngine();
步骤二: 获得对应Service对象
JBPM内部提供六个Service,用来完成不同操作
RepositoryService 用来进行流程定义操作
ExecutionService 用来进行流程实例操作
TaskService 用来进行任务操作
IdentityService 用来进行JBPM用户操作
HistoryService 用来对流程历史记录进行操作
ManagementService 用来进行定时任务调度 (管理job)
// 步骤二: 获得对应Service
RepositoryService repositoryService =
processEngine.getRepositoryService();
步骤三: 进行操作 、发布流程
常用: addResourceFromZipInputStream 、 addResourceFromClasspath
// 步骤三: 进行业务操作
NewDeployment deployment = repositoryService.createDeployment(); // 获得发布对象
deployment.addResourceFromClasspath("holiday.jpdl.xml");
deployment.addResourceFromClasspath("holiday.png");
deployment.deploy(); // 执行发布的动作
3.3. 详细分析流程定义发布过程中数据表变化
jbpm4_property 全局属性表
在初始化18张表时候,向表中已经插入一条记录
这个表中主要存在下次操作的起始记录id ,JBPM框架采用流水ID方式
下次数据库操作,id 从1 开始
jbpm4_deployment 流程定义发布表 ,每次发布一个新流程,在表中保存一条记录
jbpm4_lob 二进制数据表,在发布流程时,会发布一些文件,一个文件,对应lob中一条记录
jbpm4_deployprop 流程定义属性表,用来存放每次发布流程定义的属性信息,一个流程定义,对应四条属性信息
Key字段保存属性名称
landid: 使用JBPM的jpdl语言 的版本
pdId: 流程定义编号(唯一标识), 由 pdKey-pdVersion 组成
pdkey : 流程关键字
pdversion : 流程版本号
注意: 每次数据库操作后, jbpm4_property表 next.dbid 要更新,+10000
案例: 发布zip压缩包
NewDeployment deployment = repositoryService.createDeployment(); // 获得发布对象
deployment.addResourcesFromZipInputStream(new ZipInputStream(new FileInputStream("holiday.zip")));
deployment.deploy();
3.4. 流程定义查看
通过 ProcessDefinitionQuery查询流程定义信息
查看所有流程定义
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
List<ProcessDefinition> list = processDefinitionQuery.list();
System.out.println(list.size());
for (ProcessDefinition processDefinition : list) {
System.out.println("ID:" + processDefinition.getId());
System.out.println("名称:" + processDefinition.getName());
System.out.println("Key:" + processDefinition.getKey());
System.out.println("版本:" +
processDefinition.getVersion());
}
参考 holiday.jpdl.xml
<process name="holiday" xmlns="http://jbpm.org/4.4/jpdl">
name: holiday 对应流程定义名称
key 没有指定,将默认使用 name的值
version : 发布相同key的流程时,version版本每次+1
id : 就是流程定义编号 ,对应数据表 pdId 由 key-version 组成
为流程定义查询指定条件
3.5. 查看流程图
使用 RepositoryService 提供
getResourceAsStream(deploymentId, resourceName) 方法
这个方法 需要 发布编号 (jbpm4_deployment 的主键) 和 资源名称 (jbpm4_lob 表)
// 先根据 流程定编号 pdId ,查询流程发布编号 deploymentId
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
processDefinitionQuery.processDefinitionId("holiday-2");
ProcessDefinition processDefinition = processDefinitionQuery.uniqueResult();
String deploymentId = processDefinition.getDeploymentId(); // 发布id
// 获得资源名称
String resourceName = processDefinition.getImageResourceName(); // 资源name
// 获得图片资源流
InputStream in = repositoryService.getResourceAsStream(deploymentId, resourceName);
OutputStream out = new FileOutputStream("c:/holiday.png");
int b;
while ((b = in.read()) != -1) {
out.write(b);
}
in.close();
out.close();
3.6. 流程定义的删除
在实际已经应用的流程,不建议用户去删除 ,JBPM 在发布相同key的新流程时,version 递增 ! 没有必要将旧版本流程删除,影响到之前系统数据 。
通常使用 方式二 ,进行删除
删除 流程定义信息 jbpm4_deployment、jbpm4_lob、jbpm4_deployprop
删除 流程实例信息
4. JBPM工作流操作— 流程实例管理
问题: 流程定义和流程实例 是什么关系 ?
类似 类和对象的关系, 流程定义用来描述一个业务流程,完整节点和流转信息 (请假流程) ,流程实例是使用业务流程,进行一个具体业务数据操作 (张三请假)
* 一个流程定义 对应 很多个流程实例
4.1. 启动流程实例
对流程定义,启动一个具体的实例
对流程实例操作,使用 ExecutionService
启动流程实例可以根据 流程定义编号启动 或者 根据流程定义关键字启动
// 根据 pdid启动 (jbpm4_deployprop 流程定义属性表 )
executionService.startProcessInstanceById("holiday-1");
// 根据 pdKey启动 (jbpm4_deployprop 存在 key属性)
executionService.startProcessInstanceByKey(“holiday”); // key可以相同的
默认启动相同key 最高版本的流程!!
4.2. 详细分析启动流程实例影响的数据表
jbpm4_execution 正在运行流程实例信息表
ACTIVITYNAME_ 当前活动节点名称
ID_ (流程实例id 或者 执行id ): holiday.30001
jbpm4_hist_procinst 流程实例运行历史记录表
jbpm4_task 正在运行任务信息 (当流程执行task节点,task表插入记录 )
这里DBID 就是 taskId 任务编号 30002
jbpm4_hist_task 存在任务运行历史记录
jbpm4_hist_actinst 活动历史记录表
问题: 任务和活动 是什么关系 ?
任务是活动的一种 (活动节点 不只包含 任务节点 !!!)
表中TYPE字段,用来表示活动的类型 ,这里task,说明该活动是 任务!!!
4.3. 流程实例流转
通过ExecutionService的signalExecutionById
可以使JBPM工作流程转向下一个节点, 根据流程实例id (jbpm4_execution 表 ID_ 字段)进行流程向后流转
根据 实例id 和 目标transition的name属性 进行流转
// 根据实例id ,向后流转
// to 部门经理审批 是transition的name属性
executionService.signalExecutionById
(“holiday.30001”, “to 部门经理审批”);
4.4. 流程实例流转特殊操作 — 直接中止流程
5. JBPM工作流操作— 任务操作
ExecutionService.signalExecutionById
(流程实例id) —- 使流程向后一步,到达下一节点 !
在实际开发中, 上面这个方法,不会用于task节点流转 !
—- 任务 是需要指定的人办理完成的 ,不会自动向后流转
—- 任务节点需要指定人来办理任务,在任务办理后,自动向后流转
5.1. 通过assignee属性 指定任务节点负责人
<task g="188,105,92,52" name="员工请假申请" assignee="员工">
<transition g="-95,-17" name="to 部门经理审批" to="部门经理审批"/>
</task>
<task g="192,192,92,52" name="部门经理审批" assignee="部门经理">
<transition g="-47,-17" name="to end1" to="end1"/>
</task>
重新发布流程
5.2. 启动流程实例
executionService.startProcessInstanceByKey("holiday");
在 jbpm4_task 表
ASSIGNEE 就是当前任务的负责人 !
5.3. 任务节点操作
任务操作,需要使用 TaskService 完成
操作一: 查询当前流程实例的任务
TaskQuery taskQuery = taskService.createTaskQuery();
List<Task> list = taskQuery.executionId("holiday.10001").list();
System.out.println(list.size());
for (Task task : list) {
System.out.println("任务编号:" + task.getId());
System.out.println("任务名称:" + task.getName());
}
操作二: 我的个人任务
// 查看个人任务
List<Task> list = taskService.findPersonalTasks("员工");
System.out.println(list.size());
for (Task task : list) {
System.out.println("任务编号:" + task.getId());
System.out.println("任务名称:" + task.getName());
}
操作三: 办理个人任务
TaskService提供completeTask(taskId)
完成指定的任务
// 办理任务
// taskId 就是 jbpm4_task表 DBID 字段
taskService.completeTask("10002");
办理任务后,流程自动流向下一个节点 !
6. JBPM工作流 流程变量管理
在使用JBPM 管理业务流程后,很多业务流程数据,需要和JBPM流程进行关联
和流程实例进行关联后业务数据,也叫 流程变量!
6.1. 流程变量支持哪些类型
将JBPM 支持流程变量类型 分为两大种 :基本类型 和 自定义对象类型
自定义对象类型支持
Long类型主键的 PO对象
String类型主键的PO对象
实现Serializable 接口的可序列化的对象
6.2. 流程的读写操作
第一种: 在ExecutionService 的 startProcessInstanceById 或 startProcessInstanceByKey 启动流程实例时关联流程变量
// 关联流程变量
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("company", "传智播客");
executionService.startProcessInstanceByKey("holiday", variables);
流程变量保存 jbpm4_variable 表中!
第二种 : ExecutionService 结合 executionId 对流程变量进行读写操作
四个ID :
deploymentId 发布id : jbpm4_deployment 的 DBID
pdId (processDefinitionId) 流程定义id : jbpm4_deployprop 的pdId
executionId (processInstanceId) 流程实例id : jbpm4_execution 的 ID_
taskId 任务id : jbpm4_task 的 DBID
读取操作:
String company =
(String) executionService.getVariable("holiday.30001", "company");
System.out.println(company);
写入操作:
executionService.setVariable("holiday.30001", "pnum", 100);
第三种: 使用TaskService 结合 taskId 对变量进行读写操作
读取操作
int pnum = (Integer) taskService.getVariable("30003", "pnum");
System.out.println(pnum);
写入操作
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("weather", "多云无雨");
taskService.setVariables("30003", variables);
6.3. 复杂流程变量 写入
案例一: Serializable 可序列化对象
如果格式非法:
org.hibernate.HibernateException: instance not of expected entity type: org.jbpm.pvm.internal.type.variable.UnpersistableVariable is not a:
org.jbpm.pvm.internal.type.Variable
在 variables 表
CLASS:blob 二进制数据
CONVERTER:ser-bytes 序列化的字节
LOB : 70001 就是 jbpm4_lob 表主键
数据保存 lob 表中
案例二: long类型主键的PO对象
在variables 表 ,保存记录
CLASSNAME 存放完整类名
LONG_VALUE 存在主键值
引入PO对象,数据保存在业务表,在JBPM中只是引入 完整类名和主键
其它
课前资料
JBPM4.4入门
里面有JBPM的详细教程