- 本次,我们在web项目的基础上,设计一个请假流程。申请--->经理审批---->老板审批----->通过。中间有根据一些条件来做判断,让流程进入到不同的节点。
- 还有,加入了流程监控的功能。
- leave.jpdl.xml
<?xml version="1.0" encoding="UTF-8"?> <process name="leave" xmlns="http://jbpm.org/4.3/jpdl"> <start g="199,100,48,48" name="start1"> <transition to="申请"/> </start> <task assignee="#{owner}" form="request.jsp" g="178,190,92,52" name="申请"> <transition to="经理审批"/> </task> <task assignee="manager" form="manager.jsp" g="182,322,92,52" name="经理审批"> <transition g="-37,-11" name="批准" to="exclusive1"/> <transition name="驳回" to="申请" g="108,350;106,216:-30,-7"/> </task> <task assignee="boss" form="boss.jsp" g="358,471,92,52" name="老板审批"> <transition g="406,571:-47,-17" name="to end1" to="end1"/> </task> <decision expr="#{day > 3 ? 'to 老板审批' : 'to end1'}" g="208,425,48,48" name="exclusive1"> <transition g="-47,-17" name="to end1" to="end1"/> <transition g="405,448:-71,-17" name="to 老板审批" to="老板审批"/> </decision> <end g="211,549,48,48" name="end1"/> </process>
- login.jsp
由于在测试的过程中,要展示某某用户有哪些待办流程,或者某某用户发起了一个新流程,所以,做了一个简易的登录页面,登录后,保存当前登录的userName。
<%@ 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>登录</title> </head> <body> </body> <form name="loginForm" action="doLogin.jsp" method="post"> <div> 请输入用户名:<input type="text" name="userName" /> <input type="submit" value="登录" /> </div> </form> </html>
效果图如下:
- index.jsp
在index页面,有显示流程列表,显示已经启动的流程列表,有待办任务列表
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="java.util.*,org.jbpm.api.*,org.jbpm.api.task.*" %> <%@ include file="checkLogin.jsp" %> <% String userName = (String)session.getAttribute("userName"); ProcessEngine processEngine = Configuration.getProcessEngine(); // 创建一个流程引擎 RepositoryService repositoryService = processEngine.getRepositoryService(); // 创建一个流程服务 ExecutionService executionService = processEngine.getExecutionService(); // 实例服务 TaskService taskService = processEngine.getTaskService(); // 任务 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" "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> <link rel="Stylesheet" type="text/css" href="style.css" /> </head> <body> <div> 当前登录用户[<%=userName %>]| <a href="deploy.jsp">发布新流程</a>|<a href="login.jsp">登录</a> </div> <div> <h2>流程列表</h2> <table> <tr> <td>ID</td> <td>Name</td> <td>Version</td> <td>操作</td> </tr> <% for(ProcessDefinition pd : list) { %> <tr> <td><%=pd.getId() %></td> <td><%=pd.getName() %></td> <td><%=pd.getVersion() %></td> <td> <a href="remove.jsp?deploymentId=<%=pd.getDeploymentId() %>">删除</a>| <a href="start.jsp?id=<%=pd.getId() %>">开始</a> </td> </tr> <% } %> </table> <h2>实例列表</h2> <table> <tr> <td>ID</td> <td>活动</td> <td>状态</td> <td>操作</td> </tr> <% 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() %>">查看</a></td> </tr> <% } %> </table> <h2>任务列表</h2> <table> <tr> <td>ID</td> <td>名称</td> <td>操作</td> </tr> <% for(Task task : taskList) { %> <tr> <td><%=task.getId() %></td> <td><%=task.getName() %></td> <td><a href="<%=task.getFormResourceName() %>?taskId=<%=task.getId() %>">查看</a><br /></td> </tr> <% } %> </table> </div> </body> </html>
页面展示效果如下:
- deploy.jsp
当在index页面点击“发布新流程”超链接的时候,发起一个新的流程。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="java.util.*,org.jbpm.api.*"%> <% ProcessEngine processEngine = Configuration.getProcessEngine(); // 创建一个流程引擎 RepositoryService repositoryService = processEngine .getRepositoryService(); // 创建一个流程服务 repositoryService.createDeployment() .addResourceFromClasspath("leave.jpdl.xml").deploy(); // 发布一个流程 response.sendRedirect("index.jsp"); %>
发起一个流程后,index页面的效果如下:
- start.jsp
点击首页流程列表中的“开始”,将当前的流程ID获取到,然后根据这个流程ID来启动一个流程
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="java.util.*,org.jbpm.api.*,org.jbpm.api.task.*" %> <% String id = request.getParameter("id"); String userName = (String)session.getAttribute("userName"); ProcessEngine processEngine = Configuration.getProcessEngine(); // 创建流程引擎 ExecutionService executionService = processEngine.getExecutionService(); // Map<String, Object> map = new HashMap<String, Object>(); map.put("owner", userName); executionService.startProcessInstanceById(id, map); response.sendRedirect("index.jsp"); %>
开始一个流程后,index页面的效果图如下:
- request.jsp
假设当前登录用户为owner,由owner发起的流程,现在进入了申请阶段。任务列表中显示的是属于当前用户的待办列表。点击进去查看详情并提交申请。
<%@ 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>Request</title> <link rel="Stylesheet" type="text/css" href="style.css" /> </head> <body> <h2>申请</h2> <form action="submit.jsp" method="post"> <input type="hidden" name="taskId" value="${param.taskId }" /> <table> <tr> <td>申请人</td> <td><input type="text" name="owner" value="${sessionScope['userName'] }"/></td> </tr> <tr> <td>请假时间(天)</td> <td><input type="text" name="day" value="" /></td> </tr> <tr> <td>请假原因</td> <td><input type="text" name="reason" value="" /></td> </tr> </table> <input type="submit" value="提交" /> </form> </body> </html>
效果图如下:
- submit.jsp
当申请人提交了申请之后,我们需要获取其申请单提交的表单元素,将其执行使之进入下一步流程
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="java.util.*,org.jbpm.api.*,org.jbpm.api.task.*" %> <% request.setCharacterEncoding("UTF-8"); ProcessEngine processEngine = Configuration.getProcessEngine(); TaskService taskService = processEngine.getTaskService(); // 接收任务ID String taskId = request.getParameter("taskId"); // 接收用户名 String owner = request.getParameter("owner"); // 接收请假天数 int day = Integer.parseInt(request.getParameter("day")); // 接收请假原因 String reason = request.getParameter("reason"); Map<String, Object> map = new HashMap<String, Object>(); map.put("day", day); map.put("reason", reason); // 执行任务 taskService.completeTask(taskId, map); // 跳转到首页 response.sendRedirect("index.jsp"); %>
提交了申请之后,再看index页面,刚才的待办任务已经流转,不显示了。如下图:
然后使用manager(在leave.jpdl.xml中有定义)登录,查看属于自己的待办任务列表;如下图:
登录首页后,清楚的看到刚才owner提交的申请已经流转到了manager的名下;如下图:
- manager.jsp
点击index的待办任务列表中“查看”时,JBPM会根据在leave.jpdl.xml中的配置的form属性,自动跳转到manager页面进行经理的审批和驳回;
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ 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>Manager</title> <link rel="Stylesheet" type="text/css" href="style.css" /> </head> <body> <h2>经理审核</h2> <form action="submit_manager.jsp" method="post"> <input type="hidden" name="taskId" value="${param.taskId }" /> <table> <tr> <td>申请人</td> <td><%=taskService.getVariable(taskId, "owner") %></td> </tr> <tr> <td>请假时间(天)</td> <td><%=taskService.getVariable(taskId, "day") %></td> </tr> <tr> <td>请假原因</td> <td><%=taskService.getVariable(taskId, "reason") %></td> </tr> </table> <input type="submit" name="result" value="批准" /> <input type="submit" name="result" value="驳回" /> </form> </body> </html>
效果图如下:
- submit_manager.jsp
manager在提交了审批结果之后,在这里要处理经理提交的结果,批准或者驳回
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="java.util.*,org.jbpm.api.*,org.jbpm.api.task.*" %> <% request.setCharacterEncoding("UTF-8"); ProcessEngine processEngine = Configuration.getProcessEngine(); TaskService taskService = processEngine.getTaskService(); // 接收任务ID String taskId = request.getParameter("taskId"); // 接受命令 String result = request.getParameter("result"); // 执行任务 /* * jbpm会根据传过去的result来判断流程转向哪个task */ taskService.completeTask(taskId, result); // 跳转到首页 response.sendRedirect("index.jsp"); %>
如果批准,我们再看index页面,属于经理的待办任务已经没了。并且,流程的实例列表也空了,证明这个流程已经流转完毕;如下图:
我们再创建一个新的流程来测试驳回的效果;结果如下图:
- view.jsp和pic.jsp
点击首页实例列表中的“查看”链接即可查看当前流程走到了哪一步,实现了流程监控。
然后view页面会将此时流程图显示出来,并且能看到当前走到了哪一步;要实现这个,必须进行以下三步:
第一:将leave.jpdl.xml和自动生成的leave.png打包到一个leave.zip文件中(注意不要包含任何一层多的文件夹),并且存放在src下或者根目录下。如下图:
第二:view.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="java.util.*,org.jbpm.api.*,org.jbpm.api.model.*"%> <% String id = request.getParameter("id"); // 获取流程实例ID ProcessEngine processEngine = Configuration.getProcessEngine(); RepositoryService repositoryService = processEngine .getRepositoryService(); ExecutionService executionService = processEngine .getExecutionService(); ProcessInstance processInstance = executionService .findProcessInstanceById(id); // 根据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>View</title> <link rel="Stylesheet" type="text/css" href="style.css" /> </head> <body> <h2>流程图显示</h2> <img src="pic.jsp?id=<%=id%>" style="position: absolute; left: 0px; top: 0px" /> <div style="position:absolute;border:2px solid red;left:<%=ac.getX()%>px;top:<%=ac.getY()%>px;width:<%=ac.getWidth()%>px;height:<%=ac.getHeight()%>px;"></div> </body> </html>
第三:pic.jsp(在view.jsp中调用了pic.jsp来获取图片)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="java.util.*,org.jbpm.api.*,java.io.*"%> <% String id = request.getParameter("id"); // 获取流程实例ID ProcessEngine processEngine = Configuration.getProcessEngine(); RepositoryService repositoryService = processEngine .getRepositoryService(); ExecutionService executionService = processEngine .getExecutionService(); ProcessInstance processInstance = executionService .findProcessInstanceById(id); // 根据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; OutputStream ops = response.getOutputStream(); while ((len = inputStream.read(b, 0, 1024)) != -1) { ops.write(b, 0, len); } %>
OK,现在我们来看看,当前的展示效果:
上图的红框是程序自动生成的,并非作图的效果;
- boss.jsp,submit_boss.jsp
这个页面来处理经理审批过后,大于3天的请假流程(规则在leave.jpdl.xml中定义)。
需要查看详细代码和运行效果,请下载我的完整项目:
链接稍后奉上!
点击此处去下载完整Demo