在web开发中的表单,可以理解为与用户交互的重要入口,用户通过表单输入,然后进行流程交互。Activiti提供了多种类型的表单,比如内置表单、外置表单和业务表单。其实在前面的章节中,我们接触到的都是内置表单,这是Activiti提供的一种快速方式生成的表单,通过Activiti内置的多种表单元素,就可以开发出带流程管理的表单管理系统。
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.zioer.com/reimbursement">
<process id="reimbursement" name="费用报销" isExecutable="true">
<documentation>公司费用报销简易流程</documentation>
<startEvent id="startevent1" name="Start" activiti:initiator="startUserId">
<extensionElements>
<activiti:formProperty id="fee" name="费用" type="long" required="true"></activiti:formProperty>
<activiti:formProperty id="note" name="说明" type="string"></activiti:formProperty>
</extensionElements>
</startEvent>
<!-- <userTask id="departmentApprove" name="部门领导审批" activiti:assignee="lee">-->
<userTask id="departmentApprove" name="部门领导审批" activiti:assignee="admin">
<extensionElements>
<activiti:formProperty id="fee" name="费用" type="long" writable="false"></activiti:formProperty>
<activiti:formProperty id="note" name="说明" type="string" writable="false"></activiti:formProperty>
<activiti:formProperty id="bmyj" name="部门意见" type="string"></activiti:formProperty>
</extensionElements>
</userTask>
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="departmentApprove"></sequenceFlow>
<!-- <userTask id="reimburseApprove" name="财务部门审批" activiti:assignee="lobby">-->
<userTask id="reimburseApprove" name="财务部门审批" activiti:assignee="admin">
<extensionElements>
<activiti:formProperty id="fee" name="费用" type="long" writable="false"></activiti:formProperty>
<activiti:formProperty id="refee" name="核实费用" type="long" required="true"></activiti:formProperty>
<activiti:formProperty id="note" name="说明" type="string" writable="false"></activiti:formProperty>
<activiti:formProperty id="bmyj" name="部门意见" type="string" writable="false"></activiti:formProperty>
<activiti:formProperty id="bzhu" name="备注" type="string"></activiti:formProperty>
</extensionElements>
</userTask>
<sequenceFlow id="flow2" sourceRef="departmentApprove" targetRef="reimburseApprove"></sequenceFlow>
<userTask id="usertask1" name="申请人确认" activiti:assignee="${startUserId}">
<extensionElements>
<activiti:formProperty id="fee" name="费用" type="long" writable="false"></activiti:formProperty>
<activiti:formProperty id="refee" name="核实费用" type="long" writable="false"></activiti:formProperty>
<activiti:formProperty id="note" name="说明" type="string" writable="false"></activiti:formProperty>
<activiti:formProperty id="bmyj" name="部门意见" type="string" writable="false"></activiti:formProperty>
<activiti:formProperty id="bzhu" name="备注" type="string" writable="false"></activiti:formProperty>
</extensionElements>
</userTask>
<sequenceFlow id="flow3" sourceRef="reimburseApprove" targetRef="usertask1"></sequenceFlow>
<endEvent id="endevent2" name="End"></endEvent>
<sequenceFlow id="flow5" sourceRef="usertask1" targetRef="endevent2"></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_reimbursement">
<bpmndi:BPMNPlane bpmnElement="reimbursement" id="BPMNPlane_reimbursement">
<bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
<omgdc:Bounds height="35.0" width="35.0" x="80.0" y="160.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="departmentApprove" id="BPMNShape_departmentApprove">
<omgdc:Bounds height="55.0" width="105.0" x="160.0" y="150.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="reimburseApprove" id="BPMNShape_reimburseApprove">
<omgdc:Bounds height="55.0" width="105.0" x="310.0" y="150.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
<omgdc:Bounds height="55.0" width="105.0" x="460.0" y="150.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="endevent2" id="BPMNShape_endevent2">
<omgdc:Bounds height="35.0" width="35.0" x="610.0" y="160.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
<omgdi:waypoint x="115.0" y="177.0"></omgdi:waypoint>
<omgdi:waypoint x="160.0" y="177.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
<omgdi:waypoint x="265.0" y="177.0"></omgdi:waypoint>
<omgdi:waypoint x="310.0" y="177.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
<omgdi:waypoint x="415.0" y="177.0"></omgdi:waypoint>
<omgdi:waypoint x="460.0" y="177.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5">
<omgdi:waypoint x="565.0" y="177.0"></omgdi:waypoint>
<omgdi:waypoint x="610.0" y="177.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
在上面的这个流程定义文件里面,我们通过activiti:formProperty
元素定义好了内置表单。在前面的章节当中。我们通过实例实现了审批的流程,本章我们同样使用这个内置表单来实现历史流程的查看。
编写一个新的控制层DyHistoryformController,对应源码如下
package com.xquant.platform.test.activiti.controller;
import org.activiti.engine.*;
import org.activiti.engine.form.FormProperty;
import org.activiti.engine.form.StartFormData;
import org.activiti.engine.form.TaskFormData;
import org.activiti.engine.history.HistoricDetail;
import org.activiti.engine.impl.persistence.entity.HistoricProcessInstanceEntity;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.*;
@Controller
@RequestMapping(value = "/form")
public class DyHistoryformController {
@Autowired
private TaskService taskService;
@Autowired
private HistoryService historyService;
@RequestMapping(value = "/hlist")
public String historylist(Model model, HttpSession session) {
// 从事session中获取当前登录的用户
String userId = session.getAttribute("userId") == null ? null : session.getAttribute("userId").toString();
if (userId == null) {
return "redirect:/login/";
}
List<Map> hlist = new ArrayList<Map>();
// 创建获取历史数据的实例
List historylist = historyService.createHistoricProcessInstanceQuery()
.processDefinitionKey("reimbursement")
// 由哪个用户创建的实例
.startedBy(userId).list();
for (int i = 0; i < historylist.size(); i++) {
Map<String, Object> map = new HashMap<String, Object>();
// 历史类型实体列表
HistoricProcessInstanceEntity hpe = (HistoricProcessInstanceEntity) historylist.get(i);
map.put("id", hpe.getId());
map.put("startUserId", hpe.getStartUserId());
map.put("processInstanceId", hpe.getProcessInstanceId());
map.put("endTime", hpe.getEndTime());
map.put("startTime", hpe.getStartTime());
if (hpe.getEndTime() == null) {
// 如果结束事件为空 则当前流程还未结束
Task task = taskService.createTaskQuery()
.processInstanceId(hpe.getProcessInstanceId())
.active()
.singleResult();
if (task != null) {
// 获取当前任务的名称 比如部门领导审批
map.put("name", task.getName());
}
} else {
map.put("name", "已完成");
}
hlist.add(map);
}
//获得当前用户的任务
model.addAttribute("list", hlist);
return "reimbursement_hlist";
}
@RequestMapping(value = "/hview/{pId}")
public String historyView(@PathVariable("pId") String pId, Model model, HttpSession session) {
String userId = session.getAttribute("userId") == null ? null : session.getAttribute("userId").toString();
if (userId == null) {
return "redirect:/login/";
}
// 根据任务ID获取历史任务的详细信息
List<HistoricDetail> details = historyService
.createHistoricDetailQuery()
.processInstanceId(pId)
.orderByTime().asc()
.list();
model.addAttribute("list", details);
return "reimbursement_hview";
}
}
在这里主要通过HistoryService来获取用户的历史流程。
涉及到的两个前端页面
reimbursement_hlist.jsp
用于历史列表
<%@ page language="java" import="java.util.*" contentType="text/html; charset=utf8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf8" />
<title>Zioer-Activiti示例</title>
<link rel="stylesheet" rev="stylesheet" href="<%=basePath%>css/style.css" type="text/css" media="all" />
<script language=JavaScript>
</script>
</head>
<body class="ContentBody">
<form action="add" method="post" name="fom" id="fom">
<div class="MainDiv">
<table width="90%" border="0" cellpadding="0" cellspacing="0" class="CContent">
<tr>
<th class="tablestyle_title" >费用报销管理-我的历史</th>
</tr>
<tr>
<td class="CPanel">
<table id="subtree1" style="DISPLAY: " width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td><table width="95%" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td height="40" class="font42">
<table width="100%" border="0" cellpadding="4" cellspacing="1" bgcolor="#FFFFEE" class="newfont03">
<tr class="CTitle" >
<td height="22" colspan="11" align="center" style="font-size:16px">我的工作历史列表</td>
</tr>
<tr bgcolor="#EEEEEE">
<td width="10%" height="30">任务ID</td>
<td width="10%">实例ID</td>
<td width="25%">开始时间</td>
<td width="25%">结束时间</td>
<td width="">当前节点</td>
<td width="10%">操作</td>
</tr>
<c:forEach items="${list}" var="var" varStatus="vs">
<tr <c:if test="${vs.count%2==0}">bgcolor="#AAAABB"</c:if> align="left" >
<td >${var.id}</td>
<td height="30">${var.processInstanceId}</td>
<td ><fmt:formatDate value="${var.startTime}" type="both"/></td>
<td ><fmt:formatDate value="${var.endTime}" type="both"/></td>
<td >${var.name}</td>
<td ><a href="./hview/${var.processInstanceId}">查看</a></td>
</tr>
</c:forEach>
</table></td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
</form>
</body>
</html>
和
reimbursement_hview.jsp
用于详情查看
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html lang="en">
<head>
<title>费用报销-审批</title>
<link rel="stylesheet" rev="stylesheet" href="<%=basePath%>css/style.css" type="text/css" media="all" />
<script type="text/javascript" src="<%=basePath%>js/My97DatePicker/WdatePicker.js"></script>
<script language=JavaScript>
</script>
</head>
<body>
<form action="save/${ formData.getTask().getId()}" method="post" name="form" id="form">
<div class="MainDiv">
<table width="60%" border="0" cellpadding="0" cellspacing="0" class="CContent">
<tr>
<th class="tablestyle_title" >费用报销-表单内容查看</th>
</tr>
<tr>
<td class="CPanel">
<table border="0" cellpadding="0" cellspacing="0" style="width:100%">
<TR>
<TD width="100%">
<fieldset style="height:100%;">
<legend>内容查看</legend>
<table border="0" cellpadding="2" cellspacing="1" style="width:100%">
<c:forEach items="${list}" var="var" varStatus="vs">
<tr>
<td nowrap align="right" width="13%">${var.getPropertyId()}</td>
<td>${var.getPropertyValue()}</td>
</tr>
</c:forEach>
</table>
</fieldset>
</TD>
</TR>
</TABLE>
</td>
</tr>
<tr>
<TD colspan="2" align="center" height="50px">
<input type="button" name="Submit2" value="返回" class="button" onclick="window.history.go(-1);"/>
</TD>
</tr>
</table>
</div>
</form>
</body>
</html>
启动程序,访问地址http://localhost:8080/form/hlist
点击右方的查看