工作流flowable在項目中的應用實例

目前的項目主要有兩個審批流程,在審批過程中需要發送郵件給申請人告知目前進展,此處記錄下我在項目中是如何使用flowable工作流與業務相結合的。

1. 添加工作流依賴

<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.0</version>
		</dependency>
		<!-- spring aop -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-rest -->
		<dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-data-rest</artifactId>
		</dependency>
				
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.9</version>
        </dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!-- 郵件服務 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-web -->
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
		<dependency>
		    <groupId>com.alibaba</groupId>
		    <artifactId>fastjson</artifactId>
		    <version>1.2.61</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
		<dependency>
		    <groupId>com.fasterxml.jackson.core</groupId>
		    <artifactId>jackson-annotations</artifactId>
		</dependency>
				
		<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
		<dependency>
		    <groupId>org.aspectj</groupId>
		    <artifactId>aspectjrt</artifactId>
		</dependency>
		<!-- shiro -->
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.4.1</version>
		</dependency>
		
		<!-- 日誌 -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
		</dependency>
		
		<dependency>
		    <groupId>commons-lang</groupId>
		    <artifactId>commons-lang</artifactId>
		    <version>2.6</version>
		</dependency>
		
		<dependency>
		    <groupId>org.apache.commons</groupId>
		    <artifactId>commons-lang3</artifactId>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>3.14</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>3.14</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/com.jcraft/jsch -->
		<dependency>
		    <groupId>com.jcraft</groupId>
		    <artifactId>jsch</artifactId>
		    <version>0.1.55</version>
		</dependency>
				
		<!-- https://mvnrepository.com/artifact/commons-net/commons-net -->
		<dependency>
		    <groupId>commons-net</groupId>
		    <artifactId>commons-net</artifactId>
		    <version>3.6</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/org.flowable/flowable-spring-boot-starter-process -->
		<dependency>
		    <groupId>org.flowable</groupId>
		    <artifactId>flowable-spring-boot-starter-process</artifactId>
		    <version>6.4.0</version>
		</dependency>

		
	</dependencies>

2. 在application.yml中增加配置項

flowable:
  check-process-definitions: false #設置需要手動部署工作流

3. 畫流程圖

設置審批候選人爲固定的某個色的所有人

實際應用中,除了需要將流程完整的結束,我們通常需要跟蹤業務狀態,通常每個處理節點都會對應一個業務狀態,此處指定方法負責更新狀態和發送郵件

 

4. 由於每個業務系統都會有自己的用戶角色權限管理,因此需要與flowable的用戶組關係保持同步,一種方法是利用監聽器,當業務系統編輯用戶信息時就同步至flowable用戶表中,另一種就是刪除flowable的用戶組關係表,利用視圖將業務系統的用戶組關係同步至flowable的用戶組關係表中,並且視圖名稱與原flowable用戶組關係表名稱相同

5. 代碼

###部署工作流###
@Transactional(readOnly = false)
public Object deploy (final String processName) {
	logger.info("---- FlowService deploy begin ----");
	final Deployment deployment = processEngine.getRepositoryService()
													.createDeployment()
													.addClasspathResource("processes/" + processName + ".bpmn")
													.addClasspathResource("processes/" + processName + ".png")
													.name(processName)
													.key(processName)
													.deploy();
	final Map<String, Object> map = new HashMap<>();
	map.put("deploymentId", deployment.getId());
	map.put("deploymentKey", deployment.getKey());
	map.put("deploymentName", deployment.getName());
	map.put("deploymentEngineVersion", deployment.getEngineVersion());
	logger.info("---- FlowService deploy end ----");
	return map;
} 


###查看已部署的工作流###
public Object deployedProcessList() {
	logger.info("---- FlowService deployedProcess begin ----");
	final List<Deployment> deploymentList = processEngine.getRepositoryService()
													.createDeploymentQuery()
													.orderByDeploymenTime()
													.asc()
													.list();
	final List<Map<String, Object>> list = new ArrayList<>();
	for (Deployment deployment : deploymentList) {
		final Map<String, Object> map = new HashMap<>();
		map.put("deploymentId", deployment.getId());
		map.put("deploymentKey", deployment.getKey());
		map.put("deploymentName", deployment.getName());
		map.put("deploymentEngineVersion", deployment.getEngineVersion());
		list.add(map);
	}
	logger.info("---- FlowService deployedProcess end ----");
	return list;
}

/**
* 查詢流程定義
* @return
*/
public Object processDefinitionList () {
	logger.info("---- FlowService getProcessDefinition begin ----");
	final List<ProcessDefinition> definitionList = processEngine.getRepositoryService()
													.createProcessDefinitionQuery()
													.list();
	final List<Map<String, Object>> list = new ArrayList<>();
	for (ProcessDefinition processDefinition : definitionList) {
		final Map<String, Object> map = new HashMap<>();
		map.put("definitionId", processDefinition.getId());
		map.put("definitionKey", processDefinition.getKey());
		map.put("definitionName", processDefinition.getName());
		map.put("definitionDeploymentId", processDefinition.getDeploymentId());
		map.put("definitionResourceName", processDefinition.getResourceName());
		map.put("definitionVersion", processDefinition.getVersion());
		map.put("definitionEngineVersion", processDefinition.getEngineVersion());
		list.add(map);
	}
	logger.info("---- FlowService getProcessDefinition end ----");
	return list;
}

/**
 * 啓動一個工作流
 * 
 * @param processName 工作流模板 (啓動最新的版本)
 * @param variables 參數表
 * @param user 啓動人
 * @return
 */
@Transactional(readOnly=false)
public String startProcess(String processName, String key,  Map<String, Object> variables) {
		
	IdentityService identityService = processEngine.getIdentityService();
		identityService.setAuthenticatedUserId(UserUtils.getCurrentUser().getUserName());
	logger.info("設置啓動人");
	
	RuntimeService runtimeService = processEngine.getRuntimeService();
	ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processName, key, variables);
	return processInstance.getId();
}

/**
	 * 獲取當前角色待辦任務列表
	 * @return
	 */
	public Object getRoleTaskList() {
		logger.info("---- FlowService getRoleTaskList begin ----");
		List<Task> taskList = processEngine.getTaskService()
										 .createTaskQuery()
										 .taskCandidateGroup(UserUtils.getCurrentUser().getRoleName())
										 .orderByTaskCreateTime()
										 .asc()
										 .list();
		final List<Map<String, Object>> list = new ArrayList<>();
		for (Task task : taskList) {
			final Map<String, Object> map = new HashMap<>();
			map.put("taskId", task.getId());
			map.put("createTime", task.getCreateTime());
			map.put("taskName", task.getName());
			map.put("taskOwner", task.getOwner());
			map.put("processDefinitionId", task.getProcessDefinitionId());
			map.put("processInstanceId", task.getProcessInstanceId());
			map.put("taskDefinitionId", task.getTaskDefinitionId());
			map.put("taskDefinitiionKey", task.getTaskDefinitionKey());
			list.add(map);
		}
		logger.info("---- FlowService getRoleTaskList end ----");
		return list;
	}
	
	/**
	 * 獲取當前用戶待辦任務列表
	 * @return
	 */
	public Object getPersonalTaskList() {
		logger.info("---- FlowService getPersonalTaskList begin ----");
		final List<Task> taskList = processEngine.getTaskService()
										.createTaskQuery()
										.taskAssignee(UserUtils.getCurrentUser().getUserName())
										.orderByTaskCreateTime()
										.asc()
										.list();
		final List<Map<String, Object>> list = new ArrayList<>();
		for (Task task : taskList) {
			final Map<String, Object> map = new HashMap<>();
			map.put("taskId", task.getId());
			map.put("createTime", task.getCreateTime());
			map.put("taskName", task.getName());
			map.put("taskOwner", task.getOwner());
			map.put("processDefinitionId", task.getProcessDefinitionId());
			map.put("processInstanceId", task.getProcessInstanceId());
			map.put("taskDefinitionId", task.getTaskDefinitionId());
			map.put("taskDefinitiionKey", task.getTaskDefinitionKey());
			list.add(map);
		}
		logger.info("---- FlowService getPersonalTaskList end ----");
		return list;
	}
	
	/**
	 * 判斷所處理的任務是否是當前用戶或當前用戶角色的任務
	 * @param taskId
	 * @return
	 */
	public boolean isPersonalTask (final String taskId) {
		final String currentUserName = UserUtils.getCurrentUser().getUserName();
		final Task personalTask = processEngine.getTaskService()
												 .createTaskQuery()
												 .taskAssignee(currentUserName)
												 .taskId(taskId)
												 .singleResult();
		logger.info("current user name: " + currentUserName);
		logger.info("taskId: " + taskId);
		if (personalTask == null) {
			logger.info("personalTask is null");
		} else {
			logger.info("personal taskId: " + personalTask.getId() + "personal assignee: " + personalTask.getAssignee());
		}
		if (personalTask != null && taskId.equals(personalTask.getId())) {
			return true;
		}
		final String currentRoleName = UserUtils.getCurrentUser().getRoleName();
		final Task roleTask = processEngine.getTaskService()
											 .createTaskQuery()
											 .taskCandidateGroup(currentRoleName)
											 .taskId(taskId)
											 .singleResult();
		logger.info("taskId: " + taskId);
		if (roleTask == null) {
			logger.info("roleTask is null");
		} else {
			logger.info("role taskId: " + roleTask.getId() + "role assignee: " + roleTask.getAssignee());
		}
		if (roleTask != null && taskId.equals(taskId)) {
			return true;
		}
		
		return false;
	}
	
	/**
	 * 獲取所有未處理的任務
	 * @return
	 */
	public Object getUnresolvedTaskList() {
		List<Task> taskList = processEngine.getTaskService()
				.createTaskQuery()
				.orderByTaskCreateTime()
				.asc()
				.list();
		final List<Map<String, Object>> list = new ArrayList<>();
		for (Task task : taskList) {
			final Map<String, Object> map = new HashMap<>();
			map.put("taskId", task.getId());
			map.put("createTime", task.getCreateTime());
			map.put("taskName", task.getName());
			map.put("taskOwner", task.getOwner());
			map.put("processDefinitionId", task.getProcessDefinitionId());
			map.put("processInstanceId", task.getProcessInstanceId());
			map.put("taskDefinitionId", task.getTaskDefinitionId());
			map.put("taskDefinitiionKey", task.getTaskDefinitionKey());
			list.add(map);
		}
		return list;
	}
	
	/**
	 * 簽收任務
	 * @param taskId
	 * @param username
	 */
	@Transactional(readOnly = false)
	public void claim(String taskId, String username) {
		logger.info("簽收任務:"+ taskId + " 簽收人:" + username + " begin");

		processEngine.getTaskService().claim(taskId,username);
		
		logger.info("簽收任務:"+ taskId + " 簽收人:" + username + " end");
	}
	
	/**
	 * 執行某個流程節點
	 * @param taskId
	 * @param variables
	 */
	@Transactional(readOnly=false)
	public void completeTask(String taskId, Map<String, Object> variables) {
		if (!isPersonalTask(taskId)) {
			throw new BusinessException(ExceptionEnum.EXECUTE_BASE_CHECK_EXCPTION.setExceptionMsg("請任務處理人或處理角色操作"));
		}
		processEngine.getTaskService().complete(taskId, variables);
		logger.info("完成任務:" + taskId);
	}
	
	
	/**
	 * 執行某個流程節點, 待審批意見和附件
	 * @param taskId
	 * @param variables
	 * @param comment
	 * @param fileMap <文件路徑, 文件名稱>
	 */
	@Transactional(readOnly=false)
	public void completeTask(final String taskId, final Map<String, Object> variables, final String action, String opinion, final Map<String, Object> fileMap) {
		logger.info("task id: " + taskId + " ; action = " + action);
		if (!isPersonalTask(taskId)) {
			throw new BusinessException(ExceptionEnum.EXECUTE_BASE_CHECK_EXCPTION.setExceptionMsg("請任務處理人或處理角色操作"));
		}
		//添加批註時候的審覈人
		Authentication.setAuthenticatedUserId(UserUtils.getCurrentUser().getUserName()); 
		final TaskService taskService = processEngine.getTaskService();
		final Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		if (StringUtils.isEmpty(opinion)) {
			opinion = action;
		} else {
			opinion = action + ": " + opinion;
		}
		taskService.addComment(taskId, task.getProcessInstanceId(), opinion);
		
		if (fileMap != null) {
			final Iterator it = fileMap.keySet().iterator();
			while(it.hasNext()) {
				final String filePath = (String) it.next();
				final String fileName = (String) fileMap.get(filePath);
				String suffix = "";
				if (fileName.contains(".") && !fileName.endsWith(".")) {
					suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
				} else {
					if (filePath.contains(".") && !filePath.endsWith(".")) {
						suffix = filePath.substring(filePath.lastIndexOf(".") + 1);
					}
				}
				taskService.createAttachment(suffix, taskId, task.getProcessInstanceId(), fileName, null, filePath);
			}
		}
		try {
			taskService.complete(taskId, variables);
		} catch (Exception e) {
			logger.error("處理任務失敗", e);
			throw new BusinessException(ExceptionEnum.EXECUTE_BASE_CHECK_EXCPTION.setExceptionMsg("任務處理失敗"));
		}

		logger.info("完成任務:" + taskId);
	}
	
	/**
	 * 獲取審批歷史記錄
	 * @param processInstanceId 流程實例ID
	 * @return
	 */
	public List<ApprovalHistory> getApprovalHistory (final String processInstanceId) {
		final List<ApprovalHistory> approvalHistoryList = new ArrayList<>();
		
		//通過流程實例查詢所有的(用戶任務)歷史活動
		List<HistoricActivityInstance> historicActivityInstanceList = processEngine.getHistoryService()
																					.createHistoricActivityInstanceQuery()
																					.processInstanceId(processInstanceId)
																					.activityType("userTask")
																					.orderByHistoricActivityInstanceStartTime()
																					.asc()
																					.list();
		for (HistoricActivityInstance historicActivityInstance : historicActivityInstanceList) {
			
			final String historyTaskId = historicActivityInstance.getTaskId();
			//每個節點所產生的文檔
			final List<Attachment> attachments = processEngine.getTaskService().getTaskAttachments(historyTaskId);
			final List<HistoryFile> historyFileList = new ArrayList<>();
			for (Attachment attachment : attachments) {
				final HistoryFile historyFile = new HistoryFile();
				historyFile.setPath(attachment.getUrl());
				historyFile.setName(attachment.getName());
				historyFileList.add(historyFile);
			}
			//每個節點的評論
			final List<Comment> comments = processEngine.getTaskService().getTaskComments(historyTaskId);
			if (comments != null && comments.size() > 0) {
				for (Comment comment : comments) {
					final ApprovalHistory approvalHistory = new ApprovalHistory();
					final User user = userDao.queryByUserName(comment.getUserId());
					approvalHistory.setRoleName(user.getRoleName());
					approvalHistory.setUserName(user.getName() + " (" + user.getUserName() + ")");
					approvalHistory.setOperateTime(comment.getTime());
					approvalHistory.setOpinion(comment.getFullMessage());
					approvalHistory.setTaskId(historyTaskId);
					approvalHistory.setProcessInstanceId(processInstanceId);
					approvalHistory.setHistoryFileList(historyFileList);
					approvalHistoryList.add(approvalHistory);
				}
			}
		}
		
		return approvalHistoryList;
	}
	
	public List<Comment> getProcessComments(String processInstanceId) {
		final List<Comment> commentList = new ArrayList<>();
		//通過流程實例查詢所有的(用戶任務)歷史活動
		List<HistoricActivityInstance> historicActivityInstanceList = processEngine.getHistoryService()
																					.createHistoricActivityInstanceQuery()
																					.processInstanceId(processInstanceId)
																					.activityType("userTask")
																					.orderByHistoricActivityInstanceStartTime()
																					.asc()
																					.list();
		for (HistoricActivityInstance historicActivityInstance : historicActivityInstanceList) {
			final String historyTaskId = historicActivityInstance.getTaskId();
			List<Comment> comments = processEngine.getTaskService().getTaskComments(historyTaskId);
			if (comments != null && comments.size() > 0) {
				commentList.addAll(comments);
			}
		}
		return commentList;
	}

	/**
	 * 生成流程進展圖
	 * @param processKey
	 * @param request
	 * @return
	 */
	public void genProcessDiagram(final String processInstanceId, final HttpServletResponse response) {
		logger.info("---- FlowService genProcessDiagram begin ----");

		final HistoryService historyService = processEngine.getHistoryService();
		final RuntimeService runtimeService = processEngine.getRuntimeService();
		//獲得當前活動的節點
		String processDefinitionId = "";
		if (isFinished(processInstanceId)) {
			//如果流程已經結束,則得到結束節點
			HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery()
														.processInstanceId(processInstanceId)
														.singleResult();
			if (hpi == null) {
				throw new BusinessException(ExceptionEnum.EXECUTE_BASE_CHECK_EXCPTION.setExceptionMsg("流程定義不存在"));
			}
			processDefinitionId = hpi.getProcessDefinitionId();
		} else {
			//如果流程沒有結束,則取當前活動節點
			//根據流程實例ID獲得當前處於活動狀態的activityId合集
			final ProcessInstance instance = runtimeService.createProcessInstanceQuery()
															.processInstanceId(processInstanceId)
															.singleResult();
			if (instance == null) {
				throw new BusinessException(ExceptionEnum.EXECUTE_BASE_CHECK_EXCPTION.setExceptionMsg("流程實例不存在"));
			}
			processDefinitionId = instance.getProcessDefinitionId();
		}
		final List<String> highLightedActivitis = new ArrayList<String>();
		
		//獲得活動的節點
		List<HistoricActivityInstance> highLightActivityList = historyService.createHistoricActivityInstanceQuery()
																			 .processInstanceId(processInstanceId)
																			 .orderByHistoricActivityInstanceStartTime()
																			 .asc()
																			 .list();
		highLightActivityList = highLightActivityList.subList(highLightActivityList.size() - 1, highLightActivityList.size());
		for (HistoricActivityInstance historicActivityInstance : highLightActivityList) {
			final String activityId = historicActivityInstance.getActivityId();
			//判斷節點是否在當前節點之前
			highLightedActivitis.add(activityId);
		}
		
		//需要高亮顯示的線
		final List<String> flows = new ArrayList<>();
		
		
		final BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(processDefinitionId);
		final ProcessEngineConfiguration config = processEngine.getProcessEngineConfiguration();
		final ProcessDiagramGenerator diagramGenerator = config.getProcessDiagramGenerator();
		
		final InputStream inputStream = diagramGenerator.generateDiagram(bpmnModel, "bmp", highLightedActivitis, flows, config.getActivityFontName(),
											config.getLabelFontName(), config.getAnnotationFontName(), config.getClassLoader(), 1.0, true);
		
		OutputStream outputStream = null;
		byte[] buf = new byte[1024];
        int legth = 0;
		try {
			outputStream = response.getOutputStream();
			while ((legth = inputStream.read(buf)) != -1) {
				outputStream.write(buf, 0, legth);
            }
			outputStream.flush();
		} catch (IOException e) {
			logger.error("生成流程圖片失敗", e);
			throw new BusinessException(ExceptionEnum.EXECUTE_RUNTIME_EXCEPTION.setExceptionMsg("生成流程圖片失敗"));
		} finally {
			if (outputStream != null) {
				try {
					outputStream.close();
				} catch (IOException e) {
					logger.error("輸出流關閉失敗", e);
				}
			}
			if (inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					logger.error("輸入流關閉失敗", e);
				}
			}
		}
		logger.info("---- FlowService genProcessDiagram end ----");
		
	}
	
	/**
	 * 判斷節點是否結束
	 * @param processInstanceId
	 * @return
	 */
	public boolean isFinished(final String processInstanceId) {
		return processEngine.getHistoryService().createHistoricProcessInstanceQuery().finished().processInstanceId(processInstanceId).count() > 0;
	}
	
	/**
	 * 查看流程定義圖
	 * @param deploymentId
	 * @param response
	 */
	public void viewDefinitionDiagram(final String deploymentId, final HttpServletResponse response) {
		final RepositoryService repositoryService = processEngine.getRepositoryService();
		final ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
		if (processDefinition == null) {
			throw new BusinessException(ExceptionEnum.EXECUTE_BASE_CHECK_EXCPTION.setExceptionMsg("流程定義不存在"));
		}
		InputStream inputStream = processEngine.getRepositoryService().getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());
		OutputStream outputStream = null;
		byte[] buf = new byte[1024];
        int legth = 0;
		try {
			outputStream = response.getOutputStream();
			while ((legth = inputStream.read(buf)) != -1) {
				outputStream.write(buf, 0, legth);
            }
			outputStream.flush();
		} catch (IOException e) {
			logger.error("獲取流程定義圖片失敗", e);
			throw new BusinessException(ExceptionEnum.EXECUTE_RUNTIME_EXCEPTION.setExceptionMsg("獲取流程定義圖片失敗"));
		} finally {
			if (outputStream != null) {
				try {
					outputStream.close();
				} catch (IOException e) {
					logger.error("輸出流關閉失敗", e);
				}
			}
			if (inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					logger.error("輸入流關閉失敗", e);
				}
			}
		}
	}

	/**
	 * 根據 processInstanceId 獲取當前的任務
	 * @param processInstanceId
	 * @return
	 */
	public Task findTaskByProcessInstanceId(String processInstanceId) {
		final Task task = processEngine.getTaskService()
										.createTaskQuery()
										.processInstanceId(processInstanceId)
										.singleResult();
		return task;
	}

	/**
	 * 撤回,返回 taskID
	 * @param processInstanceId
	 * @return
	 */
	public Object withdraw(String processInstanceId) {
//		final ProcessInstance processInstance = processEngine.getRuntimeService()
//															 .createProcessInstanceQuery()
//															 .processInstanceId(processInstanceId)
//															 .singleResult();
		final TaskService taskService = processEngine.getTaskService();
		final HistoryService historyService = processEngine.getHistoryService();
		final RepositoryService repositoryService = processEngine.getRepositoryService();
		final RuntimeService runtimeService = processEngine.getRuntimeService();
		
		final String currentUserName = UserUtils.getCurrentUser().getUserName();
		
		final Task task = taskService.createTaskQuery()
									.processInstanceId(processInstanceId)
									.singleResult();
		if (task == null) {
			throw new BusinessException(ExceptionEnum.EXECUTE_BASE_CHECK_EXCPTION.setExceptionMsg("流程未啓動或已執行完成,無法撤回"));
		}
		List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery()
															.processInstanceId(processInstanceId)
															.orderByTaskCreateTime()
															.asc()
															.list();
		HistoricTaskInstance myTask = null;
		for (HistoricTaskInstance historicTaskInstance : htiList) {
			if(currentUserName.equals(historicTaskInstance.getAssignee())) {
				myTask = historicTaskInstance;
				break;
			}
		}
		if(myTask.getId() == null) {
			throw new BusinessException(ExceptionEnum.EXECUTE_BASE_CHECK_EXCPTION.setExceptionMsg("該任務非當前用戶提交,無法撤回"));
		}
		final String processDefinitionId = myTask.getProcessDefinitionId();
		final ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) processEngine.getRepositoryService()
																				.createProcessDefinitionQuery()
																				.processDefinitionId(processDefinitionId)
																				.singleResult();
		final BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
		//變量
		Map<String, VariableInstance> variables = runtimeService.getVariableInstances(task.getExecutionId());
		String myActivityId = null;
		final List<HistoricActivityInstance> haiList = historyService.createHistoricActivityInstanceQuery()
				.executionId(myTask.getExecutionId()).finished().list();
		for(HistoricActivityInstance hai : haiList) {
			if(myTask.getId().equals(hai.getTaskId())) {
				myActivityId = hai.getActivityId();
				break;
			}
		}
		FlowNode myFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(myActivityId);
		
		
		Execution execution = runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult();
		String activityId = execution.getActivityId();
		logger.warn("------->> activityId:" + activityId);
		FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityId);
		
		//記錄原活動方向
		List<SequenceFlow> oriSequenceFlows = new ArrayList<SequenceFlow>();
		oriSequenceFlows.addAll(flowNode.getOutgoingFlows());
		
		//清理活動方向
		flowNode.getOutgoingFlows().clear();
		//建立新方向
		List<SequenceFlow> newSequenceFlowList = new ArrayList<SequenceFlow>();
		SequenceFlow newSequenceFlow = new SequenceFlow();
		newSequenceFlow.setId("newSequenceFlowId");
		newSequenceFlow.setSourceFlowElement(flowNode);
		newSequenceFlow.setTargetFlowElement(myFlowNode);
		newSequenceFlowList.add(newSequenceFlow);
		flowNode.setOutgoingFlows(newSequenceFlowList);
		
		Authentication.setAuthenticatedUserId(UserUtils.getCurrentUser().getUserName());
		taskService.addComment(task.getId(), task.getProcessInstanceId(), "撤回");
		
		Map<String,Object> currentVariables = new HashMap<String,Object>();
		currentVariables.put("applier", currentUserName);
		//完成任務
		taskService.complete(task.getId(),currentVariables);
		//恢復原方向
		flowNode.setOutgoingFlows(oriSequenceFlows);
		return task.getId();
	}


###更新流程節點狀態和發送郵件###
public void updateStatus (final DelegateExecution execution, final String status) {
		String businessKey = execution.getProcessInstanceBusinessKey();
		//根據業務id自行處理業務表
		System.out.println("業務表["+businessKey+"]狀態更改成功,狀態更改爲:" + status + ", 流程實例ID:" + execution.getProcessInstanceId());
		if (businessKey.contains(":")) {
			final Integer designId = Integer.valueOf(businessKey.split(":")[1]);
			final Design design = (Design) designDao.queryById(designId);

			design.setStatus(status);
			designDao.update(design);
			if (design.getCreateUserId().equals(UserUtils.getCurrentUser().getId())) {
				return;
			}
			//根據流程關鍵字和狀態查找郵件模板
			MailTemplate mailTemplate = mailTemplateDao.findByProcessKeyAndStatus(Constant.PROCESS_KEY_DESIGN , status);
			if (mailTemplate == null) {
				mailTemplate = new MailTemplate();
				mailTemplate.setContent("郵件通知");
				mailTemplate.setSubject("郵件通知");
			}
			String content = mailTemplate.getContent();
			if (!StringUtils.isEmpty(content)) {
				content = content.replaceAll("\\$\\{name\\}", design.getName());
			}
			final User user = (User) userDao.queryById(design.getCreateUserId());
			mailService.sendMail(user.getEmail(), mailTemplate.getSubject(), content, execution.getProcessInstanceId());
		}
	}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章