IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 一、activiti如何加载流程文件 -> 正文阅读

[Java知识库]一、activiti如何加载流程文件

activiti5.0与springboot集成

添加依赖

    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-spring-boot-starter-basic</artifactId>
        <version>5.22.0</version>
    </dependency>

添加配置,以yml文件为例,数据源为mysql

activiti:
  #关闭定时任务JOB
  async-executor-activate: false
  check-process-definitions: false
  database-schema-update: true

可能出现的问题

  • 报processes文件夹不存在,这个文件夹是放生成的bpmn文件的,可以在resources文件夹下新建processes或者指定bpmn的文件夹路径
process-definition-location-prefix: classpath*:/diagrams/
  • 报找不到表,activiti总共有23张表,在启动的时候会校验,我们可以拿脚本自己去跑,或者将配置文件中database-schema-update改为true
    这样启动依旧会报错,我们需要在mysql的连接后面加上nullCatalogMeansCurrent=true,配置如下
   jdbc-url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
&nullCatalogMeansCurrent=true
   username: root
   password: 123456
   driver-class-name: com.mysql.jdbc.Driver

activiti启动加载

加载activiti-spring-boot-starter-basic包下的spring.factories

    org.activiti.spring.boot.DataSourceProcessEngineAutoConfiguration,\
    org.activiti.spring.boot.EndpointAutoConfiguration,\
    org.activiti.spring.boot.RestApiAutoConfiguration,\
    org.activiti.spring.boot.JpaProcessEngineAutoConfiguration,\
    org.activiti.spring.boot.SecurityAutoConfiguration

DataSourceProcessEngineAutoConfiguration解析

  • 加载SpringProcessEngineConfiguration
   //ConditionalOnMissingBean的意思是只加载一个bean
   @Bean
   @ConditionalOnMissingBean
   public SpringProcessEngineConfiguration springProcessEngineConfiguration(
           DataSource dataSource,
           PlatformTransactionManager transactionManager,
           SpringAsyncExecutor springAsyncExecutor) throws IOException {
     
     return this.baseSpringProcessEngineConfiguration(dataSource, transactionManager, springAsyncExecutor);
   }
   //初始化配置
 protected SpringProcessEngineConfiguration baseSpringProcessEngineConfiguration(DataSource dataSource, PlatformTransactionManager platformTransactionManager,
                                                                                 SpringAsyncExecutor springAsyncExecutor) throws IOException {

   List<Resource> procDefResources = this.discoverProcessDefinitionResources(
       this.resourceLoader, this.activitiProperties.getProcessDefinitionLocationPrefix(),
       this.activitiProperties.getProcessDefinitionLocationSuffixes(),
       this.activitiProperties.isCheckProcessDefinitions());

   SpringProcessEngineConfiguration conf = super.processEngineConfigurationBean(
       procDefResources.toArray(new Resource[procDefResources.size()]), dataSource, 
       platformTransactionManager, springAsyncExecutor);

   conf.setDeploymentName(defaultText(activitiProperties.getDeploymentName(), conf.getDeploymentName()));
   conf.setDatabaseSchema(defaultText(activitiProperties.getDatabaseSchema(), conf.getDatabaseSchema()));
   conf.setDatabaseSchemaUpdate(defaultText(activitiProperties.getDatabaseSchemaUpdate(), conf.getDatabaseSchemaUpdate()));
   conf.setDbIdentityUsed(activitiProperties.isDbIdentityUsed());
   conf.setDbHistoryUsed(activitiProperties.isDbHistoryUsed());

   conf.setJobExecutorActivate(activitiProperties.isJobExecutorActivate());
   conf.setAsyncExecutorEnabled(activitiProperties.isAsyncExecutorEnabled());
   conf.setAsyncExecutorActivate(activitiProperties.isAsyncExecutorActivate());
   
   conf.setMailServerHost(activitiProperties.getMailServerHost());
   conf.setMailServerPort(activitiProperties.getMailServerPort());
   conf.setMailServerUsername(activitiProperties.getMailServerUserName());
   conf.setMailServerPassword(activitiProperties.getMailServerPassword());
   conf.setMailServerDefaultFrom(activitiProperties.getMailServerDefaultFrom());
   conf.setMailServerUseSSL(activitiProperties.isMailServerUseSsl());
   conf.setMailServerUseTLS(activitiProperties.isMailServerUseTls());

   conf.setHistoryLevel(activitiProperties.getHistoryLevel());

   if (activitiProperties.getCustomMybatisMappers() != null) {
     conf.setCustomMybatisMappers(getCustomMybatisMapperClasses(activitiProperties.getCustomMybatisMappers()));
   }

   if (activitiProperties.getCustomMybatisXMLMappers() != null) {
     conf.setCustomMybatisXMLMappers(new HashSet<String>(activitiProperties.getCustomMybatisXMLMappers()));
   }
   
   if (processEngineConfigurationConfigurer != null) {
   	processEngineConfigurationConfigurer.configure(conf);
   }

   return conf;
 }
  • DataSourceProcessEngineConfiguration的抽象类AbstractProcessEngineAutoConfiguration中有一段代码,表示在spring
    启动时会初始化ProcessEngineFactoryBean,而ProcessEngineFactoryBean是一个FactoryBean,所以在初始化之后会调用getObject方法来真正的加载bean
 @Bean
  public ProcessEngineFactoryBean processEngine(SpringProcessEngineConfiguration configuration) throws Exception {
    return super.springProcessEngineBean(configuration);
  }

getObject()方法代码如下,在这里会调用前面初始化的流程引擎,并调用buildProcessEngine方法

    public ProcessEngine getObject() throws Exception {
        configureExpressionManager();
        configureExternallyManagedTransactions();

        if (processEngineConfiguration.getBeans() == null) {
            processEngineConfiguration.setBeans(new SpringBeanFactoryProxyMap(applicationContext));
        }

        this.processEngine = processEngineConfiguration.buildProcessEngine();
        return this.processEngine;
    }
  • 接下来调用配置的buildProcessEngine方法
org.activiti.spring.SpringProcessEngineConfiguration
    public ProcessEngine buildProcessEngine() {
        //2.2.1调用父类的buildProcessEngine
        ProcessEngine processEngine = super.buildProcessEngine();
        ProcessEngines.setInitialized(true);
        //2.2.2自动发布资源
        autoDeployResources(processEngine);
        return processEngine;
    }

父类的buildProcessEngine

org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl
    public ProcessEngine buildProcessEngine() {
        this.init();
        return new ProcessEngineImpl(this);
    }
    //activiti的核心,初始化
  protected void init() {
  	initConfigurators();
  	configuratorsBeforeInit();
    initProcessDiagramGenerator();
    initHistoryLevel();
    initExpressionManager();
    initDataSource();
    initVariableTypes();
    initBeans();
    initFormEngines();
    initFormTypes();
    initScriptingEngines();
    initClock();
    initBusinessCalendarManager();
    initCommandContextFactory();
    initTransactionContextFactory();
    initCommandExecutors();
    initServices();
    initIdGenerator();
    initDeployers();
    initJobHandlers();
    initJobExecutor();
    initAsyncExecutor();
    initTransactionFactory();
    initSqlSessionFactory();
    initSessionFactories();
    initJpa();
    initDelegateInterceptor();
    initEventHandlers();
    initFailedJobCommandFactory();
    initEventDispatcher();
    initProcessValidator();
    initDatabaseEventLogging();
    configuratorsAfterInit();
  }

自动发布资源

    //这里判断配置的文件夹下是否有配置的bpmn或者xml文件,如果有,则发布资源,这里还用到了策略模式,总共有三种模式,spring默认的是DefaultAutoDeploymentStrategy
    protected void autoDeployResources(ProcessEngine processEngine) {
        if (deploymentResources != null && deploymentResources.length > 0) {
            final AutoDeploymentStrategy strategy = getAutoDeploymentStrategy(deploymentMode);
            strategy.deployResources(deploymentName, deploymentResources, processEngine.getRepositoryService());
        }
    }
    //走进DefaultAutoDeploymentStrategy的deployResources,这里没什么逻辑,就是获取文件流,然后统一调用deploy方法
    public void deployResources(final String deploymentNameHint, final Resource[] resources, final RepositoryService repositoryService) {

        // Create a single deployment for all resources using the name hint as the
        // literal name
         //通过enableDuplicateFiltering将isDuplicateFilterEnabled置为true,判断如果与表里最后一条记录的数据相同则不发布
        final DeploymentBuilder deploymentBuilder = repositoryService.createDeployment().enableDuplicateFiltering().name(deploymentNameHint);

        for (final Resource resource : resources) {
            final String resourceName = determineResourceName(resource);

            try {
                if (resourceName.endsWith(".bar") || resourceName.endsWith(".zip") || resourceName.endsWith(".jar")) {
                    deploymentBuilder.addZipInputStream(new ZipInputStream(resource.getInputStream()));
                } else {
                    deploymentBuilder.addInputStream(resourceName, resource.getInputStream());
                }
            } catch (IOException e) {
                throw new ActivitiException("couldn't auto deploy resource '" + resource + "': " + e.getMessage(), e);
            }
        }

        deploymentBuilder.deploy();

    }
    //走进DeploymentBuilder的deploy的方法,调用了repositoryService的deploy方法
    public Deployment deploy() {
        return repositoryService.deploy(this);
    }
    //repositoryService的deploy方法是熟悉的命令模式,我们可以知道主要逻辑就在DeployCmd的execute方法中
    public Deployment deploy(DeploymentBuilderImpl deploymentBuilder) {
        return commandExecutor.execute(new DeployCmd<Deployment>(deploymentBuilder));
    }
    public Deployment execute(CommandContext commandContext) {
        DeploymentEntity deployment = deploymentBuilder.getDeployment();
        
        deployment.setDeploymentTime(commandContext.getProcessEngineConfiguration().getClock().getCurrentTime());
        //这里isDuplicateFilterEnabled是true
        if ( deploymentBuilder.isDuplicateFilterEnabled() ) {
            
            List<Deployment> existingDeployments = new ArrayList<Deployment>();
             //跟租户相关的逻辑
          if (deployment.getTenantId() == null || ProcessEngineConfiguration.NO_TENANT_ID.equals(deployment.getTenantId())) {
            DeploymentEntity existingDeployment = commandContext
                     .getDeploymentEntityManager()
                     .findLatestDeploymentByName(deployment.getName());
            if (existingDeployment != null) {
                existingDeployments.add(existingDeployment);
            }
          } else {
            //没有租户则通过查询表ACT_RE_DEPLOYMENT来获取最后发布的数据
             List<Deployment> deploymentList = commandContext
                 .getProcessEngineConfiguration().getRepositoryService()
                 .createDeploymentQuery()
                 .deploymentName(deployment.getName())
                 .deploymentTenantId(deployment.getTenantId())
                 .orderByDeploymentId().desc().list();
             
             if (!deploymentList.isEmpty()) {
                 existingDeployments.addAll(deploymentList);
             }
          }
                
          DeploymentEntity existingDeployment = null;
          if(!existingDeployments.isEmpty()) {
            //这里还是只取existingDeployments中的第一条数据
            existingDeployment = (DeploymentEntity) existingDeployments.get(0);
          }
            //2.2.2.1重点,判断是否有改动,如果没有改动则直接返回
          if ( (existingDeployment!=null)
               && !deploymentsDiffer(deployment, existingDeployment)) {
            return existingDeployment;
          }
        }
        //如果判断文件流有改动,则发布
        deployment.setNew(true);

        // Save the data,在ACT_RE_DEPLOYMENT表中插入一条数据
        commandContext
          .getDeploymentEntityManager()
          .insertDeployment(deployment);
         //发布创建Entity事件
        if (commandContext.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
            commandContext.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
                    ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_CREATED, deployment));
        }
        
        // Deployment settings
        Map<String, Object> deploymentSettings = new HashMap<String, Object>();
        deploymentSettings.put(DeploymentSettings.IS_BPMN20_XSD_VALIDATION_ENABLED, deploymentBuilder.isBpmn20XsdValidationEnabled());
        deploymentSettings.put(DeploymentSettings.IS_PROCESS_VALIDATION_ENABLED, deploymentBuilder.isProcessValidationEnabled());
        
        // Actually deploy 
        // 2.2.2.2发布资源
        commandContext
          .getProcessEngineConfiguration()
          .getDeploymentManager()
          .deploy(deployment, deploymentSettings);
        
        if (deploymentBuilder.getProcessDefinitionsActivationDate() != null) {
          scheduleProcessDefinitionActivation(commandContext, deployment);
        }
        
        if (commandContext.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
            commandContext.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
                    ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_INITIALIZED, deployment));
        }
        
        return deployment;
    }
判断流程文件是否有改动
    protected boolean deploymentsDiffer(DeploymentEntity deployment, DeploymentEntity saved) {
        //调用getResources方法获取对应的资源,如果不为空,则进行比对
        if(deployment.getResources() == null || saved.getResources() == null) {
          return true;
        }
        
        Map<String, ResourceEntity> resources = deployment.getResources();
        Map<String, ResourceEntity> savedResources = saved.getResources();
        
        for (String resourceName: resources.keySet()) {
          ResourceEntity savedResource = savedResources.get(resourceName);
          
          if(savedResource == null) return true;
          
          if(!savedResource.isGenerated()) {
            ResourceEntity resource = resources.get(resourceName);
            
            byte[] bytes = resource.getBytes();
            byte[] savedBytes = savedResource.getBytes();
            if (!Arrays.equals(bytes, savedBytes)) {
              return true;
            }
          }
        }
        return false;
    }
    //看下getResources方法,就是根据传入的deployId来查询ACT_GE_BYTEARRAY表记录,然后构造map返回
    public Map<String, ResourceEntity> getResources() {
        if (resources==null && id!=null) {
          List<ResourceEntity> resourcesList = Context
            .getCommandContext()
            .getResourceEntityManager()
            .findResourcesByDeploymentId(id);
          resources = new HashMap<String, ResourceEntity>();
          for (ResourceEntity resource: resourcesList) {
            resources.put(resource.getName(), resource);
          }
        }
        return resources;
    }
发布资源文件
    public void deploy(DeploymentEntity deployment, Map<String, Object> deploymentSettings) {
    //deployers就只有一个BpmnDeployer,似乎还有另一个RulesDeployer?可以在其他地方再看看用法
        for (Deployer deployer: deployers) {
          deployer.deploy(deployment, deploymentSettings);
        }
      }
    //BpmnDeployer的deploy方法
    public void deploy(DeploymentEntity deployment, Map<String, Object> deploymentSettings) {
        log.debug("Processing deployment {}", deployment.getName());
        
        List<ProcessDefinitionEntity> processDefinitions = new ArrayList<ProcessDefinitionEntity>();
        Map<String, ResourceEntity> resources = deployment.getResources();
        Map<String, BpmnModel> bpmnModelMap = new HashMap<String, BpmnModel>();
        
        final ProcessEngineConfigurationImpl processEngineConfiguration = Context.getProcessEngineConfiguration();
        for (String resourceName : resources.keySet()) {
        
          log.info("Processing resource {}", resourceName);
          if (isBpmnResource(resourceName)) {
            ResourceEntity resource = resources.get(resourceName);
            byte[] bytes = resource.getBytes();
            ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
            //链式调用构建BpmnParse对象
            BpmnParse bpmnParse = bpmnParser
              .createParse()
              .sourceInputStream(inputStream)
              .setSourceSystemId(resourceName)
              .deployment(deployment)
              .name(resourceName);
            
            if (deploymentSettings != null) {
                
                // Schema validation if needed
                if (deploymentSettings.containsKey(DeploymentSettings.IS_BPMN20_XSD_VALIDATION_ENABLED)) {
                    bpmnParse.setValidateSchema((Boolean) deploymentSettings.get(DeploymentSettings.IS_BPMN20_XSD_VALIDATION_ENABLED));
                }
                
                // Process validation if needed
                if (deploymentSettings.containsKey(DeploymentSettings.IS_PROCESS_VALIDATION_ENABLED)) {
                    bpmnParse.setValidateProcess((Boolean) deploymentSettings.get(DeploymentSettings.IS_PROCESS_VALIDATION_ENABLED));
                }
                
            } else {
                // On redeploy, we assume it is validated at the first deploy
                bpmnParse.setValidateSchema(false);
                bpmnParse.setValidateProcess(false);
            }
            //校验bpmn文件
            bpmnParse.execute();
            
            for (ProcessDefinitionEntity processDefinition: bpmnParse.getProcessDefinitions()) {
              processDefinition.setResourceName(resourceName);
              //这里租户id是空字符串
              if (deployment.getTenantId() != null) {
                processDefinition.setTenantId(deployment.getTenantId()); // process definition inherits the tenant id
              }
              
              String diagramResourceName = getDiagramResourceForProcess(resourceName, processDefinition.getKey(), resources);
                       
              // Only generate the resource when deployment is new to prevent modification of deployment resources 
              // after the process-definition is actually deployed. Also to prevent resource-generation failure every
              // time the process definition is added to the deployment-cache when diagram-generation has failed the first time.
              if(deployment.isNew()) {
                if (processEngineConfiguration.isCreateDiagramOnDeploy() &&
                      diagramResourceName==null && processDefinition.isGraphicalNotationDefined()) {
                  try {
                      //生成图片流
                      byte[] diagramBytes = IoUtil.readInputStream(processEngineConfiguration.
                        getProcessDiagramGenerator().generateDiagram(bpmnParse.getBpmnModel(), "png", processEngineConfiguration.getActivityFontName(),
                            processEngineConfiguration.getLabelFontName(),processEngineConfiguration.getAnnotationFontName(), processEngineConfiguration.getClassLoader()), null);
                      diagramResourceName = getProcessImageResourceName(resourceName, processDefinition.getKey(), "png");
                      //保存ACT_GE_BYTEARRAY数据
                      createResource(diagramResourceName, diagramBytes, deployment);
                  } catch (Throwable t) { // if anything goes wrong, we don't store the image (the process will still be executable).
                    log.warn("Error while generating process diagram, image will not be stored in repository", t);
                  }
                } 
              }
              
              processDefinition.setDiagramResourceName(diagramResourceName);
              processDefinitions.add(processDefinition);
              bpmnModelMap.put(processDefinition.getKey(), bpmnParse.getBpmnModel());
            }
          }
        }
        
        // check if there are process definitions with the same process key to prevent database unique index violation
        List<String> keyList = new ArrayList<String>();
        for (ProcessDefinitionEntity processDefinition : processDefinitions) {
          if (keyList.contains(processDefinition.getKey())) {
            throw new ActivitiException("The deployment contains process definitions with the same key '"+ processDefinition.getKey() +"' (process id atrribute), this is not allowed");
          }
          keyList.add(processDefinition.getKey());
        }
        
        CommandContext commandContext = Context.getCommandContext();
        ProcessDefinitionEntityManager processDefinitionManager = commandContext.getProcessDefinitionEntityManager();
        DbSqlSession dbSqlSession = commandContext.getSession(DbSqlSession.class);
        for (ProcessDefinitionEntity processDefinition : processDefinitions) {
          List<TimerEntity> timers = new ArrayList<TimerEntity>();
          if (deployment.isNew()) {
            int processDefinitionVersion;
            //查询ACT_RE_PROCDEF
            ProcessDefinitionEntity latestProcessDefinition = null;
            if (processDefinition.getTenantId() != null && !ProcessEngineConfiguration.NO_TENANT_ID.equals(processDefinition.getTenantId())) {
                latestProcessDefinition = processDefinitionManager
                        .findLatestProcessDefinitionByKeyAndTenantId(processDefinition.getKey(), processDefinition.getTenantId());
            } else {
                latestProcessDefinition = processDefinitionManager
                        .findLatestProcessDefinitionByKey(processDefinition.getKey());
            }
            //增加版本号
            if (latestProcessDefinition != null) {
              processDefinitionVersion = latestProcessDefinition.getVersion() + 1;
            } else {
              processDefinitionVersion = 1;
            }
        
            processDefinition.setVersion(processDefinitionVersion);
            processDefinition.setDeploymentId(deployment.getId());
        
            String nextId = idGenerator.getNextId();
            String processDefinitionId = processDefinition.getKey() 
              + ":" + processDefinition.getVersion()
              + ":" + nextId; // ACT-505
                       
            // ACT-115: maximum id length is 64 charcaters
            if (processDefinitionId.length() > 64) {          
              processDefinitionId = nextId; 
            }
            processDefinition.setId(processDefinitionId);
            
            if(commandContext.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
                commandContext.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
                        ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_CREATED, processDefinition));
            }
        
            removeObsoleteTimers(processDefinition);
            addTimerDeclarations(processDefinition, timers);
            
            removeExistingMessageEventSubscriptions(processDefinition, latestProcessDefinition);
            addMessageEventSubscriptions(processDefinition);
            
            removeExistingSignalEventSubScription(processDefinition, latestProcessDefinition);
            addSignalEventSubscriptions(processDefinition);
            //插入表ACT_RE_PROCDEF
            dbSqlSession.insert(processDefinition);
            addAuthorizations(processDefinition);
        
            if(commandContext.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
                commandContext.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
                        ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_INITIALIZED, processDefinition));
            }
        
            scheduleTimers(timers);
        
          } else {
            String deploymentId = deployment.getId();
            processDefinition.setDeploymentId(deploymentId);
            
            ProcessDefinitionEntity persistedProcessDefinition = null; 
            if (processDefinition.getTenantId() == null || ProcessEngineConfiguration.NO_TENANT_ID.equals(processDefinition.getTenantId())) {
                persistedProcessDefinition = processDefinitionManager.findProcessDefinitionByDeploymentAndKey(deploymentId, processDefinition.getKey());
            } else {
                persistedProcessDefinition = processDefinitionManager.findProcessDefinitionByDeploymentAndKeyAndTenantId(deploymentId, processDefinition.getKey(), processDefinition.getTenantId());
            }
            
            if (persistedProcessDefinition != null) {
                processDefinition.setId(persistedProcessDefinition.getId());
                processDefinition.setVersion(persistedProcessDefinition.getVersion());
                processDefinition.setSuspensionState(persistedProcessDefinition.getSuspensionState());
            }
          }
        
          // Add to cache
          DeploymentManager deploymentManager = processEngineConfiguration.getDeploymentManager();
          deploymentManager.getProcessDefinitionCache().add(processDefinition.getId(), processDefinition);
          addDefinitionInfoToCache(processDefinition, processEngineConfiguration, commandContext);
          
          // Add to deployment for further usage
          deployment.addDeployedArtifact(processDefinition);
          
          createLocalizationValues(processDefinition.getId(), bpmnModelMap.get(processDefinition.getKey()).getProcessById(processDefinition.getKey()));
        }
    }

总结

  • spring启动时会加载流程引擎类并调用buildProcessEngine方法
  • 发布时会拿文件夹下的所有文件与表中的byte数组逐个对比,有一个不一样则全量发布
  • 发布时会记录
    act_re_deployment:本次发布的信息,
    act_ge_bytearray:本次发布的文件流包括bpmn文件及生成的图片流,
    act_re_procdef:记录发布的路径及版本号信息
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-11-09 19:20:29  更:2021-11-09 19:23:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:12:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码