在上一篇文章中我们已经基本上实现了一个请假流程定义的发布和删除操作,并且我们已经将jbpm4的流程定义集成到了web服务中。下面我们将要做如下几件事:
1)在web应用中实现请假流程的发起;
2)针对不同用户的登录,我们显示不同的代办任务以实现用户完成自己的task。
(再次声明:这只是我的个人学习笔记,主要是通过看了family168网--临远的视频教程,感谢原作。)
具体操作如下:
1、web应用程序的整体文件架构
图5-1 程序的整体文件架构
这里简要作如下说明:
1)对于程序的src目录下的文件主要是请假流程leave.jpdl.xml的流程定义文件和jbpm4的注册文件;
2)在src目录下为了通过编译我们导入了jbpm4.4的第三方库文件;
3)在WebContent目录下的文件主要是web应用中运行时使用的jsp文件,此处我们为了实现程序视图和逻辑处理的分离将相应的操作放在特定的jsp文件中实现;
4)在WebContent/WEB-INF/lib目录下我们导入了jbpm4.4运行时所需要的第三方库文件;
具体程序的实现细节以及每个jsp文件的作用我们将在后面详细给出。
2、流程定义的改动
流程定义源文件:leave.jpdl.xml文件的源码如下
- <?xml version="1.0" encoding="UTF-8"?>
- <process name="leave" xmlns="http://jbpm.org/4.4/jpdl">
- <start g="136,49,48,48" name="start1">
- <transition to="申请"/>
- </start>
- <!-- #{owner}的作用是实现变量存储申请人,从而达到谁申请谁就能获得代办任务列表 -->
- <task assignee="#{owner}" form="request.jsp" g="112,143,92,52" name="申请">
- <transition to="经理审批"/>
- </task>
- <task assignee="manager" form="manager.jsp" g="113,247,92,52" name="经理审批">
- <transition g="-79,-22" name="批准" to="exclusive1"/>
- <transition g="47,270;48,169:-45,-22" name="驳回" to="申请"/>
- </task>
- <decision expr="#{day > 3 ? '老板审批' : '结束'}" g="131,354,48,48" name="exclusive1">
- <transition g="273,375:-69,-22" name="老板审批" to="老板审批"/>
- <transition g="-50,-22" name="结束" to="end1"/>
- </decision>
- <task assignee="boss" form="boss.jsp" g="228,401,92,52" name="老板审批">
- <transition g="275,473:" to="end1"/>
- </task>
- <end g="135,450,48,48" name="end1"/>
- </process>
这里注意的是我们将第一个task节点的任务分配给#{owner}变量,从而实现了不同用户的动态登录都可以申请请假,而我们的“经理审批”task节点则分配给了manager用户,"老板审批"task节点则分配给了boss用户,这些操作都可以在图形界面的property中设置。
另外需要说明的是对于任务的完成人我们并不需要显示的在程序中保存,jbpm会自动保存。
流程定义的图形界面如下:
图5-2 流程定义图形界面
3、index.jsp的设计和实现
index.jsp是整个web应用程序的主界面,其代码如下:
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <!-- 检测用户是否已经登录 -->
- <%@include file="checkLogin.jsp" %>
- <%@page import="java.util.*,org.jbpm.api.*,org.jbpm.api.task.*"%>
- <!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>Index</title>
- </head>
- <body>
- <%
- //获得processEngine流程引擎
- ProcessEngine processEngine=Configuration.getProcessEngine();
- //获得RepositoryService对象
- //三个作用:1、流程发布定义 2、管理流程定义 3、删除流程定义
- RepositoryService repositoryService=processEngine.getRepositoryService();
- //获得ExecutionService对象
- ExecutionService executionService=processEngine.getExecutionService();
- //获得TaskService对象
- TaskService taskService=processEngine.getTaskService();
- //获得登录用户名
- String username=(String)session.getAttribute("username");
- //获得触发连接并处理
- /*String action=request.getParameter("action");
- if("deploy".equals(action))
- {
- //部署流程定义
- repositoryService.createDeployment().addResourceFromClasspath("leave.jpdl.xml").deploy();
- }else if("remove".equals(action))
- {
- //删除已部署的流程定义
- repositoryService.deleteDeploymentCascade(request.getParameter("id"));
- }*/
- //获得流程定义
- List<ProcessDefinition> list =repositoryService.createProcessDefinitionQuery().list();
- %>
- <!-- 部署流程定义对应连接 -->
- <a href="deploy.jsp">发布新流程</a> | [username:<%=username%>] | <a href="login.jsp">登录</a><br>
- <table border="1" width="100%">
- <caption>流程定义</caption>
- <thead>
- <tr>
- <td>id</td>
- <td>name</td>
- <td>version</td>
- <td>action</td>
- </tr>
- </thead>
- <%
- //for循环显示流程部署
- for (ProcessDefinition pd: list)
- {
- %>
- <tr>
- <td><%=pd.getId() %></td>
- <td> <%=pd.getName() %></td>
- <td><%=pd.getVersion() %></td>
- <td><a href="remove.jsp?id=<%=pd.getDeploymentId()%>">remove</a>
- |
- <a href="start.jsp?id=<%=pd.getId()%>">start</a></td>
- </tr>
- <%
- }
- %>
- </table>
- <%
- //for循环显示流程实例列表
- List <ProcessInstance> piList = executionService.createProcessInstanceQuery().list();
- %>
- <table border="1" width="100%">
- <caption>流程实例</caption>
- <thead>
- <tr>
- <td>id</td>
- <td>activity</td>
- <td>state</td>
- <td>detail</td>
- </tr>
- </thead>
- <%
- for (ProcessInstance pi:piList)
- {
- %>
- <tr>
- <td><%=pi.getId() %></td>
- <td><%=pi.findActiveActivityNames() %></td>
- <td><%=pi.getState() %></td>
- <td><a href="view.jsp?id=<%=pi.getId() %>">view</a></td>
- </tr>
- <%
- }
- %>
- </table>
- <%
- List<Task> taskList = taskService.findPersonalTasks(username);
- %>
- <table border="1" width="100%">
- <caption>代办任务</caption>
- <thead>
- <tr>
- <td>id</td>
- <td>name</td>
- <td> </td>
- </tr>
- </thead>
- <%
- for (Task task:taskList)
- {
- %>
- <tr>
- <td><%=task.getId() %></td>
- <td><%=task.getActivityName() %></td>
- <!-- 获取jpdl中所注册的task业务处理的jsp页面链接并显示 -->
- <td><a href="<%=task.getFormResourceName()%>?id=<%=task.getId() %>">view</a></td>
- </tr>
- <%
- }
- %>
- </table>
- </body>
- </html>
index.jsp主要由5部分构成,分别加以说明:
1)获得jbpm4流程定义、管理等操作的基本对象;
2)定义连接,调用deploy.jsp实现流程的发布,定义连接,调用login.sjp实现用户登录;
3)通过List<ProcessDefinition> list =repositoryService.createProcessDefinitionQuery().list();获得当前流程定义并以表格的形式显示出来;
4)通过List <ProcessInstance> piList = executionService.createProcessInstanceQuery().list();获得当前已经发起的流程定义并以表格方式显示出来;
5)通过List<Task> taskList = taskService.findPersonalTasks(username); 获得当前登录用户的待处理任务并显示,同时显示在leave.jpdl.xml中注册的相应任务接点处理所对应的就是jsp页面链接。例如:
对于:“经理审批” 节点
<task assignee="manager" form="manager.jsp" g="113,247,92,52" name="经理审批">
我们通过
<td><a href="<%=task.getFormResourceName()%>?id=<%=task.getId() %>">view</a></td>
来显示manager.jsp页面的链接。
另注:我认为jbpm自动保存任务的完成者也是通过此处完成的。
4、相关jsp源码
login.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <!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="doLogin.jsp" method="post">
- 用户名:<input type="text" name="username" value=""/><br/>
- <input type="submit">
- </form>
- </fieldset>
- </body>
- </html>
doLogin.jsp
- <%
- session.setAttribute("username", request.getParameter("username"));
- response.sendRedirect("index.jsp");
- %>
checkLogin.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <!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>
- <% if (session.getAttribute("username") == null) {
- response.sendRedirect("login.jsp");
- }%>
- </body>
- </html>
注:以上三个jsp页面主要实现用户登录的相应功能。
deploy.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <%@ page import="java.util.*,org.jbpm.api.*,java.util.zip.*" %>
- <!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>
- <%
- 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");
- %>
- </body>
- </html>
注:此处实现了流程定义的发布
request.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <!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.jsp" method="post">
- <input type="hidden" name="taskId" value="${param.id}">
- 申请人:<input type="text" name="owner" value="${sessionScope['username']}"/><br/>
- 请假时间:<input type="text" name="day" value=""/><br/>
- 请假原因:<textarea name="reason"></textarea><br/>
- <input type="submit"/>
- </form>
- </fieldset>
- </body>
- </html>
submit.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <%@ page import="java.util.*,org.jbpm.api.*" %>
- <!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>
- <%
- ProcessEngine processEngine = Configuration.getProcessEngine();
- TaskService taskService = processEngine.getTaskService();
- String taskId = request.getParameter("taskId");
- String owner = 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");
- %>
- </body>
- </html>
注:这两个jsp页面实现了普通用户申请请假的功能。值得说明的是在submit.jsp中的如下两句代码:
- Map map = new HashMap();
- map.put("day", day);
- map.put("reason", reason);
- taskService.completeTask(taskId, map);
将用户申请的请假天数和请假原因作为流程变量保存在数据库中,同时实现了对"申请"节点task任务的完成。
manager.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <%@page import="org.jbpm.api.*,org.jbpm.api.task.*" %>
- <%
- ProcessEngine processEngine = Configuration.getProcessEngine();
- TaskService taskService = processEngine.getTaskService();
- String taskId = request.getParameter("id");
- 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_manager.jsp">
- <input type="hidden" name="taskId" value="${param.id}">
- 申请人:<%=taskService.getVariable(taskId, "owner") %><br/>
- 请假时间:<%=taskService.getVariable(taskId, "day") %><br/>
- 请假原因:<%=taskService.getVariable(taskId, "reason") %><br/>
- <input name="result" type="submit" value="批准"/><input name="result" type="submit" value="驳回"/>
- </form>
- </fieldset>
- </body>
- </html>
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <%@ page import="java.util.*,org.jbpm.api.*" %>
- <!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>
- <%
- ProcessEngine processEngine = Configuration.getProcessEngine();
- TaskService taskService = processEngine.getTaskService();
- String taskId = request.getParameter("taskId");
- String result = request.getParameter("result");
- result = new String(result.getBytes("ISO-8859-1"), "UTF-8");
- taskService.completeTask(taskId, result);
- response.sendRedirect("index.jsp");
- %>
- </body>
- </html>
注:这两个页面实现了“经理审批”节点的task,此处要说明的对于流程图中批准和驳回的实现,我们主要是使用taskService.completeTask(tsaskId,result);函数来实现,此处的result并不是流程变量而是我们所要选择的流程路径。对于TaskService.completeTask函数我这里做如下不规范说明:
该函数包含三个参数,一个必备参数:taskId,即流程ID;两个可选参数:流程变量参数Map类型和后继路径选择参数String类型(应该与流程定义中的路径transaction名相同)。
boss.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <%@page import="org.jbpm.api.*,org.jbpm.api.task.*" %>
- <%
- ProcessEngine processEngine = Configuration.getProcessEngine();
- TaskService taskService = processEngine.getTaskService();
- String taskId = request.getParameter("id");
- 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">
- <input type="hidden" name="taskId" value="${param.id}">
- 申请人:<%=taskService.getVariable(taskId, "owner") %><br/>
- 请假时间:<%=taskService.getVariable(taskId, "day") %><br/>
- 请假原因:<%=taskService.getVariable(taskId, "reason") %><br/>
- <input name="result" type="submit" value="提交审批内容"/>
- </form>
- </fieldset>
- </body>
- </html>
submit_boss.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <!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>
- <%@page import="java.util.*,org.jbpm.api.*"%>
- <%
- ProcessEngine processEngine = Configuration.getProcessEngine();
- TaskService taskService = processEngine.getTaskService();
- String taskId = request.getParameter("taskId");
- taskService.completeTask(taskId);
- response.sendRedirect("index.jsp");
- %>
- </body>
- </html>
至此为止请假流程web应用的最基本的功能已经实现。
5、程序运行结果