DevOps持续集成-Jenkins(4)

news2024/11/16 17:59:57

❤️作者简介:2022新星计划第三季云原生与云计算赛道Top5🏅、华为云享专家🏅、云原生领域潜力新星🏅

💛博客首页:C站个人主页🌞

💗作者目的:如有错误请指正,将来会不断的完善笔记,帮助更多的Java爱好者入门,共同进步!

文章目录

    • DevOps
      • DevOps概述
      • Jenkins流水线任务入门⭐
        • Jenkins流水线任务的Hello World体验⭐
        • Jenkins流水线语法例子
        • Jenkins流水线语法生成器⭐
      • Jenkins实战4:构建pipeline(流水线)的Jenkins项目⭐
        • 项目架构图
        • Jenkins实战4的初步流水线模板(功能全部都未实现)⭐
        • Jenkinsfile配置⭐
          • 在项目中编写Jenkinsfile来维护pipeline模板(以后我们的pipeline语法都放在这个文件上)⭐
          • 在Jenkins中配置Jenkinsfile在gitlab上的地址⭐
          • 测试构建,看看Jenkinsfile是否能生效
        • 架构图第2步案例:将gitlab上面的项目代码拉取到Jenkins中⭐
        • 架构图第3步案例:利用Maven构建项目的jar包⭐
        • 架构图第4步案例:给Jenkins的pipeline任务配置SonarQube自动进行代码质量检测⭐
        • 架构图第5步案例:Jenkins制作自定义镜像并上传到Harbor⭐
        • 架构图第6-7步案例:通知目标服务器可以从Harbor上拉取镜像,并运行容器(注意:这里有个坑!)⭐
        • Jenkins流水线整合钉钉:在构建完成后通知信息(新增⭐)
          • 下载安装钉钉,并且注册账号(电脑版和手机版都行)⭐
          • 在Jenkins中下载钉钉插件(DingTalk 2.4.7版本)⭐
          • 在钉钉创建一个企业(不然无法申请项目群)⭐
          • 在钉钉创建一个新的项目群⭐
          • 在钉钉的项目群里创建一个机器人⭐
          • 在Jenkins中配置这个机器人⭐
          • Jenkinsfile配置钉钉⭐
        • 实战4的Jenkinsfile全部代码⭐

DevOps

DevOps概述

软件开发最初是由两个团队共同组成:(没有采用DevOps之前)

  • 开发团队:从头开始设计和整体系统的构建(编写代码)。需要系统不停的迭代更新。
  • 运维团队:将开发团队的代码进行测试通过后再部署上线。确保系统稳定运行。

没有采用DevOps的缺点:

  • 这看似两个目标不同的团队需要协同完成一个软件的开发。在开发团队指定好计划并完成编写代码后,需要把代码交给运维团队。运维团队向开发团队反馈需要修复的BUG以及一些需要返工的任务。这时开发团队需要经常等待运维团队的反馈。这无疑会延长整个软件开发的周期。

采用DevOps的优点?

  • DevOps的方式可以让公司能够更快地应对更新和市场发展变化,开发可以快速交付,部署也更加稳定。核心就在于简化Dev和Ops团队之间的流程,使整体软件开发过程更快速。说白了就是DevOps有利于快速完成项目,不会浪费时间)

整体的软件开发流程:

  • PLAN:开发团队根据客户的目标制定开发计划
  • CODE:根据PLAN开始编码过程,需要将不同版本的代码存储在一个库中。
  • BUILD:编码完成后,需要将代码构建并且运行。
  • TEST:成功构建项目后,需要测试代码是否存在BUG或错误。
  • DEPLOY:代码经过手动测试和自动化测试后,认定代码已经准备好部署并且交给运维团队。
  • OPERATE:运维团队将代码部署到生产环境中。
  • MONITOR:项目部署上线后,需要持续的监控产品。
  • INTEGRATE:然后将监控阶段收到的反馈发送回PLAN阶段,整体反复的流程就是DevOps的核心即持续集成、持续部署。

为了保证整体流程可以高效的完成,各个阶段都有比较常见的工具,如下图:

Jenkins流水线任务入门⭐

Jenkins流水线任务的Hello World体验⭐

在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

Jenkins流水线语法例子
// 所有脚本命令包含在pipeline{}中
pipeline {  
	// 指定任务在哪个Jenkins集群节点中执行(Jenkins是支持分布式)
	// 这里的agent any是指该任务可以在任何Jenkins集群节点上执行。
    agent any
    
    // 声明全局变量,格式为:key='value'
    environment{
    	host = '192.168.184.80'
    }

    // 存放所有任务的合集
    stages {
    	// 单个任务1
        stage('任务1') {
        	// 实现任务的具体流程
            steps {
                echo '做任务1'
            }
        }
		// 单个任务2
        stage('任务2') {
        	// 实现任务的具体流程
            steps {
                echo '做任务2'
            }
        }
        // 单个任务3
        stage('任务3') {
        	// 实现任务的具体流程
            steps {
                echo '做任务3'
            }
        }
        
        
        
    }
}
Jenkins流水线语法生成器⭐

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

Jenkins实战4:构建pipeline(流水线)的Jenkins项目⭐

项目架构图

在这里插入图片描述

Jenkins实战4的初步流水线模板(功能全部都未实现)⭐
pipeline {
    agent any

    // 存放所有任务的集合
    stages {
        stage('拉取Git仓库代码') {
            steps {
                echo '拉取Git仓库代码 - SUCCESS'
            }
        }
        
        stage('通过maven构建项目') {
            steps {
                echo '通过maven构建项目 - SUCCESS'
            }
        }
        
        stage('通过SonarQube做代码质量检测') {
            steps {
                echo '通过SonarQube做代码质量检测 - SUCCESS'
            }
        }

        stage('通过Docker制作自定义镜像') {
            steps {
                echo '通过Docker制作自定义镜像 - SUCCESS'
            }
        }

        stage('将自定义镜像推送到Harbor仓库') {
            steps {
                echo '将自定义镜像推送到Harbor仓库 - SUCCESS'
            }
        }

        stage('通过Publish Over SSH通知目标服务器') {
            steps {
                echo '通过Publish Over SSH通知目标服务器 - SUCCESS'
            }
        }
    }
}
Jenkinsfile配置⭐
在项目中编写Jenkinsfile来维护pipeline模板(以后我们的pipeline语法都放在这个文件上)⭐
  • 注意:该文件名一定要为:Jenkinsfile
  • Jenkinsfile文件内容放在了上面,可以直接复制!

在这里插入图片描述

在Jenkins中配置Jenkinsfile在gitlab上的地址⭐

在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

测试构建,看看Jenkinsfile是否能生效

在这里插入图片描述

架构图第2步案例:将gitlab上面的项目代码拉取到Jenkins中⭐
  • 1:配置git参数:(根据tag去拉取代码)
    在这里插入图片描述在这里插入图片描述在这里插入图片描述

  • 2:生成拉取git代码的流水线语法:

    • 生成的语法代码块如下:(注意:下面有个地方(branches的name从原来是/main被我改成了${tag},如果安装默认生成的话,则是拉取最新版本代码,我们这个意思就是安装tag去拉取对应代码)和系统生成的语法不一样!!)*
    checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'http://192.168.184.70:8929/root/mytest.git']]])
    

在这里插入图片描述在这里插入图片描述

  • 3:把生成的pipeline语法放到Jenkinsfile文件的指定位置:

在这里插入图片描述

  • 4:测试构建:

在这里插入图片描述

架构图第3步案例:利用Maven构建项目的jar包⭐
  • 1:生成流水线语法:(生成如下)
    • 注意:/var/jenkins_home/maven/bin/mvn要改成你的maven的mvn地址。
sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTests'

在这里插入图片描述

  • 2:将上面生成的语法放到Jenkinsfile的对应位置上去,然后上传到gitlab即可。(省略!)
架构图第4步案例:给Jenkins的pipeline任务配置SonarQube自动进行代码质量检测⭐
  • 1:生成流水线语法:(生成如下)
    • 注意:下面的-Dsonar.login要用自己的SonarQube的token
    • 注意:/var/jenkins_home/sonar-scanner/bin/sonar-scanner要改成你的sonar-scanner地址
sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=./target/ -Dsonar.login=7ad2200f7cca90c37a909fdba8db049ac700909f'

在这里插入图片描述

  • 2:将上面生成的语法放到Jenkinsfile的对应位置上去,然后上传到gitlab即可。(省略!)
架构图第5步案例:Jenkins制作自定义镜像并上传到Harbor⭐
  • 1:生成制作自定义镜像的流水线语法(生成如下):
sh '''mv ./target/*.jar ./docker/
docker build -t ${JOB_NAME}:${tag} ./docker/'''

在这里插入图片描述

  • 2:在Jenkinsfile文件定义全局变量environment:(记得要把下面的内容改成你自己的!)
    • harborAddress是harbor地址
    • harborRepo是harbor仓库名
    • harborUser是harbor账号
    • harborPasswd是Harbor密码
    environment{
        harborAddress = '192.168.184.80:80'
        harborRepo = 'repo'
        harborUser = 'admin'
        harborPasswd = 'Harbor12345'
    }
  • 3:生成将镜像上传到Harbor仓库的流水线语法(生成如下):
sh '''docker login -u ${harborUser} -p ${harborPasswd} ${harborAddress}
docker tag ${JOB_NAME}:${tag} ${harborAddress}/${harborRepo}/${JOB_NAME}:${tag}
docker push ${harborAddress}/${harborRepo}/${JOB_NAME}:${tag}'''

在这里插入图片描述

  • 4:防止Jenkins内部不能使用Docker,所以重新设置一下权限:(有时候即使设置了权限也会自动变回来,导致pipeline报错)

    • 切换目录到/var/run/:
    [root@centos7-jenkins harbor]# cd /var/run/
    
    • 修改docker.sock文件的所属组:
    [root@centos7-jenkins run]# chown root:root docker.sock
    
    • 修改docker.sock文件的权限:
    [root@centos7-jenkins run]# chmod o+rw docker.sock
    
  • 5:将上面生成的语法放到Jenkinsfile的对应位置上去,然后上传到gitlab即可。

在这里插入图片描述在这里插入图片描述

  • 6:执行构建即可。
  • 7:进入Harbor可视化界面,查看pipeline镜像是否push成功:

在这里插入图片描述

架构图第6-7步案例:通知目标服务器可以从Harbor上拉取镜像,并运行容器(注意:这里有个坑!)⭐
  • 1:在所有目标服务器上都放一份shell脚本文件:(原理是:Jenkins通知目标服务器去执行shell脚本文件,从而让目标服务器在Harbor上面拉取指定镜像。)
    • 原来的架构图上是把Dockerfile传到目标服务器,让目标服务器通过docker build构建镜像(缺点是当目标服务器有多台,那每一台目标服务器都需要build构建一次,n台服务器就是n次,这样十分浪费服务器资源)。
    • 现在的架构图是把镜像在Jenkins容器内构建,然后把镜像push到Harbor上,Jenkins通知所有目标服务器(不管有多少台),然后目标服务器就会执行下面的shell脚本,会从Harbor拉取指定镜像,这样一来,不管有多少台目标服务器都只是build构建一次,节省了很多资源。
vi /root/deploy.sh

内容如下:

harbor_addr=$1
harbor_repo=$2
project=$3
version=$4
host_port=$5
container_port=$6

imageName=$harbor_addr/$harbor_repo/$project:$version

containerId=`docker ps -a | grep ${project} | awk '{print $1}'`
if [ "$containerId" != "" ] ; then
    docker stop $containerId
    docker rm $containerId
fi

tag=`docker images | grep ${project} | awk '{print $2}'`

if [[ "$tag" =~ "$version" ]] ; then
    docker rmi -f $imageName
fi

docker login -u admin -p Harbor12345 $harbor_addr

docker pull $imageName

docker run -d -p $host_port:$container_port --name $project $imageName

echo "SUCCESS"
  • 2:给deploy.sh权限:
chmod a+x /root/deploy.sh
  • 3:把所有目标服务器的deploy.sh都放到/usr/bin下:
[root@centos7-jenkins ~]# mv /root/deploy.sh /usr/bin/
  • 4:配置Jenkins参数:

在这里插入图片描述在这里插入图片描述在这里插入图片描述

  • 5:生成流水线语法:

    • 提示Exec command:
    deploy.sh $harborAddress $harborRepo $JOB_NAME $tag $host_port $container_port
    

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 6:将生成的语法放到Jenkinsfile的对应位置上去,然后上传到gitlab即可。(⭐注意这里有个坑!⭐)

    • 坑坑坑!!!:sshPublisher的execCommand要用双引号,默认是单引号。(一定要改成双引号,否则语法无法生效!⭐)

    ⭐下面的是修改之后的,并且是测试通过的流水线语法!!:

sshPublisher(publishers: [sshPublisherDesc(configName: 'mytest', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "deploy.sh $harborAddress $harborRepo $JOB_NAME $tag $host_port $container_port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
  • 7:最后测试构建即可(省略!)
Jenkins流水线整合钉钉:在构建完成后通知信息(新增⭐)
下载安装钉钉,并且注册账号(电脑版和手机版都行)⭐

钉钉下载官网

在Jenkins中下载钉钉插件(DingTalk 2.4.7版本)⭐

在这里插入图片描述

在钉钉创建一个企业(不然无法申请项目群)⭐

在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述

在钉钉创建一个新的项目群⭐

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在钉钉的项目群里创建一个机器人⭐

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述

在这里插入图片描述

在Jenkins中配置这个机器人⭐

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Jenkinsfile配置钉钉⭐
  • 1:编写流水线语法:
    • 注意:robot的值就是我们在Jenkins的系统配置所设置的机器人id!!(一定要进行修改)
post {
        success {
            dingtalk (
                robot: 'Jenkins-dingding',
                type:'MARKDOWN',
                title: "success: ${JOB_NAME}",
                text: ["- 成功构建:${JOB_NAME}项目!\n- 版本:${tag}\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"]
            )
        }
        failure {
            dingtalk (
                robot: 'Jenkins-dingding',
                type:'MARKDOWN',
                title: "fail: ${JOB_NAME}",
                text: ["- 失败构建:${JOB_NAME}项目!\n- 版本:${tag}\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"]
            )
        }
    }
  • 2:将上面的语法放到Jenkinsfile的stages外面,并上传gitlab:

在这里插入图片描述

  • 3:点击构建Jenkins

在这里插入图片描述

  • 4:查看钉钉项目群:

在这里插入图片描述

实战4的Jenkinsfile全部代码⭐
pipeline {
    agent any

    environment{
        harborAddress = '192.168.184.80:80'
        harborRepo = 'repo'
        harborUser = 'admin'
        harborPasswd = 'Harbor12345'
    }
    // 存放所有任务的集合
    stages {
        stage('拉取Git仓库代码') {
            steps {
               checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'http://192.168.184.70:8929/root/mytest.git']]])
            }
        }

        stage('通过maven构建项目') {
            steps {
                sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTests'
            }
        }

        stage('通过SonarQube做代码质量检测') {
            steps {
                sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=./target/ -Dsonar.login=7ad2200f7cca90c37a909fdba8db049ac700909f'
            }
        }

        stage('通过Docker制作自定义镜像') {
            steps {
                sh '''mv ./target/*.jar ./docker/
                docker build -t ${JOB_NAME}:${tag} ./docker/'''
            }
        }

        stage('将自定义镜像推送到Harbor仓库') {
            steps {
                sh '''docker login -u ${harborUser} -p ${harborPasswd} ${harborAddress}
                docker tag ${JOB_NAME}:${tag} ${harborAddress}/${harborRepo}/${JOB_NAME}:${tag}
                docker push ${harborAddress}/${harborRepo}/${JOB_NAME}:${tag}'''
            }
        }

        stage('通过Publish Over SSH通知目标服务器') {
            steps {
            sshPublisher(publishers: [sshPublisherDesc(configName: 'mytest', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "deploy.sh $harborAddress $harborRepo $JOB_NAME $tag $host_port $container_port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
            }
        }
    }

    post {
            success {
                dingtalk (
                    robot: 'Jenkins-dingding',
                    type:'MARKDOWN',
                    title: "success: ${JOB_NAME}",
                    text: ["- 成功构建:${JOB_NAME}项目!\n- 版本:${tag}\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"]
                )
            }
            failure {
                dingtalk (
                    robot: 'Jenkins-dingding',
                    type:'MARKDOWN',
                    title: "fail: ${JOB_NAME}",
                    text: ["- 失败构建:${JOB_NAME}项目!\n- 版本:${tag}\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"]
                )
            }
        }

}

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

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

相关文章

【Android Studio】工程中文件Annotate with Git Blame 不能点击

问题描述 工程文件中想要查看代码提交信息但是相关按钮不可点击 解决方法 Android Studio -> Preferences -> Version Control-> 在Unregistered roots里找到你想要的工程文件 点击左上角➕号 然后右下角Apply即可

扩展 Calcite 中的 SQL 解析语法

Calcite中 JavaCC 的使用方法 Calcite 默认采用 JavaCC 来生成词法分析器和语法分析器。 1)使用 JavaCC 解析器 Calcite中,JavaCC 的依赖已经被封装到 calcite-core 模块当中,如果使用 Maven 作为依赖管理工具,只需要添加对应的…

PCL 视图变换(OpenGL)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 在OpenGL中存在这样一个过程,即模拟人类看东西的过程,通过一种视图变换方式将物体置入观察空间内,以此让我们可以看到这个物体。这个过程有点类似于将一个照相机移到了模型前方的某个位置,然后再设置一下照相机…

【广州华锐互动】VR消防员模拟灭火:身临其境的火场救援

随着科技的不断发展,虚拟现实(VR)技术已经逐渐渗透到各个领域,为我们带来了前所未有的沉浸式体验。在这其中,VR模拟消防员灭火体验无疑是一种极具创新性和实用性的应用。通过这项技术,人们可以亲身体验到消…

RabbitMQ原理(五):消费者的可靠性

文章目录 3.消费者的可靠性3.1.消费者确认机制3.2.失败重试机制3.3.失败处理策略3.4.业务幂等性3.4.1.唯一消息ID3.4.2.业务判断 3.5.兜底方案 3.消费者的可靠性 当RabbitMQ向消费者投递消息以后,需要知道消费者的处理状态如何。因为消息投递给消费者并不代表就一定…

STM32 invalid UTF-8 in comment 警告解决办法

这里写自定义目录标题 STM32 invalid UTF-8 in comment 警告解决办法问题描述解决办法 STM32 invalid UTF-8 in comment 警告解决办法 问题描述 …/…/libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x\stm32f10x.h(18): warning: invalid UTF-8 in comment [-Winvalid-utf8]…

正点原子嵌入式linux驱动开发——Linux PWM驱动

PWM是很常用到功能,可以通过PWM来控制电机速度,也可以使用PWM来控制LCD的背光亮度。本章就来学习一下如何在Linux下进行PWM驱动开发。 PWM驱动解析 不在介绍PWM是什么了,直接进入使用。 给LCD的背光引脚输入一个PWM信号,这样就…

Node编写更新用户信息接口

目录 前言 定义路由和处理函数 验证表单数据 实现更新用户基本信息的功能 前言 继前面几篇文章,本文介绍如何编写更新用户信息接口 定义路由和处理函数 路由 // 更新用户信息接口 router.post(/userinfo, userinfo_handler.updateUserinfo) 处理函数 // 导…

Netty实战-实现自己的通讯框架

通信框架功能设计 功能描述 通信框架承载了业务内部各模块之间的消息交互和服务调用,它的主要功能如下: 基于 Netty 的 NIO 通信框架,提供高性能的异步通信能力;提供消息的编解码框架,可以实现 POJO 的序列化和反序…

Kmeans算法实现目标客户聚类分析

文章目录 一、Kmeans简介二、数据集描述三、实现方法一、Kmeans简介 Kmeans是聚类算法中较为简单的一种,简单但实用,有如下优势和缺点: 优势 算法简单,便于使用(算法仅需要考虑一个分类数量K即可) 适合常规数据集(最好是线性可分的数据集) 适合 不适合 缺点 K值难以确…

【COMP329 LEC4 Locomotion and Kinematics】

Only for the Test 1 which include 4.2 4.3 4.4 Locomotion and Kinematics 运动和运动学 (4.2) Part 2: Wheeled Motion 1. Wheeled Robots a. 省略控制双腿需要的计算复杂度 b. 只限于easy terrain (地形) c. 不平坦uneven 不规则irregular 的地形需要…

STM32-程序占用内存大小计算

STM32中程序占用内存容量 Keil MDK下Code, RO-data,RW-data,ZI-data这几个段: Code存储程序代码。 RO-data存储const常量和指令。 RW-data存储初始化值不为0的全局变量。 ZI-data存储未初始化的全局变量或初始化值为0的全局变量。 占用的FlashCode RO Data RW Data; 运行消…

Go语言用Resty库编写的音频爬虫代码

以下是一个使用Resty库的Go语言下载器程序,用于从facebook下载音频。此程序使用了duoip/get_proxy的代码。 package mainimport ("fmt""github.com/john-nguyen09/resty""io/ioutil""net/http" )func main() {// 设置爬虫i…

互联网金融 个人身份识别技术要求

文章目录 术语缩略语个人身份识别技术框架框架与各组部分的作用个人身份识别实现的主要功能 个人身份识别凭据技术要求概述记忆凭据类静态口令生成要求使用要求设备要求及安全要求 预设问题回答生成要求使用要求 OPT令牌生成要求使用要求安全要求 数字证书无硬介质证书生成要求…

kvm webvirtcloud 如何添加直通物理机的 USB 启动U盘

第一步:查看USB设备ID 在物理机上输入 lsusb 命令 rootubuntu:/media/usb1# lsusb Bus 002 Device 002: ID 0781:5581 SanDisk Corp. Ultra Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 004: ID 0424:2514 Microchip Technolo…

【力扣】x (-x) 与 x (x - 1)

最近刷了很多位运算的题,从一开始的死记硬背x & (-x) 与 x & (x - 1)的含义,到现在彻底弄懂,花了很多时间理解。 前提知识: 内存中的计算都是按照补码进行计算的。正数的原反补相同,负数的补码等于原码取反加…

FOC系列(一)----DRV8301芯片的学习

一、 写在前面 从今年四五月份一直就想玩个无刷直流电机(BLDC),但是碍于一直没时间。其实很早就做出来了测试板的控制板,可以当做开发板使用,考虑到成本问题,最后选用STM32F103CBT6芯片,下面是很…

边缘计算发生了什么?

边缘计算(Edge computing)成为一种革命性工具,可以满足日益增长的实时数据处理需求。通过在网络边缘(更靠近数据生成位置)进行数据处理,边缘计算可显着减少延迟和带宽使用。 这是我们多年来一直被告知的故事,但随着生…

听GPT 讲Rust源代码--library/std(2)

File: rust/library/std/src/sys_common/wtf8.rs 在Rust源代码中,rust/library/std/src/sys_common/wtf8.rs这个文件的作用是实现了UTF-8编码和宽字符编码之间的转换,以及提供了一些处理和操作UTF-8编码的工具函数。 下面对这几个结构体进行一一介绍&…

封装一个vue3 Toast组件,支持组件和api调用

先来看一段代码 components/toast/index.vue <template><div v-if"isShow" class"toast">{{msg}}</div> </template><script setup> import { ref, watch } from vue const props defineProps({show: {type: Boolean,def…