SpringBoot整合Flowable【04】- 通过代码控制流程流转

一、前情回顾

在03篇中,我用Flowable-UI绘制了一个简单的绩效流程并在官方的demo中跑完了整个流程,加深了各位读者对于一个流程中包含的一些基础概念加深了认识,并且在这个过程里也渗透了一些可以应用的知识点。但我们也能想到,在实际业务中我们是要靠后端的接口去控制流程的流转,而不能靠Flowable-UI去控制。因此,本篇文章就是带领读者使用Flowable的Java Api去控制流程流转,从而熟悉对相关API的使用。

二、导入流程

本次我们演示使用的模型就是上篇中在Flowable-UI中建立的绩效模型,因此我们需要把模型文件导出。在模型管理界面,我们绘制的模型在详情页都有导出选项。

将导出的模型文件放到项目里,位置没有硬性要求,但建议放在resource目录下。

三、代码控制

虽然Flowable也可以在非Spring环境下使用,但我相信应该没人会拒绝SpringBoot,毕竟精力扑到业务和开发上,比折腾配置可有趣多了。

1.相关配置

我们需要在02篇配置的基础上添加Flowable相关的配置。

xml 复制代码
flowable:
  async-executor-activate: true # 关闭定时任务job
  database-schema-update: true # flowable自动更新表结构

2.部署流程

完成了相关的配置后,我们来定义一个流程控制器并注入一个RepositoryService对象,它提供了管理和控住部署和流程定义相关操作的API。

java 复制代码
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/process/v1")
public class ProcessControllerV1 {

    private final RepositoryService repositoryService;
    
}

接着声明一个部署流程的接口方法,当然,这里也可以编写一个测试类进行测试,只是我个人更喜欢直接用接口测:

java 复制代码
/**
 * 部署流程模型.
 *
 * @return 流程key
 */
@PostMapping("/deploy")
public ResponseEntity<Object> createProcessDef() {
    //1,创建部署对象
    Deployment deployment = repositoryService.createDeployment()
            //2.添加流程定义文件
            .addClasspathResource("process/performance.bpmn20.xml")
            //3.设置流程名称
            .name("绩效流程")
            //4.部署
            .deploy();
    //5.返回部署的流程id
    return new ResponseEntity<>(new BaseResponse<>(deployment.getId()), HttpStatus.OK);
}

完成编码通过调试工具调这个接口,当方法正常执行后,会返回流程部署的id。 此时我们可以在三张表中看到此次部署的相关信息,首先是act_ge_bytearray 表,它记录了流程定义的资源信息,包含了xml和流程图的图片信息; 其次是act_re_deployment 表,它记载了这次的部署行为; 最后是act_re_procdef 表,他记录了此次部署对应的流程定义信息;

3.启动流程

流程部署成功后,就可以启动流程了,我们需要注入一个新的服务类-RuntimeService来启动流程。

java 复制代码
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/process/v1")
public class ProcessControllerV1 {

    private final RepositoryService repositoryService;

    private final RuntimeService runtimeService;

在这里需要说明下启动流程有两个方法,分别是通过id和key。它们的区别就是id是由引擎维护的,而key是由我们自己维护的(Ps:这里迷惑的同学回到03篇看下,我们在创建流程和节点的时候都有输入Key)。因此,在实际业务开发中我建议还是通过id启动流程。

java 复制代码
runtimeService.startProcessInstanceById(processId);

runtimeService.startProcessInstanceByKey(processKey);

于是我们通过流程id来启动这个绩效流程,这个方法会返回一个流程实例对象。需要注意的是,在下面的示例中,我是直接声明的,聪明的同学一定已经想到了,在实际业务开发中,这个是在部署流程之后,由前端调这个接口并传入流程id来启动流程。

java 复制代码
/**
 * 启动流程.
 *
 * @return 流程key
 */
@PostMapping("/start")
public ResponseEntity<Object> startProcessDef() {
    //1.声明流程id
    String processId = "performance-001:1:a9d432fd-ec57-11ee-980b-c85ea9014af0";
    //2.启动流程
    ProcessInstance processInstance = runtimeService.startProcessInstanceById(processId);
    //3.返回流程实例对象id
    return new ResponseEntity<>(new BaseResponse<>(processInstance.getId()), HttpStatus.OK);
}

通过调试工具调这个接口,当方法正常执行后,会返回流程实例的id。 启动流程也需要我们关注三张表,此时我们可以在act_ru_task 表中看到当前流程走到了自评节点以及节点的承办人,即当前待办的记录信息。 而在act_ru_execution 表中则记录了每个启动了的流程分支。 另外,可以在act_hi_actinst 表中查询到这个流程的运行记录,需要注意的是:只要你启动一个流程,记录都会维护在这张表中 这里可以看到我们在部署流程启动流程 这两个方法里涉及到了两个概念-1.流程定义2.流程实例 ,它们二者的关系可以类比为Java中的类与对象 ,即定义一个流程后,我们可以根据这个流程定义启动N个流程实例

4.流程审批

流程启动成功后,为了流程的跑通,我们就需要对各个节点进行审批。因此,我们需要注入新的服务类- TaskService,它负责处理所有的节点任务。

java 复制代码
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/process/v1")
public class ProcessControllerV1 {

    private final RepositoryService repositoryService;

    private final RuntimeService runtimeService;

    private final TaskService taskService;

还记得前面提过的每个节点都有个承办人,完成节点的审批就需要各个节点的承办人来做。因此我们先写个方法来查找某个承接人待处理的待办:

java 复制代码
/**
 * 查询指定用户的待办任务.
 *
 * @param user 待办用户
 * @return 待办任务id
 */
private String findUserAgentTask(String user) {
    //1.查找指定用户的一个待办任务
    Task agentTask = taskService.createTaskQuery()
            .taskAssignee(user)
            .singleResult();
    //2.返回待办任务的id
    return agentTask.getId();
}

因为我这里演示只启动了一个流程,所以也只有一个待办,因此查询单个任务就可以了。读者们在实际开发者需要结合实际业务,如果业务场景会出现一个用户有多个待办,一定要查询任务集合,否则会报错。

java 复制代码
//待办任务集合
List<Task> list = taskService.createTaskQuery()
        .taskAssignee(user)
        .list();
//待办任务集合(带分页)
List<Task> tasks = taskService.createTaskQuery()
        .taskAssignee(user)
        .listPage(1, 10);      
      

查询到某个用户的待办后,返回待办任务的id,直接调用API完成节点审批即可。这里再复习一下:因为我们不使用引擎自带的用户关系,所以这里的审批操作其实引擎不会校验的,所以需要我们根据实际业务自行编写鉴权代码。 我这里演示也没什么要鉴权的,直接完成审批:

less 复制代码
/**
 * 完成节点任务.
 *
 * @return 流程key
 */
@PostMapping("/complete/{agentUser}")
public ResponseEntity<Object> completeTask(@PathVariable String agentUser) {
    //1.查询指定用户的待办任务
    String agentTaskId = findUserAgentTask(agentUser);
    //2.完成指定任务的审批
    taskService.complete(agentTaskId);
    //3.返回响应
    return new ResponseEntity<>(new BaseResponse<>(null), HttpStatus.OK);
}

通过调试工具调这个接口并在调用时传入承接人数据,运行后提示执行成功。 各位读者不要被这个传承接人数据限制了,我只是为了演示API的使用,既然强调了引擎不会校验我们自定义的用户关系,在我们自己不加入逻辑判断的情况下,直接给完成方法穿待办任务id也是可以通过的:

java 复制代码
/**
 * 完成节点任务.
 *
 * @return 流程key
 */
@PostMapping("/complete/{agentUser}")
public ResponseEntity<Object> completeTask(@PathVariable String agentUser) {
    //1.查询指定用户的待办任务
    //String agentTaskId = findUserAgentTask(agentUser);
    //2.完成指定任务的审批
    taskService.complete("d30f9ffd-eeb2-11ee-9654-c85ea9014af0");
    //3.返回响应
    return new ResponseEntity<>(new BaseResponse<>(null), HttpStatus.OK);
}

这时候我们回到act_ru_task 表,就可以看到节点走到了上级评节点: 再次调用接口,就可以看到节点走到了隔级评节点: 最后调用一次,会发现act_ru_task 表中已经没有数据了,因为我们这个流程已经完成了,后续我们想查这个流程节点的信息就只能去历史相关表里了。

四、小结

本篇主要是让各位读者了解了如何通过代码控制流程流转,介绍了几个主要的服务类和相关API地使用,至此,各位读者应该已经对Flowable可以进行初步的应用了,在以后的篇章中,会开始一些进阶的内容,比如节点引用表单、驳回功能、网关的使用等等。

相关推荐
开心工作室_kaic17 分钟前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
懒洋洋大魔王18 分钟前
RocketMQ的使⽤
java·rocketmq·java-rocketmq
武子康23 分钟前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
qq_17448285751 小时前
springboot基于微信小程序的旧衣回收系统的设计与实现
spring boot·后端·微信小程序
转世成为计算机大神1 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
qq_327342731 小时前
Java实现离线身份证号码OCR识别
java·开发语言
阿龟在奔跑3 小时前
引用类型的局部变量线程安全问题分析——以多线程对方法局部变量List类型对象实例的add、remove操作为例
java·jvm·安全·list
飞滕人生TYF3 小时前
m个数 生成n个数的所有组合 详解
java·递归
代码小鑫3 小时前
A043-基于Spring Boot的秒杀系统设计与实现
java·开发语言·数据库·spring boot·后端·spring·毕业设计
真心喜欢你吖3 小时前
SpringBoot与MongoDB深度整合及应用案例
java·spring boot·后端·mongodb·spring