目录
理解JBPM(java Business Process Management)的基本概念: 1
七、 checkLogin.jsp检验用户是否登录页面 13
十三、 manager_submit.jsp经理审批提交页面 15
一、 将jpdl.xml文件与流程图片打包成zip文件进行发布 19
第1步:更改jbpm.default.cfg.xml配置文件,将下面的部分注释掉 20
第2步:更改jbpm.tx.hibernate.cfg.xml配置文件: 20
第3步:在Spring配置文件中写bean,processEngine和template: 21
三、 Caused by: java.lang.ClassNotFoundException: de.odysseus.el.util.SimpleResolver 22
四、 java.lang.NoClassDefFoundError: javax/el/ExpressionFactory 22
理解JBPM(java Business Process Management)的基本概念:
jPDL - JBPM Process Definition Language
1、定义流程(利用JPDL)
2、部署流程(部署到数据库)
3、创建公文并与流程实例绑定
4、可以通过JBPM的接口,触发流程向下流动
5、可以通过JBPM的接口,获得流动到某个用户那里的文档(即待处理任务列表)
6、可以通过JBPM的接口,结束某个用户的任务(这将触发流程继续向下流动)
7、如此、直至结束
jBPM是一个可扩展、灵活的流程引擎, 它可以运行在独立的服务器上或者嵌入任何Java应用中
第一课:搭建JBPM4运行环境
一、 下载JBPM4.3
可以到官方下载,然后直接解压就可以了
doc: 用户手册,javadoc和开发指南
examples: 用户手册中用到的示例流程
install: 安装脚本
lib: 第三方库和一些特定的jBPM依赖库
src: 源代码
jbpm.jar: jBPM主库归档
二、 搭建JBPM4运行环境
1、 新建一个Java Project项目
2、 添加依赖库jar包
a) jbpm.jar包
b) JBPM目录/lib下的所有的jar包,当然了,这里有些是可选的。
3、 建立配置文件(可以复制官方实例下的配置文件)文件位于src目录下
a) jbpm.hibernate.cfg.xml
b) jbpm.cfg.xml
c) logging.properties
4、 为了方便建立流程文件,需要安装eclipase的流程设计器插件
a) 插件位于:JBPM目录/install/src\gpd/jbpm-gpd-site.zip
b) 安装后重新启动Eclipse,要求Eclipse为3.5版本以上
这样JBPM的流程设计环境及运行环境建立好了。
第二课:管理流程定义
发布流程定义、
查看流程定义、
删除流程定义
一、 流程定义
首先定义一个流程文件。
二、 部署(发布)流程定义
* 在jBPM内部通过各种服务相互作用。 服务接口可以从ProcessEngine中获得, 它是从Configuration构建的
* RepositoryService repositoryService = processEngine.getRepositoryService();
* ExecutionService executionService = processEngine.getExecutionService();
* TaskService taskService = processEngine.getTaskService();
* HistoryService historyService = processEngine.getHistoryService();
* ManagementService managementService = processEngine.getManagementService();
protected RepositoryService repositoryService;//发布,查看,删除流程
protected ExecutionService executionService;
protected ManagementService managementService;
protected TaskService taskService;
protected HistoryService historyService;
protected IdentityService identityService;
ProcessEngine processEngine;
public HelloTest(){
processEngine= Configuration.getProcessEngine();
}
@Test
public void testDeploy(){
/*
* RepositoryService 包含了用来管理发布资源的所有方法
* 通过其addResourceFromClass方法, 流程定义XML的内容可以从文件, 网址,字符串,输入流或zip输入流中获得
*/
RepositoryService repositoryService = processEngine.getRepositoryService();
//进行实际发布
repositoryService.createDeployment().addResourceFromClasspath("helloworld.jpdl.xml").deploy();
}
三、 查看已发布流程
/** * 获取已发布的流程定义 */
@Test
public void testSearchList(){
RepositoryService repositoryService = processEngine.getRepositoryService();
//获取所有已发布流程列表
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
for (ProcessDefinition pd : list){
System.out.println(pd.getId());
}
}
四、 删除流程
@Test
public void testDelete(){
/*
* RepositoryService 包含了用来管理发布资源的所有方法
* 通过其addResourceFromClass方法, 流程定义XML的内容可以从文件, 网址,字符串,输入流或zip输入流中获得
*/
RepositoryService repositoryService = processEngine.getRepositoryService();
//进行实际发布
String deployId = repositoryService.createDeployment().addResourceFromClasspath("helloworld.jpdl.xml").deploy();
System.out.println("deployid = " + deployId);
//获取所有已发布流程列表
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
System.out.println(list.size());
/*
* 删除一个流程定义会把它从数据库中删除。
* 如果在发布中的流程定义还存在活动的流程实例, 这个方法就会抛出异常。
* 如果希望级联删除一个发布中流程定义的 所有流程实例, 可以使用deleteDeploymentCascade
*/
repositoryService.deleteDeploymentCascade(deployId);
list = repositoryService.createProcessDefinitionQuery().list();
System.out.println(list.size());
}
第三课:管理流程实例
n 发起新流程
n 执行等待的流程
n 查看流程实例
n 终止流程实例
n 删除流程实例
一、 发起新的流程实例
/**
* 流程实例管理
*/
public class ProcessInstanceTest {
private ProcessEngine processEngine;
public ProcessInstanceTest(){
processEngine = Configuration.getProcessEngine();
processEngine.getRepositoryService().createDeployment().addResourceFromClasspath("helloworld.jpdl.xml").deploy();
}
/**
* 创建一个新的流程实例
*/
@Test
public void testProcessInstance(){
/** ExecutionService接口,用来管理流程实例 */
ExecutionService executionService = processEngine.getExecutionService();
/** 根据流程的key来创建一个流程实例 */
ProcessInstance pi = executionService.startProcessInstanceByKey("helloworld");
System.out.println(pi);
//检验流程实例pi,是否结束了
System.out.println(pi.isEnded());
//当流程处理等待时,我们可以手动让其向下运行
//参数是根据流程实例的ID
pi = executionService.signalExecutionById(pi.getId());
System.out.println(pi.isEnded());
}
二、 终止流程实例
/**
* 直接将流程实例结束
*/
@Test
public void testProcessInstanceEnd(){
/** ExecutionService接口,用来管理流程实例*/
ExecutionService executionService = processEngine.getExecutionService();
/**根据流程的key来创建一个流程实例
*/
ProcessInstance pi = executionService.startProcessInstanceByKey("helloworld");
System.out.println(pi);
//检验流程实例pi,是否结束了
System.out.println(pi.isEnded());
//当流程实例不需要向下进行时,而直接结束流程
//参数:一个流程实例ID,和一个结束流程的理由
executionService.endProcessInstance(pi.getId(), "取消流程实例");
}
三、 直接删除流程实例
/**
* 直接将流程实例删除
*/
@Test
public void testProcessInstanceDelete(){
/** ExecutionService接口,用来管理流程实例*/
ExecutionService executionService = processEngine.getExecutionService();
/** 根据流程的key来创建一个流程实例 */
ProcessInstance pi = executionService.startProcessInstanceByKey("helloworld");
System.out.println(pi);
//检验流程实例pi,是否结束了
System.out.println(pi.isEnded());
//当流程实例不需要,我们可以直接删除流程实例。并且可以使用级连删除
executionService.deleteProcessInstanceCascade(pi.getId());
}
四、 查看流程实例列表
/**
* 查看流程实例列表
* 可以使用
* executionService.createProcessInstanceQuery().list()
*/
@Test
public void testProcessInstanceList(){
ExecutionService executionService = processEngine.getExecutionService();
ProcessInstance pi = executionService.startProcessInstanceByKey("helloworld");
ProcessInstance pi2 = executionService.startProcessInstanceByKey("helloworld");
//获取流程实例列表
List<ProcessInstance> list = executionService.createProcessInstanceQuery().list();
//循环获取流程实例
for (ProcessInstance processInstance : list){
System.out.println(processInstance.getId());
}
}}
第四课:介绍活动
Ø 控制流程的活动
u Start开始
u End结束
u Decision决策
u Fork分支
u Join结合
u Sub-process流程
u State等待
u task任务
Ø 原子活动
指流程执行到些,并不会做其它的,而是执行一些脚本
u Java
u Script
u Sql
u Hql
u email
第五课 实例-设计请假流程
一、 请假流程定义设计
二、 集成web工程
1、 加入依赖库
2、 加入配置文件
3、 创建JSP页面。
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%@ page import="java.util.*,org.jbpm.api.*" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<a href="index.jsp?action=deploy">deploy</a><br/>
<%
ProcessEngine processEngine = Configuration.getProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
String action = request.getParameter("action");
if("deploy".equals(action)){
repositoryService.createDeployment().addResourceFromClasspath("leave.jpdl.xml").deploy();
} else if("remove".equals(request.getParameter("action"))){
repositoryService.deleteDeploymentCascade(request.getParameter("id"));
}
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
for (ProcessDefinition pd : list){
%>
<%=pd.getId() %>,<%=pd.getName() %> <a href="index.jsp?action=remove&id=<%=pd.getDeploymentId() %>">remove</a><br/>
<%
}
%>
</body>
</html>
4、 所形成的页面
第六课 完善请假流程
一、 要求:
任务人都可以申请请假,但是需要登录之后,请假申请后提交给经理审批,经理审批如果天数大于3天的还需要老板审批,不大于3天的可以直接结束。
当用户登录后,显示自己待办的任务列表
二、 流程定义设计
流程定义代码如下:
<?xml version="1.0" encoding="gbk"?>
<process name="leave" xmlns="http://jbpm.org/4.3/jpdl">
<start g="118,32,48,48" name="start1">
<transition g="-47,-17" name="to 申请" to="申请"/>
</start>
<task assignee="#{owner}" form="request.jsp" g="92,125,92,52" name="申请">
<transition to="经理审批"/>
</task>
<task assignee="manager" form="manager.jsp" g="91,223,92,52" name="经理审批">
<transition g="-23,-12" name="批准" to="exclusive1"/>
<transition g="44,236;41,154:-6,-11" name="驳回" to="申请"/>
</task>
<decision expr="#{day > 3 ? '老板审批' : '结束'}" g="112,320,48,48" name="exclusive1">
<transition g="-44,-14" name="老板审批" to="老板审批"/>
<transition g="-47,-17" name="结束" to="end1"/>
</decision>
<task assignee="boss" form="boss.jsp" g="271,322,92,52" name="老板审批">
<transition g="313,467:-47,-17" name="to end1" to="end1"/>
</task>
<end g="114,442,48,48" name="end1"/>
</process>
说明:任务标签中的form属性表示该任务所对应的表章,在实例中这些表单我们自己手动建立了。
三、 创建首页
在首页,可以发布流程定义,也可以删除流程定义,并且可以创建一个流程定义实例
代码:
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%@include file="/checkLogin.jsp" %>
<%@ page import="java.util.*,org.jbpm.api.*,org.jbpm.api.task.*" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%
ProcessEngine processEngine = Configuration.getProcessEngine();
//获取流程定义管理接口
RepositoryService repositoryService = processEngine.getRepositoryService();
//获取流程实例管理接口
ExecutionService executionService = processEngine.getExecutionService();
//获取任务管理接口
TaskService taskService = processEngine.getTaskService();
String username = (String)session.getAttribute("username");
//索取已发布的流程列表
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
//索取流程实例列表
List<ProcessInstance> piList = executionService.createProcessInstanceQuery().list();
//索取指定人员的任务列表
List<Task> taskList = taskService.findPersonalTasks(username);
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>流程管理首页</title>
</head>
<body>
当前用户:<%=username %> <a href="login.jsp">重新登陆</a><br/>
<a href="deploy.jsp">发布新流程</a>
<hr/>
<table border="1">
<tr>
<td colspan="6" align="center">已发布流程定义</td>
</tr>
<tr>
<td>序号</td>
<td>流程ID</td>
<td>流程名称</td>
<td>流程版本</td>
<td>Key</td>
<td><span> </span></td>
</tr>
<%
for (int i = 0; i < list.size(); i++){
ProcessDefinition pd = (ProcessDefinition)list.get(i);
%>
<tr>
<td><%=i+1 %></td>
<td><%=pd.getId() %></td>
<td><%=pd.getName() %></td>
<td><%=pd.getVersion() %></td>
<td><%=pd.getKey()%></td>
<td>
<a href="deletePD.jsp?deployId=<%=pd.getDeploymentId() %>">remove</a>|
<a href="start.jsp?key=<%=pd.getKey() %>">start</a>
</td>
</tr>
<%
}
%>
</table>
<hr/>
<table border="1">
<tr>
<td colspan="5">流程实例</td>
</tr>
<tr>
<td>序号</td>
<td>流程实例ID</td>
<td>活动</td>
<td>状态</td>
<td><span> </span></td>
</tr>
<%
for(int i = 0; i < piList.size(); i++){
ProcessInstance pi = (ProcessInstance)piList.get(i);
%>
<tr>
<td><%=i + 1 %></td>
<td><%=pi.getId() %></td>
<td><%=pi.findActiveActivityNames() %></td>
<td><%=pi.getState() %></td>
<td>
<a href="#"><span>查看</span></a>
</td>
</tr>
<%
}
%>
</table>
<hr/>
<table border="1">
<tr>
<td colspan="5">待办任务列表</td>
</tr>
<tr>
<td>序号</td>
<td>任务ID</td>
<td>任务名称</td>
<td>当前者</td>
<td> </td>
</tr>
<%
for (int i = 0 ; i < taskList.size(); i++){
Task task = (Task)taskList.get(i);
%>
<tr>
<td><%=i + 1 %></td>
<td><%=task.getId() %></td>
<td><%=task.getName() %></td>
<td><%=task.getAssignee() %></td>
<td>
<a href="<%=task.getFormResourceName()%>?taskId=<%=task.getId() %>">查看</a>
</td>
</tr>
<%
}
%>
</table>
</body>
</html>
首页的界面:
四、 deploy.jsp发布流程
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%@ page import="java.util.*,org.jbpm.api.*,org.jbpm.api.task.*" %>
<%
ProcessEngine processEngine = Configuration.getProcessEngine();
//获取流程定义管理接口
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.createDeployment().addResourceFromClasspath("leave.jpdl.xml").deploy();
response.sendRedirect("index.jsp");
%>
五、 deletePD.jsp删除流程定义
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%@ page import="java.util.*,org.jbpm.api.*,org.jbpm.api.task.*" %>
<%
ProcessEngine processEngine = Configuration.getProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
String deployId = request.getParameter("deployId");
repositoryService.deleteDeploymentCascade(deployId);
response.sendRedirect("index.jsp");
%>
六、 start.jsp启动流程实例
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%@ page import="java.util.*,org.jbpm.api.*,org.jbpm.api.task.*"%>
<%
ProcessEngine processEngine = Configuration.getProcessEngine();
ExecutionService executionService = processEngine
.getExecutionService();
Map map = new HashMap();
map.put("owner", session.getAttribute("username"));
executionService.startProcessInstanceByKey(request
.getParameter("key"), map);
response.sendRedirect("index.jsp");
%>
七、 checkLogin.jsp检验用户是否登录页面
因为,在创建流程实例时,需要一个用户,因此需要检验用户是否登录
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%
if (session.getAttribute("username") == null){
//如果用户没有登录,则跳转到登录页面进行用户登录
//因为用户没有登录是没有办法获取待办任务列表
response.sendRedirect("login.jsp");
}
%>
八、 login.jsp用户登录页面
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>登录</title>
</head>
<body>
<br>
<form action="doLogin.jsp" method="post">
用户名:<input name="username"><br/>
<input type="submit" value="用户登录"/>
</form>
</body>
</html>
九、 doLogin.jsp进行用户登录
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%
String username = request.getParameter("username");
if (null == username){response.sendRedirect("login.jsp");}
session.setAttribute("username", username);
response.sendRedirect("index.jsp");
%>
十、 request.jsp申请请假表单
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'reqeust.jsp' starting page</title>
</head>
<body>
<fieldset>
<legend>申请</legend>
<form action="submit.jsp" method="post">
<input type="hidden" name="taskId" value="${param.taskId }"/>
申请人:<input name="owner" value="${sessionScope['username']}"><br/>
请假时间:<input name="day" value=""/><br/>
请假原因:<textarea name="reason"></textarea><br/>
<input type="submit">
</form>
</fieldset>
</body>
</html>
十一、 submit.jsp请假提交页面(提交任务)
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%@ page import="java.util.*,org.jbpm.api.*,org.jbpm.api.task.*" %>
<%
ProcessEngine processEngine = Configuration.getProcessEngine();
//获取任务管理接口
TaskService taskService = processEngine.getTaskService();
String taskId = request.getParameter("taskId");
String ower = request.getParameter("owner");
int day = Integer.parseInt(request.getParameter("day"));
String reason = request.getParameter("reason");
Map map = new HashMap();
map.put("day", day);
map.put("reason",reason);
taskService.completeTask(taskId, map);
response.sendRedirect("index.jsp");
%>
十二、 manager.jsp经理审批页面
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%@ page import="java.util.*,org.jbpm.api.*,org.jbpm.api.task.*" %>
<%
ProcessEngine processEngine = Configuration.getProcessEngine();
TaskService taskService = processEngine.getTaskService();
String taskId = request.getParameter("taskId");
Task task = taskService.getTask(taskId);
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'manager.jsp' starting page</title>
</head>
<body>
<fieldset>
<legend>经理审批</legend>
<form action="manager_submit.jsp" method="post">
<input type="hidden" name="taskId" value="${param.taskId}">
申请人:<%=taskService.getVariable(taskId,"owner") %><br/>
申请天数:<%=taskService.getVariable(taskId,"day") %><br/>
申请原因:<%=taskService.getVariable(taskId,"reason") %><br/>
<input type="submit" value="批准"/>
<input type="submit" value="驳回"/>
</form>
</fieldset>
</body>
</html>
十三、 manager_submit.jsp经理审批提交页面
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%@ page import="java.util.*,org.jbpm.api.*,org.jbpm.api.task.*" %>
<%
ProcessEngine processEngine = Configuration.getProcessEngine();
//获取任务管理接口
TaskService taskService = processEngine.getTaskService();
String taskId = request.getParameter("taskId");
taskService.completeTask(taskId,"批准");
response.sendRedirect("index.jsp");
%>
十四、 老板审批页面
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%@ page import="java.util.*,org.jbpm.api.*,org.jbpm.api.task.*" %>
<%
ProcessEngine processEngine = Configuration.getProcessEngine();
TaskService taskService = processEngine.getTaskService();
String taskId = request.getParameter("taskId");
Task task = taskService.getTask(taskId);
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<fieldset>
<legend>老板审核</legend>
<form action="submit_boss.jsp" method="post">
<input type="hidden" name="taskId" value="${param.taskId}">
申请人:<%=taskService.getVariable(taskId, "owner") %><br/>
请假时间:<%=taskService.getVariable(taskId, "day") %><br/>
请假原因:<%=taskService.getVariable(taskId, "reason") %><br/>
<input type="submit"/>
</form>
</fieldset>
</body>
十五、 老板审批提交页面
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%@ page import="java.util.*,org.jbpm.api.*,org.jbpm.api.task.*" %>
<%
ProcessEngine processEngine = Configuration.getProcessEngine();
//获取任务管理接口
TaskService taskService = processEngine.getTaskService();
String taskId = request.getParameter("taskId");
taskService.completeTask(taskId);
response.sendRedirect("index.jsp");
%>
第七课 完成经理驳回功能
一、 修改经理审批页面
<fieldset>
<legend>经理审批</legend>
<form action="manager_submit.jsp" method="post">
<input type="hidden" name="taskId" value="${param.taskId}">
申请人:<%=taskService.getVariable(taskId,"owner") %><br/>
申请天数:<%=taskService.getVariable(taskId,"day") %><br/>
申请原因:<%=taskService.getVariable(taskId,"reason") %><br/>
<input name="r" type="submit" value="批准"/>
<input name="r" type="submit" value="驳回"/>
</form>
</fieldset>
加入一个参数,传入到审批提交页面,以告诉提交页面是批准还是驳回
二、 修改经理审批提交页面
<%
request.setCharacterEncoding("GB18030");
//response.setContentType("text/html;charset=GB18030");
ProcessEngine processEngine = Configuration.getProcessEngine();
//获取任务管理接口
TaskService taskService = processEngine.getTaskService();
String taskId = request.getParameter("taskId");
String r = request.getParameter("r");
taskService.completeTask(taskId,r);
response.sendRedirect("index.jsp");
%>
说明:当任务有多个走向时,在提交任务时需要指定任务下一个走向的路径。
<task assignee="manager" form="manager.jsp" g="91,223,92,52" name="经理审批">
<transition g="-23,-12" name="批准" to="exclusive1"/>
<transition g="44,236;41,154:-6,-11" name="驳回" to="申请"/>
</task>
以上务有“批准”和“驳回”两条路径,因此在提交时需要指明走向如下
taskService.completeTask(taskId,”批准”);
或
taskService.completeTask(taskId,”驳回”);
这样就完成了批准和驳回功能了
第八课 组织机构
Ø 用户
Ø 用户组
Ø 成员关系
一个任务可以分配给一个用户组,然后用户组中的用户可以竟争的方式来完成任务
以下为实例
一、 流程定义设计
二、 测试代码
public class TaskTest {
private ProcessEngine processEngine;
public TaskTest() {
processEngine = Configuration.getProcessEngine();
// 获取组织机构服务接口
IdentityService identityService = processEngine.getIdentityService();
// 创建一个用户组
identityService.createGroup("dev");
// 创建用户user1和user2
identityService.createUser("user1", "user1", "user1");
identityService.createUser("user2", "user2", "user2");
// 建立用户与用户组的关系,也就是将用户加入到某一个用户组
// 以下是将用户user1、user2加入到dev用户组中
identityService.createMembership("user1", "dev");
identityService.createMembership("user2", "dev");
}
@Test
public void testTask() {
RepositoryService repositoryService = processEngine
.getRepositoryService();
TaskService taskService = processEngine.getTaskService();
ExecutionService executionService = processEngine.getExecutionService();
// 发布流程
String deploymentId = repositoryService.createDeployment()
.addResourceFromClasspath("task.jpdl.xml").deploy();
//启动一个新的实例
executionService.startProcessInstanceByKey("task");
//索取用户组中指定用户的任务列表的数量
System.out.println(taskService.findGroupTasks("user1").size());
System.out.println(taskService.findGroupTasks("user2").size());
//索取用户组中指定用户的任务列表
List<Task> groupTaskList = taskService.findGroupTasks("user1");
//注意:taskService.findPersonalTasks(username);是获取指定用户的任务列表,
//取得任务列表中第一个任务
Task task = groupTaskList.get(0);
//用户user1接受任务
taskService.takeTask(task.getId(), "user1");
//提交任务
taskService.completeTask(task.getId());
}
}
第九课 监听事件
n 流程实例
u 启动
u 结束
n 活动
u 开始
u 结束
事件监听:是工作流程一个功能回调一个主要方法
第十课 显示流程定义图片并跟踪当前节点
一、 将jpdl.xml文件与流程图片打包成zip文件进行发布
文件名要求与流程文件名一样
二、 修改发布流程页面代码
<%@page import="java.util.*,org.jbpm.api.*,java.util.zip.*"%>
<%
ProcessEngine processEngine = Configuration.getProcessEngine();
RepositoryService repositoryService = processEngine
.getRepositoryService(); //repositoryService.createDeployment().addResourceFromClasspath("leave.jpdl.xml").deploy();
ZipInputStream zis = new ZipInputStream(this.getClass()
.getResourceAsStream("/leave.zip"));
repositoryService.createDeployment()
.addResourcesFromZipInputStream(zis).deploy();
response.sendRedirect("index.jsp");
%>
三、 建立显示页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@page import="org.jbpm.api.*,java.util.*,org.jbpm.api.model.*" %>
<%
String id = request.getParameter("id");
ProcessEngine processEngine = Configuration.getProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
ExecutionService executionService = processEngine.getExecutionService();
ProcessInstance processInstance = executionService.findProcessInstanceById(id);
Set<String> activityNames = processInstance.findActiveActivityNames();
ActivityCoordinates ac = repositoryService.getActivityCoordinates(processInstance.getProcessDefinitionId(),activityNames.iterator().next());
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<img src="pic.jsp?id=<%=id %>" style="position:absolute;left:0px;top:0px;">
<div style="position:absolute;border:1px solid red;left:<%=ac.getX()%>px;top:<%=ac.getY()%>px;width:<%=ac.getWidth()%>px;height:<%=ac.getHeight()%>px;"></div>
</body>
</html>
四、 加载图片的pic.jsp页面
<%@page import="org.jbpm.api.*,java.io.*"%>
<%
ProcessEngine processEngine = Configuration.getProcessEngine();
RepositoryService repositoryService = processEngine
.getRepositoryService();
ExecutionService executionService = processEngine
.getExecutionService();
String id = request.getParameter("id");
ProcessInstance processInstance = executionService
.findProcessInstanceById(id);
String processDefinitionId = processInstance
.getProcessDefinitionId();
ProcessDefinition processDefinition = repositoryService
.createProcessDefinitionQuery().processDefinitionId(
processDefinitionId).uniqueResult();
InputStream inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),"leave.png");
byte[] b = new byte[1024];
int len = -1;
while ((len = inputStream.read(b, 0, 1024)) != -1) {
response.getOutputStream().write(b, 0, len);
}
%>
附录一:整合jBPM-4与Spring
第1步:更改jbpm.default.cfg.xml配置文件,将下面的部分注释掉
<!--
<hibernate-configuration>
<cfg resource="jbpm.hibernate.cfg.xml" />
</hibernate-configuration>
<hibernate-session-factory />
-->
注释的部分是在jBPM4中创建了sessionFactory,而我们只需要一个sessionFactory。既然要将jBPM4与Spring的整合,那就希望由Spring来统一管理sessionFactory和事务,在Spring的配置文件中构造一个sessionFactory。 ProcessEngine是jBPM4的Facade模式,一切由它与外部交互,
第2步:更改jbpm.tx.hibernate.cfg.xml配置文件:
将
<standard-transaction-interceptor/>
改为
<spring-transaction-interceptor />
然后将
<transaction/>
<hibernate-session/> 改为
<hibernate-session current="true"/>
这部分修改是将jBPM4创建的spring事务和hibernate的session改成从当前的ThreadLocal中获得session和事务。
第3步:在Spring配置文件中写bean,processEngine和template:
<bean id="jbpmConfiguration" class="org.jbpm.pvm.internal.cfg.SpringConfiguration">
<constructor-arg value="jbpm/jbpm.cfg.xml" />
</bean>
<bean id="processEngine" factory-bean="jbpmConfiguration" factory-method="buildProcessEngine" />
processEngine直接使用factory-bean指向jbpmConfiguration,也就是 org.jbpm.pvm.internal.cfg.SpringConfiguration,并从SpringConfiguration的 buildProcessEngine中获得。
FAQ 问题
一、 JBPM4项目和tomcat6.0的兼容问
基于JBPM4的web项目jsp页面发布出错,错误如下:
exception
javax.servlet.ServletException: java.lang.LinkageError: loader constraint violation: when resolving interface method "javax.servlet.jsp.JspApplicationContext.getExpressionFactory()Ljavax/el/ExpressionFactory;" the class loader (instance of org/apache/jasper/servlet/JasperLoader) of the current class, org/apache/jsp/OnDuty/wfmanage_jsp, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, javax/servlet/jsp/JspApplicationContext, have different Class objects for the type javax/el/ExpressionFactory used in the signature
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:275)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
root cause
java.lang.LinkageError: loader constraint violation: when resolving interface method "javax.servlet.jsp.JspApplicationContext.getExpressionFactory()Ljavax/el/ExpressionFactory;" the class loader (instance of org/apache/jasper/servlet/JasperLoader) of the current class, org/apache/jsp/OnDuty/wfmanage_jsp, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, javax/servlet/jsp/JspApplicationContext, have different Class objects for the type javax/el/ExpressionFactory used in the signature
org.apache.jsp.OnDuty.wfmanage_jsp._jspInit(wfmanage_jsp.java:27)
org.apache.jasper.runtime.HttpJspBase.init(HttpJspBase.java:52)
org.apache.jasper.servlet.JspServletWrapper.getServlet(JspServletWrapper.java:159)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:329)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
原因是项目中WEB-INF\lib中的三个jar包(juel.jar, juel-engine.jar, juel-impl.jar)和tomcat6下lib中jar包(el-api.jar)冲突
解决方法:
方法一:换成tomcat5.5 一点问题也没有了
方法二:将juel.jar, juel-engine.jar, juel-impl.jar这三个包复制到tomcat6下lib中,并删除原来的el-api.jar,切记要把WEB-INF\lib中的juel.jar, juel-engine.jar, juel-impl.jar删除。不然还是要冲突
。
二、 org.hibernate.exception.ConstraintViolationException: could not delete: [org.jbpm.pvm.internal.model.ExecutionImpl#1]
方法:连接Mysql5时,jBPM4运行到 End结点时的错误,把 hibernate.dialect 改为 org.hibernate.dialect.MySQLInnoDBDialect
三、 Caused by: java.lang.ClassNotFoundException: de.odysseus.el.util.SimpleResolver
原因:是tomcat 6.0下面的el-api.jar
解决方法:删掉tomcat6的el.jar,加入juel.jar,juel-impl.jar,juel-engine.jar
juel.jar,juel-impl.jar,juel-engine.jar 可以在jbmp4.0的lib目录下找到,
四、 java.lang.NoClassDefFoundError: javax/el/ExpressionFactory
原因:tomcat/lib下的el-api.jar被删除
解决方法:把名为javaee.jar包放到tomcat/lib里面就可以了,可以在myeclipse下找到,