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.查看审批高亮图
该功能设计三个请求:
- 根据流程实例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())); } }
- 根据流程实例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" : [] }
- 根据第一个请求返回的部署id和资源名称获取xml
public void getProcessDefineXML(HttpServletResponse response, @RequestParam("deploymentId") String deploymentId, @RequestParam("resourceName") String resourceName) throws IOException { processDefinitionService.getProcessDefineXML(response, deploymentId, resourceName); }
- 将xml和第二个请求的响应数据结合,最后显现高亮进度图
合集:
Activity7
分类:
技术 / Activiti7
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)