Flowable入门

news2024/11/15 13:52:03

Flowable初体验

Flowable是什么

Flowable 是一个使用 Java 编写的轻量级业务流程引擎,常用于需要人工审批相关的业务,比如请假、报销、采购等业务。

为什么要使用工作流呢?

  • 对于复杂的业务流程,通过数据库的状态字段难以控制和维护,工作流引擎则更易于维护和拓展

  • 工作流的流程图更加直观,流程走到了哪里,一目了然

Flowable初体验

官网例子:Getting Started · Flowable Open Source Documentation

照着官网的例子做即可,都有详细的步骤。

SpringBoot整合Flowable

添加maven依赖

新建maven工程,pom.xml引入如下依赖:

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-spring-boot-starter</artifactId>
            <version>6.7.2</version>
        </dependency>
    </dependencies>

flowable默认使用H2数据库,这是一种内存型数据库,我们需要将数据持久化,这里使用的MySQL,SpringBoot版本则是使用2.7.5

配置信息

由于使用了flowable的starter,先看在spring.factories配置了哪些自动装配类:
在这里插入图片描述

可以看到,这里有个自动装配类:org.flowable.spring.boot.ProcessEngineAutoConfiguration

在这里插入图片描述

这里有很多Properties结尾的类,都是可以自定义的属性,以后再详细看。先看FlowableProperties这个类:

@ConfigurationProperties(
    prefix = "flowable"
)
public class FlowableProperties {
    private boolean checkProcessDefinitions = true;
    private boolean asyncExecutorActivate = true;
    private boolean asyncHistoryExecutorActivate = true;
    private boolean restApiEnabled;
    private String activityFontName = "Arial";
    private String labelFontName = "Arial";
    private String annotationFontName = "Arial";
    private String deploymentName = "SpringBootAutoDeployment";
    private String databaseSchemaUpdate = "true";
    private String databaseSchema;
    private boolean useLockForDatabaseSchemaUpdate = false;
    /** @deprecated */
    @Deprecated
    private boolean isDbIdentityUsed = true;
    private boolean isDbHistoryUsed = true;
    private HistoryLevel historyLevel;
    private String processDefinitionLocationPrefix;
    private List<String> processDefinitionLocationSuffixes;
    private boolean jpaEnabled;
    private List<String> customMybatisMappers;
    private List<String> customMybatisXMLMappers;
    protected boolean formFieldValidationEnabled;
    private Duration lockPollRate;
    private Duration schemaLockWaitTime;
    private boolean enableHistoryCleaning;
    private String historyCleaningCycle;
    @DurationUnit(ChronoUnit.DAYS)
    private Duration historyCleaningAfter;
    private int historyCleaningBatchSize;
    private boolean historyCleaningSequential;

    public FlowableProperties() {
        this.historyLevel = HistoryLevel.AUDIT;
        this.processDefinitionLocationPrefix = "classpath*:/processes/";
        this.processDefinitionLocationSuffixes = Arrays.asList("**.bpmn20.xml", "**.bpmn");
        this.jpaEnabled = true;
        this.formFieldValidationEnabled = false;
        this.lockPollRate = Duration.ofSeconds(10L);
        this.schemaLockWaitTime = Duration.ofMinutes(5L);
        this.enableHistoryCleaning = false;
        this.historyCleaningCycle = "0 0 1 * * ?";
        this.historyCleaningAfter = Duration.ofDays(365L);
        this.historyCleaningBatchSize = 100;
        this.historyCleaningSequential = false;
    }
}

这里有很多属性,先挑几个看一下:

  • checkProcessDefinitions:表示是否检查classpath*:/processes/目录下的流程定义。默认值为true,表示要检查,且会自动部署流程。若设置为false,则不会检查,也就相当于关闭了自动部署流程的功能。

  • asyncExecutorActivate:异步执行器是否开启,默认值为true,用于开启异步任务

  • processDefinitionLocationPrefix:流程定义所在位置的前缀,默认值为processDefinitionLocationPrefix,可以自定义为自己喜欢的目录。

  • processDefinitionLocationSuffixes:流程定义文件名后缀,默认支持.bpmn20.xml, .bpmn文件。

在application.yml文件中,添加配置信息,如果不添加,就使用默认配置:

server:
  port: 8888

spring:
  datasource:
    username: root
    password: root
    # nullCatalogMeansCurrent=true,加了这个参数才会自动生成表
    url: jdbc:mysql://localhost:3306/flowable_study?serverTimezone=Asia/Shanghai&useSSL=false&nullCatalogMeansCurrent=true

# flowable打印sql语句
logging:
  level:
    org.flowable.engine.impl.persistence.entity.*: debug
    org.flowable.task.service.impl.persistence.entity.*: debug

打印flowable的SQL语句,是为了方便分析调用的api底层做了什么。

表结构简单分析

启动SpringBoot项目,则会在数据库flowable_study中自动生成79张表:

其中:

  • APP 表示这都是跟应用程序相关的表。
  • CMMN 表示这都是跟 CMMN 协议相关的表。
  • CO(CONTENT)表示这都是跟内容引擎相关的表。
  • DMN 表示这都是跟 DMN 协议相关的表。
  • EVT(EVENT)表示这都是跟事件相关的表。
  • FO(FORM)表示这都是跟表单相关的表。
  • GE(GENERAL)表示这都是通用表,适用于各种用例的。
  • HI(HISTORY)这些是包含历史数据的表。当从运行时表中删除数据时,历史表仍然包含这些已完成实例的所有信息
  • ID(IDENTITY)表示这都是跟用户身份认证相关的表
  • PROCDEF(PROCESSDEFINE) 表示这都是跟记录流程定义相关的表。
  • RE(REPOSITORY)表示这都是跟流程的定义、流程的资源等等包含了静态信息相关的表。
  • RU(RUNTIME)代表运行时,这些是包含尚未完成的流程、案例等的运行时数据的运行时表。Flowable 仅在执行期间存储运行时数据,并在实例结束后删除记录,这使运行时表保持小而快
  • CHANNEL 表示这都是跟泳道相关的表。
  • EV 表示这个是跟 FLW_ 搭配的,在这里似乎并没有一个明确的含义,相关的表也都是跟 Liquibase 相关的。
  • EVENT 表示这都是跟事件相关的表。

暂时需要关注GE、RE、ID、RU、HI这5类相关的表。

流程部署

自动部署

根据配置信息部分的介绍,可以知道,flowable集成到SpringBoot后,SpringBoot程序启动时就会扫描resources/processes目录下后缀为.bpmn20.xml, .bpmn的流程文件,并且会自动部署。

手动部署

自动部署,不方便对流程进行修改,一旦修改,要重启应用,才会生效,很麻烦,而手动部署则可以解决此问题。手动部署,又分为两种情况:

  • 直接上传流程文件,进行部署

  • 通过前端流程设计流程模型,拿到流程资源,进行部署

上传流程文件

这个主要是写接口,便于通过接口进行部署更新:

    public String deployProcess(MultipartFile file){
        if (file == null){
            return "流程部署文件不能为空";
        }
        String deploymentId = null;
        try {
            Deployment deploy = repositoryService.createDeployment()
                    .addInputStream(file.getOriginalFilename(), file.getInputStream()).deploy();
            deploymentId = deploy.getId();
        } catch (IOException e) {
            System.out.println("流程部署失败");
            return "流程部署失败: " + e.getMessage();
        }
        return deploymentId;
    }

流程模型部署

对于当前前后端分离的开发模式,一般是前端通过模型设计器,设计好流程模型后,再进行部署:

    /**
     * 流程部署
     * @param modelId 模型id
     * @return
     */
    @PostMapping(value = "/deploy/{modelId}")
    public Result deploy(@PathVariable String modelId){
        Model model = repositoryService.getModel(modelId);
        // 获取model的xml内容
        byte[] source = repositoryService.getModelEditorSource(modelId);
        // 部署流程
        Deployment deployment = repositoryService.createDeployment()
                .name(model.getName())
                .key(model.getKey())
                .category(model.getCategory())
                .addBytes(model.getName() + ".bpmn", source)
                .deploy();
        return Result.ok("操作成功",deployment.getId());
    }

这里的思路,就是获取模型的流程图二进制资源,进行部署更新。

流程实例

流程定义部署之后,需要创建流程实例,才算是真正的发起了一个流程。流程定义和流程实例,可以类比类和对象的关系,流程定义可以看作是类,是对象的模板,而流程实例可以看作是对象。启动流程实例的几种方式:

  • org.flowable.engine.FormService#submitStartFormData

  • org.flowable.engine.RuntimeService#startProcessInstanceByKey

  • org.flowable.engine.RuntimeService#startProcessInstanceByKeyAndTenantId

  • org.flowable.engine.RuntimeService#startProcessInstanceById

  • org.flowable.engine.RuntimeService#startProcessInstanceWithForm

  • org.flowable.engine.RuntimeService#startProcessInstanceByMessage

  • org.flowable.engine.RuntimeService#startProcessInstanceByMessageAndTenantId

最常用的是org.flowable.engine.RuntimeService#startProcessInstanceByKey,这里的key,指的是流程xml文件里面的id:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qpcQncZM-1683429303847)(file://F:\学习笔记\工作流相关\images\流程定义key.png?msec=1683427681427)]

通过如下方法,启动流程:

在这里插入图片描述

流程启动后,便可以拿到流程实例。

流程变量

流程变量,分为以下三类:

  • 全局变量:会存入数据库,整个流程实例过程中,都可以使用

  • 局部变量:会存入数据库,针对某个Execution或Task有效,其他节点不可见

  • 瞬时变量:不存入数据库,目前我没用过

在流程实例没有结束之前,变量会被存入到表act_ru_variableact_hi_varinst中,流程结束后,只保留act_hi_varinst表中的记录,每个变量占一条记录。

下面主要看下,对于全局变量和局部变量,要怎样设置和使用:

全局变量

启动时设置

通过org.flowable.engine.RuntimeService#startProcessInstanceByXXX方法启动流程时,有一个可选参数,用于在流程实例创建及启动时设置变量,如:

在这里插入图片描述

运行时设置

  • org.flowable.engine.RuntimeService#setVariable

  • org.flowable.engine.TaskService#setVariable

局部变量

局部变量,在运行时设置,针对某个Execution或Task有效,其他节点不可见

  • org.flowable.engine.RuntimeService#setVariablesLocal

  • org.flowable.engine.TaskService#setVariablesLocal

变量的使用

流程变量,常用于:

  • 条件判断:如排他网关出线中使用变量,判断流程应该走哪条分支

  • 审批人(组)的占位:通过变量,可以达到动态设置审批人的效果

  • 事件监听器:使用Bean的名字

  • 多实例:使用变量或变量表达式

参考官网:The Flowable API · Flowable Open Source Documentation

流程任务

流程任务,包括系统服务任务、用户任务、脚本任务等,这里针对的是用户任务。

待签收任务

待签收的任务,就是待认领的任务:

  • 一个任务发给不同的人处理,任何一个人都可以抢办任务,即个人待签收任务

  • 一个任务发给同一个岗位处理的,只需要是这个岗位的其中一人处理即可,这种情况就是岗位待签收的任务

个人待签收

个人待签收任务,即当前用户可以认领的任务,认领(签收)完成之后,就变成了个人的待办任务了。查询个人待签收任务的方法如下:

taskService.createTaskQuery().taskCandidateUser(userId).list()

userId就是要查询的用户id,或者其他唯一标识符,一般通过id或者工号来标识。

如果想自定义sql查询,也是可以的:

SELECT
    RES.*
FROM
    ACT_RU_TASK RES
WHERE
    RES.ASSIGNEE_ IS NULL
AND EXISTS (
    SELECT
        LINK.ID_
    FROM
        ACT_RU_IDENTITYLINK LINK
    WHERE
        LINK.TYPE_ = 'candidate'
    AND LINK.TASK_ID_ = RES.ID_
    AND (LINK.USER_ID_ = ?)
)

api接口执行的结果,就是执行了上面的sql

岗位待签收

岗位,对于系统来说,可以认为是角色,也就是说,你可以认领这个角色下的任务,变成自己的待办任务,通过api接口查询:

taskService.createTaskQuery().taskCandidateGroupIn(Arrays.asList(roleArr)).list();

roleArr就是用户的角色id数组。

也可以通过sql查询:

SELECT
    RES.*
FROM
    ACT_RU_TASK RES
WHERE
    RES.ASSIGNEE_ IS NULL
AND EXISTS (
    SELECT
        LINK.ID_
    FROM
        ACT_RU_IDENTITYLINK LINK
    WHERE
        LINK.TYPE_ = 'candidate'
    AND LINK.TASK_ID_ = RES.ID_
    AND ((LINK.GROUP_ID_ IN(?, ?, ?)))
)

将个人待签收任务和岗位待签收任务合并,就是所有的待签收任务了。

可以通过api实现,也可以通过sql自己查询

api查询:

taskService.createTaskQuery().or().taskCandidateUser(userId).taskCandidateGroupIn(Arrays.asList(roleArr)).list()

sql查询:

SELECT
    RES.*
FROM
    ACT_RU_TASK RES
WHERE
    RES.ASSIGNEE_ IS NULL
AND EXISTS (
    SELECT
        LINK.ID_
    FROM
        ACT_RU_IDENTITYLINK LINK
    WHERE
        LINK.TYPE_ = 'candidate'
    AND LINK.TASK_ID_ = RES.ID_
    AND ((LINK.USER_ID_ = ?) OR (LINK.GROUP_ID_ IN(?, ?, ?)))
)

签收任务

签收任务就是认领任务,将待签收任务,变成待办任务

taskService.claim(taskId,userId);

也可以使用

taskService.setAssignee(taskId,userId);

两者的区别就是,如果该任务已经有人认领了:

  • taskService.claim会抛出异常,认领失败

  • taskService.setAssignee 不会抛出异常,userId成为新的任务办理人

退回已签收

当你后悔签收了任务,且没有处理任务之前,是可以退回已经签收的任务的

设置任务办理人为空即可

taskService.setAssignee(taskId, null);

这样就能将已签收的任务退回,其他人可进行签收处理。

待办任务

查询待办

待办任务,即流程的办理的人的任务。

也是两种方式:

  • 通过api查询
taskService.createTaskQuery().taskAssignee(userId).list()
  • 通过sql查询
SELECT
    RES.*
FROM
    ACT_RU_TASK RES
WHERE
    RES.ASSIGNEE_ = ?

完成待办

完成待办,就是完成自己的任务,驱动流程走向下一个节点

taskService.complete(taskId,variables);
  • taskId就是当前要完成的任务id

  • variables就是流程变量,类型是Map<String, Object>,一般需要传递一些变量,比如采购金额是多少,审批是否通过,设置下一个节点的审批人等信息

已办任务

查询已办

已办任务,一般通过查询历史数据来得到的,可以通过HistoryService来查询

historyService.createHistoricTaskInstanceQuery().finished().taskAssignee(userId).list()

当然,也可以自己写sql查询:

SELECT
    RES.*
FROM
    ACT_HI_TASKINST RES
WHERE
    RES.ASSIGNEE_ = ?
AND RES.END_TIME_ IS NOT NULL

这里的关键就是END_TIME_ 不为 NULL

任务转办与委派

任务转办

任务的转办,就是将任务交给另外一个人全权处理:

Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
// 设置原办理人是任务的委派人
taskService.setOwner(taskId,task.getAssignee());
// 设置任务新的办理者
taskService.setAssignee(taskId, targetUserId);

收到转办任务的人,通过下面的方式就可以完成任务:

taskService.complete(taskId)

任务委派

委派,就是给任务设置代理人,让他帮忙解决问题

Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
// 设置原办理人是任务的所有者
taskService.setOwner(taskId,task.getAssignee());
// 设置任务代理人
taskService.delegateTask(taskId,targetUserId);

代理人解决任务(而不是完成任务)

taskService.resolveTask(taskId)

转办与委派的区别

  • 任务委派只是委派人将当前的任务交给被委派人进行审批,解决 任务后又重新回到委派人身上。 为什么是解决呢?而不是完成,是因为当被委派人直接完成任务时,任务就不会回到委派人。

  • 任务转办就是把任务全权交给转办的人处理,不会回到原办理人。

参考链接:工作流操作-委派、转办_asarao的博客-CSDN博客

多实例任务

多实例任务,是指将任务分配给多个人处理,当满足给定的条件时,流程才会到下一个节点。根据处理任务顺序的差异,可分为:

  • 串行多实例:当上一个人处理了任务,下一个人才会接收到待办任务。例如:某个审批节点需要A、B、C三个人审批,可能的顺序是:A审批完成后,B才能接收到审批任务,B审批完成后,C才会接收到任务进行审批,依次进行。

  • 并行多实例:审批人可以同时进行审批,这就是并行。例如:某个审批节点需要A、B、C三个人审批,则A、B、C可以同时审批,不需要等其他人审批完成,就可以审批。

配置参数

  • collection(集合): 传入List参数,一般为用户ID集合

  • elementVariable(元素变量):List中单个参数的名称,自定义变量名称

  • loopCardinality(基数):循环次数

  • isSequential:是否串行

  • completionCondition(完成条件):任务出口条件

  • nrOfInstances:实例总数

  • nrOfCompletedInstances:已完成的实例个数

  • loopCounter:已经循环的次数

  • nrOfActiveInstances:未完成的实例个数

串行多实例

在流程设计里,将isSequential设置为true即可

<multiInstanceLoopCharacteristics isSequential="true">
 ...
</multiInstanceLoopCharacteristics>

图形上显示就就是三条水平的横线

在这里插入图片描述

并行多实例

在流程设计里,将isSequential设置为false即可

<multiInstanceLoopCharacteristics isSequential="false">
 ...
</multiInstanceLoopCharacteristics>

图形上显示就就是三条垂直的横线

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/498413.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软考信管高级——质量管理

质量管理内容 质量保证QA(过程符合要求/过程改进&#xff09; (1)按项目计划开展质量活动&#xff0c;使项目过程和产品符合质量要求&#xff0c;即按计划做质量&#xff1b; (2)提高项目干系人对项目将要满足质量要求的信心&#xff1b; (3)按过程改进计划进行过程改进&…

金兰组织 | 2023金兰解决方案集经营管理篇正式发布

为助力企业创新管理、提质增效&#xff0c;人大金仓携手金兰组织成员单位&#xff0c;于近期发布多项经营管理领域的联合解决方案&#xff0c;共享创新应用成果。 /人大金仓高级副总裁宋瑞/ 人大金仓高级副总裁宋瑞在致辞中表示&#xff1a;“联合解决方案创新是指通过把不同领…

利用谷歌云Pub/Sub 实现多任务并行分发处理方案

背景 目前老梁团队负责的Global Data Integration Platform每天有大量文件需要从来自不同地区的上游下载文件并进行处理后再发送到不同下游。老梁的数据集成平台集群有6个服务器节点&#xff0c;老梁希望所有机器的资源都能利用上&#xff0c;提升大量文件并行处理能力&#x…

C# Microsoft.ClearScript.V8脚本使用

1、ClearScript支持的功能和适用场景 微软的.net是非常强大和灵活的&#xff0c;除了C#体系脚本扩展&#xff0c;也支持其他流行的脚本扩展&#xff0c;Microsoft.ClearScript.V8就是一个.NET绑定到Google V8的脚本引擎。它允许.NET应用程序直接从JavaScript代码中调用函数&am…

Redis布隆过滤器的原理和应用场景,解决缓存穿透

目录 专栏导读一、布隆过滤器BloomFilter是什么二、布隆过滤器BloomFilter能干嘛?三、布隆过滤器使用场景1、解决缓存穿透问题2、黑名单3、网页爬虫对URL的去重,避免爬取相同的URL地址四、操作布隆过滤器BloomFilter1、使用布隆过滤器2、删除key3、判断是否存在五、代码实例1…

黑客开始使用双 DLL 侧载来逃避检测

一个名为“Dragon Breath”、“Golden Eye Dog”或“APT-Q-27”的 APT 黑客组织正在展示一种新趋势&#xff0c;即使用经典 DLL 旁加载技术的多种复杂变体来逃避检测。 这些攻击变体从一个初始向量开始&#xff0c;该向量利用一个干净的应用程序&#xff0c;最常见的是 Telegr…

vue_组件基础

单文件组件 Vue 单文件组件&#xff08;又名 *.vue 文件&#xff0c;缩写为 SFC&#xff09;是一种特殊的文件格式&#xff0c;它允许将 Vue 组件的模板、逻辑 与 样式封装在单个文件中 <template><h3>单文件组件</h3> </template><script> ex…

asp.net+c#操作系统课程在线教学平台

1&#xff0e;系统登录&#xff1a;系统登录是用户访问系统的路口&#xff0c;设计了系统登录界面&#xff0c;包括用户名、密码和验证码&#xff0c;然后对登录进来的用户判断身份信息&#xff0c;判断是管理员用户还是普通用户。 2&#xff0e;系统用户管理&#xff1a;不管是…

答疑解惑:开发者必须彻底搞懂的 SSL/TLS 协议

简介 本期答疑解惑将和大家一起认识SSL/TLS 协议。请尝试回答以下几个问题&#xff1a; 使用浏览器访问https网站和http网站有什么不同&#xff1f;SSL协议作用于网络模型的哪一层&#xff1f;你知道CSDN&#xff0c;博客园正在使用的是什么类型的SSL证书吗&#xff1f;SSL&a…

汇编实现LED循环点亮(延时子程序模板)

在单片机P2口外接8个发光二极管(低电平驱动)。试编写一个汇编程序&#xff0c;实现LED循环点亮功能:P2.0-P2.1-P2.2-P2.3-…-P2.7-P2.6-P25-…-P2.0的顺序&#xff0c;无限循环。要求采用软件延时方式控制闪烁时间间隔(约50ms)。 首先进行电路设计 电路原理图设计 利用 Prot…

php+vue影视电影视频点播推荐avxhe系统

影视推荐系统的主要使用者分为管理员和用户&#xff0c;实现功能包括管理员&#xff1a;首页、个人中心、用户管理、公告信息管理、电影分类管理、影视推荐管理、付费点播管理、点播信息管理、管理员管理、系统管理&#xff0c;用户&#xff1a;首页、个人中心、付费点播管理、…

数字化转型导师坚鹏:企业数字化领导力提升之道

企业数字化领导力提升之道 ——融合中西智慧&#xff0c;践行知行合一思想&#xff0c;实现知行果合一 课程背景&#xff1a; 很多企业存在以下问题&#xff1a; 不知道如何领导面临的数字化时代&#xff1f; 不清楚企业数字化领导力模型的内涵&#xff1f; 不知道如何…

开关电源基础02:基本开关电源拓扑(1)-BUCK拓扑

说在开头&#xff1a;关于海森堡的矩阵&#xff08;1&#xff09; 我们前面说了&#xff0c;海森堡和泡利到了哥本哈根跟着玻尔混&#xff0c;在哥本哈根海森堡感到了一种竞争的气氛&#xff1a;他在德国少年得志&#xff0c;是出了名的天才&#xff0c;现在突然发现身边的每一…

Python每日一练:圆桌争风吃醋的豚鼠韩信点兵(全一行代码解法)

文章目录 前言一、圆桌二、争风吃醋的豚鼠三、韩信点兵总结 前言 很显然&#xff0c;Python的受众远远大于C&#xff0c;其实笔者本人对Python的理解也是远强于C的&#xff0c;C纯粹是为了假装笔者是个职业选手才随便玩玩的&#xff0c;借着十多年前学的C的功底&#xff0c;强…

01、爬虫js逆向之-七麦数据

目标网址&#xff1a;aHR0cHM6Ly93d3cucWltYWkuY24vcmFuay9pbmRleC9icmFuZC9hbGwvZGV2aWNlL2lwaG9uZS9jb3VudHJ5L2NuL2dlbnJlLzM2 &#xff08;需要进行ba64解码即可获取到参数&#xff09; 需要逆向的加密参数&#xff1a;analysis 1、点击数据接口&#xff0c;触发请求 2、点…

2022年NOC大赛编程马拉松赛道复赛图形化低年级A卷-正式卷,包含答案

目录 选择题: 多选题: 编程题: 下载文档打印做题: 2022年NOC大赛编程马拉松赛道复赛图形化低年级A卷-正式卷 2022NOC-图形化复赛低年级A卷正式卷

天地气运流转,皆在五行生克中

在中国的传统文化里&#xff0c;常讲“气运”二字&#xff0c;把两字分开&#xff0c;便是气数与命运。 在现代人的观念里&#xff0c;气运是个复杂又抽象的概念。 天地五行之气轮流转&#xff0c;一切都在五行生克中。 而古人的方法&#xff0c;是通过五行的变化来描述气运的流…

Promise类方法

这篇主要讲一下Promise的类方法的基本使用&#xff0c;至于Promise的基本使用这里就不赘述了&#xff0c;之前也有手写过Promise、实现了Promise的核心逻辑。其实我们平时用Promise也挺多的&#xff0c;不过又出现了两个新的语法&#xff08;ES11&#xff0c;ES12新增了两个&am…

Gradle使用

下载Gradle Gradle Distributions 配置环境变量 测试是否成功 cmd输入gradle -v 在.gradle目录下创建一个init.gradle allprojects { repositories { maven { url file:///D:/maven/myRepository} ## 这里是本地maven仓库地址,没有就会依次向下设置的地址寻…

wisp5学习日记1

这里写目录标题 编译工程问题一 LSD-FET430UIF仿真器排针方向与所给排针方向示意图不一致&#xff0c;不知怎么方向问题2 拟器或仿真器无法找到连接到计算机的USB FET 编译工程 鼠标右键选择build project 问题一 LSD-FET430UIF仿真器排针方向与所给排针方向示意图不一致&…