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和第二个请求的响应数据结合,最后显现高亮进度图

Activiti7开发(三)-流程实例的更多相关文章

  1. activiti7启动流程实例,动态设置assignee人

    package com.zcc.activiti03; import org.activiti.engine.ProcessEngine;import org.activiti.engine.Proc ...

  2. activiti7流程实例启动

    package com.zcc.acvitivi; import org.activiti.engine.ProcessEngine;import org.activiti.engine.Proces ...

  3. gitlab(五):一个开发流程实例

    一个多人开发的样例 开发的流程我们都知道: 根据项目版本,创建里程碑,创建开发的issue,分配给dev dev从master clone代码,创建分支就行开发,开发完成之后,提交分支 dev给开发负 ...

  4. Activiti7 绑定业务主键以及流程定义 流程实例的挂起和激活

    绑定业务主键businessKey /** * 绑定业务主键 */ @Test public void bindingBusinessKey() { // 获取RuntimeService Runti ...

  5. Activiti7 启动流程实例

    package com.itheima.activiti; import org.activiti.engine.ProcessEngine; import org.activiti.engine.P ...

  6. Slickflow.NET 开源工作流引擎高级开发(二) -- 流程快速测试增值服务工具介绍

    前言:流程是由若干个任务节点组成,流转过程就是从一个节点转移到下一个节点,通常需要不断切换用户身份来完成流程的测试,这样使得测试效率比较低下,本文从实战出发,介绍常见的两种快速测试方法,用于提升流程测 ...

  7. pip:带你认识一个 Python 开发工作流程中的重要工具

    摘要:许多Python项目使用pip包管理器来管理它们的依赖项.它包含在Python安装程序中,是Python中依赖项管理的重要工具. 本文分享自华为云社区<使用Python的pip管理项目的依 ...

  8. iOS开发之SQLite--C语言接口规范(五)——iOS开发使用SQLite实例

    本篇博客就使用前面操作SQLite的知识来实现如何去插入,删除和更新数据.然后再把操作SQlite数据库常用的方法进行一个封装.把常用方法进行封装后,把Cars数据库中的其中一个表的数据进行查询,并在 ...

  9. Activiti工作流学习(二)流程实例、执行对象、任务

    一.前言 前面说明了基本的流程部署.定义,启动流程实例等基本操作,下面我们继续来学习流程实例.执行对象.任务. 二.流程实例.执行对象说明 整个Activiti的生命周期经过了如下的几个步骤: 1.流 ...

  10. 工作流学习——Activiti流程实例、任务管理四步曲 (zhuan)

    http://blog.csdn.net/zwk626542417/article/details/46646565 ***************************************** ...

随机推荐

  1. C# 内存回收

    开发完成之后发现自己写的程序内存占用太高,找到如下解决方案 使用了一个timer每2s调用一次ClearMemory() #region 内存回收 [DllImport("kernel32. ...

  2. L2 Gracia Final OpCodz

    [83] Gracia Final Client 00 SendLogOut 01 RequestAttack 03 RequestStartPledgeWar 04 RequestReplyStar ...

  3. scala调用fastjson JSON.toJSONString()序列化对象出错

    在scala中需要将case class 序列化为string,代码如下 results.map(JSON.toJSONString(_)).foreach(println) case class p ...

  4. 在windows下使用dbus

    介绍 DBUS是一种很方便的IPC远程调用的通信机制.可以很方便地调用其他进程提供的函数,甚至是不同计算机上提供的函数,内部通过TCP套接字进行相互通信. 不过甚至你可以修改成其他通信方式,比如USB ...

  5. MySQL Atlas 读写分离软件介绍

    MySQL Atlas介绍 目录 MySQL Atlas介绍 一.MySQL Atlas介绍 1.1.1 MySQL Atlas介绍 1.1.2 Atlas基本管理 一.MySQL Atlas介绍 1 ...

  6. vue搭建项目iview+axios+less

    项目地址:https://github.com/CinderellaStory/vue-iview-project vue搭建项目壳子已安装:iview.axios.less 已有界面:登录.左侧菜单 ...

  7. 【alive-progress】Python控制台输出动态进度条

    简介 alive-progress是一种具有实时吞吐量和非常酷的动画新型的进度条python库. 使用 from alive_progress import alive_bar import time ...

  8. 当jar包执行时,内嵌的文件找不到时,可以这样解决!

    1.加载是可以加载到的,但是只能是以流的形式存在. 2.如果要按文件进行加载,可以新建一个文件,然后以流的形式写入到新的文件中. 3.加载这个新的文件来进行处理.

  9. 狐漠漠养成日记 Cp.00003 第二周

    上一周整周都在做Unity Newbies Jam,除了一些必要的比如考试或者课程,其他的都推后了. 为了赶项目进度,这一周我可以说是废寝忘食,基本上每天一顿饭,就睡仨小时那种. 以至于到最后一天,也 ...

  10. airtest的手势滑动方法封装

    ​ 这个网上应该很多类似的方法封装,各种实现方式也很多,但是感觉最简单实用的还是swipe了:代码很简单,直接上方法了. 很多方法都不会告诉你会导入什么包,其实很多小白入门可能就是这么简单的一步就被卡 ...