当前位置: 首页 > 科技观察

哪里可以找到Flowable的完整流程?

时间:2023-03-16 23:40:30 科技观察

在上一篇文章中,宋哥和他的朋友们聊了聊。正在执行的进程信息存储在前缀为ACT_RU_的表中,完成的进程信息存储在前缀为ACT_HI_的表中。即进程历史信息表。当然,如果将这张历史信息表进一步细分,还有很多其他的类型。今天我们就来聊聊这个话题。假设我有如下流程:该流程执行后,将ACT_RU_前缀的表中的数据清空。现在如果我们要查看刚刚执行过的进程信息,就要到ACT_HI_前缀的表中去。1、通过以下方式查看历史进程信息:@Testvoidtest05(){Listlist=historyService.createHistoricProcessInstanceQuery().finished().list();对于(HistoricProcessInstancehpi:list){logger.info("name:{},startTime:{},endTime:{}",hpi.getName(),hpi.getStartTime(),hpi.getEndTime());}}调用时执行的finished()方法代表了查询已经执行过的流程信息(从这里也可以看出,没有执行过的流程信息也会保存在历史表中)。我们看一下这个查询对应的SQL,如下:SELECTRES.*,DEF.KEY_asPROC_DEF_KEY_,DEF.NAME_asPROC_DEF_NAME_,DEF.VERSION_asPROC_DEF_VERSION_,DEF.DEPLOYMENT_ID_asDEPLOYMENT_ID_fromACT_HI_PROCINSTRESDEF_DEF_PROConRES。PROC_DEF_ID_=DEF.ID_WHERERES.END_TIME_isnotNULLorderbyRES.ID_asc从这条SQL可以看出,这条查询本质上就是查询ACT_HI_PROCINST表。如下图所示:如果我们在查询的时候不限制流程是否完成,那么我们的查询方式如下:@Testvoidtest05(){Listlist=historyService.createHistoricProcessInstanceQuery().list();对于(HistoricProcessInstancehpi:list){logger.info("name:{},startTime:{},endTime:{}",hpi.getName(),hpi.getStartTime(),hpi.getEndTime());}}对应的查询SQL如下:SELECTRES.*,DEF.KEY_asPROC_DEF_KEY_,DEF.NAME_asPROC_DEF_NAME_,DEF.VERSION_asPROC_DEF_VERSION_,DEF.DEPLOYMENT_ID_asDEPLOYMENT_ID_fromACT_HI_PROCINSTRESleftouterjoinACT_RE_PROCDEFDEFonRES.PROC_DEF_ID_=DEF.ID_orderbyRES.ID_asc相对于前面的SQL少了后面SQL中的WHERERES.END_TIME_isnotNULL条件。也就是说判断一个进程是否执行,要看它的END_TIME_是否为空。如果不为空,则表示该过程已经完成。执行结束,如果为空,说明进程还在执行中。2.历史任务查询我们刚才查询的是历史进程。接下来我们看历史任务,就是查询某个进程执行过的Task信息。下面的意思是查询所有历史流程任务:@Testvoidtest06(){Listlist=historyService.createHistoricTaskInstanceQuery().list();for(HistoricTaskInstancehti:list){logger.info("name:{},assignee:{},createTime:{},endTime:{}",hti.getName(),hti.getAssignee(),hti.getCreateTime(),hti.getEndTime());}}该查询对应的SQL如下:SELECTRES.*fromACT_HI_TASKINSTRESorderbyRES.ID_asc可以看出,历史任务表为ACT_HI_TASKINST,如下图:当然还有很多其他的这里的玩法,比如查询某个进程执行过的历史任务,如下:@Testvoidtest07(){ListinstanceList=historyService.createHistoricProcessInstanceQuery().list();for(HistoricProcessInstancehpi:instanceList){Listlist=historyService.createHistoricTaskInstanceQuery().processInstanceId(hpi.getId()).finished().list();对于(HistoricTaskInstancehti:列表){logger.info(“名称:{},受让人:{},createTime:{},endTime:{}",hti.getName(),hti.getAssignee(),hti.getCreateTime(),hti.getEndTime());}}}这里面的查询历史任务SQL如下:SELECTRES。*fromACT_HI_TASKINSTRESWHERERES.PROC_INST_ID_=?andRES.END_TIME_isnotnullorderbyRES.ID_asc可以看到,和前面相比,多了两个条件:流程实例ID流程结束时间不为null可以也可以从这里看出来,这个finish方法的执行逻辑和我们之前说的一样3.历史活动查询历史任务就是各种Task,历史活动包含的内容比较多,比如开始/结束节点,connections等Activity,这个在之前的文章中宋大哥介绍过,查询代码如下:@Testvoidtest08(){Listlist=historyService.createHistoricActivityInstanceQuery().list();for(HistoricActivityInstancehai:list){logger.info("name:{},startTime:{},assignee:{},type:{}",hai.getActivityName(),hai.getStartTime(),hai.getAssignee(),hai.getActivityType());}}该查询对应的SQL如下:SELECTRES.*fromACT_HI_ACTINSTRESorderbyRES.ID_asc可以看到,ACT_HI_ACTINST表存储了历史活动信息。4、历史变量查询查询进程执行的历史变量,如下:@Testvoidtest09(){HistoricProcessInstancepi=historyService.createHistoricProcessInstanceQuery().singleResult();Listlist=historyService.createHistoricVariableInstanceQuery().processInstanceId(pi.getId()).list();for(HistoricVariableInstancehvi:list){logger.info("name:{},type:{},value:{}",hvi.getVariableName(),hvi.getVariableTypeName(),hvi.getValue());}}该查询对应的SQL如下:SELECTRES.*fromACT_HI_VARINSTRESWHERERES.PROC_INST_ID_=?orderbyRES.ID_asc可以看到ACT_HI_VARINST表中存放了进程的历史变量信息。5、历史日志查询有些朋友看到日志这个词可能会觉得奇怪,嗯?还有流程执行的日志吗?从来没有听说过!历史日志查询其实是前者的集大成者,其用法如下:@Testvoidtest10(){HistoricProcessInstancepi=historyService.createHistoricProcessInstanceQuery().singleResult();ProcessInstanceHistoryLoghistoryLog=historyService.createProcessInstanceHistoryLogQuery(pi.getId())//包含历史活动.includeActivities()//包含历史任务.includeTasks()//包含历史变量.includeVariables().singleResult();logger.info("id:{},startTime:{},endTime:{}",historyLog.getId(),historyLog.getStartTime(),historyLog.getEndTime());ListhistoricData=historyLog.getHistoricData();for(HistoricDatadata:historicData){if(datainstanceofHistoricActivityInstance){HistoricActivityInstancehai=(HistoricActivityInstance)数据;logger.info("name:{},type:{}",hai.getActivityName(),hai.getActivityType());}如果(数据ainstanceofHistoricTaskInstance){HistoricTaskInstancehti=(HistoricTaskInstance)数据;logger.info("name:{},assignee:{}",hti.getName(),hti.getAssignee());}if(datainstanceofHistoricVariableInstance){HistoricVariableInstancehvi=(HistoricVariableInstance)数据;logger.info("名称:{},类型:{},值:{}",hvi.getVariableName(),hvi.getVariableTypeName(),hvi.getValue());}}}在这里面,首先是查询基本的流程日志信息,本质上是查询历史流程实例信息。对应的SQL如下:selectRES.*,DEF.KEY_asPROC_DEF_KEY_,DEF.NAME_asPROC_DEF_NAME_,DEF.VERSION_asPROC_DEF_VERSION_,DEF.DEPLOYMENT_ID_asDEPLOYMENT_ID_fromACT_HI_PROCINSTRESleftouterjoinACT_RE_PROCDEFDEFonRES.PROC_DEF_ID_=DEF。ID_其中PROC_INST_ID_=?接下来写了三个include,每个include对应一句SQL:includeActivitiesLECT对应的SQL如下:SERES.*fromACT_HI_ACTINSTRESWHERERES.PROC_INST_ID_=?orderbyRES.ID_ascincludeTasks对应的SQL如下:SELECTRES.*fromACT_HI_TASKINSTRESWHERERES.PROC_INST_ID_=?orderbyRES.ID_ascincludeVariables对应的SQL如下:SELECTRES.*fromACT_HI_VARINSTRESWHERERES.PROC_INST_ID_=?List集合中存储的HistoricData也分为不同的类型:includeActivities方法对应HistoricActivityInstanceInstance,includeTasks方法对应HistoricTaskInstance。includeVariables方法对应最终查询到的类型是HistoricVariableInstance。遍历的时候,使用类型判断,检查是哪个变量类型。综上所述,这个历史日志查询其实是个高手。6.历史权限查询这个用于查询进程或任务的处理器,例如查询处理器的进程,方法如下:@Testvoidtest11(){HistoricProcessInstancepi=historyService.createHistoricProcessInstanceQuery().singleResult();Listlinks=historyService.getHistoricIdentityLinksForProcessInstance(pi.getId());对于(HistoricIdentityLink链接:链接){logger.info("userId:{}",link.getUserId());}}这是查询过程对应的处理器,对应的SQL如下:select*fromACT_HI_IDENTITYLINKwherePROC_INST_ID_=?如果要查询任务的处理者,对应的方法如下:@Testvoidtest12(){StringtaskName="提交请假申请";HistoricTaskInstancehti=historyService.createHistoricTaskInstanceQuery()。任务名(任务名).singleResult();Listlinks=historyService.getHistoricIdentityLinksForTask(hti.getId());for(HistoricIdentityLinklink:links){logger.info("{}任务由{}"处理,taskName,link.getUserId());}}该查询对应的SQL如下:select*fromACT_HI_IDENTITYLINKwhereTASK_ID_=?和上一个相比,其实多了一个查询条件TASK_ID_。7.自定义查询SQL类似于上面提到的很多查询。当我们了解了每个历史查询的API操作的是哪张数据表时,我们会发现历史数据的查询也是可以自定义SQL的。和朋友一起看一个例子,比如查询某个进程执行过的历史任务:@Testvoidtest13(){ListinstanceList=historyService.createHistoricProcessInstanceQuery().list();for(HistoricProcessInstancehpi:instanceList){Listlist=historyService.createNativeHistoricTaskInstanceQuery().sql("SELECTRES.*fromACT_HI_TASKINSTRESWHERERES.PROC_INST_ID_=#{pid}andRES.END_TIME_isnotnullorderbyRES.ID_asc").parameter("pid",hpi.getId()).list();for(HistoricTaskInstancehti:list){logger.info("name:{},assignee:{},createTime:{},endTime:{}",hti.getName(),hti.getAssignee(),hti.getCreateTime(),hti.getEndTime());}}}flowable底层是MyBatis,所有参数在SQL中的传递形式与MyBatis一致。8.历史数据记录级别Flowable需要记录哪些历史数据。有一个日志级别来描述这件事。默认有四个级别:无:这意味着不存储任何历史信息。好处是流程执行的时候效率会比较快。缺点是进程执行后,看不到已经执行过的进程信息。活动:这将存储所有流程实例和活动实例,并且在流程实例结束时,顶级流程实例变量的最新值将被复制到历史变量实例中,不存储任何细节。Audit:在Activity的基础上,还会存储历史细节,包括权限信息。默认日志记录级别是次要的。Full:这个是基于Audit的,也存储变量变化信息,会记录大量的数据,也会拖慢流程执行。总共有四个等级。在SpringBoot项目中,如果我们要配置日志级别,其实是很方便的。我们可以直接在application.properties中配置,如下:flowable.history-level=none配置加上这个配置,我们随便启动一个进程,然后查询ACT_HI_系列的表,发现都是空的,没有数据。如果我们将历史日志的级别改为activity,那么会记录流程信息和activity信息,但是没有执行过的Task(ACT_HI_TASKINST)等信息,包括流程参与者的信息(ACT_HI_IDENTITYLINK)等被记录下来。如果我们将历史日志的级别改为audit,就会记录上述类型的日志。但是ACT_HI_DETAIL表还是空的,不会详细记录一个流程变量的变化过程。如果我们将日志记录级别更改为完整,则会记录更多信息。流程变量的详细信息将记录在ACT_HI_DETAIL表中。整个过程我就不给小伙伴们演示了,大家可以自己试试。