Activiti——Web环境下基本业务功能

该博客围绕Activiti流程管理展开,涵盖流程定义、部署、资源读取与删除等操作,还涉及任务处理,如获取待办、签收、完成任务等,以及审批意见保存与读取、附件管理、历史流程查询等内容,使用Java和Spring MVC技术。

1、流程定义列表

@RequestMapping(value = "/process-list")
public ModelAndView processList() {

    ModelAndView mav = new ModelAndView("chapter5/process-list");

    List<ProcessDefinition> processDefinitionList = repositoryService.createProcessDefinitionQuery().list();

    mav.addObject("processDefinitionList", processDefinitionList);

    return mav;
}
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
	<%@ include file="/common/global.jsp"%>
	<%@ include file="/common/meta.jsp" %>
	<%@ include file="/common/include-base-styles.jsp" %>
	<title>已部署流程定义列表</title>

	<script src="${ctx }/js/common/jquery.js" type="text/javascript"></script>
</head>
<body>
	<c:if test="${not empty message}">
		<div id="message" class="alert alert-success">${message}</div>
		<!-- 自动隐藏提示信息 -->
		<script type="text/javascript">
		setTimeout(function() {
			$('#message').hide('slow');
		}, 5000);
		</script>
	</c:if>
	<fieldset id="deployFieldset">
		<legend>部署流程资源</legend>
		<form action="${ctx }/chapter5/deploy" method="post" enctype="multipart/form-data" style="margin-top:1em;">
			<input type="file" name="file" />
			<input type="submit" value="Submit" class="btn" />
		</form>
		<hr class="soften" />
	</fieldset>
	<table width="100%" class="table table-bordered table-hover table-condensed">
		<thead>
			<tr>
				<th>流程定义ID</th>
				<th>部署ID</th>
				<th>流程定义名称</th>
				<th>流程定义KEY</th>
				<th>版本号</th>
				<th>XML资源名称</th>
				<th>图片资源名称</th>
				<th>操作</th>
			</tr>
		</thead>
		<tbody>
			<c:forEach items="${processDefinitionList }" var="pd">
				<tr>
					<td>${pd.id }</td>
					<td>${pd.deploymentId }</td>
					<td>${pd.name }</td>
					<td>${pd.key }</td>
					<td>${pd.version }</td>
					<td><a target="_blank" href='${ctx }/chapter5/read-resource?pdid=${pd.id }&resourceName=${pd.resourceName }'>${pd.resourceName }</a></td>
					<td><a target="_blank" href='${ctx }/chapter5/read-resource?pdid=${pd.id }&resourceName=${pd.diagramResourceName }'>${pd.diagramResourceName }</a></td>
					<td>
						<a class="btn" href='${ctx }/chapter5/delete-deployment?deploymentId=${pd.deploymentId }'><i class="icon-trash"></i>删除</a>
						<a class="btn" href='${ctx }/chapter6/getform/start/${pd.id }'><i class="icon-play"></i>启动</a>
					</td>
				</tr>
			</c:forEach>
		</tbody>
	</table>
</body>
</html>

2、部署流程资源

@RequestMapping(value = "/deploy")
public String deploy(@RequestParam(value = "file", required = true) MultipartFile file) {

    // 获取上传的文件名
    String fileName = file.getOriginalFilename();

    try {
        // 得到输入流(字节流)对象
        InputStream fileInputStream = file.getInputStream();

        // 文件的扩展名
        String extension = FilenameUtils.getExtension(fileName);

        // zip或者bar类型的文件用ZipInputStream方式部署
        DeploymentBuilder deployment = repositoryService.createDeployment();
        if (extension.equals("zip") || extension.equals("bar")) {
            ZipInputStream zip = new ZipInputStream(fileInputStream);
            deployment.addZipInputStream(zip);
        } else {
            // 其他类型的文件直接部署
            deployment.addInputStream(fileName, fileInputStream);
        }
        deployment.deploy();
    } catch (Exception e) {
        logger.error("error on deploy process, because of file input stream");
    }

    return "redirect:process-list";
}

3、读取流程资源

/**
     * 读取流程资源
     *
     * @param processDefinitionId 流程定义ID
     * @param resourceName        资源名称
     */
    @RequestMapping(value = "/read-resource")
    public void readResource(@RequestParam("pdid") String processDefinitionId, @RequestParam("resourceName") String resourceName, HttpServletResponse response)
            throws Exception {
        ProcessDefinitionQuery pdq = repositoryService.createProcessDefinitionQuery();
        ProcessDefinition pd = pdq.processDefinitionId(processDefinitionId).singleResult();

        // 通过接口读取
        InputStream resourceAsStream = repositoryService.getResourceAsStream(pd.getDeploymentId(), resourceName);

        // 输出资源内容到相应对象
        byte[] b = new byte[1024];
        int len = -1;
        while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
            response.getOutputStream().write(b, 0, len);
        }
    }

4、删除部署的流程

/**
     * 删除部署的流程,级联删除流程实例
     *
     * @param deploymentId 流程部署ID
     */
    @RequestMapping(value = "/delete-deployment")
    public String deleteProcessDefinition(@RequestParam("deploymentId") String deploymentId) {
        repositoryService.deleteDeployment(deploymentId, true);
        return "redirect:process-list";
    }

5、读取流程启动表单

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="org.activiti.engine.form.*, org.apache.commons.lang3.*" %>
<!DOCTYPE html>
<html>
<head>
	<%@ include file="/common/global.jsp"%>
	<%@ include file="/common/meta.jsp" %>
	<%@ include file="/common/include-base-styles.jsp" %>
	<title>启动流程</title>
	<script type="text/javascript" src="${ctx }/js/common/jquery.js"></script>
	<script type="text/javascript" src="${ctx }/js/common/bootstrap.min.js"></script>
	<script type="text/javascript" src="${ctx }/js/common/bootstrap-datepicker.js"></script>
	<script type="text/javascript">
	$(function() {
		$('.datepicker').datepicker();
	});
	</script>
</head>
<body>
	<h3>启动流程—
		<c:if test="${hasStartFormKey}">
			[${processDefinition.name}],版本号:${processDefinition.version}
		</c:if>
		<c:if test="${!hasStartFormKey}">
			[${startFormData.processDefinition.name}],版本号:${startFormData.processDefinition.version}
		</c:if>
	</h3>
	<hr/>
	<form action="${ctx }/chapter6/process-instance/start/${processDefinitionId}" class="form-horizontal" method="post">
		<c:if test="${hasStartFormKey}">
		${startFormData}
		</c:if>

		<c:if test="${!hasStartFormKey}">
			<c:forEach items="${startFormData.formProperties}" var="fp">
				<c:set var="fpo" value="${fp}"/>
				<%
					// 把需要获取的属性读取并设置到pageContext域
					FormType type = ((FormProperty)pageContext.getAttribute("fpo")).getType();
					String[] keys = {"datePattern"};
					for (String key: keys) {
						pageContext.setAttribute(key, ObjectUtils.toString(type.getInformation(key)));
					}
				%>
				<div class="control-group">
				<%-- 文本或者数字类型 --%>
				<c:if test="${fp.type.name == 'string' || fp.type.name == 'long'}">
					<label class="control-label" for="${fp.id}">${fp.name}:</label>
					<div class="controls">
						<input type="text" id="${fp.id}" name="${fp.id}" data-type="${fp.type.name}" value="" />
					</div>
				</c:if>

				<%-- 日期 --%>
				<c:if test="${fp.type.name == 'date'}">
					<label class="control-label" for="${fp.id}">${fp.name}:</label>
					<div class="controls">
						<input type="text" id="${fp.id}" name="${fp.id}" class="datepicker"  data-type="${fp.type.name}" data-date-format="${fn:toLowerCase(datePattern)}" />
					</div>
				</c:if>

				<%-- Javascript --%>
				<c:if test="${fp.type.name == 'javascript'}">
					<script type="text/javascript">${fp.value};</script>
				</c:if>
				</div>
			</c:forEach>
		</c:if>

		<%-- 按钮区域 --%>
		<div class="control-group">
			<div class="controls">
				<a href="javascript:history.back();" class="btn"><i class="icon-backward"></i>返回列表</a>
				<button type="submit" class="btn"><i class="icon-play"></i>启动流程</button>
			</div>
		</div>
	</form>
</body>
</html>
@RequestMapping(value = "getform/start/{processDefinitionId}")
public ModelAndView readStartForm(@PathVariable("processDefinitionId") String processDefinitionId) throws Exception {
    ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
    boolean hasStartFormKey = processDefinition.hasStartFormKey();

    // 根据是否有formkey属性判断使用哪个展示层
    String viewName = "chapter6/start-process-form";
    ModelAndView mav = new ModelAndView(viewName);

    // 判断是否有formkey属性
    if (hasStartFormKey) {
        Object renderedStartForm = formService.getRenderedStartForm(processDefinitionId);
        mav.addObject("startFormData", renderedStartForm);
        mav.addObject("processDefinition", processDefinition);
    } else { // 动态表单字段
        StartFormData startFormData = formService.getStartFormData(processDefinitionId);
        mav.addObject("startFormData", startFormData);
    }
    mav.addObject("hasStartFormKey", hasStartFormKey);
    mav.addObject("processDefinitionId", processDefinitionId);
    return mav;
}

6、根据表单启动流程

@RequestMapping(value = "process-instance/start/{processDefinitionId}")
public String startProcessInstance(@PathVariable("processDefinitionId") String pdid, HttpServletRequest request, RedirectAttributes redirectAttributes) {

    ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(pdid).singleResult();
    boolean hasStartFormKey = processDefinition.hasStartFormKey();

    Map<String, String> formValues = new HashMap<String, String>();

    if (hasStartFormKey) { // formkey表单
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<Entry<String, String[]>> entrySet = parameterMap.entrySet();
        for (Entry<String, String[]> entry : entrySet) {
            String key = entry.getKey();
            formValues.put(key, entry.getValue()[0]);
        }
    } else { // 动态表单
        // 先读取表单字段在根据表单字段的ID读取请求参数值
        StartFormData formData = formService.getStartFormData(pdid);

        // 从请求中获取表单字段的值
        List<FormProperty> formProperties = formData.getFormProperties();
        for (FormProperty formProperty : formProperties) {
            String value = request.getParameter(formProperty.getId());
            formValues.put(formProperty.getId(), value);
        }
    }

    // 获取当前登录的用户
    User user = UserUtil.getUserFromSession(request.getSession());
    // 用户未登录不能操作,实际应用使用权限框架实现,例如Spring Security、Shiro等
    if (user == null || StringUtils.isBlank(user.getId())) {
        return "redirect:/login?timeout=true";
    }
    identityService.setAuthenticatedUserId(user.getId());

    // 提交表单字段并启动一个新的流程实例
    ProcessInstance processInstance = formService.submitStartFormData(pdid, formValues);
    logger.debug("start a processinstance: {}", processInstance);
    redirectAttributes.addFlashAttribute("message", "流程已启动,实例ID:" + processInstance.getId());
    return "redirect:/chapter5/process-list";
}

7、获取待办任务

@RequestMapping(value = "task/list")
public ModelAndView todoTasks(HttpSession session) throws Exception {
    String viewName = "chapter6/task-list";
    ModelAndView mav = new ModelAndView(viewName);
    User user = UserUtil.getUserFromSession(session);

    // 读取直接分配给当前人或者已经签收的任务
    List<Task> doingTasks = taskService.createTaskQuery().taskAssignee(user.getId()).list();

    // 等待签收的任务
    List<Task> waitingClaimTasks = taskService.createTaskQuery().taskCandidateUser(user.getId()).list();

    // 合并两种任务
    List<Task> allTasks = new ArrayList<Task>();
    allTasks.addAll(doingTasks);
    allTasks.addAll(waitingClaimTasks);

    // 5.16版本可以使用一下代码待办查询
    // List<Task> tasks = taskService.createTaskQuery().taskCandidateOrAssigned(user.getId()).list();

    mav.addObject("tasks", allTasks);
    return mav;
}
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
	<%@ include file="/common/global.jsp"%>
	<%@ include file="/common/meta.jsp" %>
	<%@ include file="/common/include-base-styles.jsp" %>
	<title>待办任务列表--chapter6</title>

	<script src="${ctx }/js/common/jquery.js" type="text/javascript"></script>
</head>
<body>
	<c:if test="${not empty message}">
		<div id="message" class="alert alert-success">${message}</div>
		<!-- 自动隐藏提示信息 -->
		<script type="text/javascript">
		setTimeout(function() {
			$('#message').hide('slow');
		}, 5000);
		</script>
	</c:if>
	<table width="100%" class="table table-bordered table-hover table-condensed">
		<thead>
			<tr>
				<th>任务ID</th>
				<th>任务名称</th>
				<th>流程实例ID</th>
				<th>流程定义ID</th>
				<th>任务创建时间</th>
				<th>办理人</th>
				<th>操作</th>
			</tr>
		</thead>
		<tbody>
			<c:forEach items="${tasks }" var="task">
				<tr>
					<td>${task.id }</td>
					<td>${task.name }</td>
					<td>${task.processInstanceId }</td>
					<td>${task.processDefinitionId }</td>
					<td>${task.createTime }</td>
					<td>${task.assignee }</td>
					<td>
						<c:if test="${empty task.assignee }">
							<a class="btn" href="claim/${task.id}"><i class="icon-eye-open"></i>签收</a>
						</c:if>
						<c:if test="${not empty task.assignee }">
							<a class="btn" href="getform/${task.id}"><i class="icon-user"></i>办理</a>
						</c:if>
					</td>
				</tr>
			</c:forEach>
		</tbody>
	</table>
</body>
</html>

8、签收任务

@RequestMapping(value = "task/claim/{id}")
public String claim(@PathVariable("id") String taskId, HttpSession session, RedirectAttributes redirectAttributes) {
    String userId = UserUtil.getUserFromSession(session).getId();
    taskService.claim(taskId, userId);
    redirectAttributes.addFlashAttribute("message", "任务已签收");
    return "redirect:/chapter6/task/list";
}

9、读取任务表单

@RequestMapping(value = "task/getform/{taskId}")
public ModelAndView readTaskForm(@PathVariable("taskId") String taskId) throws Exception {
    String viewName = "chapter6/task-form";
    ModelAndView mav = new ModelAndView(viewName);
    TaskFormData taskFormData = formService.getTaskFormData(taskId);
    if (taskFormData.getFormKey() != null) {
        Object renderedTaskForm = formService.getRenderedTaskForm(taskId);
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        mav.addObject("task", task);
        mav.addObject("taskFormData", renderedTaskForm);
        mav.addObject("hasFormKey", true);
    } else {
        mav.addObject("taskFormData", taskFormData);
    }
    return mav;
}
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="org.activiti.engine.form.*, org.apache.commons.lang3.*" %>
<!DOCTYPE html>
<html>
<head>
	<%@ include file="/common/global.jsp"%>
	<%@ include file="/common/meta.jsp" %>
	<%@ include file="/common/include-base-styles.jsp" %>
	<title>任务办理</title>
	<script type="text/javascript" src="${ctx }/js/common/jquery.js"></script>
	<script type="text/javascript" src="${ctx }/js/common/bootstrap.min.js"></script>
	<script type="text/javascript" src="${ctx }/js/common/bootstrap-datepicker.js"></script>
	<script type="text/javascript">
	$(function() {
		$('.datepicker').datepicker();
	});
	</script>
</head>
<body>
	<h3>任务办理—[${hasFormKey ? task.name : taskFormData.task.name}],流程定义ID:[${hasFormKey ? task.processDefinitionId : taskFormData.task.processDefinitionId}]</h3>
	<hr/>
	<form action="${ctx }/chapter6/task/complete/${hasFormKey ? task.id : taskFormData.task.id}" class="form-horizontal" method="post">
		<c:if test="${hasFormKey}">
			${taskFormData}
		</c:if>
		<c:if test="${!hasFormKey}">
		<c:forEach items="${taskFormData.formProperties}" var="fp">
			<c:set var="fpo" value="${fp}"/>
			<c:set var="disabled" value="${fp.writable ? '' : 'disabled'}" />
			<c:set var="readonly" value="${fp.writable ? '' : 'readonly'}" />
			<c:set var="required" value="${fp.required ? 'required' : ''}" />
			<%
				// 把需要获取的属性读取并设置到pageContext域
				FormType type = ((FormProperty)pageContext.getAttribute("fpo")).getType();
				String[] keys = {"datePattern", "values"};
				for (String key: keys) {
					pageContext.setAttribute(key, type.getInformation(key));
				}
			%>
			<div class="control-group">
			<%-- 文本或者数字类型 --%>
			<c:if test="${fp.type.name == 'string' || fp.type.name == 'long'}">
				<label class="control-label" for="${fp.id}">${fp.name}:</label>
				<div class="controls">
					<input type="text" id="${fp.id}" name="${fp.id}" data-type="${fp.type.name}" value="${fp.value}" ${readonly} ${required} />
				</div>
			</c:if>

			<%-- 日期 --%>
			<c:if test="${fp.type.name == 'date'}">
				<label class="control-label" for="${fp.id}">${fp.name}:</label>
				<div class="controls">
					<input type="text" id="${fp.id}" name="${fp.id}" class="datepicker" value="${fp.value}" data-type="${fp.type.name}" data-date-format="${fn:toLowerCase(datePattern)}" ${readonly} ${required}/>
				</div>
			</c:if>

			<%-- 下拉框 --%>
			<c:if test="${fp.type.name == 'enum'}">
				<label class="control-label" for="${fp.id}">${fp.name}:</label>
				<div class="controls">
					<select name="${fp.id}" id="${fp.id}" ${disabled} ${required}>
						<c:forEach items="${values}" var="item">
							<option value="${item.key}" <c:if test="${item.value == fp.value}">selected</c:if>>${item.value}</option>
						</c:forEach>
					</select>
				</div>
			</c:if>

			<%-- Javascript --%>
			<c:if test="${fp.type.name == 'javascript'}">
				<script type="text/javascript">${fp.value};</script>
			</c:if>

			</div>
		</c:forEach>
		</c:if>

		<%-- 按钮区域 --%>
		<div class="control-group">
			<div class="controls">
				<a href="javascript:history.back();" class="btn"><i class="icon-backward"></i>返回列表</a>
				<button type="submit" class="btn"><i class="icon-ok"></i>完成任务</button>
			</div>
		</div>
	</form>
</body>
</html>

10、完成任务

@RequestMapping(value = "task/complete/{taskId}")
public String completeTask(@PathVariable("taskId") String taskId, HttpServletRequest request) throws Exception {
    TaskFormData taskFormData = formService.getTaskFormData(taskId);
    String formKey = taskFormData.getFormKey();
    // 从请求中获取表单字段的值
    List<FormProperty> formProperties = taskFormData.getFormProperties();
    Map<String, String> formValues = new HashMap<String, String>();

    if (StringUtils.isNotBlank(formKey)) { // formkey表单
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<Entry<String, String[]>> entrySet = parameterMap.entrySet();
        for (Entry<String, String[]> entry : entrySet) {
            String key = entry.getKey();
            formValues.put(key, entry.getValue()[0]);
        }
    } else { // 动态表单
        for (FormProperty formProperty : formProperties) {
            if (formProperty.isWritable()) {
                String value = request.getParameter(formProperty.getId());
                formValues.put(formProperty.getId(), value);
            }
        }
    }
    formService.submitTaskFormData(taskId, formValues);
    return TASK_LIST;
}

11、保存审批意见

@RequestMapping(value = "save", method = RequestMethod.POST)
@ResponseBody
public Boolean addComment(@RequestParam("taskId") String taskId, @RequestParam("processInstanceId") String processInstanceId,
                          @RequestParam("message") String message, HttpSession session) {
    //设置当前人,引擎会把当前人作为意见的所属人
    identityService.setAuthenticatedUserId(UserUtil.getUserFromSession(session).getId());
    //调用保存意见的方法
    taskService.addComment(taskId, processInstanceId, message);
    return true;
}

12、读取审批意见

@RequestMapping(value = "list/{processInstanceId}")
@ResponseBody
public Map<String, Object> list(@PathVariable("processInstanceId") String processInstanceId) {

    Map<String, Object> result = new HashMap<String, Object>();
    //根据流程实例ID读取意见
    List<Comment> taskComments = taskService.getProcessInstanceComments(processInstanceId);
    List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).list();
    Map<String, String> taskNames = new HashMap<String, String>();
    for (HistoricTaskInstance historicTaskInstance : list) {
        //读取历史任务以键值对形式保存任务ID和名称
        taskNames.put(historicTaskInstance.getId(), historicTaskInstance.getName());
    }
    result.put("comments", taskComments);
    result.put("taskNames", taskNames);
    return result;
}

13、更改任务属性

在这里插入图片描述

14、添加任务参与人

在这里插入图片描述

15、删除任务参与人

在这里插入图片描述
在这里插入图片描述

16、添加候选人、候选组

在这里插入图片描述

17、删除参与人、候选人及候选组

在这里插入图片描述

18、添加子任务

在这里插入图片描述

19、查询子任务及上级任务

在这里插入图片描述

20、查询历史任务

在这里插入图片描述

21、保存文件类型附件

@RequestMapping(value = "new/file")
public String newFile(@RequestParam("taskId") String taskId, @RequestParam(value = "processInstanceId", required = false) String processInstanceId,
                      @RequestParam("attachmentName") String attachmentName, @RequestParam(value = "attachmentDescription", required = false) String attachmentDescription,
                      @RequestParam("file") MultipartFile file, HttpSession session) {
    try {
        //获取文件扩展名
        String attachmentType = file.getContentType() + ";" + FilenameUtils.getExtension(file.getOriginalFilename());
        identityService.setAuthenticatedUserId(UserUtil.getUserFromSession(session).getId());
        Attachment attachment = taskService.createAttachment(attachmentType, taskId, processInstanceId, attachmentName, attachmentDescription,
                file.getInputStream());
        taskService.saveAttachment(attachment);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return "redirect:/chapter6/task/getform/" + taskId;
}

22、保存URL类型附件

@RequestMapping(value = "new/url")
public String newUrl(@RequestParam("taskId") String taskId, @RequestParam(value = "processInstanceId", required = false) String processInstanceId,
                     @RequestParam("attachmentName") String attachmentName, @RequestParam(value = "attachmentDescription", required = false) String attachmentDescription,
                     @RequestParam("url") String url, HttpSession session) {
    String attachmentType = "url";
    identityService.setAuthenticatedUserId(UserUtil.getUserFromSession(session).getId());
/*Attachment attachment = */
    taskService.createAttachment(attachmentType, taskId, processInstanceId, attachmentName, attachmentDescription, url);
/*
 * 如果要更新附件内容,先读取附件对象,然后设置属性(只能更新name和description),最后保存附件对象
 */
//    taskService.saveAttachment(attachment);
    return "redirect:/chapter6/task/getform/" + taskId;
}

23、下载附件

@RequestMapping(value = "download/{attachmentId}")
public void downloadFile(@PathVariable("attachmentId") String attachmentId, HttpServletResponse response) throws IOException {
    //查询附件对象
    Attachment attachment = taskService.getAttachment(attachmentId);
    //读取附件的二进制流
    InputStream attachmentContent = taskService.getAttachmentContent(attachmentId);
    //根据规则获取文件的类型
    String contentType = StringUtils.substringBefore(attachment.getType(), ";");
    response.addHeader("Content-Type", contentType + ";charset=UTF-8");
    //根据规则获取文件的扩展名
    String extensionFileName = StringUtils.substringAfter(attachment.getType(), ";");
    //下载
    String fileName = attachment.getName() + "." + extensionFileName;
    response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
    IOUtils.copy(new BufferedInputStream(attachmentContent), response.getOutputStream());
}

24、删除附件

@RequestMapping(value = "delete/{attachmentId}")
@ResponseBody
public String delete(@PathVariable("attachmentId") String attachmentId) {
    taskService.deleteAttachment(attachmentId);
    return "true";
}

25、查询用户参与过的流程

@RequestMapping("execution/list")
public ModelAndView list(HttpServletRequest request) {
    ModelAndView mav = new ModelAndView("chapter13/execution-list");
/* 标准查询
List<ProcessInstance> processInstanceList = runtimeService.createProcessInstanceQuery().list();
List<Execution> list = runtimeService.createExecutionQuery().list();
mav.addObject("list", list);
*/

    User user = UserUtil.getUserFromSession(request.getSession());
    Page<Execution> page = new Page<Execution>(PageUtil.PAGE_SIZE);
    int[] pageParams = PageUtil.init(page, request);
    NativeExecutionQuery nativeExecutionQuery = runtimeService.createNativeExecutionQuery();

    // native query
    String sql = "select distinct * from (select RES.* from ACT_RU_EXECUTION RES left join ACT_HI_TASKINST ART on ART.PROC_INST_ID_ = RES.PROC_INST_ID_ "
            + " left join ACT_HI_PROCINST AHP on AHP.PROC_INST_ID_ = RES.PROC_INST_ID_ "
            + " where SUSPENSION_STATE_ = '1' and (ART.ASSIGNEE_ = #{userId} or AHP.START_USER_ID_ = #{userId}) "
            + " and ACT_ID_ is not null and IS_ACTIVE_ = 'TRUE' order by ART.START_TIME_ desc)";

    nativeExecutionQuery.parameter("userId", user.getId());

    List<Execution> executionList = nativeExecutionQuery.sql(sql).listPage(pageParams[0], pageParams[1]);

    // 查询流程定义对象
    Map<String, ProcessDefinition> definitionMap = new HashMap<String, ProcessDefinition>();

    // 任务的英文-中文对照
    Map<String, Task> taskMap = new HashMap<String, Task>();

    // 每个Execution的当前活动ID,可能为多个
    Map<String, List<String>> currentActivityMap = new HashMap<String, List<String>>();

    // 设置每个Execution对象的当前活动节点
    for (Execution execution : executionList) {
        ExecutionEntity executionEntity = (ExecutionEntity) execution;
        String processInstanceId = executionEntity.getProcessInstanceId();
        String processDefinitionId = executionEntity.getProcessDefinitionId();

        // 缓存ProcessDefinition对象到Map集合
        definitionCache(definitionMap, processDefinitionId);

        // 查询当前流程的所有处于活动状态的活动ID,如果并行的活动则会有多个
        List<String> activeActivityIds = runtimeService.getActiveActivityIds(execution.getId());
        currentActivityMap.put(execution.getId(), activeActivityIds);

        for (String activityId : activeActivityIds) {

            // 查询处于活动状态的任务
            Task task = taskService.createTaskQuery().taskDefinitionKey(activityId).executionId(execution.getId()).singleResult();

            // 调用活动
            if (task == null) {
                ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                        .superProcessInstanceId(processInstanceId).singleResult();
                if (processInstance != null) {
                    task = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).singleResult();
                    definitionCache(definitionMap, processInstance.getProcessDefinitionId());
                }
            }
            taskMap.put(activityId, task);
        }
    }

    mav.addObject("taskMap", taskMap);
    mav.addObject("definitions", definitionMap);
    mav.addObject("currentActivityMap", currentActivityMap);

    page.setResult(executionList);
    page.setTotalCount(nativeExecutionQuery.sql("select count(*) from (" + sql + ")").count());
    mav.addObject("page", page);

    return mav;
}

/**
 * 流程定义对象缓存
 *
 * @param definitionMap
 * @param processDefinitionId
 */
private void definitionCache(Map<String, ProcessDefinition> definitionMap, String processDefinitionId) {
    if (definitionMap.get(processDefinitionId) == null) {
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        processDefinitionQuery.processDefinitionId(processDefinitionId);
        ProcessDefinition processDefinition = processDefinitionQuery.singleResult();

        // 放入缓存
        definitionMap.put(processDefinitionId, processDefinition);
    }
}

26、查询已经结束的流程实例

@RequestMapping(value = "finished/list")
public ModelAndView finishedProcessInstanceList(HttpServletRequest request) {
    ModelAndView mav = new ModelAndView("chapter13/finished-process");
    Page<HistoricProcessInstance> page = new Page<HistoricProcessInstance>(PageUtil.PAGE_SIZE);
    int[] pageParams = PageUtil.init(page, request);
    HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery().finished();
    List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery.listPage(pageParams[0], pageParams[1]);

    // 查询流程定义对象
    Map<String, ProcessDefinition> definitionMap = new HashMap<String, ProcessDefinition>();

    for (HistoricProcessInstance historicProcessInstance : historicProcessInstances) {
        definitionCache(definitionMap, historicProcessInstance.getProcessDefinitionId());
    }

    page.setResult(historicProcessInstances);
    page.setTotalCount(historicProcessInstanceQuery.count());
    mav.addObject("page", page);
    mav.addObject("definitions", definitionMap);

    return mav;
}

27、查询历史流程实例相关信息

@RequestMapping(value = "finished/view/{processInstanceId}")
public ModelAndView historyDatas(@PathVariable("processInstanceId") String processInstanceId) {
    ModelAndView mav = new ModelAndView("chapter13/view-finished-process");

    List<HistoricActivityInstance> activityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list();

    // 查询历史流程实例
    HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
            .processInstanceId(processInstanceId).singleResult();

    // 查询流程有关的变量
    List<HistoricVariableInstance> variableInstances = historyService.createHistoricVariableInstanceQuery()
            .processInstanceId(processInstanceId).list();

    List<HistoricDetail> formProperties = historyService.createHistoricDetailQuery().processInstanceId(processInstanceId).formProperties().list();

    // 查询流程定义对象
    ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
            .processDefinitionId(historicProcessInstance.getProcessDefinitionId()).singleResult();

    mav.addObject("historicProcessInstance", historicProcessInstance);
    mav.addObject("variableInstances", variableInstances);
    mav.addObject("activities", activityInstances);
    mav.addObject("formProperties", formProperties);
    mav.addObject("processDefinition", processDefinition);

    return mav;
}

28、删除历史流程实例

@RequestMapping(value = "finished/delete/{processInstanceId}")
public String deleteProcessInstance(@PathVariable("processInstanceId") String processInstanceId,
                                    RedirectAttributes redirectAttributes) {
    redirectAttributes.addFlashAttribute("message", "ID为" + processInstanceId + "的历史流程已删除!");
    historyService.deleteHistoricProcessInstance(processInstanceId);
    return "redirect:/chapter13/history/process/finished/manager";
}

29、流程跟踪

@Controller
@RequestMapping(value = "/chapter13/process")
public class TraceProcessController {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    TaskService taskService;

    @Autowired
    HistoryService historyService;

    @Autowired
    RuntimeService runtimeService;

    @Autowired
    RepositoryService repositoryService;

    @Autowired
    protected IdentityService identityService;

    @Autowired
    ProcessEngineConfiguration processEngineConfiguration;

    /**
     * 读取流程资源
     */
    @RequestMapping(value = "trace/data/auto/{executionId}")
    public void readResource(@PathVariable("executionId") String executionId, HttpServletResponse response)
            throws Exception {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(executionId).singleResult();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService.createProcessDefinitionQuery().processDefinitionId(processInstance.getProcessDefinitionId()).singleResult();
        List<String> activeActivityIds = runtimeService.getActiveActivityIds(executionId);
        ProcessDiagramGenerator diagramGenerator = processEngineConfiguration.getProcessDiagramGenerator();
        List<String> highLightedFlows = getHighLightedFlows(processDefinition, processInstance.getId());
        InputStream imageStream =diagramGenerator.generateDiagram(bpmnModel, "png", activeActivityIds, highLightedFlows);

        // 输出资源内容到相应对象
        byte[] b = new byte[1024];
        int len;
        while ((len = imageStream.read(b, 0, 1024)) != -1) {
            response.getOutputStream().write(b, 0, len);
        }
    }

    private List<String> getHighLightedFlows(ProcessDefinitionEntity processDefinition, String processInstanceId) {
        List<String> highLightedFlows = new ArrayList<String>();
        List<HistoricActivityInstance> historicActivityInstances = historyService
                .createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByHistoricActivityInstanceStartTime().asc().list();

        List<String> historicActivityInstanceList = new ArrayList<String>();
        for (HistoricActivityInstance hai : historicActivityInstances) {
            historicActivityInstanceList.add(hai.getActivityId());
        }

        // add current activities to list
        List<String> highLightedActivities = runtimeService.getActiveActivityIds(processInstanceId);
        historicActivityInstanceList.addAll(highLightedActivities);

        // activities and their sequence-flows
        for (ActivityImpl activity : processDefinition.getActivities()) {
            int index = historicActivityInstanceList.indexOf(activity.getId());

            if (index >= 0 && index + 1 < historicActivityInstanceList.size()) {
                List<PvmTransition> pvmTransitionList = activity
                        .getOutgoingTransitions();
                for (PvmTransition pvmTransition : pvmTransitionList) {
                    String destinationFlowId = pvmTransition.getDestination().getId();
                    if (destinationFlowId.equals(historicActivityInstanceList.get(index + 1))) {
                        highLightedFlows.add(pvmTransition.getId());
                    }
                }
            }
        }
        return highLightedFlows;
    }

    /**
     * 读取历史数据
     *
     * @return
     */
    @RequestMapping(value = "trace/view/{executionId}")
    public ModelAndView historyDatas(@PathVariable("executionId") String executionId) {
        ModelAndView mav = new ModelAndView("chapter13/trace-process");

        // 查询Execution对象
        Execution execution = runtimeService.createExecutionQuery().executionId(executionId).singleResult();

        // 查询所有的历史活动记录
        String processInstanceId = execution.getProcessInstanceId();
        List<HistoricActivityInstance> activityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list();

        // 查询历史流程实例
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();

        // 查询流程有关的变量
        List<HistoricVariableInstance> variableInstances = historyService.createHistoricVariableInstanceQuery()
                .processInstanceId(processInstanceId).list();

        List<HistoricDetail> formProperties = historyService.createHistoricDetailQuery().processInstanceId(processInstanceId).formProperties().list();

        // 查询流程定义对象
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(historicProcessInstance.getProcessDefinitionId()).singleResult();

        // 查询运行时流程实例
        ProcessInstance parentProcessInstance = runtimeService.createProcessInstanceQuery()
                .subProcessInstanceId(execution.getProcessInstanceId()).singleResult();

        mav.addObject("parentProcessInstance", parentProcessInstance);
        mav.addObject("historicProcessInstance", historicProcessInstance);
        mav.addObject("variableInstances", variableInstances);
        mav.addObject("activities", activityInstances);
        mav.addObject("formProperties", formProperties);
        mav.addObject("processDefinition", processDefinition);
        mav.addObject("executionId", executionId);

        return mav;
    }

    /**
     * 读取跟踪数据
     *
     * @param executionId
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "trace/data/{executionId}")
    @ResponseBody
    public List<Map<String, Object>> readActivityDatas(@PathVariable("executionId") String executionId) throws Exception {
        ExecutionEntity executionEntity = (ExecutionEntity) runtimeService.createExecutionQuery().executionId(executionId).singleResult();
        List<String> activeActivityIds = runtimeService.getActiveActivityIds(executionId);

        RepositoryServiceImpl repositoryServiceImpl = (RepositoryServiceImpl) repositoryService;
        ReadOnlyProcessDefinition deployedProcessDefinition = repositoryServiceImpl
                .getDeployedProcessDefinition(executionEntity.getProcessDefinitionId());

        ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) deployedProcessDefinition;
        List<ActivityImpl> activitiList = processDefinition.getActivities();//获得当前任务的所有节点

        List<Map<String, Object>> activityInfos = new ArrayList<Map<String, Object>>();
        for (ActivityImpl activity : activitiList) {

            ActivityBehavior activityBehavior = activity.getActivityBehavior();

            boolean currentActiviti = false;
            // 当前节点
            String activityId = activity.getId();
            if (activeActivityIds.contains(activityId)) {
                currentActiviti = true;
            }
            Map<String, Object> activityImageInfo = packageSingleActivitiInfo(activity, executionEntity.getId(), currentActiviti);
            activityInfos.add(activityImageInfo);

            // 处理子流程
            if (activityBehavior instanceof SubProcessActivityBehavior) {
                List<ActivityImpl> innerActivityList = activity.getActivities();
                for (ActivityImpl innerActivity : innerActivityList) {
                    String innerActivityId = innerActivity.getId();
                    if (activeActivityIds.contains(innerActivityId)) {
                        currentActiviti = true;
                    } else {
                        currentActiviti = false;
                    }
                    activityImageInfo = packageSingleActivitiInfo(innerActivity, executionEntity.getId(), currentActiviti);
                    activityInfos.add(activityImageInfo);
                }
            }

        }

        return activityInfos;
    }

    /**
     * 封装输出信息,包括:当前节点的X、Y坐标、变量信息、任务类型、任务描述
     *
     * @param activity
     * @param currentActiviti
     * @return
     */
    private Map<String, Object> packageSingleActivitiInfo(ActivityImpl activity, String executionId,
                                                          boolean currentActiviti) throws Exception {
        Map<String, Object> activityInfo = new HashMap<String, Object>();
        activityInfo.put("currentActiviti", currentActiviti);

        // 设置图形的XY坐标以及宽度、高度
        setSizeAndPositonInfo(activity, activityInfo);

        Map<String, Object> vars = new HashMap<String, Object>();
        Map<String, Object> properties = activity.getProperties();
        vars.put("任务类型", ActivityUtil.getZhActivityType(properties.get("type").toString()));
        vars.put("任务名称", properties.get("name"));

        // 当前节点的task
        if (currentActiviti) {
            setCurrentTaskInfo(executionId, activity.getId(), vars);
        }

        logger.debug("trace variables: {}", vars);
        activityInfo.put("vars", vars);
        return activityInfo;
    }

    /**
     * 获取当前节点信息
     *
     * @return
     */
    private void setCurrentTaskInfo(String executionId, String activityId, Map<String, Object> vars) {
        Task currentTask = taskService.createTaskQuery().executionId(executionId)
                .taskDefinitionKey(activityId).singleResult();
        logger.debug("current task for processInstance: {}", ToStringBuilder.reflectionToString(currentTask));

        if (currentTask == null) return;

        String assignee = currentTask.getAssignee();
        if (assignee != null) {
            User assigneeUser = identityService.createUserQuery().userId(assignee).singleResult();
            String userInfo = assigneeUser.getFirstName() + " " + assigneeUser.getLastName() + "/" + assigneeUser.getId();
            vars.put("当前处理人", userInfo);
            vars.put("创建时间", new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(currentTask.getCreateTime()));
        } else {
            vars.put("任务状态", "未签收");
        }

    }

    /**
     * 设置宽度、高度、坐标属性
     *
     * @param activity
     * @param activityInfo
     */
    private void setSizeAndPositonInfo(ActivityImpl activity, Map<String, Object> activityInfo) {
        activityInfo.put("width", activity.getWidth());
        activityInfo.put("height", activity.getHeight());
        activityInfo.put("x", activity.getX());
        activityInfo.put("y", activity.getY());
    }
}

30、用户及组管理

@Controller
@RequestMapping("/chapter14/identity")
public class IdentityController {

    @Autowired
    IdentityService identityService;


    /**
     * 组列表
     *
     * @param request
     * @return
     */
    @RequestMapping("group/list")
    public ModelAndView groupList(HttpServletRequest request) {
        ModelAndView mav = new ModelAndView("chapter14/group-list");

        Page<Group> page = new Page<Group>(PageUtil.PAGE_SIZE);
        int[] pageParams = PageUtil.init(page, request);

        GroupQuery groupQuery = identityService.createGroupQuery();
        List<Group> groupList = groupQuery.listPage(pageParams[0], pageParams[1]);

        page.setResult(groupList);
        page.setTotalCount(groupQuery.count());
        mav.addObject("page", page);

        return mav;
    }

    /**
     * 保存Group
     *
     * @return
     */
    @RequestMapping(value = "group/save", method = RequestMethod.POST)
    public String saveGroup(@RequestParam("groupId") String groupId,
                            @RequestParam("groupName") String groupName,
                            @RequestParam("type") String type,
                            RedirectAttributes redirectAttributes) {
        Group group = identityService.createGroupQuery().groupId(groupId).singleResult();
        if (group == null) {
            group = identityService.newGroup(groupId);
        }
        group.setName(groupName);
        group.setType(type);
        identityService.saveGroup(group);
        redirectAttributes.addFlashAttribute("message", "成功添加组[" + groupName + "]");
        return "redirect:/chapter14/identity/group/list";
    }

    /**
     * 删除Group
     */
    @RequestMapping(value = "group/delete/{groupId}", method = RequestMethod.GET)
    public String deleteGroup(@PathVariable("groupId") String groupId,
                              RedirectAttributes redirectAttributes) {
        identityService.deleteGroup(groupId);
        redirectAttributes.addFlashAttribute("message", "成功删除组[" + groupId + "]");
        return "redirect:/chapter14/identity/group/list";
    }

    /**
     * 用户列表
     *
     * @param request
     * @return
     */
    @RequestMapping("user/list")
    public ModelAndView userList(HttpServletRequest request) {
        ModelAndView mav = new ModelAndView("chapter14/user-list");

        Page<User> page = new Page<User>(PageUtil.PAGE_SIZE);
        int[] pageParams = PageUtil.init(page, request);

        UserQuery userQuery = identityService.createUserQuery();
        List<User> userList = userQuery.listPage(pageParams[0], pageParams[1]);

        // 查询每个人的分组,这样的写法比较耗费性能、时间,仅供读者参考
        Map<String, List<Group>> groupOfUserMap = new HashMap<String, List<Group>>();
        for (User user : userList) {
            List<Group> groupList = identityService.createGroupQuery().groupMember(user.getId()).list();
            groupOfUserMap.put(user.getId(), groupList);
        }

        page.setResult(userList);
        page.setTotalCount(userQuery.count());
        mav.addObject("page", page);
        mav.addObject("groupOfUserMap", groupOfUserMap);

        // 读取所有组
        List<Group> groups = identityService.createGroupQuery().list();
        mav.addObject("allGroup", groups);

        return mav;
    }

    /**
     * 保存User
     *
     * @param redirectAttributes
     * @return
     */
    @RequestMapping(value = "user/save", method = RequestMethod.POST)
    public String saveUser(@RequestParam("userId") String userId,
                           @RequestParam("firstName") String firstName,
                           @RequestParam("lastName") String lastName,
                           @RequestParam(value = "password", required = false) String password,
                           @RequestParam(value = "email", required = false) String email,
                           RedirectAttributes redirectAttributes) {
        User user = identityService.createUserQuery().userId(userId).singleResult();
        if (user == null) {
            user = identityService.newUser(userId);
        }
        user.setFirstName(firstName);
        user.setLastName(lastName);
        user.setEmail(email);
        if (StringUtils.isNotBlank(password)) {
            user.setPassword(password);
        }
        identityService.saveUser(user);
        redirectAttributes.addFlashAttribute("message", "成功添加用户[" + firstName + " " + lastName + "]");
        return "redirect:/chapter14/identity/user/list";
    }

    /**
     * 删除User
     */
    @RequestMapping(value = "user/delete/{userId}", method = RequestMethod.GET)
    public String deleteUser(@PathVariable("userId") String userId,
                             RedirectAttributes redirectAttributes) {
        identityService.deleteUser(userId);
        redirectAttributes.addFlashAttribute("message", "成功删除用户[" + userId + "]");
        return "redirect:/chapter14/identity/user/list";
    }

    /**
     * 为用户设置所属组
     * @param userId
     * @param groupIds
     * @return
     */
    @RequestMapping(value = "group/set", method = RequestMethod.POST)
    public String groupForUser(@RequestParam("userId") String userId, @RequestParam("group") String[] groupIds) {
        List<Group> groupInDb = identityService.createGroupQuery().groupMember(userId).list();
        for (Group group : groupInDb) {
            identityService.deleteMembership(userId, group.getId());
        }
        for (String group : groupIds) {
            identityService.createMembership(userId, group);
        }
        return "redirect:/chapter14/identity/user/list";
    }

}

31、作业控制

@Controller
@RequestMapping(value = "/chapter14/job")
public class JobController {

    @Autowired
    ManagementService managementService;

    public static Map<String, String> JOB_TYPES = new HashMap<String, String>();

    static {
        JOB_TYPES.put("activate-processdefinition", "激活流程定义");
        JOB_TYPES.put("timer-intermediate-transition", "中间定时");
        JOB_TYPES.put("timer-transition", "边界定时");
        JOB_TYPES.put("timer-start-event", "定时启动流程");
        JOB_TYPES.put("suspend-processdefinition", "挂起流程定义");
        JOB_TYPES.put("async-continuation", "异步锁");
    }

    /**
     * Job列表
     *
     * @return
     */
    @RequestMapping(value = "list")
    public ModelAndView jobList(HttpServletRequest request) {
        ModelAndView mav = new ModelAndView("chapter14/job-list");
        JobQuery jobQuery = managementService.createJobQuery();

        Page<Job> page = new Page<Job>(PageUtil.PAGE_SIZE);
        int[] pageParams = PageUtil.init(page, request);
        List<Job> jobList = jobQuery.listPage(pageParams[0], pageParams[1]);

        page.setResult(jobList);
        page.setTotalCount(jobQuery.count());

        Map<String, String> exceptionStacktraces = new HashMap<String, String>();
        for (Job job : jobList) {
            if (StringUtils.isNotBlank(job.getExceptionMessage())) {
                exceptionStacktraces.put(job.getId(), managementService.getJobExceptionStacktrace(job.getId()));
            }
        }

        mav.addObject("page", page);
        mav.addObject("exceptionStacktraces", exceptionStacktraces);
        mav.addObject("JOB_TYPES", JOB_TYPES);

        return mav;
    }

    /**
     * 删除作业
     *
     * @param jobId
     * @return
     */
    @RequestMapping(value = "delete/{jobId}")
    public String deleteJob(@PathVariable("jobId") String jobId) {
        managementService.deleteJob(jobId);
        return "redirect:/chapter14/job/list";
    }

    /**
     * 执行作业
     *
     * @param jobId
     * @return
     */
    @RequestMapping(value = "execute/{jobId}")
    public String executeJob(@PathVariable("jobId") String jobId) {
        managementService.executeJob(jobId);
        return "redirect:/chapter14/job/list";
    }

    /**
     * 更改作业可重试次数
     *
     * @param jobId
     * @return
     */
    @RequestMapping(value = "change/retries/{jobId}")
    public String changeRetries(@PathVariable("jobId") String jobId, @RequestParam("retries") int retries) {
        managementService.setJobRetries(jobId, retries);
        return "redirect:/chapter14/job/list";
    }

    /**
     * 读取作业异常信息
     *
     * @param jobId
     * @return
     */
    @RequestMapping(value = "stacktrace/{jobId}")
    @ResponseBody
    public String getJobExceptionStacktrace(@PathVariable("jobId") String jobId) {
        return managementService.getJobExceptionStacktrace(jobId);
    }

}

32、流程定义管理

@Controller
@RequestMapping(value = "/chapter14/process")
public class ProcessManagerController {

    @Autowired
    RepositoryService repositoryService;

    @Autowired
    ProcessDefinitionService processDefinitionService;

    /**
     * 流程定义状态控制
     *
     * @param state               active|suspend
     * @param processDefinitionId 流程定义ID
     * @return
     */
    @RequestMapping(value = "{state}", method = RequestMethod.POST)
    public String changeState(@PathVariable(value = "state") String state,
                              @RequestParam(value = "processDefinitionId") String processDefinitionId,
                              @RequestParam(value = "cascade", required = false) boolean cascadeProcessInstances,
                              @RequestParam(value = "effectiveDate", required = false) String strEffectiveDate) {

        Date effectiveDate = null;

        if (StringUtils.isNotBlank(strEffectiveDate)) {
            try {
                effectiveDate = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(strEffectiveDate);
            } catch (ParseException e) {
                //e.printStackTrace();
            }
        }

        if (StringUtils.equals("active", state)) {
            repositoryService.activateProcessDefinitionById(processDefinitionId, cascadeProcessInstances, effectiveDate);
        } else if (StringUtils.equals("suspend", state)) {
            repositoryService.suspendProcessDefinitionById(processDefinitionId, cascadeProcessInstances, effectiveDate);
        }
        return "redirect:/chapter5/process-list";
    }

    /**
     * 设置流程定义对象的候选人、候选组
     * @return
     */
    @RequestMapping(value = "startable/set/{processDefinitionId}", method = RequestMethod.POST)
    @ResponseBody
    public String addStartables(@PathVariable("processDefinitionId") String processDefinitionId,
            @RequestParam(value = "users[]", required = false) String[] users, @RequestParam(value = "groups[]", required = false) String[] groups) {
        processDefinitionService.setStartables(processDefinitionId, users, groups);
        return "true";
    }

    /**
     * 读取已设置的候选启动人、组
     * @param processDefinitionId
     * @return
     */
    @RequestMapping(value = "startable/read/{processDefinitionId}", method = RequestMethod.GET)
    @ResponseBody
    public Map<String, List<String>> readStartableData(@PathVariable("processDefinitionId") String processDefinitionId) {
        Map<String, List<String>> datas = new HashMap<String, List<String>>();
        ArrayList<String> users = new ArrayList<String>();
        ArrayList<String> groups = new ArrayList<String>();

        List<IdentityLink> links = repositoryService.getIdentityLinksForProcessDefinition(processDefinitionId);
        for (IdentityLink link : links) {
            if (StringUtils.isNotBlank(link.getUserId())) {
                users.add(link.getUserId());
            }
            if (StringUtils.isNotBlank(link.getGroupId())) {
                groups.add(link.getGroupId());
            }
        }
        datas.put("users", users);
        datas.put("groups", groups);
        return datas;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值