SpringBoot整合Flowable【05】- 使用流程变量传递业务数据

简介: 本文介绍了如何使用Flowable的流程变量来管理绩效流程中的自定义数据。首先回顾了之前的简单绩效流程,指出现有流程缺乏分数输入和保存步骤。接着详细解释了流程变量的定义、分类(运行时变量和历史变量)及类型。通过具体代码示例展示了如何在绩效流程中插入全局和局部流程变量,实现各节点打分并维护分数的功能。最后总结了流程变量的使用场景及其在实际业务中的灵活性,并承诺将持续更新Flowable系列文章,帮助读者更好地理解和应用Flowable。简要来说,本文通过实例讲解了如何利用Flowable的流程变量功能优化绩效评估流程,确保每个环节都能记录和更新分数,同时提供了全局和局部变量的对比和使用方法。

一、前情回顾

在04篇中,我们用代码的形式控制了一个简单的绩效流程的运转,并且基本熟悉了流程运行过程中涉及到的相关表。让我们继续回到这个简单的绩效流程,它依然是有所欠缺的,比如在实际业务场景中,我们在绩效的每个环节都应该有个分数,但目前我们只是指派个人去完成各个节点,并没有输入分数和保存分数的步骤。因此,在今天的文章中,我们将使用Flowable包含的流程变量来管理流程中的自定义数据。

二、认识流程变量

1.定义

首先,我们来看下流程变量的官方定义:在Flowable中,流程变量是在流程实例按步骤执行时需要保存并使用的数据,这些数据被称为变量(variable)。流程实例可以持有变量,这些变量被称为流程变量。

我们目前只需要知道变量可以在Java服务任务中用于调用外部服务(例如为服务调用提供输入或结果存储),参考上面绩效分数的例子。我们在实际业务中执行任何流程都可能涉及到有数据流转,流程变量负责的就是在流程流转的过程中传递业务参数。

2.分类

为了提高使用效率,Flowable将变量分为两种:运行时变量和历史变量:

  • 运行时变量:这是流程实例运行时的变量,存入act_ru_variable表中。在流程实例运行结束时,此实例的变量在表中删除。在流程实例创建及启动时,可以设置流程变量,也可以在流程执行中加入变量。由于流程实例结束时,对应在运行时表的数据跟着被删除,所以,查询一个已经完结流程实例的变量,只能在历史变量表中查找。

  • 历史变量:历史变量存入act_hi_varinst表中。在流程启动时,流程变量会同时存入历史变量表中。这样即使在流程结束时,历史表中的变量仍然存在。这里可以想想前文中的历史流程也是这样,在Flowable的设计中,我们一个流程启动到结束过程中涉及到的所有东西都可以在相应的历史表上查到。

    3.类型

    一般来说,一个变量由一个名称和值组成,就是个经典的KV结构。K是字符串类型的,V可以是基本数据类型,也可以是个Java对象(Ps:实现了Serializable接口)。如果流程变量名称相同的时候,后一次的值替换前一次的值。

三、使用流程变量

说了这么多,接下来让我们在我们前面定义的绩效流程中加入流程变量的使用,在自评阶段就需要打分,然后上级评和隔级评都需要打分,并且最后隔级评给出的分数权重最大,也就是本次绩效的最终的分数。

1.接口优化

部署流程模型就不赘述了,详情请翻阅04篇,这里主要为了更贴近实际,部署流程后返回流程定义id,这样前端拿到流程定义id也就可以发起请求来启动流程了,这里大家具体看下代码,和原本相比,多了第2步:

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

2.插入全局流程变量

完成了流程的部署后就可以启动流程了,因为我们在部署成功之后返回了流程定义id,那么这里就可以传参调用了。我们也需要在这时创建这个分数变量,大家可以在这里结合具体场景想想,作为执行层是不是得在完成自评前写好自评分数然后提交。于是我们对原有的启动流程接口进行改造:

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

在原有代码的基础上我们通过runtimeService设置了一个流程变量,这个流程变量是全局的,也就是这个流程没结束的情况下都可以查到并且进行维护,相同key的value会被最新的覆盖,我们执行这个接口后看下act_ru_variable表的变化:
1.png

2.png
在这张流程变量表上我们可以看到多了一条数据,注意看我圈起来的3个字段:NAMETEXT很明了,就对应着前面的key和value,这个EXECUTION_ID则是我们设置的流程实例ID,如果我们不设置,引擎也会自动生成,我这里只是方便演示这么做的(Ps:不建议自己改,因为当你的流程有分支时,这个执行ID它就是动态的),我们要通过这个执行ID进行对应变量的查询与维护(Ps:再次强调,这张表只负责运行时变量)。

3.维护流程变量

既然在启动流程的时候设置了变量,那么在接下来的每个节点都可以对变量进行更新,从而实现我们提到的需求,通过前面设置的执行ID查询关联的变量,并根据key对value进行维护,代码如下:

@PostMapping("/complete/agentUser/{agentUser}/score/{score}/processInstanceId/{processInstanceId}")
public ResponseEntity<Object> completeTask(@PathVariable String agentUser,
                                           @PathVariable String score,
                                           @PathVariable String processInstanceId) {
   
    //1.查询指定用户的待办任务
    String agentTaskId = findUserAgentTask(agentUser);
    //2.更新绩效流程变量
    runtimeService.setVariable(processInstanceId, "score", score);
    //3.完成指定任务的审批
    taskService.complete(agentTaskId);
    //4.返回响应
    return new ResponseEntity<>(new BaseResponse<>(null), HttpStatus.OK);
}

然后使用Apifox进行接口测试,对比04篇这个接口多了两个参数,分别是分数和流程实例ID。我说明下分数在实际场景中肯定是用户填写后由前端传来的;而流程实例ID在前面的启动流程中我们也有返回,所以前端同学也能拿到:
3.png
执行成功后,我们再去观察下act_ru_variable表中的那条流程变量,会发现它也同步更新了:
4.png
那么我们这里结合实际场景思考下,在我们现在设计的这套流程里,是不是每个节点都能通过流程ID查询并维护这个分数变量从而实现前面提到的业务需求。需要注意的是:我这里只是假设的业务场景,所以各位读者在自己实操的时候要根据自己业务需求来做,这个系列的文章主要目的是尽可能帮各位读者理清各种表的作用和各种API的用法。

4.查询历史变量

当我们这个流程执行结束的时候,act_ru_variable表中的这条数据就消失了:
5.png
这时候我们想再查到它就需要到act_hi_varinst表里,也就是流程变量历史表,通过流程ID就可以查到它,那么大家想想如果业务需要查询历史绩效包括分数,是不是就很简单了:
6.png

5.插入局部流程变量

02小标题进行对比,我们发现区别在于一个是全局,另一个是局部。大家观察下前面的部分里的流程变量在这个流程没结束前,任何节点都可以查询和维护,可以理解成它的生命周期伴随着那个流程。但局部流程变量是我们在某个节点声明,一旦这个节点执行过之后,它就和节点的任务一样都只能去历史表里查询了,所以全局和局部最大的区别就是生命周期的不同。

知道了它们的区别,接下来我们看看怎么使用,首先runtimeServicetaskService都可以设置流程变量,这里主要是API的变化,代码如下:

@PostMapping("/complete/agentUser/{agentUser}/score/{score}/processInstanceId/{processInstanceId}")
public ResponseEntity<Object> completeTask(@PathVariable String agentUser,
                                           @PathVariable String score,
                                           @PathVariable String processInstanceId) {
   
    //1.查询指定用户的待办任务
    String agentTaskId = findUserAgentTask(agentUser);
    //2.更新绩效流程变量
    runtimeService.setVariable(processInstanceId, "score", score);
    //3.设置任务节点流程变量
    taskService.setVariableLocal(agentTaskId, "score2", score);
    //4.完成指定任务的审批
    taskService.complete(agentTaskId);
    //5.返回响应
    return new ResponseEntity<>(new BaseResponse<>(null), HttpStatus.OK);
}

03处就是在设置局部流程变量,我在完成任务接口上设置了一个任务节点变量,也就是当我执行这个接口后,只能在历史表里看到这条score2的数据,调用接口测试下:
7.png
执行成功后,我们再去act_hi_varinst表查看有没有key为score2的数据:
8.png
可以看到此时key为score2的流程变量直接在历史表里,大家需要明白的是,无论是全局流程变量和局部流程变量都需要结合实际业务需求与场景进行使用,我这里只是告诉大家有这么个东西,在项目中怎么用是需要思考的,假设我们当前的这个绩效流程需要查询绩效历史的时候同时展示各个历史节点的分数,大家想想这个局部流程变量是不是就可以派上用场了。但是这也只是一种实现思路,其实用全局流程变量也可以实现,在每个节点设置变量的时候多设置一下,这个新变量在原key的基础上加上任务id,后续它就不会被覆盖了。所以API是很丰富的,主要看大家想怎么用。

6.补充

在这里补充一下,runtimeService也有设置局部流程变量,但传的ID是会影响结果的。如果你传的是流程ID,它就是全局,即使你用这个API;如果你传的是任务ID,它则是关联对应任务的局部流程变量。

runtimeService.setVariableLocal(XXId, "score", score);

四、小结

首先对一直支持该系列的读者表示感谢,同时也对大家表示抱歉,由于近期工作较忙,导致文章更新速度较慢。其实一开始写这个系列只是想让自己回顾下,但是随着慢慢的更新,开始有读者在评论区“催更”,让我看到了这个系列是有价值的,确实可以帮到别人,所以我也会持续更新下去的,给大家打个包票该系列至少更新10篇,尽可能地为大家详细介绍Flowable的用法以及引导大家结合实际业务进行思考。另外,个人水平毕竟有限,如果文章中有错误的地方,也欢迎大家批评指正!

目录
相关文章
|
12月前
|
JSON Java 数据格式
微服务——SpringBoot使用归纳——Spring Boot返回Json数据及数据封装——封装统一返回的数据结构
本文介绍了在Spring Boot中封装统一返回的数据结构的方法。通过定义一个泛型类`JsonResult&lt;T&gt;`,包含数据、状态码和提示信息三个属性,满足不同场景下的JSON返回需求。例如,无数据返回时可设置默认状态码&quot;0&quot;和消息&quot;操作成功!&quot;,有数据返回时也可自定义状态码和消息。同时,文章展示了如何在Controller中使用该结构,通过具体示例(如用户信息、列表和Map)说明其灵活性与便捷性。最后总结了Spring Boot中JSON数据返回的配置与实际项目中的应用技巧。
889 0
|
12月前
|
JSON Java fastjson
微服务——SpringBoot使用归纳——Spring Boot返回Json数据及数据封装——使用 fastJson 处理 null
本文介绍如何使用 fastJson 处理 null 值。与 Jackson 不同,fastJson 需要通过继承 `WebMvcConfigurationSupport` 类并覆盖 `configureMessageConverters` 方法来配置 null 值的处理方式。例如,可将 String 类型的 null 转为 &quot;&quot;,Number 类型的 null 转为 0,避免循环引用等。代码示例展示了具体实现步骤,包括引入相关依赖、设置序列化特性及解决中文乱码问题。
608 0
|
12月前
|
JSON Java fastjson
微服务——SpringBoot使用归纳——Spring Boot返回Json数据及数据封装——Spring Boot 默认对Json的处理
本文介绍了在Spring Boot中返回Json数据的方法及数据封装技巧。通过使用`@RestController`注解,可以轻松实现接口返回Json格式的数据,默认使用的Json解析框架是Jackson。文章详细讲解了如何处理不同数据类型(如类对象、List、Map)的Json转换,并提供了自定义配置以应对null值问题。此外,还对比了Jackson与阿里巴巴FastJson的特点,以及如何在项目中引入和配置FastJson,解决null值转换和中文乱码等问题。
1616 0
|
前端开发 Java API
SpringBoot整合Flowable【06】- 查询历史数据
本文介绍了Flowable工作流引擎中历史数据的查询与管理。首先回顾了流程变量的应用场景及其局限性,引出表单在灵活定制流程中的重要性。接着详细讲解了如何通过Flowable的历史服务API查询用户的历史绩效数据,包括启动流程、执行任务和查询历史记录的具体步骤,并展示了如何将查询结果封装为更易理解的对象返回。最后总结了Flowable提供的丰富API及其灵活性,为后续学习驳回功能做了铺垫。
1172 0
SpringBoot整合Flowable【06】- 查询历史数据
|
8月前
|
JSON Java 数据格式
Spring Boot返回Json数据及数据封装
在Spring Boot中,接口间及前后端的数据传输通常使用JSON格式。通过@RestController注解,可轻松实现Controller返回JSON数据。该注解是Spring Boot新增的组合注解,结合了@Controller和@ResponseBody的功能,默认将返回值转换为JSON格式。Spring Boot底层默认采用Jackson作为JSON解析框架,并通过spring-boot-starter-json依赖集成了相关库,包括jackson-databind、jackson-datatype-jdk8等常用模块,简化了开发者对依赖的手动管理。
742 3
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
1238 2
|
12月前
|
前端开发 Cloud Native Java
Java||Springboot读取本地目录的文件和文件结构,读取服务器文档目录数据供前端渲染的API实现
博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
Java||Springboot读取本地目录的文件和文件结构,读取服务器文档目录数据供前端渲染的API实现
|
Java 关系型数据库 MySQL
SpringBoot 通过集成 Flink CDC 来实时追踪 MySql 数据变动
通过详细的步骤和示例代码,您可以在 SpringBoot 项目中成功集成 Flink CDC,并实时追踪 MySQL 数据库的变动。
3061 45
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
776 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
SQL 前端开发 关系型数据库
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
436 9

热门文章

最新文章