当前位置: 首页 > 后端技术 > Java

Flowable流程部署与删除

时间:2023-04-01 23:49:41 Java

本篇,我们一起来看看流程部署的细节。其实我们在使用SpringBoot的时候,默认会自动部署进程,基本上不需要我们额外做任何事情。不过,这些操作还是有很多细节的。今天宋哥就带大家来梳理一下。1.默认行为首先我们来梳理一下默认行为。默认情况下,我们放在resources/processes目录下的所有流程文件都会自动部署,流程文件的后缀有两种形式:bpmn20.xml或bpmn。当然,无论是工艺文件存放的位置,还是工艺文件的格式,都可以自定义。主要涉及三个属性,可以在application.properties中配置:**.bpmn20.xml,**.bpmnflowable.check-process-definitions:这个表示是否在项目启动的时候,去检查文件目录下是否有对应的流程文件,如果这个属性为true,表示如果有进程文件,会自动部署,如果为false,表示不勾选,则不会自动部署。flowable.process-definition-location-prefix:这是流程文件的位置。默认为类路径*:/processes/。当然,开发者也可以配置。flowable.process-definition-location-suffixes:这是流程文件的后缀。默认有两个,分别是**.bpmn20.xml和**.bpmn。当然,开发者也可以配置它们。这个配置应该没什么好说的。2、动态部署有时候,我们的流程可能不是事先设计好的,而是在项目启动后,动态部署的。比如项目启动成功后,动态上传一个流程的XML文件进行部署。这也是一个比较常见的场景,对于这种情况,我们可以这样部署:@RestControllerpublicclassProcessDeployController{@AutowiredRepositoryServicerepositoryService;@PostMapping("/deploy")publicRespBeandeploy(MultipartFilefile)throwsIOException{DeploymentBuilderdeploymentBuilder=repositoryService.createDeployment().category("javaboy工作流分类").name("javaboy工作流名称").addInputStream(file.getOriginalFilename(),file.getInputStream()).key("javaboy工作流密钥");部署deployment=deploymentBuilder.deploy();returnRespBean.ok("部署成功",deployment.getId());}}这里给出了一个简单的文件上传接口,文件上传部分就不多说了。我们来看看流程部署:首先,通过repositoryService.createDeployment()方法创建一个流程部署构建器DeploymentBuilder。接下来,为DeploymentBuilder设置类别、名称和键等属性。关键方法是addInputStream,通过它指定进程文件。官方有几种方式来指定进程文件;除了addInputStream,还有一个addString,就是将流程文件转成字符串传入;addBytes是将进程文件转成字节数组传进来;addClasspathResource方法是直接从classpath目录加载进程文件。这些方法可以根据自己的使用场景选择合适的方法来调用。这里有一个地方需要强调一下,就是addInputStream/addBytes/addString等方法需要设置资源名称。这个名字可以随意设置,但是要注意名字的后缀,需要是bpmn20.xml或者bpmn,否则流程不会被部署。.为什么进程名后缀是bpmn20.xml还是bpmn?请参阅第一小节。3、表分析在我们的流程部署过程中,一共有三张表参与了我们的工作。虽然宋大哥之前写过一篇文章,让大家梳理一下flowable中各个数据表的作用,但当时只是笼统的介绍。待会儿,不细说了,我们先看看这次涉及到的三张表。ACT_RE_DEPLOYMENT表是流程部署表。每部署一个进程,都会在这个表中增加一条新的记录来描述我们刚才定义的进程:ID_、NAME_、CATEGORY_等,这里是我们在部署进程参数时设置的。ACT_RE_PROCDEF这是流程定义表。我们定义的每一个流程都会被记录在这个表中:这个表中有很多字段,我这里只列出其中的一部分。该表中有一个DEPLOYMENT_ID字段,它与ACT_RE_DEPLOYMENT表相关联,所以ACT_RE_DEPLOYMENT和ACT_RE_PROCDEF表之间的关系实际上是一对一的关系,部署表中的一条记录对应于定义表中的一条记录.另外,表中还有一个CATEGORY_字段,代表流程的分类。请注意,这与部署的分类不同。流程部署的分类参数第二段代码,流程的分类,其实就是我们的流程定义XML文件中的targetNamespace属性,如下图所示:可以修改targetNamespace属性的值根据您的实际需要。值改变后,ACT_RE_PROCDEF表中的CATEGORY_字段也会相应改变。另外表中还有一个VERSION_字段,就是描述记录的版本号。当我们修改流程内容并重新部署时,ACT_RE_DEPLOYMENT表和ACT_RE_PROCDEF表会自动增加记录数。其中流程定义表ACT_RE_PROCDEF中记录的VERSION_字段的值会自动加1,这样我们就可以看到不同历史版本的流程定义。那么系统如何识别修改后的流程与之前的流程相同呢?主要看进程的id属性,如下图所示:这个进程的id属性对应表,就是ACT_RE_PROCDEF表的KEY_字段。ACT_GE_BYTEARRAY涉及的第三张表是一般数据存储表,该表的字段比较少,如下图:process部署记录对应ACT_GE_BYTEARRAY表中的两条记录,分别是recordXMLfile和recordprocesspicture。该表中有一个BYTES_字段。我们部署的流程的XML文件保存在这里。同时,系统会默认根据XML文件生成过程画面并保存在这里。图片是这样的:所以一个流程Deployment,这个表里面有两条记录,一条记录XML文件,一条记录流程图片。好了,流程部署涉及到的就是这三张表。4、查询操作接下来强烈建议大家在SpringBoot的application.properties中添加如下配置开启flowablelogging:logging.level.org.flowable=debug该配置表示开启flowablelogging。开启日志的好处是我们可以看到底层的SQL,学习flowable,在调用API的时候,不能只掌握API的使用。调用API的时候想一想你操作的是哪个表,这样可以学得更快。4.1查询部署信息比如我们现在要查询进程的部署信息,如下:@Testvoidtest01()throwsIOException{Listlist=repositoryService.createDeploymentQuery().list();for(Deploymentdeployment:list){logger.info("id:{};key:{}",deployment.getId(),deployment.getKey());}}创建一个查询,然后返回所有进程部署信息并打印出来,我们看这个IDEA控制台打印出SQL信息时:可以看到最底层执行的SQL其实是查询ACT_RE_DEPLOYMENT表。下面我们来看一些查询方法,应该很容易理解意思:朋友们可以看到我们可以使用流程部署的名称、类别、ID等各种信息进行查询,可以是精确匹配,也可以是模糊匹配.比如我想查询key为javaboyworkflowkey的流程部署文件,但是我之前多次部署过这个流程(版本升级),现在想查询最新的流程部署信息,查询方法如下如下:@Testvoidtest01()throwsIOException{Deploymentdeployment=repositoryService.createDeploymentQuery().deploymentKey("javaboy'sworkflowkey").latest().singleResult();logger.info("id:{};key:{}",deployment.getId(),deployment.getKey());}让我们看看控制台打印出来的SQL:---[main]i.p.e.D.selectDeploymentsByQueryCriteria:==>准备:SELECTRES.*fromACT_RE_DEPLOYMENTRESWHERERES.KEY_=?RES.DEPLOY_TIME_=(selectmax(DEPLOY_TIME_)fromACT_RE_DEPLOYMENTwhereKEY_=RES.KEY_andDERIVED_FROM_isnulland((TENANT_ID_ISNOTNULLandTENANT_ID_=RES.TENANT_ID_)or(TENANT_ID_ISNULLandRES.TENANT_L)_IS)orderbyRES.ID_asc---[main]i.p.e.D.selectDeploymentsByQueryCriteria:==>Parameters:javaboyworkflowkey(String)---[main]i.p.e.D.selectDeploymentsByQueryCriteria:<==Total:1这个SQL写的有点复杂,但是仔细看也就一个意思。给定查询的key是javaboy的workflowkey,查询时间是最大时间,很容易理解。4.2查询流程定义信息接下来我们来看查询流程定义信息。查询所有流程定义信息,如下:@Testvoidtest02(){Listlist=repositoryService.createProcessDefinitionQuery().list();for(ProcessDefinitionpd:list){logger.info("id:{};key:{};version:{};",pd.getId(),pd.getKey(),pd.getVersion());}}看一下控制台打印的SQL:可以看到,是到流程定义表ACT_RE_PROCDEF中去查看全部。基于此,其他查询API就很容易理解了。比如根据流程定义的KEY查询所有的流程定义。这个KEY其实就是流程定义XML文件中的id:@Testvoidtest02(){Listlist=repositoryService.createProcessDefinitionQuery().processDefinitionKey("javaboy_submit_an_expense_account").list();for(ProcessDefinitionpd:list){logger.info("id:{};key:{};version:{};",pd.getId(),pd.getKey(),pd.getVersion());}}再看查询SQL:其他的查询API我就不一一演示了,方法基本都知道了。4.3原生查询如果觉得使用API??查询还不够,我们也可以自己写SQL查询。和之前一样,比如我想查询key为javaboyworkflowkey的流程部署文件,但是我之前多次部署过这个流程(版本升级),现在想查询最新的流程部署信息,查询方法如下:@Testvoidtest03(){Deploymentdeployment=repositoryService.createNativeDeploymentQuery().sql("SELECTRES.*fromACT_RE_DEPLOYMENTRESWHERERES.KEY_=#{key}andRES.DEPLOY_TIME_=(selectmax(DEPLOY_TIME_)fromACT_RE_DEPLOYMENTwhereRESKEY_.KEY_)orderbyRES.ID_asc").parameter("key","javaboyworkflowkey").singleResult();logger.info("id:{};key:{}",deployment.getId(),deployment.getKey());}SQL自己写就行了,参数用#占位,因为底层这里的SQL操作其实就是MyBatis。同理,我想根据流程定义的KEY查询流程定义信息。原生查询方法如下:@Testvoidtest04(){Listlist=repositoryService.createNativeProcessDefinitionQuery().sql("SELECTRES.*fromACT_RE_PROCDEFRESWHERERES.KEY_=#{key}orderbyRES.ID_asc").parameter("key","javaboy_submit_an_expense_account").list();for(ProcessDefinitionpd:list){logger.info("id:{};key:{};version:{};",pd.getId(),pd.getKey(),pd.getVersion());}}好了,流程的部署和定义说了这么多,下篇我们来看流程示例吧~