微服务CI/CD实践(五)Jenkins Docker 自动化构建部署Node服务

news2024/12/23 18:04:18

微服务CI/CD实践系列:
 
微服务CI/CD实践(一)环境准备及虚拟机创建
微服务CI/CD实践(二)服务器先决准备
微服务CI/CD实践(三)gitlab部署及nexus3部署
微服务CI/CD实践(四)Jenkins部署及环境配置
微服务CI/CD实践(五)Jenkins + Dokcer 部署微服务后端项目
微服务CI/CD实践(六)Jenkins + Dokcer 部署微服务前端VUE项目
微服务CI/CD实践(七)Minio服务器部署及应用

文章目录

  • 一、先决条件
    • 1.1 服务器先决条件
    • 1.2 项目配置
      • Dockerfile
      • Nginx配置文件
      • 部署脚本
  • 二、Jenkins构建部署
    • 2.1 创建项目
    • 2.2 配置项目基本信息
    • 2.3 定义 Pipeline script
    • 2.4 构建部署项目

前端项目是基于NodeJS(Vue)框架开发,我们通过打包成Docker镜像的方式进行部署,原理是先将项目打包成静态页面,然后再将静态页面直接copy到Nginx镜像中运行。构建部署流程如下:

  • 拉取代码
  • jenkins服务器进行nodejs编译
  • 使用dockerfile构建镜像并打包镜像
  • 上传镜像包
  • 执行sh

一、先决条件

1.1 服务器先决条件

Jenkins 和 server服务器先决条件参考微服务CI/CD实践(二)服务器先决准备 和 微服务CI/CD实践(四)Jenkins部署及环境配置

1.2 项目配置

Dockerfile

使用Jenkins本地编译项目在构建镜像

FROM nginx:latest
# 将生成的静态页面文件复制到nginx的/usr/share/nginx/html/目录
COPY dist/ /usr/share/nginx/html/
# 将mime文件复制到nginx的/etc/nginx/目录 后续配置ng会使用
COPY mime.types /etc/nginx/mime.types
# 容器启动时运行的命令
CMD ["nginx", "-g", "daemon off;"]

也可以直接使用docker 镜像编译-构建镜像,此模式jenkins服务器可以不需要node环境

# Install dependencies
FROM node:18.20.4 as builder
WORKDIR /app
# Install pnpm
RUN npm i -g pnpm
# copy file for next stage
COPY . /app
RUN pnpm install && pnpm run build
# copy dist from the first stage for Production
FROM nginx:latest AS runner
COPY --from=builder /app/dist/ /usr/share/nginx/html
COPY --from=builder /app/nginx.conf /etc/nginx/conf.d/default.conf

不过此模式在docker-hub停止国内服务后可能无法正常拉取镜像。

Nginx配置文件

根据项目要求编写ng配置

cd /data/container/nginx/etc
vi nginx.conf
# 编写配置并保存

vi mime.types
# 编写配置并保存

以下为nginx.conf配置示例


events {
    worker_connections 1024;
}

http {
    # 需要引入mime.types配置或者显示配置静态文件mimetype类型,否则运行后,浏览器会因为文件类型导致无法正常加载静态文件
    include       mime.types;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    tcp_nopush      on;
    tcp_nodelay     on;
    keepalive_timeout  65;
    types_hash_max_size 2048;
    client_max_body_size 100m;

    server {
        listen       80;
        listen  [::]:80;
        server_name  localhost;
        
        # 设置 CORS 相关的响应头
        add_header 'Access-Control-Allow-Origin' '*' always;
        add_header 'Access-Control-Allow-Methods' '*' always;
        add_header 'Access-Control-Max-Age' 1728000 always;
        add_header 'Access-Control-Allow-Headers' '*' always;
        add_header 'Access-Control-Allow-Credentials' 'true' always;
        
        gzip on;
        gzip_buffers 32 4k;
        gzip_comp_level 6;
        gzip_min_length 100;
        gzip_types application/javascript text/css text/xml text/plain application/x-javascript image/jpeg image/gif image/png;
        gzip_disable "MSIE [1-6]\.";
        gzip_vary on;

        charset utf8;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
            try_files $uri $uri/ /index.html;
            if (!-e $request_filename) {
                rewrite ^/(.*) /index.html last;
                break;
            }
        }

        location  ~ .*\.(jpg|png|js|css|woff2|ttf|woff|eot)$ {
            root   /usr/share/nginx/html;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
        
        # 配置全局代理并统一处理CORS 
        location /gateway-api/ {
           proxy_set_header Host $http_host;               
           proxy_set_header X-Real-Ip $remote_addr;
           proxy_set_header REMOTE-HOST $remote_addr;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_pass http://192.168.1.103:10000/;

           # 添加 CORS 相关的响应头
           add_header 'Access-Control-Allow-Origin' '*' always;
           add_header 'Access-Control-Allow-Methods' '*' always;
           add_header 'Access-Control-Max-Age' 1728000 always;
           add_header 'Access-Control-Allow-Headers' '*' always;
           add_header 'Access-Control-Allow-Credentials' 'true' always;

           # 处理 OPTIONS 请求
           if ($request_method = 'OPTIONS') {
               return 204;
           }
       }
    }
}

以下为mime.type示例

types {
    text/html                 html htm shtml;
    text/css                  css;
    image/gif                gif;
    image/jpeg               jpeg jpg;
    application/javascript    js;
    application/xml          xml;
    application/json         json;
    application/pdf          pdf;
    application/rss+xml      rss;
    application/atom+xml     atom;
    text/mathml              mml;
    text/plain               txt;
    text/vnd.sun.j2me.app-descriptor jad;
    text/vnd.wap.wml         wml;
    text/x-component         htc;
    image/png               png;
    image/svg+xml           svg;
    image/tiff              tif tiff;
    image/vnd.wap.wbmp      wbmp;
    image/x-icon            ico;
    image/x-jng             jng;
    image/x-ms-bmp          bmp;
    application/zip          zip;
    application/tar          tar;
    application/x-7z-compressed 7z;
    application/x-java-archive jar;
    application/x-rar-compressed rar;
    application/x-web-app-manifest+json webapp;
    application/xhtml+xml   xhtml;
    application/x-msdownload  exe dll;
    audio/midi              mid midi kar;
    audio/mpeg             mp3;
    video/mp4              mp4;
    video/mpeg             mpeg mpg;
    video/webm             webm;
    video/x-msvideo         avi;
    video/x-ms-wmv         wmv;
    video/x-ms-asf         asx asf;
    video/x-flv            flv;
    application/x-shockwave-flash swf;
    application/vnd.ms-excel  xls;
    application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
    application/vnd.openxmlformats-officedocument.spreadsheetml.sheet  xlsx;
    application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;
    application/vnd.ms-fontobject eot;
    application/vnd.apple.mpegurl m3u8;
    application/x-font-ttf  ttc ttf;
    application/x-httpd-php-source phps;
}

部署脚本

step1 定义入参
可以通过Jenkins任务将参数传入脚本中,我们定义了下面7个参数:
container_name : 容器名称
image_name : 镜像名称
version : 镜像版本
portal_port: 宿主主机端口映射
server_port: 容器内服务端口
portal_ssl_port: 宿主主机端口映射
serve_sslr_port: 容器内服务端口

step2 定义入参对参数进行检查
将必传参数放在最前面,这里根据自己的实际情况判断,检查是否传递参数。比如设置container_name、image_name、version 、portal_port、server_port5个参数必须传入,就设置参数的个数不能小于5。

echo "param validate"
if [ $# -lt 5 ]; then  
  echo "you must use like this : /usr/docker-sh/your_script.sh <container_name> <image_name> <version> [portal port] [server port] [portal ssl port] [server ssl port]"  
  exit  
fi

step3 入参赋值
如果有参数传入,则赋值参数

# 前五个参数是必传参数,无需判断直接赋值
container_name="$1"
image_name="$2"
version="$3"
portal_port="$4"
server_port="$5"
if [ "$6" != "" ]; then
   portal_ssl_port="$6"
fi
echo "portal_ssl_port=" $portal_ssl_port
if [ "$7" != "" ]; then
   serve_sslr_port="$7"
fi

step4 停止并删除容器

echo "执行docker ps"
docker ps 
if [[ "$(docker inspect $container_name 2> /dev/null | grep $container_name)" != "" ]]; 
then 
  echo $container_name "容器存在,停止并删除"
  echo "docker stop" $container_name
  docker stop $container_name
  echo "docker rm" $container_name
  docker rm $container_name
else 
  echo $container_name "容器不存在"
fi

step5 停止并删除镜像

# 删除镜像
echo "执行docker images"
docker images
if [[ "$(docker images -q $image_name 2> /dev/null)" != "" ]]; 
then 
  echo $image_name '镜像存在,删除镜像'
  docker rmi $(docker images -q $image_name 2> /dev/null) --force
else 
  echo $image_name '镜像不存在'
fi

step6 备份和加载安装包

#bak image
echo "bak image" $image_name
BAK_DIR=/opt/bak/docker/$image_name/`date +%Y%m%d`
mkdir -p "$BAK_DIR"
cp "/opt/tmp/$container_name.tar" "$BAK_DIR"/"$image_name"_`date +%H%M%S`.tar

echo "docker load" $image_name
docker load --input /opt/tmp/$container_name.tar

step7 执行运行镜像命令

echo "docker run" $image_name
docker run -d -p $portal_port:$server_port --name=$container_name --network=my-network -e TZ="Asia/Shanghai" --restart=always -v /data/container/nginx/www:/var/www -v /data/container/nginx/logs:/var/log/nginx -v /data/container/nginx/etc:/etc/nginx -v /data/container/nginx/etc/nginx.conf:/etc/nginx/nginx.conf -v /data/container/nginx/etc/mime.types:/etc/nginx/mime.types -v /etc/localtime:/etc/localtime -v /usr/share/zoneinfo/Asia/Shanghai:/etc/timezone $image_name

step8 执行删除安装包命令

echo "remove tmp " $image_name
rm -rf /opt/tmp/$container_name.tar

以下为完整的安装部署脚本

#!/usr/bin/env bash

echo "param validate"
if [ $# -lt 5 ]; then  
  echo "you must use like this : /usr/docker-sh/your_script.sh <container_name> <image_name> <version> [portal port] [server port] [portal ssl port] [server ssl port]"  
  exit  
fi

container_name="$1"
image_name="$2"
version="$3"
portal_port="$4"
server_port="$5"
if [ "$6" != "" ]; then
   portal_ssl_port="$6"
fi
echo "portal_ssl_port=" $portal_ssl_port
if [ "$7" != "" ]; then
   serve_sslr_port="$7"
fi

echo "执行docker ps"
docker ps 
if [[ "$(docker inspect $container_name 2> /dev/null | grep $container_name)" != "" ]]; 
then 
  echo $container_name "容器存在,停止并删除"
  echo "docker stop" $container_name
  docker stop $container_name
  echo "docker rm" $container_name
  docker rm $container_name
else 
  echo $container_name "容器不存在"
fi
# 删除镜像
echo "执行docker images"
docker images
if [[ "$(docker images -q $image_name 2> /dev/null)" != "" ]]; 
then 
  echo $image_name '镜像存在,删除镜像'
  docker rmi $(docker images -q $image_name 2> /dev/null) --force
else 
  echo $image_name '镜像不存在'
fi

#bak image
echo "bak image" $image_name
BAK_DIR=/opt/bak/docker/$image_name/`date +%Y%m%d`
mkdir -p "$BAK_DIR"
cp "/opt/tmp/$container_name.tar" "$BAK_DIR"/"$image_name"_`date +%H%M%S`.tar

echo "docker load" $image_name
docker load --input /opt/tmp/$container_name.tar

echo "docker run" $image_name
docker run -d -p $portal_port:$server_port --name=$container_name --network=my-network -e TZ="Asia/Shanghai" --restart=always -v /data/container/nginx/www:/var/www -v /data/container/nginx/logs:/var/log/nginx -v /data/container/nginx/etc:/etc/nginx -v /data/container/nginx/etc/nginx.conf:/etc/nginx/nginx.conf -v /data/container/nginx/etc/mime.types:/etc/nginx/mime.types -v /etc/localtime:/etc/localtime -v /usr/share/zoneinfo/Asia/Shanghai:/etc/timezone $image_name

echo "remove tmp " $image_name
rm -rf /opt/tmp/$container_name.tar

echo "Docker Portal is starting,please try to access $container_name conslone url"

二、Jenkins构建部署

2.1 创建项目

新建一个流水线任务
在这里插入图片描述

2.2 配置项目基本信息

创建完成项目,点击项目进入项目页面,点击左侧菜单》配置,进行项目基本配置
step1 项目构建历史存储策略配置
在这里插入图片描述
根据项目实际情况配置存储策略
step2 配置参数化构建过程
Jenkins List Git Branches插件 构建选择指定git分支,点击添加参数选择List Git branchers选项进行Jenkins List Git Branches插件配置
在这里插入图片描述
Jenkins List Git Branches插件配置流程如下:

  • 配置name
  • 配置仓库并选择凭证
  • 选择Parameter Type
  • 配置Branch Filter

在这里插入图片描述

2.3 定义 Pipeline script

step1 配置全局变量

environment {   
    REPOSITORY="http://192.168.1.101:8929/hka/hka-admin-wocwin.git"
	projectdir="hka-web-01"
	projectname="hka-admin-wocwin"
}

step2 获取代码
检出选择指定git分支的代码

stages {
        stage('获取代码') {
			steps {
				echo "start fetch code from git:${REPOSITORY} ${branch}"
				deleteDir()
				checkout([
                    $class: 'GitSCM',
                    branches: [[name: '${branch}']],
                    doGenerateSubmoduleConfigurations: false,
                    extensions: [],
                    userRemoteConfigs: [[
                        credentialsId: '2',
                        url: 'http://192.168.1.101:8929/hka/hka-admin-wocwin.git'
                    ]]
                ])
			}
		}

step3 编译项目

这里需要显示指定node的环境变量,否则执行编译命令会抛异常

stage('Build NodeJS Vue') {
            steps {
                echo "build nodejs code"
                nodejs('node') {
                    sh 'export PATH="/usr/local/nodejs/bin:$PATH"'
                    sh 'node -v'
                    sh 'npm -v'
                    sh 'pnpm -v'
                    sh 'pnpm install'
                    sh 'pnpm run prod'
                }
                echo "build nodejs success"
            }
        }

step4 删除历史容器和镜像
如何没有在jenkins服务器运行容器可以忽略Delete Old Docker Container步骤

stage('Delete Old Docker Container') {
            steps {
                echo "delete docker container"
                sh '''if [[ "$(docker inspect ${projectname} 2> /dev/null | grep ${projectname})" != "" ]]; 
                then 
                  echo ${projectname} "容器存在,停止并删除"
                  echo "docker stop" ${projectname}
                  docker stop ${projectname}
                  echo "docker rm" ${projectname}
                  docker rm ${projectname}
                else 
                  echo ${projectname} "容器不存在"
                fi'''
            }
        }
        
        stage('Delete Old Docker Image') {
            steps {
                echo "delete docker image"
                sh '''if [[ "$(docker images -q ${projectname} 2> /dev/null)" != "" ]]; 
                    then 
                      echo ${projectname} \'镜像存在,删除镜像\'
                      docker rmi $(docker images -q ${projectname} 2> /dev/null) --force
                    else 
                      echo ${projectname} \'镜像不存在,创建镜像\'
                    fi'''
            }
            
        }

step5 构建镜像

stage('Build Docker Image') {
             steps {
                echo "start docker build ${projectname} code"
                sh 'docker build -t ${projectname} .'
                echo "save docker images tar"
                sh 'docker save -o ${projectname}.tar ${projectname}'
             }
            
        }
stage('Delete New Docker Image') {
            steps {
                echo "delete docker image"
                sh '''if [[ "$(docker images -q ${projectname} 2> /dev/null)" != "" ]]; 
                    then 
                      echo ${projectname} \'镜像存在,删除镜像\'
                      docker rmi $(docker images -q ${projectname} 2> /dev/null) --force
                    else 
                      echo ${projectname} \'镜像不存在,创建镜像\'
                    fi'''
            }
        }

step6 上传镜像包
这里的configName: ‘103’, 就是微服务CI/CD实践(四)Jenkins部署及环境配置### 2.2.4 全局系统配置 SSH Server配置
该流水线步骤会通过ssh将 镜像tar包上传到SSH Server配置的Remote Directory目录下

stage('Upload img tar') {
            steps {
                sshPublisher(
                    publishers: [
                        sshPublisherDesc(
                            configName: '103',
                            transfers: [
                                sshTransfer(
                                    cleanRemote: false,
                                    excludes: '',
                                    makeEmptyDirs: false,
                                    noDefaultExcludes: false,
                                    patternSeparator: '[, ]+',
                                    remoteDirectory: '',
                                    remoteDirectorySDF: false,
                                    removePrefix: '',
                                    sourceFiles: '${projectname}.tar'
                                )
                            ],
                            usePromotionTimestamp: false,
                            useWorkspaceInPromotion: false,
                            verbose: false
                        )
                    ]
                )
            }
        }

step7 执行安装部署脚本
这里的configName: ‘103’, 就是微服务CI/CD实践(四)Jenkins部署及环境配置### 2.2.4 全局系统配置 SSH Server配置
该步骤通过ssh远程执行sh安装部署脚本

stage('Execute Command sh') {
            steps {
                sshPublisher(
                    publishers: [
                        sshPublisherDesc(
                            configName: '103',
                            transfers: [
                                sshTransfer(
                                    execCommand: '/usr/docker-sh/publish_hka-admin-wocwin.sh hka-admin-wocwin hka-admin-wocwin latest 80 80',
                                    execTimeout: 300000
                                )
                            ],
                            usePromotionTimestamp: false,
                            useWorkspaceInPromotion: false,
                            verbose: false
                        )
                    ]
                )
            }
        }

以下为完整流水线定义

pipeline {
    agent any
    
    environment {   
        REPOSITORY="http://192.168.1.101:8929/hka/hka-admin-wocwin.git"
		projectdir="hka-web-01"
		projectname="hka-admin-wocwin"
    }
    
    stages {
        stage('获取代码') {
			steps {
				echo "start fetch code from git:${REPOSITORY} ${branch}"
				deleteDir()
				checkout([
                    $class: 'GitSCM',
                    branches: [[name: '${branch}']],
                    doGenerateSubmoduleConfigurations: false,
                    extensions: [],
                    userRemoteConfigs: [[
                        credentialsId: '2',
                        url: 'http://192.168.1.101:8929/hka/hka-admin-wocwin.git'
                    ]]
                ])
			}
		}
		
        stage('Build NodeJS Vue') {
            steps {
                echo "build nodejs code"
                nodejs('node') {
                    sh 'export PATH="/usr/local/nodejs/bin:$PATH"'
                    sh 'node -v'
                    sh 'npm -v'
                    sh 'pnpm -v'
                    sh 'pnpm install'
                    sh 'pnpm run prod'
                }
                echo "build nodejs success"
            }
        }
        
        stage('Delete Old Docker Container') {
            steps {
                echo "delete docker container"
                sh '''if [[ "$(docker inspect ${projectname} 2> /dev/null | grep ${projectname})" != "" ]]; 
                then 
                  echo ${projectname} "容器存在,停止并删除"
                  echo "docker stop" ${projectname}
                  docker stop ${projectname}
                  echo "docker rm" ${projectname}
                  docker rm ${projectname}
                else 
                  echo ${projectname} "容器不存在"
                fi'''
            }
        }
        
        stage('Delete Old Docker Image') {
            steps {
                echo "delete docker image"
                sh '''if [[ "$(docker images -q ${projectname} 2> /dev/null)" != "" ]]; 
                    then 
                      echo ${projectname} \'镜像存在,删除镜像\'
                      docker rmi $(docker images -q ${projectname} 2> /dev/null) --force
                    else 
                      echo ${projectname} \'镜像不存在,创建镜像\'
                    fi'''
            }
            
        }
        
        stage('Build Docker Image') {
             steps {
                echo "start docker build ${projectname} code"
                sh 'docker build -t ${projectname} .'
                echo "save docker images tar"
                sh 'docker save -o ${projectname}.tar ${projectname}'
             }
            
        }
        
        stage('Delete New Docker Image') {
            steps {
                echo "delete docker image"
                sh '''if [[ "$(docker images -q ${projectname} 2> /dev/null)" != "" ]]; 
                    then 
                      echo ${projectname} \'镜像存在,删除镜像\'
                      docker rmi $(docker images -q ${projectname} 2> /dev/null) --force
                    else 
                      echo ${projectname} \'镜像不存在,创建镜像\'
                    fi'''
            }
        }
        
        stage('Upload img tar') {
            steps {
                sshPublisher(
                    publishers: [
                        sshPublisherDesc(
                            configName: '103',
                            transfers: [
                                sshTransfer(
                                    cleanRemote: false,
                                    excludes: '',
                                    makeEmptyDirs: false,
                                    noDefaultExcludes: false,
                                    patternSeparator: '[, ]+',
                                    remoteDirectory: '',
                                    remoteDirectorySDF: false,
                                    removePrefix: '',
                                    sourceFiles: 'hka-admin-wocwin.tar'
                                )
                            ],
                            usePromotionTimestamp: false,
                            useWorkspaceInPromotion: false,
                            verbose: false
                        )
                    ]
                )
            }
        }

        stage('Execute Command sh') {
            steps {
                sshPublisher(
                    publishers: [
                        sshPublisherDesc(
                            configName: '103',
                            transfers: [
                                sshTransfer(
                                    execCommand: '/usr/docker-sh/publish_hka-admin-wocwin.sh hka-admin-wocwin hka-admin-wocwin latest 80 80 4413 4413',
                                    execTimeout: 300000
                                )
                            ],
                            usePromotionTimestamp: false,
                            useWorkspaceInPromotion: false,
                            verbose: false
                        )
                    ]
                )
            }
        }
        
        stage('Publish Results') {
            steps {
               echo "End Publish ${projectname}"  
            }
        }

        
    }
}

2.4 构建部署项目

回到项目页面,点击参数化构建,选择用于构建的分支点击Build执行构建任务。
在这里插入图片描述

在这里插入图片描述

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

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

相关文章

为什么现在那么多人用骨传导耳机?怎么选骨传导耳机?答案来了!

随着健康生活观念的深入人心&#xff0c;运动健身已成为一种生活态度&#xff0c;而音乐则是这场健康之旅中不可或缺的伴侣。然而&#xff0c;传统耳机在运动时的不便促使市场呼唤更加人性化的产品。骨传导耳机的出现&#xff0c;正是对这一需求的精准把握。它采用非入耳技术&a…

VTK平面切割

文章目录 一、vtkClipPolyData二、CapClip三、SolidClip四、vtkClipClosedSurface 本文的主要内容&#xff1a;简单介绍VTK中通过平面切割模型的相关功能。 哪些人适合阅读本文&#xff1a;有一定VTK基础的人。 一、vtkClipPolyData VTK官网描述&#xff1a; vtkClipPolyData使…

AI绘画 | Stable diffusion 修复老照片

大家好呀&#xff01;今天我要和大家分享一个使用Stable diffusion修复老照片的功能。 你有没有遇到这样的问题&#xff1a;想要修复一张老照片&#xff0c;但是发现照片质量太差&#xff0c;噪点太多&#xff0c;根本无法修复&#xff1f; 别担心&#xff01;Stable diffusio…

DS18B20温度传感器详解(STM32)

目录 一、介绍 二、传感器原理 1.原理图 2.工作时序 3.工作原理&#xff1a;复位脉冲与应答脉冲 4.工作原理&#xff1a;写时序 5.工作原理&#xff1a;读时序 6.工作原理&#xff1a;DS18B20读取的数据格式 7.工作原理&#xff1a;DS18B20配置步骤 三、程序设计 ma…

vue 批量自动引入并注册组件或路由

有时候有大量的组件.vue后缀的,或.js,或.ts文件, 需要一个个的手动引入很麻烦,那么你可以尝试这样创建一个index.js 本项目使用vue3.x, vue2.x也可以照样用; 这里在components里面创建了一个idnex.js 文件 require.context 可以读取文件, 第一个参数是指当前文件夹, 第二个参…

路径优化 minimum-snap(对A*的全局路径进行优化)

实现效果&#xff1a; 介绍&#xff1a; 使用Astar进行路径规划&#xff0c;使用minimum-snap进行路径优化处理&#xff0c;建议参考文章&#xff1a; 【附源码和详细的公式推导】Minimum Snap轨迹生成&#xff0c;闭式求解Minimum Snap问题&#xff0c;机器人轨迹优化&#…

泥水位监测站——水文百科

传统的水位监测往往依赖于人工定期巡检&#xff0c;这不仅费时费力&#xff0c;而且可能受到天气、交通等多种因素的限制。而水位监测站的全自动化监测则能够24小时不间断地工作&#xff0c;无需人员现场值守&#xff0c;从而显著减少了人工巡检的次数和成本。自动化监测系统能…

全面解析BotSharp:如何利用.Net和LLMs革新你的业务系统

作为一名关注.Net与AI相关技术的博主&#xff0c;今天我要推荐一个开源项目——BotSharp。BotSharp 是一个基于 .Net的智能代理应用程序构建框架&#xff0c;专注于连接大型语言模型&#xff08;LLMs&#xff09;到现有业务系统中&#xff0c;以促进会话即平台(Conversation as…

模型案例:| 垃圾桶识别模型

导读 2023年以ChatGPT为代表的大语言模型横空出世&#xff0c;它的出现标志着自然语言处理领域取得了重大突破。它在文本生成、对话系统和语言理解等方面展现出了强大的能力&#xff0c;为人工智能技术的发展开辟了新的可能性。同时&#xff0c;人工智能技术正在进入各种应用领…

【Java|Stream流】不可变集合

文章目录 1.什么是不可变集合2.创建不可变集合的方式2.1 List类型2.2 Set2.3 Map 1.什么是不可变集合 不可变集合:不可以被修改的集合 不可变集合优点: 安全性 由于不可变集合不能被修改&#xff0c;所以可以安全地在多个线程之间共享&#xff0c;而不用担心被意外修改&#xf…

H264编码

H264是一种针对视频的压缩编码方式。 一、压缩方法 H264主要基于以下几种方法&#xff0c;将数据进行压缩&#xff1a; 1.帧内预测压缩&#xff1a;解决空间域数据冗余的问题 2.帧间预测压缩&#xff1a;&#xff08;运动估计与补偿&#xff09;解决时间域数据冗余的问题 3…

AD5270 AD5271 STM32 SPI驱动设计

硬件设计 AD5270 AD5271 简介&#xff1a;1024位、1%电阻容差误差、SPI接口和50-TP存储器数字变阻器。特性&#xff1a;单通道、1024/256位分辨率&#xff1b;标称电阻&#xff1a;20 kΩ&#xff0c;50 kΩ和100 kΩ&#xff1b;标称电阻容差误差&#xff1a;1%&#xff08;最…

Android 11添加系统服务,并封装jar包供第三方应用使用

概述&#xff1a; 如果你是做技术支持&#xff0c;有没有遇到这种情况&#xff0c;客户既要实现具备系统权限的功能&#xff0c;但是呢&#xff0c;又不想把自己的应用做成系统应用。这时候你咋办。 我们可以添加一个具备系统权限的服务&#xff0c;不管前台的&#xff0c;还是…

原来这就是 布隆过滤器

1.布隆过滤器的引出 一个有趣的现象 不知道大家有没有发现这么一个现象&#xff0c;当我们在使用一些软件的时候&#xff0c;比如像 CSDN、这种具有推荐算法的应用&#xff0c;他并不会给我们推送我们已经浏览过的内容&#xff0c;这是怎么做到的呢&#xff1f; 说白了就是人…

【物理教学】高中物理速度时间练习

速度时间图像代码 这段代码是一个使用Python编写的脚本&#xff0c;它利用matplotlib库来绘制物理问题中的速度-时间图。代码的主要优点如下&#xff1a; 用户交互&#xff1a;代码通过input函数与用户进行交互&#xff0c;允许用户输入物理问题的参数&#xff0c;如初始速度…

钢结构厂房通风天窗使用场景探讨

钢结构厂房通风天窗作为现代建筑中高效通风的解决方案&#xff0c;广泛应用于多个领域&#xff0c;为各类建筑提供优质的室内环境。成都昱合昇带大家一起探讨通风天窗在不同使用场景下的表现。 1、工业厂房降温 工业厂房是通风天窗典型的应用场景之一。在高温季节或生产过程中产…

苏州科技大学商学院:加强生态保护,推动绿色发展

原标题&#xff1a;苏州科技大学商学院&#xff1a;加强生态保护&#xff0c;推动绿色发展&#xff0c;在美丽中国建设中贡献青春力量 建设美丽中国是全面建设社会主义现代化国家的重要目标&#xff0c;也是激励全国人民为实现中华民族伟大复兴中国梦而共同奋斗的伟大旗帜。中…

CSS3 文本效果(text-shadow,box-shadow,white-space等)文本溢出隐藏并且显示省略号

一 text-shadow text-shadow 属性是 CSS3 中用于为文本添加阴影效果的工具。它可以增强文本的可读性和视觉吸引力&#xff0c;提供丰富的视觉效果 1 语法 text-shadow: offset-x offset-y blur-radius color;offset-x&#xff1a;阴影相对于文本的水平偏移量。可以是正值&am…

STM32CUBEIDE FreeRTOS操作教程(四):timer软件定时器

STM32CUBEIDE FreeRTOS操作教程&#xff08;四&#xff09;&#xff1a;timer软件定时器 STM32CUBE开发环境集成了STM32 HAL库进行FreeRTOS配置和开发的组件&#xff0c;不需要用户自己进行FreeRTOS的移植。这里介绍最简化的用户操作类应用教程。以STM32F401RCT6开发板为例&am…

18047 水仙花数

### 思路 1. 遍历所有的三位数&#xff08;100到999&#xff09;。 2. 对于每个数&#xff0c;提取其百位、十位和个位数字。 3. 计算这些数字的立方和。 4. 如果立方和等于原数&#xff0c;则该数是水仙花数&#xff0c;输出该数。 ### 伪代码 1. 遍历i从100到999&#xff1a…