一、前情回顾
在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可以进行初步的应用了,在以后的篇章中,会开始一些进阶的内容,比如节点引用表单、驳回功能、网关的使用等等。