Activiti7開發(三)-流程實例


0.前言

流程實例是與業務相關聯的,先介紹一下業務:用戶申請物品,領導進行審批(同意/拒絕),同意:流程結束,申請狀態為通過;拒絕:流程結束,申請狀態為拒絕。

下圖為流程圖,key為material_apply

可以看到,"銷售支持審批"設置的是變量${sale_support_member},邏輯是只能角色是"銷售支持"的用戶才可以審批。

saleSupportVerify這個用戶任何節點設置了兩個表單屬性

FormProperty_regionAdvice--__!!radio--__!!審批意見--__!!i--__!!同意--__--不同意
FormProperty_regionText--__!!textarea--__!!批注--__!!f__!!null

一個單選按鈕:同意/駁回;一個輸入框:可以寫駁回理由等等。

在走向結束時,設置一個監聽器,用來修改實體類的狀態

@Slf4j
@Controller
public class MaterialListener implements ExecutionListener{
    //獲取流程圖設置的狀態值
    private Expression state;

    //一旦是走拒絕和最后審批的同意的都會觸發這個監聽器
    //拒絕 state=2
    //最后一個審批的同意 state=3
    @Override
    public void notify(DelegateExecution delegateExecution) {
        Material material = new Material();
        String processInstanceId = delegateExecution.getProcessInstanceId();

        String status = (String)state.getValue(delegateExecution);

        ProcessInstance processInstance = SpringUtils.getBean(RuntimeService.class).createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        material.setId(Long.parseLong(processInstance.getBusinessKey()));
        if(status.equals("3")){
            material.setApplyStatus('3');
        }else if(status.equals("2")){
            material.setApplyStatus('2');
        }
        material.setUpdateBy(SecurityUtils.getUsername());
        material.setUpdateTime(new Date());

        SpringUtils.getBean(IMaterialService.class).updateById(material);
    }
}

1.創建流程實例

注:businessKey是關鍵點,是實體類的id,從而與流程定義進行關聯,並設置候選人(在此有一個問題,如果后期將某個人設置角色為銷售支持,但他在自己的待辦任務里面是看不到之前銷售提交的審批任務的)

public AjaxResult submitApply(@RequestBody Material material){
    //目前只設計了一級審批 銷售支持部審批
    try{
        //將角色與每個審批用戶做關聯
        List<String> saleSupportList = materialService.listByRoleName("sale_support_member");

        String saleSupportJoin = StringUtils.join(saleSupportList,",");

        // regionManager regionDirector president
        ProcessInstance processInstance = runtimeService.createProcessInstanceBuilder()
                .processDefinitionKey("material_apply")
                .name(material.getApplyTitle())
                //將流程實例與物料做關聯
                .businessKey(material.getId()+"")
                .variable("sale_support_member",saleSupportJoin)
                .start();

        log.info("processInstanceId: "+processInstance.getProcessInstanceId());;
        log.info("id: "+processInstance.getId());

        material.setInstanceId(processInstance.getId());
        //申請中
        material.setApplyStatus('1');
        materialService.updateById(material);
        return AjaxResult.success("提交申請成功");
    }catch (Exception e){
        log.error("submitApply error: "+e.getMessage());
        return AjaxResult.error("提交申請失敗");
    }
}

2.撤銷申請(未實現)

邏輯:刪除流程實例或者修改流程實例的狀態為掛起
問題: 根據流程實例id沒有獲取到流程實例?

如果流程實例已結束,根據流程實例id獲取不到流程實例;但目前只是剛創建了流程實例

public AjaxResult cancelApply(@RequestBody String instanceId) {
	String msg = processDefinitionService.cancelApply(instanceId, "用戶撤銷");
	return success(msg);
}

public String cancelApply(String instanceId, String reason) {
        ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId)
                .singleResult();
        if(instance != null){
            //說明流程實例還在進行中,可以撤銷
            runtimeService.deleteProcessInstance(instanceId,reason);
            return "撤銷申請成功";
        }else{
            return "流程已結束,不允許撤銷申請";
        }
}

// 執行此方法后未審批的任務 act_ru_task 會被刪除,流程歷史 act_hi_taskinst 不會被刪除,並且流程歷史的狀態為finished完成
public String cancelApply(String instanceId, String reason) {
	ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId("e7361785-ec2c-11eb-89e3-0068ebbadc17")
					.singleResult();
		//true-暫停 false-激活
		boolean suspend = instance.isSuspended();
		String processInstanceId = instance.getId();

		if(suspend){
			//如果已暫停,就激活
			runtimeService.activateProcessInstanceById(processInstanceId);
			log.info("流程實例已激活");
			runtimeService.deleteProcessInstance(instanceId, reason);
			return "流程實例已激活";
		}else{
			//如果已激活,就暫停
			runtimeService.suspendProcessInstanceById(processInstanceId);
			log.info("流程實例已暫停");
			runtimeService.deleteProcessInstance(instanceId, reason);
			return "流程實例已暫停";
		}
	}
}

3.查看審批歷史(流程實例)

有兩種:

  • 只獲取審批節點(即只獲取userTask)
  • 獲取全部節點,比如startEvent、userTask、gateWay、endEvent
public AjaxResult historyProcess(@PathVariable("instanceId") String instanceId) {

        List<HistoricTaskInstance> list=historyService // 歷史相關Service
                .createHistoricTaskInstanceQuery() // 創建歷史任務實例查詢
                .processInstanceId(instanceId) // 用流程實例id查詢
                .finished() // 查詢已經完成的任務
                .list();
				
		list.stream().sorted(Comparator.comparing(HistoricTaskInstance::getStartTime));

        List<ApplyHis> applyHisList = new ArrayList<>();
        list.stream().forEach(
                ht -> {
                    ApplyHis applyHis = new ApplyHis();
                    applyHis.setTaskName(ht.getName());
                    applyHis.setAssignee(ht.getAssignee());
                    applyHis.setStartTime(ht.getStartTime());
                    if(ht.getEndTime() != null){
                        applyHis.setEndTime(ht.getEndTime());
                    }
                    applyHisList.add(applyHis);
                }
        );

        return AjaxResult.success(applyHisList);
 }

4.查看審批高亮圖

該功能設計三個請求:

  1. 根據流程實例id獲取流程定義id、部署id、資源名
public AjaxResult getDefinitionsByInstanceId(@PathVariable("instanceId") String instanceId){
     ProcessInstance pi = runtimeService // 獲取運行時Service
            .createProcessInstanceQuery() // 創建流程實例查詢
            .processInstanceId(instanceId) // 用流程實例id查詢
            .singleResult();
    if(pi != null){
        log.info("流程正在執行!");
        log.info("流程定義id: "+pi.getProcessDefinitionId());
        return AjaxResult.success(processDefinitionService.getDefinitionsByInstanceId(instanceId));
    }else{
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(instanceId).singleResult();
        String processDefinitionId = historicProcessInstance.getProcessDefinitionId();
        ProcessDefinitionQuery pdq = repositoryService.createProcessDefinitionQuery();
        ProcessDefinition pd = pdq.processDefinitionId(processDefinitionId).singleResult();
        log.info("********************************************************************************");
        log.info("deploymentId: "+pd.getDeploymentId());
        String resourceName = pd.getResourceName();
        log.info("resourceName: "+resourceName);
        log.info("流程定義id: "+pd.getId());
        log.info("********************************************************************************");
        return AjaxResult.success(new DefinitionIdDTO(pd.getDeploymentId(),resourceName,pd.getId()));

    }
}
  1. 根據流程實例id和流程定義id獲取json形式的高亮數據
public AjaxResult gethighLine(@RequestParam("instanceId") String instanceId,@RequestParam("processDefinitionId") String processDefinitionId) {
	ActivitiHighLineDTO activitiHighLineDTO = activitiHistoryService.getHighLine(instanceId,processDefinitionId);
	return AjaxResult.success(activitiHighLineDTO);
}

public ActivitiHighLineDTO getHighLine(String instanceId,String processDefinitionId) {

	//只有流程沒走完的才能查找到流程實例
	//ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult();
	//獲取bpmnModel對象
	BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
	//因為我們這里只定義了一個Process 所以獲取集合中的第一個即可
	Process process = bpmnModel.getProcesses().get(0);
	//獲取所有的FlowElement信息
	Collection<FlowElement> flowElements = process.getFlowElements();

	Map<String, String> map = new HashMap<>();
	for (FlowElement flowElement : flowElements) {
		//判斷是否是連線
		if (flowElement instanceof SequenceFlow) {
			SequenceFlow sequenceFlow = (SequenceFlow) flowElement;
			String ref = sequenceFlow.getSourceRef();
			String targetRef = sequenceFlow.getTargetRef();
			map.put(ref + targetRef, sequenceFlow.getId());
		}
	}

	//獲取流程實例 歷史節點(全部)
	List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
			.processInstanceId(instanceId)
			.list();
	//各個歷史節點   兩兩組合 key
	Set<String> keyList = new HashSet<>();
	for (HistoricActivityInstance i : list) {
		for (HistoricActivityInstance j : list) {
			if (i != j) {
				keyList.add(i.getActivityId() + j.getActivityId());
			}
		}
	}
	//高亮連線ID
	Set<String> highLine = new HashSet<>();
	keyList.forEach(s -> highLine.add(map.get(s)));


	//獲取流程實例 歷史節點(已完成)
	List<HistoricActivityInstance> listFinished = historyService.createHistoricActivityInstanceQuery()
			.processInstanceId(instanceId)
			.finished()
			.list();
	//高亮節點ID
	Set<String> highPoint = new HashSet<>();
	listFinished.forEach(s -> highPoint.add(s.getActivityId()));

	//獲取流程實例 歷史節點(待辦節點)
	List<HistoricActivityInstance> listUnFinished = historyService.createHistoricActivityInstanceQuery()
			.processInstanceId(instanceId)
			.unfinished()
			.list();

	//需要移除的高亮連線
	Set<String> set = new HashSet<>();
	//待辦高亮節點
	Set<String> waitingToDo = new HashSet<>();
	listUnFinished.forEach(s -> {
		waitingToDo.add(s.getActivityId());

		for (FlowElement flowElement : flowElements) {
			//判斷是否是 用戶節點
			if (flowElement instanceof UserTask) {
				UserTask userTask = (UserTask) flowElement;

				if (userTask.getId().equals(s.getActivityId())) {
					List<SequenceFlow> outgoingFlows = userTask.getOutgoingFlows();
					//因為 高亮連線查詢的是所有節點  兩兩組合 把待辦 之后  往外發出的連線 也包含進去了  所以要把高亮待辦節點 之后 即出的連線去掉
					if (outgoingFlows != null && outgoingFlows.size() > 0) {
						outgoingFlows.forEach(a -> {
							if (a.getSourceRef().equals(s.getActivityId())) {
								set.add(a.getId());
							}
						});
					}
				}
			}
		}
	});

	highLine.removeAll(set);
	Set<String> iDo = new HashSet<>(); //存放 高亮 我的辦理節點
	//當前用戶已完成的任務
	List<HistoricTaskInstance> taskInstanceList = historyService.createHistoricTaskInstanceQuery()
//                    .taskAssignee(SecurityUtils.getUsername())
			.finished()
			.processInstanceId(instanceId).list();

	taskInstanceList.forEach(a -> iDo.add(a.getTaskDefinitionKey()));

	ActivitiHighLineDTO activitiHighLineDTO =new ActivitiHighLineDTO();
	activitiHighLineDTO.setHighPoint(highPoint);
	activitiHighLineDTO.setHighLine(highLine);
	activitiHighLineDTO.setWaitingToDo(waitingToDo);
	activitiHighLineDTO.setiDo(iDo);

	return activitiHighLineDTO;
}

返回結果

{
  "highPoint" : ["StartEvent_1"],
  "highLine" : [null,"Flow_0w19svd"],
  "waitingToDo" : ["saleSupportVerify"],
  "iDo" : []
}
  1. 根據第一個請求返回的部署id和資源名稱獲取xml
public void getProcessDefineXML(HttpServletResponse response,
                                    @RequestParam("deploymentId") String deploymentId,
                                    @RequestParam("resourceName") String resourceName) throws IOException {
        processDefinitionService.getProcessDefineXML(response, deploymentId, resourceName);
}
  1. 將xml和第二個請求的響應數據結合,最后顯現高亮進度圖


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM