Jbpm4
常用操作
一、
ProcessEngine
:流程引擎。是
JBPM
上层类,相当于
Hibernate
的
SessionFactory
级别。
//
获得方式:
ProcessEngine
processEngine
= Configuration.getProcessEngine();
/*Configuration
类会读取
classpath
下的
jbpm.cfg.xml
文件进行流程引擎的加载。
ProcessEngine
是单例模式,即整个系统只会有一个
processEngine
实例。
*/
二、流程定义
1.
部署流程定义
ProcessEngine
processEngine = Configuration.getProcessEngine();
RepositoryService
repositoryService
=
processEngine
.getRepositoryService();
例:布署文件中的流程
//
布署当前目录下
pd.jpdl.xml
文件
String
deploymentId = repositoryService.createDeployment()
.addResourceFromClasspath(
"process.jpdl.xml"
).deploy();
/* deploymentId
是发布的流程返回的
ID
号
*/
2.
删除流程定义
类
ProcessDefinition
包含如下属性:
ID
:流程定义
ID
号
DeploymentId
:流程定义的布署
ID
号
Key
:关键字
name
:流程名
version
:版本号
数据如下
ID Key
名称
版本
hello-1 hello hello 1
//
获取类
ProcessDefinition
的属性
ID
String
deploymentId
= request.getParameter(
"deploymentId"
);
//
根据流程
ID
获取流程定义实例
ProcessDefinition
pd
=
repositoryService
.createProcessDefinitionQuery()
.processDefinitionId(
deploymentId
).uniqueResult();
//
根据流程定义的布署
ID
号,删除该流程定义(根据流程定义的
ID
号级联删除)
//
注意
:jbpm4
是不允许直接根据流程定义的
ID
来直接删除流程定义的,因为还要删除其它配置数据
repositoryService.deleteDeploymentCascade(pd.getDeploymentId());
3.
获取全部流程定义
根据流程名获取所有流程定义
List<ProcessDefinition> processDefinitions = repositoryService
.createProcessDefinitionQuery().orderAsc( ProcessDefinitionQuery.PROPERTY_NAME).list();
//
还可以根据以下顺序进行排序
(org.jbpm.api.ProcessDefinitionQuery)
public
static
final
java.lang.String
PROPERTY_DEPLOYMENT_TIMESTAMP
"deployment.timestamp"
public
static
final
java.lang.String
PROPERTY_ID
"idProperty.stringValue"
public
static
final
java.lang.String
PROPERTY_KEY
"keyProperty.stringValue"
public
static
final
java.lang.String
PROPERTY_NAME
"idProperty.objectName"
public
static
final
java.lang.String PROPERTY_VERSION
"versionProperty.longValue"
二、流程实例
1.
启动一个流程实例
1.1
根据
key
启动流程实例
//
用户必须为新启动的流程实例分配一个
key
,
这个
key
是用户执行的时候定义的且唯一。通常在业务流程领域找到这种
key
。
比如,一个订单
id
或者一个保险单号。
ProcessInstance
processInstance = executionService.startProcessInstanceByKey(
"ICL"
,
"CL92837"
);
//key
可以用来创建流程实例的
id
,
格式为
{process-key}.{execution-id}
。
所以上面的代码会创建一个
id
为
ICL.CL92837
的流向
(
execution
)。
1.2
根据数据库主键启动流程实例
//
如果没有提供用户定义的
key
,数据库就会把主键作为
key
。
这样可以使用如下方式获得
id
:
ProcessInstance processInstance = executionService.startProcessInstanceByKey(
"ICL"
);
String
pid
=
processInstance
.getId();
//
最好使用一个用户定义的
key
。提供给一个用户定义的
key
,
你可以组合流向的
id
,而不是执行一个基于流程变量的搜索
-
那种方式太消耗资源了。
1.3
根据变量启动流程实例
//
为一个新的流程实例启动时就提供一组对象参数。
将这些参数放在
variables
变量里,
然后可以在流程实例创建和启动时使用。
Map
<String,Object> variables =
new
HashMap<String,Object>();
variables.put(
"customer"
,
"John Doe"
);
variables.put(
"type"
,
"Accident"
);
variables.put(
"amount"
,
new
Float(763.74));
ProcessInstance processInstance = executionService.startProcessInstanceByKey(
"ICL"
, variables);
//
//JBPM4.4
支持变量历史
//
变量可以被标记为作为历史记录保存。这意味着,当流程实例结束,
它的运行阶段的信息被删除,历史细节依然会被保存。
//
通过公共
API ExecutionService
启用变量的历史功能
void
createVariable(String executionId, String name, Object value,
boolean
historyEnabled);
void
createVariables(String executionId, Map<String, ?> variables,
boolean
historyEnabled);
//
通过变量定义
<variable name=
"declaredVar"
type=
"string"
init-expr=
"testing declared variable"
history=
"true"
/>
2.
根据流程定义,查看流程实例
//
根据类
ProcessDefinition
的属性
ID
,查看该流程的所有实例
String processDefinitionId = request.getParameter(
"processDefinitionId"
);
return
executionService.createProcessInstanceQuery().processDefinitionId(processDefinitionId).list();
3.
执行实例
//
根据类
ProcessInstance
的属性
ID(
流程实例
ID)
,执行流程实例
String processInstanceId = request.getParameter(
"processInstanceId"
);
executionService.signalExecutionById(processInstanceId);
四
.
任务
//
假设流程定义
4-1
如下:
<process name=
"TaskAssignee"
>
<start>
<transition to=
"review"
/>
</start>
<task name=
"review"
assignee=
"#{order.owner}"
>
<transition to=
"work"
/>
</task>
<task name=
"review"
assignee=
"de style="
color: rgb(255, 102, 0);
">johndoede>"
>
<transition to=
"wait"
/>
</task>
<state name=
"wait"
/>
</process>
assignee=
"johndoe"
//
表示任务会被分配给用户
ID
为
"johndoe"
的人。
assignee=
"#{order.owner}"
//
任务被分配给
#{order.owner}
。表示通过
Order
对的
getOwner()
方法会用来获得用户
id
,该用户负责完成这个任务。
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;
}
}
1.
获取任务列表
1.1
根据用户
ID
获取任务列表
List<Task> taskList = taskService.findPersonalTasks(
"johndoe"
);
1.2
根据任务候选人或候选组获取任务列表
任务可能被分配给一组用户。
其中的一个用户应该接受这个任务并完成它。
candidate-groups
:一个使用逗号分隔的组
id
列表。
所有组内的用户将会成为这个任务的候选人。
candidate-users
:一个使用逗号分隔的用户
id
列表。
所有的用户将会成为这个任务的候选人。
例如:
<task name=
"review"
candidate-groups=
"sales-dept"
>
<transition to=
"wait"
/>
</task>
假设:
sales-dept
有两个成员:
johndoe
和
joesmoe
//
这个任务被创建时,不显示在任何人的个人任务列表中。
下面的任务列表会是空的。
taskService.getAssignedTasks(
"johndoe"
);
taskService.getAssignedTasks(
"joesmoe"
);
分组任务列表中,用户接口必须只接受对这些任务的
“
接受
”
操作。
taskService.takeTask(task.getDbid(),
"johndoe"
);
当一个用户接受了一个任务,这个任务的分配人就会变成当前用户。任务会从所有候选人的分组任务列表中消失,它会出现在用户的已分配列表中。
1.3
在一个列表中显示该某人的所有任务
包括他的个人任务,候选任务,这时直接用
jbpm4
提供的
api
完成不了该功能要求。于是可以使用以下方式进行扩展:
/**
*
取得用户的对应的任务列表
*
@param
userId
*
@return
*/
public
List<TaskImpl> getTasksByUserId(String userId){
AppUser user=(AppUser)getHibernateTemplate().load(AppUser.
class
,
new
Long(userId));
Iterator<AppRole> rolesIt=user.getRoles().iterator();
StringBuffer groupIds=
new
StringBuffer();
int
i=0;
while
(rolesIt.hasNext()){
if
(i>0)groupIds.append(
","
);
groupIds.append(
"'"
+rolesIt.next().getRoleId().toString()+
"'"
);
}
/**
* select * from `jbpm4_task` task
left join jbpm4_participation pt on task.`DBID_`=pt.`TASK_`
where task.`ASSIGNEE_`='1' or ( pt.`TYPE_` = 'candidate' and (pt.`USERID_`='1')
or pt.`GROUPID_`in ('1'))
*/
StringBuffer hqlSb=
new
StringBuffer();
hqlSb.append(
"select task from org.jbpm.pvm.internal.task.TaskImpl task left join task.participations pt where task.assignee=?"
);
hqlSb.append(
" or (pt.type = 'candidate' and ((pt.userId=?)"
);
if
(user.getRoles().size()>0){
hqlSb.append(
" or (pt.groupId in ("
+groupIds.toString()+
"))"
);
}
hqlSb.append(
"))"
);
hqlSb.append(
" order by task.priority desc"
);
return
findByHql(hqlSb.toString(),
new
Object[]{userId,userId});
}
2
分配任务
如果在流程定义文件中将任务指定到了个人,则
jbpm
自动分配给个人。否则需要进行指定
2.1
给用户组的用户分配任务
流程定义文件
:
<task name=
"review"
candidate-groups=
"sales-dept"
>
<transition to=
"wait"
/>
</task>
假设:
sales-dept
有两个成员:
johndoe
和
joesmoe
分组任务列表中,用户接口必须只接受对这些任务的
“
接受
”
操作。
taskService.takeTask(task.getDbid(),
"johndoe"
);
当一个用户接受了一个任务,这个任务的分配人就会变成当前用户。任务会从所有候选人的分组任务列表中消失,它会出现在用户的已分配列表中。
2.2
任务分配处理器分配任务
一个
AssignmentHandler
可以通过编程方式来计算
一个任务的分配人和候选人
。
public
interface
AssignmentHandler
extends
Serializable {
void
assign(Assignable assignable, OpenExecution execution)
throws
Exception;
}
Assignable
是任务和泳道的通用接口。
所以任务分配处理器可以使用在任务,
也可以用在泳道中。
包含任务分配处理器的流程定义
4-2
如下:
<process name=
"TaskAssignmentHandler"
xmlns=
"http://jbpm.org/4.2/jpdl"
>
<start g=
"20,20,48,48"
>
<transition to=
"review"
/>
</start>
<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>
<state name=
"wait"
g=
"255,16,88,52"
/>
</process>
类
AssignTask
代码如下
:
public
class
AssignTask
implements
AssignmentHandler {
String
assignee
;
public
void
assign(Assignable assignable, OpenExecution execution) {
assignable.setAssignee(
assignee
);
}
}
请注意,默认
AssignmentHandler
实现可以使用使用流程变量,任何其他
Java
API
可以访问资源
,像你的应用数据库来计算分配人和候选人用户和组。
启动一个
TaskAssignmentHandler
的新流程实例
,
会立即让新流程实例运行到任务节点。
一个新
review
任务被创建,在这个时候
AssignTask
的分配处理器被调用
。这将设置
johndoe
为分配人。
所以
John
Doe
将在他自己的任务列表中找到这个任务
。
2.3
给泳道分配任务
任务泳道如下面的流程文件
4
-3
:
<process name=
"TaskSwimlane"
xmlns=
"http://jbpm.org/4.2/jpdl"
>
<swimlane name=
"sales representative"
candidate-groups=
"sales-dept"
/>
<start>
<transition to=
"enter order data"
/>
</start>
<task name=
"enter order data"
swimlane=
"sales representative"
>
<transition to=
"calculate quote"
/>
</task>
<task name=
"calculate quote"
swimlane=
"sales representative"
>
</task>
</process>
在这个例子中,我们在身份组件中
创建了下面的信息
:
identityService.createGroup(
"sales-dept"
);
identityService.createUser(
"johndoe"
,
"johndoe"
,
"John"
,
"Doe"
);
identityService.createMembership(
"johndoe"
,
"sales-dept"
);
在启动一个新流程实例后,用户
johndoe
将成为
enter
order
data
的一个候选人
。还是像上一个流程候选人例子一样,
John
Doe
可以像这样接收任务
:
taskService.takeTask(task.getDbid(),
"johndoe"
);
接收这个任务将让
johndoe
成为任务的负责人。
直到任务与泳道
sales
representative
关联
,
分配人
johndoe
也会关联到泳道中作为负责人。接下来,
John
Doe
可以像下面这样完成任务
:
taskService.completeTask(taskDbid);
完成任务会将流程执行到下一个任务,下一个任务是calculate quote。这个任务也关联着泳道。因此,任务会分配给johndoe。