SpringBoot整合Flowable【06】- 查询历史数据

简介: 本文介绍了Flowable工作流引擎中历史数据的查询与管理。首先回顾了流程变量的应用场景及其局限性,引出表单在灵活定制流程中的重要性。接着详细讲解了如何通过Flowable的历史服务API查询用户的历史绩效数据,包括启动流程、执行任务和查询历史记录的具体步骤,并展示了如何将查询结果封装为更易理解的对象返回。最后总结了Flowable提供的丰富API及其灵活性,为后续学习驳回功能做了铺垫。

一、引子

在05篇中我们学习了如何使用流程变量,如果业务需求为固定的内容,其实流程变量就可以当“表单”使用的,K-V的结构几乎天然支持了这部分。但是,如果你的业务需求需要用户灵活定制流程变量,这里用文字说明可能有的同学不太理解,具体案例大家可以去参考钉钉的工作流,用户可以在每个节点自己定义和管理变量,这种场景流程变量就无法很好地支持了,就需要用到Flowable提供的表单来操作了。

上述的内容其实是对流程变量的一个小结,可以让大家对流程变量有更好的理解,也是我们后续内容的一个预告。说回正题,前面我们多次提到了历史这个词,历史流程、历史变量等等,在实际的业务场景中,我们当然会有查询历史记录的需求,所以在06篇中我们来学习下怎么查询历史数据。

二、认识“历史”

在前面的文章中,提到了历史流程历史变量这两个概念。“历史”这一设计可以很好地实现我们实际业务场景中的一些需求,比如我在上篇中提到的想要查看某个人的历史绩效数据。另外,以流程变量为例,它在整个流程以及各节点中都是随时可变的,不是“最终结果”,而一旦随着流程或任务结束进入历史表的变量将无法再改变,也是一种“最终结果”。

三、实操

这里我们依然使用前面的绩效流程,明确一下节点为自评->上级评->隔级评,包含两个全局流程变量,分别为分数和绩效所属人。完成任务接口发生了一点小变化,就是查询变成了根据流程定义ID查询当前流程所处的任务节点,具体看代码:

/**
 * 查询流程的待办任务.
 *
 * @param procDefId 流程定义ID
 * @return 待办任务id
 */
private String findUserAgentTask(String procDefId) {
   
    //1.查询流程的待办任务
    Task agentTask = taskService.createTaskQuery()
            .processDefinitionId(procDefId)
            .singleResult();
    //2.返回待办任务的id
    return agentTask.getId();
}

除了修改这里的查询逻辑,我们还需要做一步处理,还要额外声明个全局流程变量来表示这个绩效流程的所属人,毕竟在实际场景中,一个绩效肯定会属于一个人嘛,也是让我们在查询历史流程时有查询依据,这里我为了方便,就直接写死个值,实际场景中前端传也好,后端获取也好,设置成你们自己系统里的用户唯一标识即可(Ps:这应该大多数都是userId吧!),代码如下:

@PostMapping("/start/{processId}")
public ResponseEntity<Object> startProcessDef(@PathVariable String processId) {
   
    //1.启动流程
    ProcessInstance processInstance = runtimeService.startProcessInstanceById(processId);
    //2.维护该流程的分数变量
    runtimeService.setVariable(processInstance.getId(), "score", 0);
    //3.维护该流程的所属用户
    runtimeService.setVariable(processInstance.getId(),"ownerId", 88);
    //4.返回流程实例对象id
    return new ResponseEntity<>(new BaseResponse<>(processInstance.getId()), HttpStatus.OK);
}

1.启动流程

完成了上述改造之后,我们启动三个属于用户id为88的流程,这时在act_re_procdef表中就可以看到这三条流程定义:
1.png
act_ru_task表中也可以看到三个流程的三个节点都开始自评了:
2.png
以及在act_ru_variable表中可以看到六个流程变量:
3.png

2.执行流程

既然三个流程都正常启动了,我们现在把它们全部都完成,接下来就可以到act_hi_procinst历史流程表里看到这三条记录:
4.png
act_hi_varinst历史变量表就可以查到那三个历史流程关联的六条历史变量:
5.png

3.查询历史流程

到目前为止,准备工作就做好了,我们再来回忆下场景:查询某个人的历史绩效,以我们这里的数据为例,就是查询用户id为88的历史流程,代码如下:

/**
 * 查询指定用户的历史绩效.
 *
 * @param userId 用户id
 * @return 历史流程集合
 */
@PostMapping("/history-process-def/userId/{userId}")
public ResponseEntity<Object> getHistoryProcessDef(@PathVariable Long userId) {
   
    //1.根据用户id查询历史流程
    List<HistoricVariableInstance> historicVariableInstanceList = historyService
            .createHistoricVariableInstanceQuery()
            .variableValueEquals("ownerId", userId)
            .list();
    //2.抽出流程插入ID
    Set<String> processInstanceIds = historicVariableInstanceList.stream()
            .map(HistoricVariableInstance::getProcessInstanceId)
            .collect(Collectors.toSet());
    //3.根据流程插入ID查询历史流程
    List<HistoricProcessInstance> historicProcessInstanceList = historyService
            .createHistoricProcessInstanceQuery()
            .processInstanceIds(processInstanceIds)
            .list();
    //4.抽出流程定义ID集合
    Set<String> processDefinitionIds = historicProcessInstanceList.stream()
            .map(HistoricProcessInstance::getProcessDefinitionId)
            .collect(Collectors.toSet());
    //5.根据流程定义ID获取流程定义
    List<ProcessDefinition> processDefinitionList = repositoryService
            .createProcessDefinitionQuery()
            .processDefinitionIds(processDefinitionIds)
            .list();
    //6.抽出流程部署id
    Set<String> deploymentIds = processDefinitionList.stream()
            .map(ProcessDefinition::getDeploymentId)
            .collect(Collectors.toSet());
    //7.返回流程部署id
    return new ResponseEntity<>(new BaseResponse<>(deploymentIds), HttpStatus.OK);
}

通过调用接口,返回三条流程部署id:
6.png

这里只是为了给大家展示Flowable提供的丰富的查询API,可以让我们从历史变量一路向上查询到流程部署,可能有的同学还没想到这里的用处,所以我需要再额外封装个对象给大家演示下,代码如下:

/**
 * 历史绩效VO.
 */
@Data
public class HistoryPerformanceVo implements Serializable {
   

    /**
     * 绩效名称.
     */
    private String performanceName;

    /**
     * 绩效分数.
     */
    private String score;
}

然后在部署模型时更改名称,这里我们模拟实际业务中每月进行绩效考核,代码如下:

/**
 * 部署流程模型.
 *
 * @return 流程key
 */
@PostMapping("/deploy")
public ResponseEntity<Object> createProcessDef() {
   
    //1.创建部署对象
    Deployment deployment = repositoryService.createDeployment()
            //2.添加流程定义文件
            .addClasspathResource("process/performance.bpmn20.xml")
            //3.设置流程名称
            .name("2024年4月绩效")
            //4.部署
            .deploy();
    //5.通过流程部署id查询流程定义id
    ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
            .deploymentId(deployment.getId()).singleResult();
    //6.返回流程定义id
    return new ResponseEntity<>(new BaseResponse<>(processDefinition.getId()), HttpStatus.OK);
}

设置流程名称来模拟实际业务场景中的绩效名称,结果如下:
7.png

然后我们执行前面的步骤,开启流程和完成任务,最终又回到了历史表,这时候我们对查询历史的接口再次进行迭代,代码如下:

/**
 * 查询指定用户的历史绩效.
 *
 * @param userId 用户id
 * @return 历史流程集合
 */
@PostMapping("/history-process-def/userId/{userId}")
public ResponseEntity<Object> getHistoryProcessDef(@PathVariable Long userId) {
   
    //1.根据用户id查询历史流程
    List<HistoricVariableInstance> historicVariableInstanceList = historyService
            .createHistoricVariableInstanceQuery()
            .variableValueEquals("ownerId", userId.intValue())
            .list();
    //2.抽出流程插入ID
    Set<String> processInstanceIds = historicVariableInstanceList.stream()
            .map(HistoricVariableInstance::getProcessInstanceId)
            .collect(Collectors.toSet());
    //3.根据流程插入ID查询历史流程
    List<HistoricProcessInstance> historicProcessInstanceList = historyService
            .createHistoricProcessInstanceQuery()
            .processInstanceIds(processInstanceIds)
            .list();
    //4.转为map,键为流程定义id,值为流程插入id
    Map<String, String> processInstanceIdMap = historicProcessInstanceList
            .stream()
            .collect(Collectors.toMap(HistoricProcessInstance::getProcessDefinitionId,
                    HistoricProcessInstance::getId));
    //5.抽出流程定义ID集合
    Set<String> processDefinitionIds = historicProcessInstanceList.stream()
            .map(HistoricProcessInstance::getProcessDefinitionId)
            .collect(Collectors.toSet());
    //6.根据流程定义ID获取流程定义
    List<ProcessDefinition> processDefinitionList = repositoryService
            .createProcessDefinitionQuery()
            .processDefinitionIds(processDefinitionIds)
            .list();
    //7.抽出流程部署id
    List<String> deploymentIds = processDefinitionList.stream()
            .map(ProcessDefinition::getDeploymentId)
            .collect(Collectors.toList());
    //8.转为map,键为流程部署id,值为流程定义id
    Map<String, String> deploymentIdMap = processDefinitionList
            .stream()
            .collect(Collectors.toMap(ProcessDefinition::getDeploymentId,
                    ProcessDefinition::getId));
    //9.查询流程部署信息
    List<Deployment> deploymentList = repositoryService
            .createDeploymentQuery()
            .deploymentIds(deploymentIds)
            .list();
    //10.声明结果集
    List<HistoryPerformanceVo> historyPerformanceVos = new ArrayList<>();
    //11.遍历流程部署集合,为返回对象赋值
    deploymentList.forEach(deployment -> {
   
        //11-1.声明历史流程对象
        HistoryPerformanceVo historyPerformanceVo = new HistoryPerformanceVo();
        //11-2.设置绩效名称
        historyPerformanceVo.setPerformanceName(deployment.getName());
        //11-3.设置绩效分数
        String processDefinitionId = deploymentIdMap.get(deployment.getId());
        String processInstanceId = processInstanceIdMap.get(processDefinitionId);
        List<HistoricVariableInstance> historicVariableInstances = historyService
                .createHistoricVariableInstanceQuery()
                .processInstanceId(processInstanceId)
                .list();
        List<HistoricVariableInstance> score = historicVariableInstances.stream()
                .filter(historicVariableInstance -> historicVariableInstance
                        .getVariableName().equals("score"))
                .toList();
        historyPerformanceVo.setScore((String) score.get(0).getValue());
        //11-4.添加进集合
        historyPerformanceVos.add(historyPerformanceVo);
    });
    //12.返回流程绩效对象
    return new ResponseEntity<>(new BaseResponse<>(historyPerformanceVos), HttpStatus.OK);
}

这时候我们调用接口的测试结果如下:
8.png
看到这里想必大家已经能想到应用场景了,我为了演示API查了一条链路,其实这里这个需求有更简单的方案,既然只需要返回指定用户的历史绩效和分数,那就多加一个全局流程变量记录绩效名称就好了,所以Flowable为我们提供的API非常灵活,同一个需求的实现方案也有很多,大家在实际使用中多想想怎么做是最优解。

四、小结

不知不觉已经写到了06篇,下一篇将会讲讲在流程中常见的功能-驳回,学习一下Flowable是怎么设计它的以及我们要怎么用。

目录
相关文章
|
3天前
|
Java 开发者
SpringBoot整合Flowable【01】- 初识工作流引擎
本文介绍了工作流的基本概念,重点讲解了BPM(业务流程管理)和BPMN 2.0(业务流程建模符号)的关系,以及工作流引擎的发展。BPM是一种管理思想,BPMN是实现该思想的工具。文中还介绍了Flowable、Activiti等主流工作流引擎,并详细说明了流程设计的五种方式,包括FlowableUI、BPMN.js自定义、第三方设计器和代码实现等。最后通过一个请假流程图解释了流程图的组成元素,如事件、连线、任务和网关,帮助读者更好地理解工作流的设计与实现。
20 3
|
3天前
|
存储 Java 数据安全/隐私保护
SpringBoot整合Flowable【03】- 通过Flowable-UI体验一个简单流程
本文介绍了如何使用Flowable 7.0以下版本的flowable-ui进行流程建模、发布和执行。首先,通过解压并启动flowable-ui war包,访问http://localhost:8080/flowable-ui/idm/#/login登录系统。接着,创建并绘制一个简单的绩效流程模型,包含开始节点、任务节点(自评、上级评、隔级评)和结束节点,并为各节点分配处理人。然后,创建应用并发布绩效流程。最后,通过创建a、b、c三个用户分别完成各节点任务,演示了整个流程的执行过程。本文旨在帮助读者理解Flowable的基本操作和流程元素,后续将介绍通过Java代码控制流程的方法。
21 0
SpringBoot整合Flowable【03】- 通过Flowable-UI体验一个简单流程
|
3天前
|
存储 Java API
SpringBoot整合Flowable【02】- 整合初体验
本文介绍了如何基于Flowable 6.8.1版本搭建工作流项目。首先,根据JDK和Spring Boot版本选择合适的Flowable版本(7.0以下)。接着,通过创建Spring Boot项目并配置依赖,包括Flowable核心依赖、数据库连接等。然后,建立数据库并配置数据源,确保Flowable能自动生成所需的表结构。最后,启动项目测试,确认Flowable成功创建了79张表。文中还简要介绍了这些表的分类和常用表的作用,帮助初学者理解Flowable的工作原理。
39 0
SpringBoot整合Flowable【02】- 整合初体验
|
2天前
|
前端开发 Java API
SpringBoot整合Flowable【07】- 驳回节点任务
本文通过绩效流程的业务场景,详细介绍了如何在Flowable工作流引擎中实现任务驳回功能。具体步骤包括:获取目标任务节点和当前任务节点信息,进行必要的判空和逻辑校验,调用API完成节点回退,并清理相关脏数据(如历史任务和变量)。最后通过测试验证了驳回功能的正确性,确保流程能够成功回退到指定节点并清除中间产生的冗余数据。此功能在实际业务中非常有用,能够满足上级驳回自评等需求。
16 0
|
3天前
|
存储 前端开发 Java
SpringBoot整合Flowable【05】- 使用流程变量传递业务数据
本文介绍了如何使用Flowable的流程变量来管理绩效流程中的自定义数据。首先回顾了之前的简单绩效流程,指出现有流程缺乏分数输入和保存步骤。接着详细解释了流程变量的定义、分类(运行时变量和历史变量)及类型。通过具体代码示例展示了如何在绩效流程中插入全局和局部流程变量,实现各节点打分并维护分数的功能。最后总结了流程变量的使用场景及其在实际业务中的灵活性,并承诺将持续更新Flowable系列文章,帮助读者更好地理解和应用Flowable。 简要来说,本文通过实例讲解了如何利用Flowable的流程变量功能优化绩效评估流程,确保每个环节都能记录和更新分数,同时提供了全局和局部变量的对比和使用方法。
22 0
|
3天前
|
XML 前端开发 Java
SpringBoot整合Flowable【04】- 通过代码控制流程流转
本文介绍了如何使用Flowable的Java API控制流程流转,基于前文构建的绩效流程模型。首先,通过Flowable-UI导出模型文件并部署到Spring Boot项目中。接着,详细讲解了如何通过代码部署、启动和审批流程,涉及`RepositoryService`、`RuntimeService`和`TaskService`等核心服务类的使用。最后,通过实际操作演示了流程从部署到完成的全过程,并简要说明了相关数据库表的变化。本文帮助读者初步掌握Flowable在实际业务中的应用,后续将深入探讨更多高级功能。
17 0
|
2月前
|
SQL 前端开发 关系型数据库
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
79 9
|
2月前
|
XML Java 数据库连接
SpringBoot集成Flowable:打造强大的工作流管理系统
在企业级应用开发中,工作流管理是一个核心组件,它能够帮助我们定义、执行和管理业务流程。Flowable是一个开源的工作流和业务流程管理(BPM)平台,它提供了强大的工作流引擎和建模工具。结合SpringBoot,我们可以快速构建一个高效、灵活的工作流管理系统。本文将探讨如何将Flowable集成到SpringBoot应用中,并展示其强大的功能。
481 1
|
2月前
|
XML 存储 Java
SpringBoot集成Flowable:构建强大的工作流引擎
在企业级应用开发中,工作流管理是核心功能之一。Flowable是一个开源的工作流引擎,它提供了BPMN 2.0规范的实现,并且与SpringBoot框架完美集成。本文将探讨如何使用SpringBoot和Flowable构建一个强大的工作流引擎,并分享一些实践技巧。
281 0
|
3月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
215 1
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等