《企業級前端部署方案:Jenkins+MinIO+SSH+Gitee+Jenkinsfile自動化實踐》

文章目錄

  • 前言
    • 前端項目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;能完成許多手工測試無…