文章目录

  • 前言
    • 前端项目CICD时序图
    • 一、环境准备
      • 1、服务器相关
      • 2、Jenkins凭据
      • 3、注意事项
    • 二、设计思想
      • 1. 模块化设计
      • 2.多环境支持
      • 3. 制品管理
      • 4. 安全部署机制
      • 5. 回滚机制
    • 三、CI阶段
      • 1、构建节点选择
      • 2、代码拉取
      • 3、代码编译
      • 4、打包并上传至minio
    • 四、CD阶段
    • 五、回滚阶段
    • 六、构建通知
    • 七、实战演示--发布/回滚前端项目
      • 1、Jenkins创建流水线项目
      • 2、执行构建
      • 3、执行回滚
  • 八、完整pipeline

前言

在现代化前端工程中,高效的CI/CD流程已成为团队标配。本文将详细解析如何通过Jenkins Pipeline实现从代码提交到自动化部署的全流程,重点分享多服务器并行部署、MinIO制品管理以及一键回滚等核心功能的实现方案。文中提供的Jenkinsfile模板可直接用于生产环境,助你快速搭建企业级部署平台。

前端项目CICD时序图

在这里插入图片描述

一、环境准备

1、服务器相关

ip部署
192.168.56.101nginx1
192.168.56.102nignx2、Jenkins、nodejs(18.16.0)、minio(minio-RELEASE_2023_05_18)

minio服务器设置myminio

[root@k8s-node ~]# mc config host add myminio http://192.168.56.102:8021 OpsMinIO OpsAdmin081524

minio服务器设置前端制品库桶

在这里插入图片描述

2、Jenkins凭据

minio账密凭据--usernamePassword类型

在这里插入图片描述

服务器账密凭据--usernamePassword类型

在这里插入图片描述

3、注意事项

1、服务器账密保持一致,因为后续pipeline中连接部署服务器会使用
2、Jenkins服务器需要安装nodejs、yarn等编译前端代码的组件
3、Jenkins需要安装nodejs插件、ssh相关插件,并在全局工具配置中设置npm路径

在这里插入图片描述

二、设计思想

1. 模块化设计

采用共享库模式将功能解耦为独立模块:

  • build.groovy :封装构建逻辑,支持前端不同构建工具(npm、yarn)

    在这里插入图片描述

  • tools.groovy :提供统一的日志输出和可视化工具

    在这里插入图片描述

  • toemailF.groovy :处理通知机制,实现标准化的邮件模板

    在这里插入图片描述

2.多环境支持

通过环境变量实现配置与逻辑分离:

String Tenv="${env.Tenv}"
environment {BUILD_TIME = sh(script: "date '+%Y%m%d_%H%M%S'", returnStdout: true).trim()MINIO_BUCKET = 'frontend-artifacts' 
}
构建参数如 buildType 、 buildshell、Tenv 等通过Jenkins job参数动态注入

3. 制品管理

采用MinIO作为制品仓库,实现版本追踪:

// 保存部署信息
env.DEPLOY_INFO = """应用: ${JOB_NAME}版本: ${BUILD_TIME}-${env.GIT_COMMIT}包路径: ${MINIO_BUCKET}/${JOB_NAME}/${env.ARTIFACT_NAME}
"""

4. 安全部署机制

  • 凭据管理:通过 withCredentials 安全使用SSH和MinIO密钥
  • 签名验证:动态生成AWS签名头保障MinIO访问安全
DATE_VALUE_REMOTE=\$(date -R)
SIGNATURE_REMOTE=\$(echo -en "GET\\n\\n\\n\${DATE_VALUE_REMOTE}\\n/${MINIO_BUCKET}/${JOB_NAME}/${env.ARTIFACT_NAME}" | openssl sha1 -hmac "\${MINIO_SECRET_KEY}" -binary | base64)

5. 回滚机制

实现完整的版本追溯和回滚流程:

  1. 从MinIO获取历史版本列表
  2. 交互式选择回滚目标
  3. 保持与部署相同的安全机制

三、CI阶段

1、构建节点选择

核心思想:1、后端服务采用Jenkins动态slave-pod的方式,将其部署到k8s2、前端服务采用宿主机Jenkins服务将其构建部署

设置构建节点

在这里插入图片描述

pipeline{agent {label 'master' #此名称跟上述图片中的名称保持一致}options {timestamps()skipDefaultCheckout()  // 禁用隐式 Checkouttimeout(time: 1, unit: 'HOURS') //设置流水线超时}
}

2、代码拉取

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

#!groovy
@Library("jenkinslib") _//func from sharelibrary调用共享库
def build=new org.devops.build()
def tools=new org.devops.tools()
def toemailF=new org.devops.toemailF()//调用Jenkins构建参数
String Tenv="${env.Tenv}"
String srcURL="${env.SrcURL}"
String branch="${env.branchName}"pipeline{stages{stage("CheckOut"){when { expression { !rollback } }  // 非回滚时执行steps{script{tools.PrintMsg("获取分支: ${branch}","checkout")tools.PrintMsg("获取代码","checkout")checkout([$class: 'GitSCM', branches: [[name: "${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: 'gitee_registry_ssh', url: "${srcURL}"]]])// 记录当前commit信息用于追踪env.GIT_COMMIT = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()}}}}
}

在这里插入图片描述

3、代码编译

#!groovy
@Library("jenkinslib") _//func from sharelibrary调用共享库
def build=new org.devops.build()
def tools=new org.devops.tools()
def toemailF=new org.devops.toemailF()String Tenv="${env.Tenv}"
String buildType="${env.buildType}"
String buildshell="${env.buildshell}"pipeline{environment {BUILD_TIME = sh(script: "date '+%Y%m%d_%H%M%S'", returnStdout: true).trim()MINIO_BUCKET = 'frontend-artifacts'}stage("代码编译"){when { expression { !rollback } }  // 非回滚时执行steps{script{tools.PrintMsg("代码编译","build")// 使用共享库中的构建方法,会自动处理依赖安装和构建build.Builds(buildType,buildshell)// 生成带版本号的构建产物名称env.ARTIFACT_NAME = "${JOB_NAME}-${BUILD_TIME}-${env.GIT_COMMIT}.tar.gz"}}}
}

在这里插入图片描述

4、打包并上传至minio

pipeline{environment {BUILD_TIME = sh(script: "date '+%Y%m%d_%H%M%S'", returnStdout: true).trim()MINIO_BUCKET = 'frontend-artifacts'}stage("打包并上传至minio"){when { expression { !rollback } }  // 非回滚时执行steps{script{tools.PrintMsg("构建好的包上传至minio","image_tag")sh """tar -czf ${env.ARTIFACT_NAME} dist/mc cp ${env.ARTIFACT_NAME} myminio/${MINIO_BUCKET}/${JOB_NAME}/"""// 保存部署信息env.DEPLOY_INFO = """应用: ${JOB_NAME}版本: ${BUILD_TIME}-${env.GIT_COMMIT}包路径: ${MINIO_BUCKET}/${JOB_NAME}/${env.ARTIFACT_NAME}"""}}}
}

在这里插入图片描述

四、CD阶段

1、Jenkins凭据添加服务器ssh账密、minio账密
2、将多个destIp按逗号分割成数组,使用each 循环遍历每个服务器IP
3、动态生成minio签名并结合curl命令从minio下载部署包
4、通过sshpass命令连接单个服务器IPa、删除源部署路径下的文件,然后将从minio下载的部署包解压到指定目录b、删除多余目录和下载的tar包
        stage("部署"){when { expression { !rollback } }steps{script {tools.PrintMsg("开始部署", "deploy")withCredentials([usernamePassword(credentialsId: 'target-server-credential',usernameVariable: 'SSH_USER',passwordVariable: 'SSH_PASS'),usernamePassword(credentialsId: 'minio-credentials',usernameVariable: 'MINIO_ACCESS_KEY',passwordVariable: 'MINIO_SECRET_KEY')]) {// 将destIp按逗号分割成数组def servers = destIp.split(',')servers.each { server ->sh """DATE_VALUE=\$(date -R)SIGNATURE=\$(echo -en "GET\\n\\n\\n\${DATE_VALUE}\\n/${MINIO_BUCKET}/${JOB_NAME}/${env.ARTIFACT_NAME}" | openssl sha1 -hmac "\${MINIO_SECRET_KEY}" -binary | base64)# 直接在SSH会话中生成签名和下载sshpass -p \${SSH_PASS} ssh -o StrictHostKeyChecking=no \${SSH_USER}@${server} <<'EOS'cd ${destPath}rm -rf ${destPath}/*# 在远程服务器上重新生成签名DATE_VALUE_REMOTE=\$(date -R)SIGNATURE_REMOTE=\$(echo -en "GET\\n\\n\\n\${DATE_VALUE_REMOTE}\\n/${MINIO_BUCKET}/${JOB_NAME}/${env.ARTIFACT_NAME}" | openssl sha1 -hmac "${MINIO_SECRET_KEY}" -binary | base64)curl -v -X GET -H "Date: \${DATE_VALUE_REMOTE}" \\-H "Authorization: AWS ${MINIO_ACCESS_KEY}:\${SIGNATURE_REMOTE}" \\-o ${env.ARTIFACT_NAME} \\"http://192.168.56.102:8021/${MINIO_BUCKET}/${JOB_NAME}/${env.ARTIFACT_NAME}"if [ -s ${env.ARTIFACT_NAME} ] && file ${env.ARTIFACT_NAME} | grep -q 'gzip compressed data'; thentar xzf ${env.ARTIFACT_NAME} -C ${destPath}/mv ${destPath}/dist/* ${destPath}rm -rf ${destPath}/dist ${destPath}/${env.ARTIFACT_NAME}elseecho "下载的文件无效或不是gzip压缩包"exit 1fi
EOS"""}}}}}

五、回滚阶段

1、Jenkins凭据添加服务器ssh账密、minio账密
2、通过mc ls myminio结合awk命令获取到对应桶中目录下所有的tar包
3、手动选择要回滚的包
4、将多个destIp按逗号分割成数组,使用each 循环遍历每个服务器IP
5、通过sshpass命令连接单个服务器IP,将选择的tar包传入curl下载命令中a、动态生成minio签名并结合curl命令从minio下载回滚的包b、删除源部署路径下的文件,然后将从minio下载的回滚包解压到指定目录c、删除多余目录和下载的tar包
        stage("回滚"){when { expression { rollback } }steps{script {tools.PrintMsg("执行回滚", "rollback")// 获取可用版本列表def versions = sh(script: "mc ls myminio/${MINIO_BUCKET}/${JOB_NAME}/ | awk '{print \$6}'", returnStdout: true).trim().split(',')def selectedVersion = input(message: '选择要回滚的版本', parameters: [choice(name: 'selectedVersion', choices: versions.join(','), description: '可用的构建版本')])// 设置回滚部署信息env.DEPLOY_INFO = """版本: ${selectedVersion}"""withCredentials([usernamePassword(credentialsId: 'target-server-credential',usernameVariable: 'SSH_USER',passwordVariable: 'SSH_PASS'),usernamePassword(credentialsId: 'minio-credentials',usernameVariable: 'MINIO_ACCESS_KEY',passwordVariable: 'MINIO_SECRET_KEY')]) {// 将destIp按逗号分割成数组def servers = destIp.split(',')servers.each { server ->sh """sshpass -p \${SSH_PASS} ssh -o StrictHostKeyChecking=no \${SSH_USER}@${server} <<'EOS'cd ${destPath}rm -rf ${destPath}/*# 在远程服务器上生成签名DATE_VALUE_REMOTE=\$(date -R)SIGNATURE_REMOTE=\$(echo -en "GET\\n\\n\\n\${DATE_VALUE_REMOTE}\\n/${MINIO_BUCKET}/${JOB_NAME}/${selectedVersion}" | openssl sha1 -hmac "${MINIO_SECRET_KEY}" -binary | base64)curl -v -X GET -H "Date: \${DATE_VALUE_REMOTE}" \\-H "Authorization: AWS ${MINIO_ACCESS_KEY}:\${SIGNATURE_REMOTE}" \\-o ${selectedVersion} \\"http://192.168.56.102:8021/${MINIO_BUCKET}/${JOB_NAME}/${selectedVersion}"if [ -s ${selectedVersion} ] && file ${selectedVersion} | grep -q 'gzip compressed data'; thentar xzf ${selectedVersion} -C ${destPath}/mv ${destPath}/dist/* ${destPath}/rm -rf ${destPath}/dist ${destPath}/${selectedVersion}elseecho "下载的文件无效或不是gzip压缩包"exit 1fi
EOS"""}}}}}}

六、构建通知

1、不管构建成功还是失败,都发送对应的邮件给接收者

在这里插入图片描述

    post {always {script {TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"))env.BUILD_TIME = new Date().format("yyyyMMdd_HHmmss")def buildTime = env.BUILD_TIME ?: "N/A"def buildDuration = currentBuild.durationString ?: "N/A"toemailF.Email(currentBuild.currentResult,"${Tenv}","${env.emailUser}","${JOB_NAME}","${branch}","${env.BUILD_USER}",buildTime,buildDuration,rollback,"服务器: ${destIp}",env.DEPLOY_INFO ?: "无部署信息","${srcURL}")}}}

七、实战演示–发布/回滚前端项目

1、Jenkins创建流水线项目

在这里插入图片描述

在这里插入图片描述

2、执行构建

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

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

3、执行回滚

1、构建rollback选项
2、部署路径不变
3、勾选回滚机器IP destIp

在这里插入图片描述

在这里插入图片描述

八、完整pipeline

#!groovy
@Library("jenkinslib") _//func from sharelibrary调用共享库
def build=new org.devops.build()
def tools=new org.devops.tools()
def toemailF=new org.devops.toemailF()String Tenv="${env.Tenv}"
String buildType="${env.buildType}"
String buildshell="${env.buildshell}"
String srcURL="${env.SrcURL}"
String branch="${env.branchName}"
String destPath="${env.destPath}"
String destIp="${env.destIp}"
Boolean rollback = (env.rollback == 'true')
pipeline{agent {label 'master'}options {timestamps()skipDefaultCheckout()  // 禁用隐式 Checkouttimeout(time: 1, unit: 'HOURS') //设置流水线超时}environment {BUILD_TIME = sh(script: "date '+%Y%m%d_%H%M%S'", returnStdout: true).trim()MINIO_BUCKET = 'frontend-artifacts'}stages{stage("CheckOut"){when { expression { !rollback } }  // 非回滚时执行steps{script{tools.PrintMsg("获取分支: ${branch}","checkout")tools.PrintMsg("获取代码","checkout")checkout([$class: 'GitSCM', branches: [[name: "${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: 'gitee_registry_ssh', url: "${srcURL}"]]])// 记录当前commit信息用于追踪env.GIT_COMMIT = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()}}}stage("代码编译"){when { expression { !rollback } }  // 非回滚时执行steps{script{tools.PrintMsg("代码编译","build")// 使用共享库中的构建方法,会自动处理依赖安装和构建build.Builds(buildType,buildshell)// 生成带版本号的构建产物名称env.ARTIFACT_NAME = "${JOB_NAME}-${BUILD_TIME}-${env.GIT_COMMIT}.tar.gz"}}}stage("打包并上传至minio"){when { expression { !rollback } }  // 非回滚时执行steps{script{tools.PrintMsg("构建好的包上传至minio","image_tag")sh """tar -czf ${env.ARTIFACT_NAME} dist/mc cp ${env.ARTIFACT_NAME} myminio/${MINIO_BUCKET}/${JOB_NAME}/"""// 保存部署信息env.DEPLOY_INFO = """应用: ${JOB_NAME}版本: ${BUILD_TIME}-${env.GIT_COMMIT}包路径: ${MINIO_BUCKET}/${JOB_NAME}/${env.ARTIFACT_NAME}"""}}}stage("部署"){when { expression { !rollback } }steps{script {tools.PrintMsg("开始部署", "deploy")withCredentials([usernamePassword(credentialsId: 'target-server-credential',usernameVariable: 'SSH_USER',passwordVariable: 'SSH_PASS'),usernamePassword(credentialsId: 'minio-credentials',usernameVariable: 'MINIO_ACCESS_KEY',passwordVariable: 'MINIO_SECRET_KEY')]) {// 将destIp按逗号分割成数组def servers = destIp.split(',')servers.each { server ->sh """# 直接在SSH会话中生成签名和下载sshpass -p \${SSH_PASS} ssh -o StrictHostKeyChecking=no \${SSH_USER}@${server} <<'EOS'cd ${destPath}rm -rf ${destPath}/*# 在远程服务器上重新生成签名DATE_VALUE_REMOTE=\$(date -R)SIGNATURE_REMOTE=\$(echo -en "GET\\n\\n\\n\${DATE_VALUE_REMOTE}\\n/${MINIO_BUCKET}/${JOB_NAME}/${env.ARTIFACT_NAME}" | openssl sha1 -hmac "${MINIO_SECRET_KEY}" -binary | base64)curl -v -X GET -H "Date: \${DATE_VALUE_REMOTE}" \\-H "Authorization: AWS ${MINIO_ACCESS_KEY}:\${SIGNATURE_REMOTE}" \\-o ${env.ARTIFACT_NAME} \\"http://192.168.56.102:8021/${MINIO_BUCKET}/${JOB_NAME}/${env.ARTIFACT_NAME}"if [ -s ${env.ARTIFACT_NAME} ] && file ${env.ARTIFACT_NAME} | grep -q 'gzip compressed data'; thentar xzf ${env.ARTIFACT_NAME} -C ${destPath}/mv ${destPath}/dist/* ${destPath}rm -rf ${destPath}/dist ${destPath}/${env.ARTIFACT_NAME}elseecho "下载的文件无效或不是gzip压缩包"exit 1fi
EOS"""}}}}}// 5. 回滚机制stage("回滚"){when { expression { rollback } }steps{script {tools.PrintMsg("执行回滚", "rollback")// 获取可用版本列表def versions = sh(script: "mc ls myminio/${MINIO_BUCKET}/${JOB_NAME}/ | awk '{print \$6}'", returnStdout: true).trim().split(',')def selectedVersion = input(message: '选择要回滚的版本', parameters: [choice(name: 'selectedVersion', choices: versions.join(','), description: '可用的构建版本')])// 设置回滚部署信息env.DEPLOY_INFO = """版本: ${selectedVersion}"""withCredentials([usernamePassword(credentialsId: 'target-server-credential',usernameVariable: 'SSH_USER',passwordVariable: 'SSH_PASS'),usernamePassword(credentialsId: 'minio-credentials',usernameVariable: 'MINIO_ACCESS_KEY',passwordVariable: 'MINIO_SECRET_KEY')]) {// 将destIp按逗号分割成数组def servers = destIp.split(',')servers.each { server ->sh """sshpass -p \${SSH_PASS} ssh -o StrictHostKeyChecking=no \${SSH_USER}@${server} <<'EOS'cd ${destPath}rm -rf ${destPath}/*# 在远程服务器上生成签名DATE_VALUE_REMOTE=\$(date -R)SIGNATURE_REMOTE=\$(echo -en "GET\\n\\n\\n\${DATE_VALUE_REMOTE}\\n/${MINIO_BUCKET}/${JOB_NAME}/${selectedVersion}" | openssl sha1 -hmac "${MINIO_SECRET_KEY}" -binary | base64)curl -v -X GET -H "Date: \${DATE_VALUE_REMOTE}" \\-H "Authorization: AWS ${MINIO_ACCESS_KEY}:\${SIGNATURE_REMOTE}" \\-o ${selectedVersion} \\"http://192.168.56.102:8021/${MINIO_BUCKET}/${JOB_NAME}/${selectedVersion}"if [ -s ${selectedVersion} ] && file ${selectedVersion} | grep -q 'gzip compressed data'; thentar xzf ${selectedVersion} -C ${destPath}/mv ${destPath}/dist/* ${destPath}/rm -rf ${destPath}/dist ${destPath}/${selectedVersion}elseecho "下载的文件无效或不是gzip压缩包"exit 1fi
EOS"""}}}}}}post {always {script {TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"))env.BUILD_TIME = new Date().format("yyyyMMdd_HHmmss")def buildTime = env.BUILD_TIME ?: "N/A"def buildDuration = currentBuild.durationString ?: "N/A"toemailF.Email(currentBuild.currentResult,"${Tenv}","${env.emailUser}","${JOB_NAME}","${branch}","${env.BUILD_USER}",buildTime,buildDuration,rollback,"服务器: ${destIp}",env.DEPLOY_INFO ?: "无部署信息","${srcURL}")}}}
}

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go语言超时控制方案全解析:基于goroutine的优雅实现

一、引言 在构建高可靠的后端服务时&#xff0c;超时控制就像是守护系统稳定性的"安全阀"&#xff0c;它确保当某些操作无法在预期时间内完成时&#xff0c;系统能够及时止损并释放资源。想象一下&#xff0c;如果没有超时控制&#xff0c;一个简单的数据库查询卡住…

WTK6900C-48L:离线语音芯片重构玩具DNA,从“按键操控”到“声控陪伴”的交互跃迁

一&#xff1a;开发背景 随着消费升级和AI技术进步&#xff0c;传统玩具的机械式互动已难以满足市场需求。语音控制芯片的引入使玩具实现了从被动玩耍到智能交互的跨越式发展。通过集成高性价比的语音识别芯片&#xff0c;现代智能玩具不仅能精准响应儿童指令&#xff0c;还能实…

WebSocket的原理及QT示例

一.WebSocket 介绍 1.概述 WebSocket 是一种在单个 TCP 连接上进行全双工通讯的协议&#xff0c;它在 2011 年被 IETF 定为标准 RFC 6455&#xff0c;并由 RFC7936 补充规范。与传统的 HTTP 协议不同&#xff0c;WebSocket 允许服务器和客户端之间进行实时、双向的数据传输&a…

设置GO程序在离线情况下读取本地缓存的模块

在 Go 中&#xff0c;GOPROXY 环境变量用于指定模块代理服务器的地址。如果你想让 GOPROXY 读取本地的模块&#xff0c;可以通过以下几种方式实现&#xff1a; 1. 使用本地代理服务器 你可以搭建一个本地的 Go 模块代理服务器&#xff0c;将需要的模块代码推送到代理服务器中…

live555开发笔记(三):live555创建RTSP服务器源码剖析,创建h264文件rtsp服务器源码深度剖析

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/147879917 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

STM32-模电

目录 一、MOS管 二、二极管 三、IGBT 四、运算放大器 五、推挽、开漏、上拉电阻 一、MOS管 1. MOS简介 这里以nmos管为例&#xff0c;注意箭头方向。G门极/栅极&#xff0c;D漏极&#xff0c;S源极。 当给G通高电平时&#xff0c;灯泡点亮&#xff0c;给G通低电平时&a…

基于定制开发开源AI智能名片S2B2C商城小程序的公私域流量融合运营策略研究

摘要&#xff1a;本文以定制开发开源AI智能名片S2B2C商城小程序为技术载体&#xff0c;系统探讨公域流量向私域流量沉淀的数字化路径。研究通过分析平台流量&#xff08;公域流量&#xff09;与私域流量的共生关系&#xff0c;提出"公域引流-私域沉淀-数据反哺"的闭环…

mysql中索引的使用

前言 最近一直在学习mysql以及忙学校课程的事情。已经好久没写过博客了&#xff0c;今天跟大家分享一下在mysql中关于索引的知识&#xff0c;希望可以帮助到大家。 索引的定义 mysql中的索引是一种数据结构&#xff0c;它可以帮助数据库高效地查询&#xff0c;更新数据表中的…

深度拆解!MES如何重构生产计划与排产调度全流程?

☂引言 在制造业数字化转型浪潮中&#xff0c;生产计划与排产调度的精准性直接决定企业竞争力。深蓝易网MES系统通过智能化调度与全流程管控&#xff0c;帮助企业破解排产难题&#xff0c;实现资源高效协同与生产透明化管理&#xff0c;为制造企业打造柔性化、敏捷化的生产体系…

【深度学习】计算机视觉(18)——从应用到设计

文章目录 1 不同的注意力机制1.1 自注意力1.2 多头注意力1.3 交叉注意力1.3.1 基础1.3.2 进阶 1 不同的注意力机制 在学习的过程中&#xff0c;发现有很多计算注意力的方法&#xff0c;例如行/列注意力、交叉注意力等&#xff0c;如果对注意力机制本身不是特别实现&#xff0c…

洛谷 P1955 [NOI2015] 程序自动分析

【题目链接】 洛谷 P1955 [NOI2015] 程序自动分析 【题目考点】 1. 并查集 2. 离散化 【解题思路】 多组数据问题&#xff0c;对于每组数据&#xff0c;有多个 x i x j x_ix_j xi​xj​或 x i ≠ x j x_i \neq x_j xi​xj​的约束条件。 所有相等的变量构成一个集合&…

[Java] 输入输出方法+猜数字游戏

目录 1. 输入输出方法 1.1 输入方法 1.2 输出方法 2. 猜数字游戏 1. 输入输出方法 Java中输入和输出是属于Scanner类里面的方法&#xff0c;如果要使用这两种方法需要引用Scanner类。 import java.util.Scanner; java.util 是Java里面的一个包&#xff0c;里面包含一些工…

zst-2001 上午题-历年真题 UML(13个内容)

UML基础 UML - 第1题 ad UML - 第2题 依赖是暂时使用对象&#xff0c;关联是长期连接 依赖&#xff1a;依夜情 关联&#xff1a;天长地久 组合&#xff1a;组一辈子乐队 聚合&#xff1a;好聚好散 bd UML - 第3题 adc UML - 第4题 bad UML - 第5题 d UML…

WebFlux vs WebMVC vs Servlet 对比

WebFlux vs WebMVC vs Servlet 技术对比 WebFlux、WebMVC 和 Servlet 是 Java Web 开发中三种不同的技术架构&#xff0c;它们在编程模型、并发模型和适用场景上有显著区别。以下是它们的核心对比&#xff1a; 核心区别总览 特性ServletSpring WebMVCSpring WebFlux编程模型…

htmlUnit和Selenium的区别以及使用BrowserMobProxy捕获网络请求

1. Selenium&#xff1a;浏览器自动化之王 核心定位&#xff1a; 跨平台、跨语言的浏览器操控框架&#xff0c;通过驱动真实浏览器实现像素级用户行为模拟。 技术架构&#xff1a; 核心特性&#xff1a; 支持所有主流浏览器&#xff08;含移动端模拟&#xff09; 精…

SSRF相关

SSRF(Server Side Request Forgery,服务器端请求伪造)&#xff0c;攻击者以服务器的身份发送一条构造好的请求给服务器所在地内网进行探测或攻击。 产生原理&#xff1a; 服务器端提供了能从其他服务器应用获取数据的功能&#xff0c;如从指定url获取网页内容、加载指定地址的图…

SaaS备份的必要性:厂商之外的数据保护策略

在当今数字化时代&#xff0c;企业对SaaS&#xff08;软件即服务&#xff09;应用的依赖程度不断攀升。SaaS应用为企业提供了便捷的生产力工具&#xff0c;然而&#xff0c;这也使得数据安全面临诸多挑战&#xff0c;如意外删除、勒索软件攻击以及供应商故障等。因此&#xff0…

【Python 基础语法】

Python 基础语法是编程的基石&#xff0c;以下从核心要素到实用技巧进行系统梳理&#xff1a; 一、代码结构规范 缩进规则 使用4个空格缩进&#xff08;PEP 8标准&#xff09;缩进定义代码块&#xff08;如函数、循环、条件语句&#xff09; def greet(name):if name: # 正确缩…

利用“Flower”实现联邦机器学习的实战指南

一个很尴尬的现状就是我们用于训练 AI 模型的数据快要用完了。所以我们在大量的使用合成数据&#xff01; 据估计&#xff0c;目前公开可用的高质量训练标记大约有 40 万亿到 90 万亿个&#xff0c;其中流行的 FineWeb 数据集包含 15 万亿个标记&#xff0c;仅限于英语。 作为…

自动化测试与功能测试详解

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 什么是自动化测试? 自动化测试是指利用软件测试工具自动实现全部或部分测试&#xff0c;它是软件测试的一个重要组成 部分&#xff0c;能完成许多手工测试无…