Jenkins声明式Pipeline流水线语法示例

news2024/11/8 9:24:11

系列文章目录

docker搭建Jenkins2.346.3版本及常用工具集成配置(ldap、maven、ansible、npm等)
docker安装低版本的jenkins-2.346.3,在线安装对应版本插件失败的解决方法


文章目录

  • 系列文章目录
  • jenkins流水线基础
      • 1、pipeline
        • 1.1、什么是pipeline?
        • 1.2、为什么使用pipeline?
        • 1.3、pipeline定义
        • 1.4、jenkinsfile
        • 1.5、声明式pipeline示例
        • 1.6、参数解读
      • 2、声明式流水线语法
        • 2.1、pipeline语法-agent(代理)
        • 2.2、post
        • 2.3、stages(阶段)
        • 2.4、steps(步骤)
          • 2.4.1、script
        • 2.5、指令
          • 2.5.1、environment
          • 2.5.2、options
          • 2.5.3、参数
            • 参数构建化过程配置参数如下示例:
            • jenkinsfile中定义参数示例:
        • 2.6、触发器(trigger)
        • 2.7、tool
        • 2.8、input
        • 2.9、when
          • 内置条件
          • when使用示例
        • 2.10、parallel并行
  • 总结

jenkins流水线基础

首先,创建一个简单的流水线项目,体验并完成一条流水线项目的构建过程。如下图示
切记: 流水线的运行方式取决于定义的jenkinsfile

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1、pipeline

提前安装插件 Pipeline:Declarative
1.1、什么是pipeline?
1、pipeline是jenkins的核心功能,提供一组可扩展的工具
2、通过pipeline的DSL语法完成从简到难的交付流水线实现
3、jenkins的pipeline是通过jenkinsfile来实现的
4、这个文件可以定义jenkins的执行步骤,例如:代码拉取、代码检查等
1.2、为什么使用pipeline?
本质上,jenkins是一个自动化引擎,它支持许多自动模式。

流水线向Jenkins添加了一组强大的工具,支持用例、简单的持续集成到全面的持续交付流水线。 
通过对一系列的发布任务建立标准的模板,用户可以利用更多流水线的特性,比如:
	代码化: 流水线是在代码中实现的,通常会存放到源代码控制,使团队具有编辑、审查和更新他们项目的交付流水线的能力。
	耐用性: 流水线可以从Jenkins的master节点重启后继续运行。
	可暂停的: 流水线可以由人功输入或批准继续执行流水线。
	解决复杂发布: 支持复杂的交付流程。例如循环、并行执行。
	可扩展性: 支持扩展DSL和其他插件集成

在这里插入图片描述

1.3、pipeline定义
一条流水线通过Jenkinsfile描述
安装声明式插件Pipeline: Declarative
Jenkinsfile组成
	指定node节点/workspace
	指定指定运行选项
	指定stages阶段
	指定构建后操作
1.4、jenkinsfile
Jenkinsfile使用两种语法进行编写,分别是声明式和脚本式。
声明式和脚本式的流水线从根本上是不同的。
声明式是jenkins流水线更友好的特性。
脚本式的流水线语法,提供更丰富的语法特性。
声明式流水线使编写和读取流水线代码更容易设计。
声明式Pipeline: 使用agent指定运行的slave节点可以是label。
pipeline{
    agent any
    stages{
    //    
    }
}
脚本式Pipleine: 使用node指定运行slave可以是label
node("slave"){
    stage("GetCode"){
    //
    }
}
1.5、声明式pipeline示例
String workspace = "/home/vagrant/workspace" 

//Pipeline 
pipeline {
    agent { node { label "master"   //指定运行节点的标签或者名称
                     customWorkspace "${workspace}" //指定运行工作目录(可选)
            }
    }

    options { 
        timestamps()    //日志会有时间
        skipDefaultCheckout()  //删除隐式checkout scm 语句
        disableConcurrentBuilds()  //静止并行
        timeout(time: 1, unit: 'HOURS')  //流水线超时设置1h
    }

    stages { 
    //下载代码
        stage("GetCode"){   //阶段名称
            steps{   //名称
                timeout(time:5, unit:"MINUTES"){   //步骤超时时间
                    script{   //填写运行代码
                        println('获取代码') 
                    } 
                } 
            } 
        }
       //构建
        stage("Build"){ 
            steps{
                timeout(time:20, unit:"MINUTES"){ 
                    script{ 
                        println('应用打包')
                    }
                } 
            }
        }

        //代码扫描
        stage("CodeScan"){
            steps{ 
                timeout(time:30, unit:"MINUTES"){ 
                    script{ 
                        print('代码扫描')
                    } 
                }
            }
        }
    } 

    //构建后操作
    post {
        always { 
            script{ 
                println("always") 
            } 
        } 

        success {
            script{
                currentBuild.description += "\n 构建成功!" 
            } 
        }

        failure {
            script{ 
                currentBuild.description += "\n 构建失败!" 
            } 
        }

        aborted { 
            script{ 
                currentBuild.description += "\n 构建取消!" 
            } 
        } 
    } 
}
1.6、参数解读

Agent-Options

  • 指定node节点/workspace
  • 指定运行选项
  • 声明式Pipeline: 使用agent指定运行的slave节点可以是label
pipeline{
     agent { node { label "master"   //指定运行节点的标签或者名称
                     customWorkspace "${workspace}" //指定运行工作目录(可选)
            }
    }

    options { 
        timestamps()    //日志会有时间
        skipDefaultCheckout()  //删除隐式checkout scm 语句
        disableConcurrentBuilds()  //静止并行
        timeout(time: 1, unit: 'HOURS')  //流水线超时设置1h
    }

    
}

脚本式Pipleine: 使用node指定运行slave可以是label

node("slave"){
   options { 
        timestamps()    //日志会有时间
        skipDefaultCheckout()  //删除隐式checkout scm 语句
        disableConcurrentBuilds()  //静止并行
        timeout(time: 1, unit: 'HOURS')  //流水线超时设置1h
    }
}

Stages

  • stage定义了在整个流水线的执行任务的概念性的不同的阶段。例如: GetCodeBuildTestDeployCodeScan每个阶段。

  • 解释:上述示例添加了三个阶段

    • GetCode
    • Build
    • CodeScan
  • 声明式pipeline: 定义stages->stage

pipeline{
    agent any
    stages{
    stage("GetCode"){
        //steps  
    }

    stage("build"){
       //step
    }
  }
}
  • 脚本式Pipeline: 直接使用stage
node("slave"){
    stage("GetCode"){
    //
    }

    stage("build"){
    //
    }
}

step(步骤)

  • step是每个阶段中要执行的每个步骤。
  • 例如: 在执行GetCode的时候需要判断用户提供的参数srcType的值是Git还是svn
pipeline{
agent any
stages{
    stage("GetCode"){
        steps{ 
            sh "ls "    //step
            } 
        }    
    }
}
  • 脚本式Pipeline: 不需要step关键字。
node("slave"){
stage("GetCode"){
    //step
    if("${srcType}" == "Git"){
        //用git方式代码检出
    } else if ("${srcType}" == "SVN"){
        //用svn方式代码检出
    } else {
        error "srcType is not in [Git|SVN]"
    }
}
}

Post

  • 指定构建后操作
  • 解释:
    • always{}:总是执行脚本片段
    • success{}:成功后执行
    • failure{}:失败后执行
    • aborted{}:取消后执行
  • currendBuild是jenkins内部的全局变量
    • description:构建描述

2、声明式流水线语法

2.1、pipeline语法-agent(代理)
agent指定了流水线的执行节点
参数:
	any  在任何可以节点上执行pipeline
	none  没有指定agent的时候默认
	label 在指定标签的节点上执行pipeline
	node  允许额外的选项
语法示例一:
	agent {
		node {
			label 'labelname'
		}
	}
语法示例二:
	agent {
		label 'labelname'
	}
2.2、post
	定义一个或多个steps,这些阶段根据流水线或阶段的完成情况而运行(取决于流水线中post部分的位置),post支持以下post-condition块其中之一:always、changed、failure、success、unstable、aborted,这些条件块允许在post部分的步骤的执行取决于流水线阶段的完成状态。
	
always: 无论流水线或者阶段的完成状态。
changed: 只有当流水线或者阶段完成状态与之前不同时。
failure: 只有当流水线或者阶段状态为”failure”运行。
success: 只有当流水线或者阶段状态为”success”运行。
unstable: 只有当流水线或者阶段状态为”unstable”运行。例如:测试失败。
aborted: 只有当流水线或者阶段状态为”aborted “运行。例如:手动取消。
如下示例
pipeline {
agent any
stages {
    stage('Example') {
        steps {
            echo 'Hello World'
        }
    }
}
post { 
    always { 
        echo 'I will always say Hello again!'
    }
}
}
2.3、stages(阶段)
	包含一系列一个或多个stage指令,建议stages至少包含一个stage指令用于连续交付过程的每个离散部分,比如:构建、测试、部署等
pipeline {
    agent any
    stages { 
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
}
2.4、steps(步骤)
每个阶段要执行的步骤
	pipeline {
    agent any
    stages {
        stage('Example') {
            steps { 
                echo 'Hello World'
            }
        }
    }
}
2.4.1、script
	script 步骤需要 [scripted-pipeline]块并在声明式流水线中执行。
	对于大多数用例来说,应该声明式流水线中的“脚本”步骤是不必要的,但是它可以提供一个有用的”逃生出口”。非平凡的规模和/或复杂性的script块应该被转移到 共享库 。
pipeline {
    agent any
    stages {
        stage('Example') {
            steps {
                echo 'Hello World'

                script {
                    def browsers = ['chrome', 'firefox']
                    for (int i = 0; i < browsers.size(); ++i) {
                        echo "Testing the ${browsers[i]} browser"
                    }
                }
            }
        }
    }
}
2.5、指令
2.5.1、environment
	environment 指令指定一个键值对序列,也称为环境变量,该序列将被定义为所有步骤的环境变量,或者是特定于阶段的步骤,这取决于 environment 指令在流水线内的位置。
	该指令支持一个特殊的方法 credentials() ,该方法可用于在Jenkins环境中通过标识符访问预定义的凭证。对于类型为 “Secret Text”的凭证, credentials() 将确保指定的环境变量包含秘密文本内容。对于类型为 “SStandard username and password”的凭证, 指定的环境变量指定为 username:password ,并且两个额外的环境变量将被自动定义 :分别为 MYVARNAME_USR 和 MYVARNAME_PSW 。
pipeline {
    agent any
    environment { 
        CC = 'clang'
    }
    stages {
        stage('Example') {
            environment { 
                AN_ACCESS_KEY = credentials('my-prefined-secret-text') 
            }
            steps {
                sh 'printenv'
            }
        }
    }
}
2.5.2、options
	options 指令允许从流水线内部配置特定于流水线的选项。 
	流水线提供了许多这样的选项, 比如buildDiscarder,但也可以由插件提供, 比如 timestamps。
	buildDiscarder: 为最近的流水线运行的特定数量保存组件和控制台输出。
    disableConcurrentBuilds: 不允许同时执行流水线。 可被用来防止同时访问共享资源等。
    overrideIndexTriggers: 允许覆盖分支索引触发器的默认处理。
    skipDefaultCheckout: 在agent 指令中,跳过从源代码控制中检出代码的默认情况。
    skipStagesAfterUnstable: 一旦构建状态变得UNSTABLE,跳过该阶段。
    checkoutToSubdirectory: 在工作空间的子目录中自动地执行源代码控制检出。
    timeout: 设置流水线运行的超时时间, 在此之后,Jenkins将中止流水线。
    retry: 在失败时, 重新尝试整个流水线的指定次数。
    timestamps: 预测所有由流水线生成的控制台输出,与该流水线发出的时间一致。
//指定一个小时的全局执行超时, 在此之后,Jenkins将中止流水线运行。
pipeline {
agent any
options {
    timeout(time: 1, unit: 'HOURS') 
}
stages {
    stage('Example') {
        steps {
            echo 'Hello World'
        }
    }
}
}
2.5.3、参数

在这里插入图片描述

如上图所示,再上述位置配置的参数其实都可以再Jenkinsfile中定义实现
为流水线运行时设置项目相关的参数,参数定义的两种方法
	1、参数可以在这个参数化构建过程中定义,然后再Jenkinsfile中调用
	2、参数也可以再jenkinsfile中定义并使用参数
参数构建化过程配置参数如下示例:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

jenkinsfile中定义参数示例:

在这里插入图片描述

在这里插入图片描述

值得注意的是,当保存后再构建页面中是看不到新添加的参数,只有执行一次构建过程后,该页面才会有新添加的参数,如下所示

在这里插入图片描述

2.6、触发器(trigger)
定时去做某件事情时可以考虑使用,如下示例
  • cron 计划任务定期执行构建。

    triggers { cron('H */4 * * 1-5') }
    
  • pollSCM 与cron定义类似,但是由jenkins定期检测源码变化。

    triggers { pollSCM('H */4 * * 1-5') }
    
  • upstream 接受逗号分隔的工作字符串和阈值。 当字符串中的任何作业以最小阈值结束时,流水线被重新触发。

    triggers { upstream(upstreamProjects: 'job1,job2', threshold: hudson.model.Result.SUCCESS) }
    
pipeline {
agent any
triggers {
    cron('H */4 * * 1-5')
}
2.7、tool
	获取通过自动安装或手动放置工具的环境变量。支持maven/jdk/gradle。工具的名称必须在系统设置->全局工具配置中定义。
	使用示例如下: 在jenkinsfile中使用全局工具maven

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.8、input
input用户在执行各个阶段的时候,由人工确认是否继续进行。比较常用
    message 呈现给用户的提示信息。
    id 可选,默认为stage名称。
    ok 默认表单上的ok文本。
    submitter 可选的,以逗号分隔的用户列表或允许提交的外部组名。默认允许任何用户。
    submitterParameter 环境变量的可选名称。如果存在,用submitter 名称设置。
    parameters 提示提交者提供的一个可选的参数列表。
如下示例:
	1、使用流水线语法生成一个示例input
	2、将生成的input粘贴至pipeline
	3、执行构建,查看是否有提示

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.9、when
	when 指令允许流水线根据给定的条件决定是否应该执行阶段。 
	when 指令必须包含至少一个条件。 
	如果when 指令包含多个条件, 所有的子条件必须返回True,阶段才能执行。 
	这与子条件在 allOf 条件下嵌套的情况相同。
内置条件
  • branch: 当正在构建的分支与模式给定的分支匹配时,执行这个阶段,这只适用于多分支流水线例如:

    when { branch 'master' }
    
  • environment: 当指定的环境变量是给定的值时,执行这个步骤,例如:

    when { environment name: 'DEPLOY_TO', value: 'production' }
    
  • expression 当指定的Groovy表达式评估为true时,执行这个阶段, 例如:

    when { expression { return params.DEBUG_BUILD } }
    
  • not 当嵌套条件是错误时,执行这个阶段,必须包含一个条件,例如:

    when { not { branch 'master' } }
    
  • allOf 当所有的嵌套条件都正确时,执行这个阶段,必须包含至少一个条件,例如:

    when { allOf { branch 'master'; environment name: 'DEPLOY_TO', value: 'production' } }
    
  • anyOf 当至少有一个嵌套条件为真时,执行这个阶段,必须包含至少一个条件,例如:

    when { anyOf { branch 'master'; branch 'staging' } }
    
when使用示例
当参数test的值是123456时执行下载代码操作,即GetCode动作

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.10、parallel并行
	声明式流水线的阶段可以在他们内部声明多个嵌套阶段, 它们将并行执行。 
	注意,一个阶段必须只有一个 steps 或 parallel的阶段。 嵌套阶段本身不能包含 进一步的 parallel 阶段, 但是其他的阶段的行为与任何其他 stageparallel的阶段不能包含 agent 或 tools阶段, 因为他们没有相关 steps。
	另外, 通过添加 failFast true 到包含parallel的 stage中, 当其中一个进程失败时,你可以强制所有的 parallel 阶段都被终止
	
	如下示例:
		因为打包和扫描时间较长,将这两个操作添加到并行操作

在这里插入图片描述

总结

本篇文章主要针对常用的声明式Jenkinsfile流水线脚本的参数和框架做出了一个示例及简单的解释,因为平常接触和编写最多的就是声明式的流水线脚本。加油,开始练习写声明式流水线脚本吧,光看不练假把式~~~

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

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

相关文章

【NLP】使用 SpaCy、ollama 创建用于命名实体识别的合成数据集

命名实体识别 (NER) 是自然语言处理 (NLP) 中的一项重要任务&#xff0c;用于自动识别和分类文本中的实体&#xff0c;例如人物、位置、组织等。尽管它很重要&#xff0c;但手动注释大型数据集以进行 NER 既耗时又费钱。受本文 ( https://huggingface.co/blog/synthetic-data-s…

【数据集】【YOLO】【目标检测】道路裂缝数据集 5466 张,YOLO/VOC格式标注!

数据集介绍 【数据集】道路裂缝数据集 5466 张&#xff0c;目标检测&#xff0c;包含YOLO/VOC格式标注。数据集中包含一种分类&#xff0c;检测范围城市道路裂缝、高速道路裂缝、乡村道路裂缝。 戳我头像获取数据&#xff0c;或者主页私聊博主哈~ 一、数据概述 道路裂缝检测…

C++用string实现字符串相加

. - 力扣&#xff08;LeetCode&#xff09; -》》》》》题目链接 实现思路&#xff1a;计算数字符串长度并用数组的方式计算出字符位置&#xff0c;用字符的ask码‘0’计算出字符本身。 class Solution { public:string addStrings(string num1, string num2) {string str;int…

easyexcel实现自定义的策略类, 最后追加错误提示列, 自适应列宽,自动合并重复单元格, 美化表头

easyexcel实现自定义的策略类, 最后追加错误提示列, 自适应列宽,自动合并重复单元格, 美化表头 原版表头和表体字体美化自动拼接错误提示列自适应宽度自动合并单元格使用Easyexcel使用poi导出 在后台管理开发的工作中,离不开的就是导出excel了. 如果是简单的导出, 直接easyexce…

brainpy 动力学编程基础

文章参考&#xff1a; 《神经计算建模实战——基于brainpy》 吴思 【brainpy学习笔记】基础知识2(动力学模型的编程基础)-CSDN博客 Brainpy手册 文章目录 积分器&#xff1a;定义ODE函数数值积分方法 更新函数和动力系统计算介绍什么是brainpy.DynamicalSystem&#xff1f;如…

高级图像处理工具

图像处理-高级 1、功能概览 随着社交媒体的普及和个人创作需求的增长&#xff0c;图像处理成为了日常生活中不可或缺的一部分。无论是专业的设计师还是爱好者&#xff0c;都需要一款强大的工具来帮助他们完成各种任务。今天&#xff0c;我们将介绍一款基于Python开发的高级图…

【Zookeeper集群搭建】安装zookeeper、zookeeper集群配置、zookeeper启动与关闭、zookeeper的shell命令操作

目录 一、安装Zookeeper 二、配置Zookeeper集群 三、Zookeeper服务的启动与关闭 四、Zookeeper的shell操作 前情提要&#xff1a;延续上篇【Hadoop和Hbase集群配置】继续配置Zookeeper&#xff0c;开启三台虚拟机Hadoop1、Hadoop2、Hadoop3&#xff0c;进入终端&#xff0c…

Transformer和BERT的区别

Transformer和BERT的区别比较表&#xff1a; 两者的位置编码&#xff1a; 为什么要对位置进行编码&#xff1f; Attention提取特征的时候&#xff0c;可以获取全局每个词对之间的关系&#xff0c;但是并没有显式保留时序信息&#xff0c;或者说位置信息。就算打乱序列中token…

Python爬虫如何处理验证码与登录

Python爬虫如何处理验证码与登录 Python 爬虫在抓取需要登录的网站数据时&#xff0c;通常会遇到两个主要问题&#xff1a;登录验证和验证码处理。这些机制是网站用来防止自动化程序过度抓取数据的主要手段。本文将详细讲解如何使用 Python 处理登录与验证码&#xff0c;以便进…

《深入浅出Apache Spark》系列②:Spark SQL原理精髓全解析

导读&#xff1a;SQL 诞生于 20 世纪 70 年代&#xff0c;至今已有半个世纪。SQL 语言具有语法简单&#xff0c;低学习门槛等特点&#xff0c;诞生之后迅速普及与流行开来。由于 SQL 具有易学易用的特点&#xff0c;使得开发人员容易掌握&#xff0c;企业若能在其计算机软件中支…

JS实现,防抖节流 + 闭包

防抖&#xff08;Debounce&#xff09; 防抖是指短时间内大量触发同一事件&#xff0c;只会在最后一次事件完成后延迟执行一次函数。 防抖的典型应用场景是输入框的搜索建议功能&#xff0c;用户输入时不需要每次输入都去查询&#xff0c;而是在用户停止输入一段时间后才进行…

安卓编程最方便的读写资料类SharedPreferences,多个APP共享

本文介绍Android平台进行数据存储的五大方式,分别如下: 1 使用SharedPreferences存储数据 2 文件存储数据 3 SQLite数据库存储数据 4 使用ContentProvider存储数据 5 网络存储数据 下面详细讲解这五种方式的特点 第一种&#xff1a; 使用SharedPreferences存储数据 …

数据分析:转录组差异fgsea富集分析

文章目录 介绍加载R包数据链接导入数据数据预处理DE testing: 2BP vs no-BP比较limma-voomLoad steroid dataIn No-BP patientsIn 2BP patientsCompare gene expression vs bacterial mass其他系统信息介绍 转录组差异fgsea富集分析是一种基于基因集的富集分析方法,它关注的是…

Day13杨辉三角

给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 class Solution {public List<List<Integer>> generate(int numRows) {List<List<Integer>> res new Arra…

Avalonia11如何优雅的跨组件通信

背景&#xff1a; 官网只介绍了推荐适用ReactiveUI&#xff0c;没有过多的案例介绍&#xff0c;对于初入桌面应用开发的小白极其不友好。 本文介绍在Avalonia应用中通过ReactiveUI中的MessageBus进行跨组件通信. 假设需求案例&#xff1a; MainWindowViewModel中发送消息&a…

【开发实战】彻底了解 ThreadLocal

👉博主介绍: 博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家,WEB架构师,阿里云专家博主,华为云云享专家,51CTO 专家博主 ⛪️ 个人社区:个人社区 💞 个人主页:个人主页 🙉 专栏地址: ✅ Java 中级 🙉八股文专题:剑指大厂,手撕 J…

基于开源 AI 智能名片、S2B2C 商城小程序的用户获取成本优化分析

摘要&#xff1a;本文围绕用户获取成本&#xff08;CAC&#xff09;这一关键指标展开深入剖析&#xff0c;详细阐述其计算方式&#xff0c;并紧密结合开源 AI 智能名片与 S2B2C 商城小程序的独特性质&#xff0c;从多个维度探讨如何通过挖掘新的获客渠道、巧妙运用私域流量池等…

KV260 - PYNQ 主目录 - U盘挂载

目录 1. 简介 2. 具体操作 2.1 查看 USB 设备 2.2 查看 U 盘设备节点 2.3 挂载 U 盘到指定目录 2.4 查看挂载状态 2.5 卸载 U 盘 3. 总结 1. 简介 在 KV260 使用 Jupyter Lab 可以非常方便开发各种应用。有时不方便在 PC 端连接 U 盘&#xff0c;那么可以把 U 盘连在 …

金媒婚恋相亲系统10.4择爱开源旗舰版支持微信小程和抖音小程序上架

最近大家应该注意到了&#xff0c;金媒婚恋相亲系统已经更新至最新的10.4版本了&#xff01;本人作为商业用户也已经更新至最新的旗舰版了&#xff0c;更新的内容是啥&#xff01;这个官方都有列出&#xff0c;一个方面就是更新了多端的登录逻辑和UI 和后台CRM及很多细节的优化…

用环形数组实现队列(多种高级方法,由浅入深)

同普通数组实现的队列相比&#xff0c;普通数组的头结点和尾节点都是固定的&#xff0c;在进行移除的时候如果移除了一个节点&#xff0c;后面所有节点都需要进行移除操作&#xff0c;需要的时间复杂度更高 在环形数组中&#xff0c;确定了头尾指针的环形数组很好地解决了这一…