关于JBPM工作流
- 2. JBPM
jBPM,全称是Java Business Process Management,是一种基于J2EE的轻量级工作流管理系统。JBPM使用Hibernate进行数据库操作,也就是说只要Hibernate支持的数据库它都可以使用,数据库主要是存放流程的定义,流程实例的信息,还有用户的信息等。
Jbpm工作流适用于:
n 项目流程比较多,流程复杂的项目。
n 系统运行和维护、升级时,流程可能需要修改、调整和跟踪、控制的项目。
1、JBPM4表说明:
JBPM4_DEPLOYMENT 流程定义表
JBPM4_DEPLOYPROP 流程定义属性表
JBPM4_EXECUTION 流程实例表
JBPM4_HIST_ACTINST 流程活动( 节点) 实例表
JBPM4_HIST_DETAIL 流程历史详细表
JBPM4_HIST_PROCINST 流程实例历史表
JBPM4_HIST_TASK 流程任务实例历史表
JBPM4_HIST_VAR 流程变量( 上下文) 历史表
JBPM4_ID_GROUP 组表
JBPM4_ID_MEMBERSHIP 用户角色表
JBPM4_ID_USER 用户表
JBPM4_JOB 定时表
JBPM4_LOB 存储表 存放流程定义的xml和png图片文件
JBPM4_PARTICIPATION 参与者表
JBPM4_SWIMLANE 泳道表
JBPM4_TASK 任务表
JBPM4_VARIABLE 上下文表
jBPM4.4的数据库表分成以下几类:
1)和系统相关:这个只有JBPM4_PROPERTY
2)和ProcessDefinition相关的表:JBPM4_DEPLOYMENT、JBPM4_DEPLOYPROP、JBPM4_LOB
3)和开启一个instance相关: 有JBPM4_EXECUTION、JBPM4_TASK、JBPM4_JOB、JBPM4_VARIABLE、JBPM4_SWIMLANE、 JBPM_PARTICIPATION
4)和历史相关的表: JBPM4_HIS_ACTINST、JBPM4_HIS_DETAIL、JBPM4_HIS_PROCINST、JBPM4_HIS_TASK、JBPM4_HIS_VAR
5)和用户/组相关的表有: JBPM4_ID_USER、JBPM4_ID_GROUP、JBPM4_ID_MEMBERSHIP 具体数据库的详细数据结果可以参看,随文所附的jbpm.pdm文件,使用powerdesigner打开。
2、工作流的基本思路:
2.1 、描述工作流
2.2 、发布和存储工作流
2.3 、装载和解析工作流
2.4 、顶层对象:流程、活动、转移
2.5 、流程定义和流程实例
2.6 、活动定义和活动实例
2.7 、令牌驱动,petri网
2.8 、转移:隐式、显示、fork(分支)、join、按条件等等
2.9 、活动:人工活动、自动活动等
2.10、人工活动会涉及:活动的处理页面、活动的数据
2.11、workList:活动的列表、接收、拒收、重分配、活动的响应等
3、jBPM有什么,简介jBPM的Service API
1:ProcessEngine:流程引擎。并不负责具体的业务,而是用于获取各种Service。
2:RepositoryService:流程资源服务的接口,如流程定义发布、查询、删除等。
{
在流程仓库里包含部署管理、
}
3:ExecutioService:用于操作流程实例的服务,可以进行流程实例发布、查询、流程推进、设置流程变量等操作。
4:TaskService:用于操作人工任务的服务,可以进行任务创建、查询、获取、提交完成、保存、删除等操作。
5:HistoryService:用于操作流程历史的服务,提供对流程历史库(就是已经完成的流程实例)的操作。比如:历史流程实例,历史活动实例等。
6:IdentityService:用于操作用户、用户组以及成员关系的服务
7:ManagementService:流程管理控制服务的接口,只提供异步工作(Job)相关的执行和查询操作。
4、jPDL基础--1
全称是jBoss jPBM Process Definition Language,这种一种构建于jBPM架构之上的流程语言之一。jPDL提供了图形化处理的界面,跟VB语言差不多,拖拖拽拽就能做出个东西来,非常直观。这里面提供了很多图形化节点:
start和end节点在每个jBPM项目中都会用到,分别为开始节点和结束节点;
。在jPDL中提供了任务(tasks)、待处理状态(wait states)、计时器(timers)、自动处理(automated
actions)…等术语,并通过图型化的流程定义,很直观地描述业务流程。
n 流程定义(ProcessDefinition)
就是对一个流程抽象的对象化定义。一套系统中,用户可以定义并保存多
个流程定义实体,如:报销流程定义、请假流程定义、人事录用流程定义等。
n 流程节点
是对流程中的过程环节/行为的抽象对象化定义。结点有两个主要职责:
一,实现某个指定行为,这在jBPM中就是执行一段制定的Java代码;二,传递、
维持流程的延续,直至达到最终结点。
流程实例(ProcessInstance)
流程实例是流程定义的运行时状态,它记录了一个流程运行的起始时间、
结束时间等状态信息。
n 任务实例(Task)
用来描述一个任务实例对象,可以分配给指定的操作者处理,当任务完成
后,将触发流程继续向下流转。任务实例的生命周期很简单,生成实例-->处理-->任务结束。
5、流程操作
1、如何发布流程
1、如何发布流程
- //如果是读取默认的jbpm.cfg.xml文件
- ProcessEngine engine = Configuration.getProcessEngine();
- //如果不是读取默认的jbpm.cfg.xml文件
- ProcessEngine engine = new Configuration()
- .setResource("ccjbpm.cfg.xml")
- .buildProcessEngine();
- RepositoryService repositoryService = processEngine.getRepositoryService();
- repositoryService.createDeployment()
- .addResourceFromClasspath("cn/javass/jbpm4/hello/hello.jpdl.xml")
- .deploy();
2、如何检索流程定义
- ProcessEngine processEngine = Configuration.getProcessEngine();
- RepositoryService repositoryService = processEngine.getRepositoryService();
- List<ProcessDefinition> pdList = repositoryService.createProcessDefinitionQuery().list();
- for (ProcessDefinition pd:pdList){
- System.out.println("id:"+pd.getId());
- System.out.println("name:"+pd.getName());
- System.out.println("version:"+pd.getVersion());
- System.out.println("deploymentId:"+pd.getDeploymentId());
- System.out.println("---------------");
- }
3、如何启动一个实例
- ProcessEngine processEngine = Configuration.getProcessEngine();
- ExecutionService executionService = processEngine.getExecutionService();
- Map map = new HashMap();
- map.put("pm","ProjectManager");
- map.put("dm", "DepartmentManager ");
- map.put("ceo", "Manager");
- executionService.startProcessInstanceByKey("MyProcess",map);
4、如何检索流程实例
- ProcessEngine processEngine = Configuration.getProcessEngine();
- ExecutionService executionService = processEngine.getExecutionService();
- List<ProcessInstance> piList = executionService.createProcessInstanceQuery().list();
- for (ProcessInstance pi : piList) {
- System.out.println("id:"+pi.getId());
- System.out.println("activeActivityNames:“+pi.findActiveActivityNames());
- System.out.println("state:"+pi.getState());
- System.out.println("-----------------");
5、如何检索出Task
- ProcessEngine processEngine = Configuration.getProcessEngine();
- TaskService taskService = processEngine.getTaskService();
- List<Task> list = taskService.createTaskQuery().list();
- for(Task t : list){
- System.out.println("activityName="+t.getActivityName()+",user="
- +t.getAssignee()+",id="+t.getId());
6、如何完成task
- ProcessEngine processEngine = Configuration.getProcessEngine();
- TaskService taskService = processEngine.getTaskService();
- String taskId = “70003”;//这个是流程运行中生成的任务id
- Map map = new HashMap();
- map.put("dmResult", 1);
- map.put("days", 15);
- taskService.completeTask(taskId,map);
7、如何检索出历史的流程实例
- ProcessEngine engine = Configuration.getProcessEngine();
- HistoryService hs = engine.getHistoryService();
- List<HistoryProcessInstance> list = hs.createHistoryProcessInstanceQuery().list();
- for(HistoryProcessInstance hpi : list){
- System.out.println("state="+hpi.getState()+" ,pdid=“+hpi.getProcessDefinitionId()+
- ",piid="+hpi.getProcessInstanceId()+",startTime="+hpi.getStartTime());
- }
6、流程的描述
1、start(流程开始) 用于描述流程的开始节点,即流程从哪里开始,包含子节点transition,用来描述流程开始后的去向
2、end(流程结束) 用于描述该流程已经结束,包含子节点end-cancel和end-error表示流程结束原因
3、state(流程状态) 描述流程正处于等待外界的调用,与task不同的是他不会将任务分配给某个人
如果是同时只有单个state的情况,可以简单的使用:
executionService.signalExecutionById(“这里默认使用流程实例的id");
如果是同时有多个state的话,应该要先查找到Execution的id,如下使用:
- ExecutionService exe = engine.getExecutionService();
- Execution e = exe.createProcessInstanceQuery()
- .processInstanceId(piid).uniqueResult()
- .findActiveExecutionIn(“state活动名称");
- exe.signalExecutionById(e.getId());
4、decision(决策) 用于判断其中每一个transition元素的转移条件,当遇到一个transition的condition值为true的时候,就流向这个transition,decision活动的expr属性是一个三目运算符用来判断是否流向这个transition,decision活动的handler子元素,通过实现decisionHandler接口来在代码中决定要走向那个流程
方法一:
- <decision name="evaluate document">
- <handler class="org.jbpm.examples.decision.handler.ContentEvaluation" />
- <transition name="good" to="submit document" />
- <transition name="bad" to="try again" />
- <transition name="ugly" to="give up" />
- </decision>
- public class ContentEvaluation implements DecisionHand
- public String decide(OpenExecution execution) {
- String content = (String) execution.getVariable("content");
- if (content.equals("you're great")) {
- return "good";
- }
- if (content.equals("you gotta improve")) {
- return "bad";
- }
- return "ugly";
- }
- }
方法二:
- <decision>
- <transition name="good" to="submit document" />
- <transition name="bad" to="try again" />
- <transition name="ugly" to="give up" />
- </decision>
- Map<String, Object> variables = new HashMap<String, Object>();
- variables.put("content", "good");
- ProcessInstance processInstance =
- executionService.startProcessInstanceByKey("DecisionExpression", variables);
方法三:
- <decision name="evaluate document">
- <transition to="submit document">
- <condition expr="#{content=="good"}" />
- </transition>
- <transition to="try again">
- <condition expr="#{content=="not so good"}" />
- </transition>
- <transition to="give up" />
- </decision>
- Map<String, Object> variables = new HashMap<String, Object>();
- variables.put("content", "good");
- ProcessInstance processInstance =
- executionService.startProcessInstanceByKey("DecisionConditions", variables);
5、task(任务)一般用来处理涉及人机交互的活动,流程引擎会停在这里等待人
工的操作。
assignee属性:用来指定任务分配给谁(可以用变量定义){
- <task name="review" assignee="#{order.owner}" > 《或者assignee="johndoe"》
- <transition to="wait" />
- </task>
- public class Order implements Serializable {
- String owner;
- public Order(String owner) {
- this.owner = owner;
- }
- public String getOwner() {
- return owner;
- }
- public void setOwner(String owner) {
- this.owner = owner;
- }
- }
- Map<String, Object> variables = new HashMap<String, Object>();
- variables.put("order", new Order("johndoe"));
- ProcessInstance processInstance = executionService
- .startProcessInstanceByKey("TaskAssignee", variables);
- List<Task> taskList = taskService.findPersonalTasks("johndoe");
};
candidate-users属性:(可以用逗号分隔用户id列表)用来定义任务的候选人,用户想要接收这个任务需要人工的接受任务takeTask{
TaskService taskService = processEngine.getTaskService();
taskService.takeTask(“task的id”, “领取task的人员");
};
任务候选组candidate-groups:(类似于candidate-users){
- <task name="review" candidate-groups="sales" >
- <transition to="wait" />
- </task>
- IdentityService identityService = processEngine.getIdentityService();
- identityService.createGroup("sales");
- identityService.createUser(“zhang", “zhang", “san");
- identityService.createUser(“li", “li", “si");
- identityService.createMembership(“zhang", "sales");
- identityService.createMembership(“li", "sales");
- taskService.findGroupTasks("zhang");
- taskService.findGroupTasks("li");
注意:为了防止同一个任务被一个分组中的多个人领取,需要将这个任务分配给指定的个人后才能开始执行任务,例如下面
taskService.takeTask(task.getDbid(), "zhang");并且任务呗某一个用户领取之后,应该将该任务标识为已领取状态,以避免造成重复。
};
任务分配器AssignmentHandler:支持使用java代码来进行任务分配{
- <task name="review" g="96,16,127,52">
- <assignment-handler class="org.jbpm.examples.task.assignmenthandler.AssignTask">
- <field name="assignee">
- <string value="johndoe" />
- </field>
- </assignment-handler>
- <transition to="wait" />
- </task>
- public class AssignTask implements AssignmentHandler{
- private String name;
- public String getName() {
- return name;
- }
- public void setName(String name) { this.name = name; }
- public void assign(Assignable assignable, OpenExecution execution)
- throws Exception {
- assignable.setAssignee(name);
- }
- }
注意:Please note that potentially, AssignmentHandler implementations can use the process variables and any other Java API to access resources like your application database to calculate the assignee and candidate users and groups.
}
6、并发(concurrency)包含join(合并分支)和fork(拆分分支)
7、java活动可以指定一个Java类的方法,当流程执行到此活动时,马上自动执行此Java方法。
class属性用来指定此Java类的全类名,要注意这个类要有public无参的默认构造方法。
method属性用来指定调用的方法。
var属性存储方法执行结果的流程变量名称。
- <java g="246,135,92,52" name="java1" class="cn.javass.test.java.MyJava"
- method="sayHello" var="manager">
- <field name="user1"><object expr="#{user1}"/></field>
- <field name="user2"><string value="user2"/></field>
- <arg><string value="xyz"/></arg>
- <arg><object expr="#{abc}"/></arg>
- <transition to="task1"/>
- </java>
- public class MyJava{
- private String user1;
- private String user2;
- …user1和user2的setter
- public String sayHello(String arg1,String arg2){
- System.out.println("user1=="+user1);
- System.out.println("user2=="+user2);
- System.out.println("arg1=="+arg1);
- System.out.println("arg2=="+arg2);
- return “Hello";
- }
- }
8、script活动可以指定一个表达式,当流程执行到此活动时,马上自动执行此表达式,默认用的是juEL
9、sql活动能够支持使用sql直接从数据库中查询数据,并将结果返回到流程变量中。
- <sql g="192,438,92,52" name="sql1" unique="true" var="sqlV">
- <query>
- select * from tbl_user where uuid=:uuid
- </query>
- <parameters>
- <object name="uuid" expr="#{uuid}"></object>
- </parameters>
- <transition to="hql1"/>
- </sql>
10、hql活动能够支持使用hql直接从数据库中查询数据,并将结果返回到流程变量中。
- <hql name="hql1" g="404,457,92,52" unique="true" var="hqlV">
- <query>
- select o from Parent o where o.id=:id
- </query>
- <parameters>
- <string name="id" value="22"/>
- </parameters>
- <transition to="task2"/>
- </hql>
11、foreach活动使得通过一条单独的流程路径来执行多条流程分支的功能
in:将被迭代的集合。集合中的每个元素会生成一个新的同步分支。in执行任意类型的集合,数组和以逗号分隔的字符串。。
var:用来保存集合中当前元素的变量。这个变量会设置到同步流程分支中,并且只对这个流程分支可见。
与join活动连用
通常情况下,foreach活动后面是多次执行的活动,在这个活动后面应该跟一个join活动,并且把join活动的multiplicity设置成为foreach的数量,这样才会等到foreach的多个task执行完成,流程才继续向下,否则,只要有一个foreach的task完成了,流程就向下流转了。
- <foreach name="foreach1" in="D1,D2,D3" var="nowDep">
- <transition to="task5"/>
- </foreach>
- <task name="task5">
- <transition to="join1"/>
- </task>
- <join name="join1" multiplicity="3">
- <transition to="task6"/>
- </join>
12、jBPM的事件机制使得我们可以很方便的在流程、活动、任务生命周期的各个阶段插入定制的代码逻辑,以便实现特定的业务逻辑操作。正是这种机制赋予了jBPM无限的可扩展性
on活动:监听器在jpdl中可以被定为on活动。
on活动的event属性{start|end}指明了监听器是在进入还是结束时触发<event-listener>、<java>、<sql>、<hql>等自动活动还可以作为<transition>元素的子元素,在流经这个<transition>的时候被执行。
- <on event="start">
- <event-listener class="org.jbpm.examples.eventlistener.LogListener">
- <field name="msg"><string value="start on process definition"/></field>
- </event-listener>
- </on>
- <start>
- <transition to="wait"/>
- </start>
- <state name="wait">
- <on event="start">
- <event-listener class="org.jbpm.examples.eventlistener.LogListener">
- <field name="msg"><string value="start on activity wait"/></field>
- </event-listener>
- </on>
- <on event="end">
- <event-listener class="org.jbpm.examples.eventlistener.LogListener">
- <field name="msg"><string value="end on activity wait"/></field>
- </event-listener>
- </on>
- <transition to="park">
- <event-listener class="org.jbpm.examples.eventlistener.LogListener">
- <field name="msg"><string value="take transition"/></field>
- </event-listener>
- </transition>
- </state>
- public class MyEventListener implements EventListener{
- public void notify(EventListenerExecution exection) throws Exception {
- System.out.println("走出Decistion");
- }
- }
13、会签的概念
1、概念:会签,又称会审,也就是流程中某个业务需要经过多人表决,并且根据表决意见的汇总结果,匹配设定的规则,决定流程的走向
7、tomcat的配置:
在将jBPM与web项目结合的时候,需要把jBPM资源包中的juel-engine.jar和juel-impl.jar添加到tomcat/lib下,同时在Web应用的lib下面,把juel-api.jar、juel-engine.jar和juel-impl.jar 删除掉