activiti自定义流程之整合(五):启动流程时获取自定义表单

流程定义部署之后,自然就是流程定义列表了,但和前一节一样的是,这里也是和之前单独的activiti没什么区别,因此也不多说。我们先看看列表页面以及对应的代码,然后在一步步说明点击启动按钮时如何调用自定义的form表单。


流程定义列表页面如下:
activiti自定义流程之整合(五):启动流程时获取自定义表单


对应的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方法,便是因为在上一节部署的时候进行了设置,否则这个方法是无法正常使用的。


那么这个对话框弹出界面视图如下:
activiti自定义流程之整合(五):启动流程时获取自定义表单

需要注意的是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开始,那么如果我们原样保存到数据库,以后查询时自然就会有问题了,所以这里就根据每个流程中流程节点行号的唯一性进行了重新组合,然后把这些数据保存为流程变量。


上一篇:浅谈脱壳中的附加数据问题(overlay)


下一篇:C/C++ 入门建议