JBPM基本用法得介绍!

 0hi猿团提供了移动跨平台开发视频,包括html5,apicloud appcan,dcloud,具体请看http://www.9y.cm   

工作流程!什么是jbmp进行了解释!

JBPM基本用法

工作流基本知识

JBPM基本用法

JBPM高级用法

各种类型节点的用法及应用场景

JBPM实现原理

系统架构和数据结构

基于JBPM的工作流应用平台开发

工作流应用平台介绍

设计和实现策略

 

工作流基本知识

概念和术语

JBPM基本概况

jBPM中与工作流领域对应的概念

JBPM基本用法

基本API的用法以及应用策略

实例开发

实例编写一个报销审批流程的相关代码

课堂交流和答疑

 

l jBPM 是什么
• 是基于 java 实现的流程业务处理框架 ( B usiness P rocess M anagement)
l jBPM 能做什么
• 支撑企业的 流程性 业务应用:解释业务规则,使得 协作 自动化
l 特点
• 没有采用 WFMC 的规范 xPDL (尤其是业务定义部分)
• 强大的业务逻辑描述能力( jPDL
• 核心组件是流程调度引擎
• 轻量级, core engine 无须运行于 JEEContainer
• 采用 hibernate 作为数据持久化的工具,兼容多种数据库
• 简单易用,灵活、可扩展,同一需求有多种解决策略

 

l 区别
Workflow 更侧重于对流程的处理模型,属于技术领域范畴
BPM 除了对流程的处理,还要提供灵活的编程模型,易于企业应用的集 成,更侧重于业务范畴
l 用 workflow 替代 BPM
• 我们在后面的课程中将以 workflow 名词为主

 

 

 

l 什么是工作流?
WFMC 定义: The automation of a business process, in whole or part, during which documents, information or tasks are passed from one participant to another for action, according to a set of procedural rules.
要素: 任务 ( task) ,参与者 (participant )
l 什么是工作流管理系统
WFMC 定义: A system that defines, creates and manages the execution of workflows through the use of software, running on one or more workflow engines, which is able to interpret the process definition, interact with workflow participants and, where required, invoke the use of IT tools and applications.
要素 工作流的管理、工作流的调度执行、工作流引擎

 

 

l 工作流带来的益处
• 实现了无纸化的工作模式;
• 过程可监控:便于对执行过程的跟踪和监控
• 数据可管理:便于对数据进行检索、分析
• 可靠性:减少人 - 人交互的主观错误的机率
l 常见应用领域
• 行政管理:行政、事业单位、大中型(国有)企业
• 产品研发和制造:用于对整个研发、生产制造过程的管理和调度
• 电子商务:订单处理
• 其他 如大型内容管理系统的多步审核
l 常见场景
• 公文流转、行政审批、订单处理、产品研发、制造过程
• 其他需要多个角色协作、多步完成的活动

 

 

请假条得实例:

package cn.itcast.jbpm.init;

 

import org.hibernate.cfg.Configuration;

import org.junit.Test;

 

public class CreateSchema {

 

/**

* 建表

*/

@Test

public void createSchema(){ 

new Configuration().configure().buildSessionFactory();

}

}

 

 

/**

* <pre>

* 任务实例的状态:已创建、已开始、已完成

* </pre>

*/

// 3,获取任务列表(未完成的任务实例列表)

@SuppressWarnings("unchecked")

@Test

public void getTaskList() {

// String actorId = "员工(张三)";

String actorId = "部门经理(李四)";

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();

 

// List<TaskInstance> taskList = jbpmContext.getTaskList(actorId);

List<TaskInstance> taskList = jbpmContext.getTaskMgmtSession().findTaskInstances(actorId);

for (TaskInstance ti : taskList) {

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

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

+ ",actorId=" + ti.getActorId()//

+ ",create=" + ti.getCreate()//

+ ",start=" + ti.getStart()//

+ ",end=" + ti.getEnd());

}

 

jbpmContext.close();

}

 

private long taskInstanceId = 2;

 

// 4-1,办理任务_开始任务

@Test

public void startTask() {

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();

 

TaskInstance ti = jbpmContext.getTaskInstance(taskInstanceId);

ti.start();

 

jbpmContext.close();

}

 

// 4-2,办理任务_结束任务

@Test

public void endTask() {

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();

 

TaskInstance ti = jbpmContext.getTaskInstance(taskInstanceId);

ti.end();

 

jbpmContext.close();

}

 

}

package cn.itcast.jbpm.variable;

 

import org.jbpm.JbpmConfiguration;

import org.jbpm.JbpmContext;

import org.jbpm.graph.def.ProcessDefinition;

import org.jbpm.graph.exe.ProcessInstance;

import org.jbpm.graph.exe.Token;

import org.jbpm.taskmgmt.exe.TaskInstance;

import org.junit.Test;

 

public class VariableTest {

JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();

 

// 0,部署流程定义

@Test

public void deploy() {

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); // 创建Session,开始事务

 

String xmlResource = "cn/itcast/jbpm/variable/leave/processdefinition.xml";

ProcessDefinition pd = ProcessDefinition.parseXmlResource(xmlResource);

jbpmContext.getGraphSession().deployProcessDefinition(pd);

 

jbpmContext.close(); // 提交/回滚 事务,关闭Session

}

 

// 1,启动流程实例

@Test

public void startProcess() {

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();

 

ProcessDefinition pd = jbpmContext.getGraphSession().findLatestProcessDefinition("leave");

ProcessInstance pi = pd.createProcessInstance(); // new ProcessInstance(pd);

// jbpmContext.save(pi);

 

// 设置变量

pi.getContextInstance().setVariable("employee", "张三");

pi.getContextInstance().setVariable("manager", "李四");

 

// 离开开始节点

Token token = pi.getRootToken(); // 根令牌

token.signal();

 

jbpmContext.close();

}

 

private long taskInstanceId = 6;

 

// 2,办理任务:提交申请

@Test

public void submit() {

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();

 

TaskInstance ti = jbpmContext.getTaskInstance(taskInstanceId);

ti.start();

 

ProcessInstance pi = ti.getProcessInstance();

pi.getContextInstance().setVariable("days", 3); // 请假天数

 

ti.end();

 

jbpmContext.close();

}

 

// 2,办理任务:部门经理审批

@Test

public void audit() {

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();

 

TaskInstance ti = jbpmContext.getTaskInstance(taskInstanceId + 1);

ti.start();

 

ProcessInstance pi = ti.getProcessInstance();

int days = (Integer) pi.getContextInstance().getVariable("days");

System.out.println("请假的天数为:" + days + "天");

 

ti.end();

 

jbpmContext.close();

}

}

 

1.JPDL的流程定义元素 1)第一层:GraphElement 这个容易理解,因为在画流程定义时,每个拖拉的对象都是一个graph的元素。GraphElement有四个属性: (1)processDefine 表示当前元素属于哪个流程定义 (2)events 表示可以接收哪些event (3)name 名字 (4)exceptionHandlers 异常处理类集合(List) 2)第二层:node、processDefinition、Transition、Task 它们都继承自GraphElement (1)processDefinition表示流程定义(implements NodeCollection),它有下面的属性:name、version、nodes、startState。nodes表示流程中所有的node,startState用于启动流程时找到首节点。 (2)Transition表示转移,它有三个属性:from(Node),to(Node),supportedEventTypes表示支持的event类型 (3)node表示节点,它有四个属性:leaving transitions、arriving transitions、action、superState。 (4)Task 定义任务 3)第三层:各种不同的node 它们都继承自node。 Decision、EndState、Fork、Join、Merge、Milestone、 InterleaveEnd、InterleaveStart、ProcessState、State。 2.jBPM的token jbpm中最重要的概念,应该是令牌(Token)和信令(Signal)。在整个流程实例运行过程中,我们可以迅速的利用token得到其当前的current state。在解决“并行”等(比如Fork)问题时,jBpm让Token对象维护了父子关系,这种关系在涉及到Fork的时候会产生。 jBpm让Token这个对象身兼了多种使命: (1)快速定位current state (2)用于fork,join算法 (3)用于告知任务执行者的任务索引。 如下代码: //pd是process definition,pi是process instance ProcessInstance pi = new ProcessInstance( pd ); //得到根令牌 Token token = pi.getRootToken(); //发信令 token.signal(); Token的signal方法也可以传入transition参数,这个方法把信令发送给Token,这样,令牌将被激活,并沿指定的transition离开当前的状态(如果没有指定transition,将沿缺省的transition 离开当前状态)。 jbpm是怎么实现的呢?其实很简单: 1)Token记录了当前的状态(current state),只有当前的状态(或称节点)拥有该令牌 2)向TOKEN发signal后,当前状态收到该signal 3)当前状态把令牌传给signal中指定的transition 4)transition收到令牌后,不强占,马上把令牌传给下个状态. 5)根据令牌的位置,流程的状态已经发生改变. 3.process definition 一个process definition代表了一个正式的业务流程,它以一个流程图为基础。这个流程图由许多node和transition组成。每个node在这个流程图里都有着各自特殊的类型,这些不同的类型决定了node在运行时的不同行为。一个process definition只有一个start state 。 4.token 一个token代表了一条执行路径,它包含了这条执行路径的当前的执行状态(current state)。 5.process instance 一个process instance(流程实例)即一个process definition(流程定义)的流程执行实例。一个process definition可以对应多个process instance。当一个process instance被创建的时候,一个主执行路径token同时被创建,这个token叫做root token,它指向流程定义的start state(processDefinition.getStartState()==token.getNode())。 6.signal 一个signal 发送给token通知token 继续流程的执行。如果signal 没有指定transition,token将沿缺省的transition离开当前状态,如果signal 指定transition,token将沿指定的transition离开当前的状态。看源代码可以看到发给process instance的signal 其实都是发送给了root token。 7.Actions jbpm提供了灵活的action ,当流程执行,token 进入node和transition时,会触发相应的一些event(事件)。在这些event上附上我们自己写的action,就会带动action 的执行。action里是我们自己的相关java操作代码,非常方便。注意的是event(事件)是内置的,无法扩展。另外,action也可以直接挂在node上,而不依赖于event(事件)的触发,这个很重要。 8.node 一个流程图由许多node和transition组成。每个node都有一种类型,这个类型决定了当流程执行到这个node时的不同行为。jbpm有一组node type可以供你选择,当然你可以定制自己node 。 node的作用 node有两个主要的作用: 1)执行java代码,比如说创建task instance(任务实例)、发出通知、更新数据库等等。很典型的就是在node 上挂上我们的action 2) 控制流程的执行: A、等待状态:流程进入到这个node时将处于等待状态,直到一个signal 的发出 B、流程将沿着一个leaving transition越过这个node,这种情况特殊一点,需要有个action挂在这个node上(注意这个action不是event触发的!),action中将会调用到API里 executionContext.leaveNode(String transitionName),transitionName即这里的leaving transition名字。 C、创建新的执行路径: 很典型的就是fork node。流程在这里会分叉,产生新的执行路径。这样就创建了新的token,每个新的token代表一个新的执行路径。注意的是,这些新的token和产生前的token是父子关系! D、结束执行路径:一个node可以结束一条执行路径,这同样意味着相应的token的结束和流程的结束。 9.流程图中的node type 1)task-node 一个task-node可以包含一个或多个task,这些task分配给特定的user。当流程执行到task-node时,task instance将会被创建,一个task对应一个task instance。task instances 创建后,task-node就处于等待状态。当所有的task instances被特定的user执行完毕后,将会发出一个新的signal 到token,即流程继续执行。 2)state state是一个纯粹的wait state(等待状态)。它和task-node的区别就是它不会创建task instances。很典型的用法是,当进入这个节点时(通过绑定一个action到node-enter event),发送一条消息到外部的系统,然后流程就处于等待状态。外部系统完成一些操作后返回一条消息,这个消息触发一个signal 到token,然后流程继续执行。(不常用) 3)decision 当需要在流程中根据不同条件来判断执行不同路径时,就可以用decision节点。两种方法:最简单的是在transitions里增加condition elements(条件),condition是beanshell script写的,它返回一个boolean。当运行的时候,decision节点将会在它的 leaving transitions里循环,同时比较 leaving transitions里的condition,最先返回'true'的condition,那个leaving transitions将会被执行;作为选择,你可以实现DecisionHandler接口,它有一个decide()方法,该方法返回一个String(leaving transition的名字)。 4)fork fork节点把一条执行路径分离成多条同时进行(并发)的执行路径,每条离开fork节点的路径产生一个子token。 5)join 默认情况下,join节点会认为所有到达该节点的token都有着相同的父token。join 节点会结束每一个到达该节点的token,当所有的子token都到达该节点后,父token会激活。当仍然有子token处于活动状态时,join 节点是wait state(等待状态)。 6)node node节点就是让你挂自己的action用的(注意:不是event触发!),当流程到达该节点时,action会被执行。你的action要实现ActionHandler接口。同样,在你的action里要控制流程。 10. Actions的说明 存在两种action,一种是 event触发的action,一种是挂在node 节点的action。要注意它们的区别,event触发的action无法控制流程,也就是说它无法决定流程经过这个节点后下一步将到哪一个leaving transition;而挂在node 节点的action就不同,它可以控制流程。不管是哪一种action都要实现ActionHandler接口。 11. Task(任务jbpm一个相当重要的功能就是对任务进行管理。Task(任务)是流程定义里的一部分,它决定了task instance的创建和分配。Task(任务)可以在task-node节点下定义,也可以挂在process-definition节点下。最普遍的方式是在task-node节点下定义一个或多个任务。默认情况下,流程在task-node节点会处于等待状态,直到所有的任务被执行完毕。任务的名称在整个流程中必须是唯一的。一个TaskNode对应多个Task。 对于这样的流程定义: xml 代码 1. <task-node name='a'> 2. <task name='laundry' /> 3. <task name='dishes' /> 4. <task name='change nappy' /> 5. <transition to='b' /> 6. </task-node> 只有当节点中的三个任务都完成后,流程才进入后面的节点 对于这样的流程定义: xml 代码 1. <task-node name='a' signal='first'>> 2. <task name='laundry' /> 3. <task name='dishes' /> 4. <task name='change nappy' /> 5. <transition to='b' /> 6. </task-node> 当第一个任务完成后,token就指向后面的节点 对于这样的流程定义: xml 代码 1. <task-node name='a' signal='never'>> 2. <task name='laundry' /> 3. <task name='dishes' /> 4. <task name='change nappy' /> 5. <transition to='b' /> 6. </task-node> 三个任务都完成后,token仍然不会指向后面的节点;需要自己手动调用processInstance.signal()才会驱动流程到下面的节点。 对于这样的流程定义: xml 代码 1. <task-node name='a' signal='unsynchronized'>> 2. <task name='laundry' /> 3. <task name='dishes' /> 4. <task name='change nappy' /> 5. <transition to='b' /> 6. </task-node> token不会在本节点停留,而是直接到后面的节点 12. jbpm任务管理实现 一个Task instance(任务实例)可以被分配给一个actorId (java.lang.String)。所有的Task instance都被保存在数据库中的表jbpm_taskinstance里。当你想得到特定用户的任务清单时,你就可以通过一个与用户关联的actorId来查询这张表。 一个流程定义有一个TaskMgmtDefinition;一个TaskMgmtDefinition对应多个swimlane,同时对应多个task;一个swimlane有多个task,可以从TaskMgmtDefinition中通过task的名称直接获取相应的task; swimlane对象有四个属性,分别是name(名字)、assignmentDelegation(分配代理类)、taskMgmtDefinition、tasks(Set 对应多个task),可以增加task task对象主要的属性:taskMgmtDefinition、swimlane、assignmentDelegation、taskNode,需要注意的是swimlane和assignmentDelegation中间只是可以一个属性有值,因为它们都和任务的分配有关系。 一个流程实例有一个TaskMgmtInstance;一个TaskMgmtInstance对应多个swimlaneInstance,同时对应多个taskInstance;一个swimlaneInstance有多个taskInstance,可以从TaskMgmtInstance中直接获取相应的taskInstance; swimlaneInstance对象主要有五个属性,分别是name、actorId、pooledActors(Set)、swimlane、taskMgmtInstance。 taskInstance对象的主要属性:name、actorId、task、swimlaneInstance、taskMgmtInstance、pooledActors。 当对任务进行分配时,一般需要实现AssignmentHandler这个接口,这个接口的方法只有一个: void assign( Assignable assignable, ExecutionContext executionContext) throws Exception; 一个典型的实现(把名字是'change nappy'的任务交给NappyAssignmentHandler这个类来分配) xml 代码 1. <task name='change nappy'> 2. <assignment class='org.jbpm.tutorial.taskmgmt.NappyAssignmentHandler' /> 3. task> NappyAssignmentHandler类: java 代码 1. public void assign(Assignable assignable, ExecutionContext executionContext) { 2. assignable.setActorId("papa"); 3. } 同样,Assignable只是一个接口,它有两个方法:setActorId()和setPooledActors(),Assignable的具体实现类也是两个:swimlaneInstancehe和taskInstance。这样就不不难理解整个任务分配流程了: 1、流程进入TaskNode节点,执行TaskNode类的execute()方法,该方法首先获得TaskMgmtInstance实例,然后通过它来创建TaskInstance。taskMgmtInstance.createTaskInstance(task, executionContext); 2、在上面的createTaskInstance(task, executionContext)里,该方法调用了taskInstance.assign(executionContext)对taskInstance进行分配。 3、在assign(executionContext)方法里,首先会判断task属性里是否存在swimlane,如果有的话,这个taskInstance就会分配给swimlane指定的ActorId或 PooledActors;如果不存在,再去找task属性里 assignmentDelegation(分配代理类)通过代理类(即我们自己写的实现AssignmentHandler这个接口的类)指定ActorId或 PooledActors。 13. jbpm的用户角色管理 jbpm在用户角色管理上共设计了四个类:Entity、Membership、Group、User。 Entity类是其他三个类的父类,它包含了两个属性:name(String)、permissions(Set); User类继承Entity类,包含三个属性:password(String)、email(String)、memberships(Set); Group类继承Entity类,包含四个属性: type(String)、parent(Group)、children(Set)、memberships(Set); Membership类继承Entity类,包含三个属性:role(String)、user(User)、group(Group) 很明显,一个user对应一个用户,一个group对应一个用户组,它们之间通过membership关联,并且一个user可以属于多个不同类型(type)的group,user和 group之间是多对多的关系。Membership类的role属性个人感觉用途不大,反倒是name属性代表了user在group里的role(角色)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhchzh1000

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值