流程定义部署之后,自然就是流程定义列表了,但和前一节一样的是,这里也是和之前单独的activiti没什么区别,因此也不多说。我们先看看列表页面以及对应的代码,然后在一步步说明点击启动按钮时如何调用自定义的form表单。
流程定义列表页面如下:
对应的html代码:
<div id="logdiv1" ng-init="init();">
<p style="font-size:24px;margin:3px">流程列表</p>
<center>
<table border="1px" style="margin-top:1px;width:87%;font-size:14px;text-align:center;margin-top:1px;margin-left:2px;position:relative;float:left;" cellSpacing="0px" cellPadding="0px">
<tr style="background-color:#ccc">
<td>ID</td>
<td>NAME</td>
<td>DeploymentID</td>
<td>KEY</td>
<td>版本</td>
<td>resourceName</td>
<td>DiagramResourceName</td>
<td>操 作</td>
</tr>
<tr ng-repeat="process in processList | orderBy:'id'" >
<td>{{process.id}}</td>
<td>{{process.name}}</td>
<td>{{process.deploymentId}}</td>
<td>{{process.key}}</td>
<td>{{process.version}}</td>
<td>{{process.resourceName}}</td>
<td>{{process.diagramResourceName}}</td>
<td><a href="script:;" ng-click="toProcess(process)">启动</a>
<a href="script:;" ng-click="deleteProcess(process)">删除</a>
</td>
</tr>
</table>
<div id="handleTemplate" ></div>
</center>
</div>
对应的angularjs代码:
angular.module('activitiApp')
.controller('processCtr', ['$rootScope','$scope','$http','$location', function($rootScope,$scope,$http,$location){
$scope.init=function(){
$http.post("./processList.do").success(function(result) {
if(result.isLogin==="yes"){
$rootScope.userName=result.userName;
$scope.processList=result.data;
}else{
$location.path("/login");
}
});
}
//开始流程
$scope.toProcess= function(process){
$rootScope.process=process;
$('#handleTemplate').html('').dialog({
title:'流程名称[' + process.name + ']',
modal: true,
width: $.common.window.getClientWidth() * 0.6,
height: $.common.window.getClientHeight() * 0.9,
open: function() {
// 获取json格式的表单数据,就是流程定义中的所有field
readForm.call(this, process.deploymentId);
},
buttons: [{
text: '启动流程',
click: function() {
$("#handleTemplate").dialog("close");
sendStartupRequest();
setTimeout(function(){
window.location.href =("#/findFirstTask");
},1500);
}
}]
}).position({
//my: "center",
//at: "center",
offset:'300 300',
of: window,
collision:"fit"
});
;
};
//读取流程启动表单
function readForm(deploymentId) {
var dialog = this;
// 读取启动时的表单
$.post('./getStartForm.do',deploymentId, function(result) {
// 获取的form是字符行,html格式直接显示在对话框内就可以了,然后用form包裹起来
$(dialog).append("<div class='formContent' />");
$('.formContent').html('').wrap("<form id='startform' class='formkey-form' method='post' />");
var $form = $('.formkey-form');
// 设置表单action getStartFormAndStartProcess
$form.attr('action', './getStartFormAndStartProcess');
//设置部署的Id
$form.append("<input type='hidden' name='deploymentId' value="+deploymentId+">");
$form.append(result.form);
// 初始化日期组件
$form.find('.datetime').datetimepicker({
stepMinute: 5
});
$form.find('.date').datepicker();
// 表单验证
$form.validate($.extend({}, $.common.plugin.validator));
});
}
/**
* 提交表单
* @return {[type]} [description]
*/
function sendStartupRequest() {
if ($(".formkey-form").valid()) {
var url = './getStartFormAndStartProcess.do';
var args = $('#startform').serialize();
$.post(url, args, function(data){
$("#handleTemplate").dialog("close");
$location.path("/findFirstTask");
});
}
}
}])
在上边的代码中就有需要注意的地方了,从代码中可以看到,当我们点击页面的启动按钮时,会触发toProcess方法,而这个方法就使用到了dialog对话框,对话框中显示的内容便是之前自定义的表单,从后台数据库中请求过来。
那么读取的时候发送了getStartForm.do的请求,后台对应的代码如下:
@RequestMapping(value = "/getStartForm.do", method = RequestMethod.POST, produces = "application/json;charset=utf-8")
@ResponseBody
public Object getStartForm(@RequestBody String deploymentId) {
Map<String, String> map = new HashMap<String, String>();
String deString = null;
deString = deploymentId.replaceAll("=", "");
String form = this.getStartForm1(deString);
map.put("form", form);
return map;
}
public String getStartForm1(String deploymentId) {
String deString = null;
deString = deploymentId.replaceAll("=", "");
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
.deploymentId(deString).singleResult();
String form = (String) formService.getRenderedStartForm(pd.getId());
return form;
}
要说明的是这里之所以能使用formService.getRenderedStartForm方法,便是因为在上一节部署的时候进行了设置,否则这个方法是无法正常使用的。
那么这个对话框弹出界面视图如下:
需要注意的是dialog的css样式在jquery-ui.css中,不要忘了导入进来,当然了,也可以按自己的喜好修改。
那么填写好相关的数据点击提交,同过上边的js可以知道就走到了后台getStartFormAndStartProcess这里,启动流程实例:
/**
* @throws XMLStreamException
* 启动流程
*
* @author:tuzongxun
* @Title: startProcess
* @param @return
* @return Object
* @date Mar 17, 2016 2:06:34 PM
* @throws
*/
@RequestMapping(value = "/getStartFormAndStartProcess.do", method = RequestMethod.POST, produces = "application/json;charset=utf-8")
@ResponseBody
public Object startProcess1(HttpServletRequest req)
throws XMLStreamException {
Map<String, String[]> formMap = req.getParameterMap();
String deploymentId = formMap.get("deploymentId")[0];
// 拿到第一个data_1设置申请人
String person1 = (String) formMap.get("data_1")[0];
Map<String, String> map = new HashMap<String, String>();
boolean isLogin = this.isLogin(req);
if (isLogin) {
if (deploymentId != null) {
HttpSession session = req.getSession();
String assginee = (String) session.getAttribute("userName");
ProcessDefinition pd = repositoryService
.createProcessDefinitionQuery()
.deploymentId(deploymentId).singleResult();
String processDefinitionId = pd.getId();
Map<String, String> formProperties = new HashMap<String, String>();
Iterator<FlowElement> iterator1 = this
.findFlow(processDefinitionId);
// 取第一个节点,开始节点的行号
String row = null;
while (iterator1.hasNext()) {
FlowElement flowElement = iterator1.next();
row = flowElement.getXmlRowNumber() + "";
break;
}
// 从request中读取参数然后转换
Set<Entry<String, String[]>> entrySet = formMap.entrySet();
for (Entry<String, String[]> entry : entrySet) {
String key = entry.getKey();
String value = entry.getValue()[0];
if (!key.equals("deploymentId")) {
String keyString = key + row;
formProperties.put(keyString, value);
}
}
formProperties.put("deploymentId", deploymentId);
Iterator<FlowElement> iterator = this.findFlow(pd.getId());
int i = 1;
while (iterator.hasNext()) {
FlowElement flowElement = iterator.next(); // 申请人
if (flowElement.getClass().getSimpleName()
.equals("UserTask")
&& i == 1) {
UserTask userTask = (UserTask) flowElement;
String assignee = userTask.getAssignee();
int index1 = assignee.indexOf("{");
int index2 = assignee.indexOf("}");
formProperties
.put(assignee.substring(index1 + 1, index2),
person1);
break;
}
}
identityService.setAuthenticatedUserId(assginee);
ProcessInstance processInstance = formService
.submitStartFormData(processDefinitionId,
formProperties);
map.put("userName",
(String) req.getSession().getAttribute("userName"));
map.put("isLogin", "yes");
map.put("result", "success");
} else {
map.put("result", "fail");
}
} else {
map.put("isLogin", "no");
}
return map;
}
而这里最重要的是对前台数据的处理,如果大家使用了ueditor插件,会发现他传递到后台的数据是存放在request中的一个map中,而map的key都是data_1、data_2、data_3的形式。
这样问题就来了,到后边对任务进行操作的时候,这些数据还是这样从data_1开始,那么如果我们原样保存到数据库,以后查询时自然就会有问题了,所以这里就根据每个流程中流程节点行号的唯一性进行了重新组合,然后把这些数据保存为流程变量。