Windows .NET8 实现 远程一键部署,几秒完成发布,提高效率 - CICD

news2024/9/20 22:24:52

1. 前言

场景 (工作环境 一键部署 到 远端服务器 [阿里云])

在这里插入图片描述

CICD 基本步骤回顾

https://blog.csdn.net/CsethCRM/article/details/141604638

2. 环境准备

服务器端IP:106.15.74.25(阿里云服务器)
客户端:工作电脑/开发电脑

2.1 安装 7z

服务器 和 客户端(工作电脑) 均需安装
安装目录:C:\Program Files\7-Zip\7z.exe

2.2 安装 Open SSH

参照文章:https://blog.csdn.net/CsethCRM/article/details/141605350

2.3 SSH 服务器设置免密登录

参照文章:https://blog.csdn.net/CsethCRM/article/details/141854199

2.4 远端服务器准备 [ 阿里云 ]

在这里插入图片描述

2.5 本地开发环境 新建一个Web项目即可

CI.bat 放在项目目录

在这里插入图片描述

3.运行CI.bat,进行一键部署 【几秒钟就结束了】

点击CI.bat 进行一键部署

项目源代码 -> publish -> 服务器部署 -> 站点正常运行 几秒钟就完成了

CI一键部署WebSite

一键部署完毕,服务器如下:

在这里插入图片描述

4. 改动代码,再次运行 CI.bat,服务器端已经是改变后的代码 【从改完代码到部署上线只要几秒钟】

改代码后,使用CI再次发布

5.总结

  • 掌握了 利用 bat 进行 cicd
  • 从编码结束 到 部署上线
  • 整个过程 只需要 几秒钟
  • 大大提高日常的效率

附录

CI.bat 参照(中文乱码时,文件要用GB2312 格式):

@echo off
setlocal EnableDelayedExpansion

:: ---------- 时间统计输出 start
for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
  set "DEL=%%a"
)
:start
set StartTimeTxt=CI开始时间是%time:~0,2%点%time:~3,2%分%time:~6,2%秒
call :ColorText 0a "%StartTimeTxt%"
echo.
set StartTime=%time%
:: ---------- 时间统计输出 end


:: 打开当前目录
cd /d %~dp0
:: 返回上一级
cd..


:: ---------- 1. 自定义设置 start ...

:: [ -- 自定义-- ] 设置7z的命令行程序路径  ↓↓↓ 7z环境设置
set zip7=C:\Program Files\7-Zip\7z.exe

:: [ -- 自定义-- ] 发布环境 ↓↓↓ 多环境设置
set Env=Staging

:: [ -- 自定义-- ] 项目名称,发布使用  ↓↓↓ 发布Web站点的设置
set PrjName=MyMvcWeb
:: [ -- 自定义-- ] 解决方案目录 
set SlnDir=D:\vscode-workspace\MyWeb
:: [ -- 自定义-- ] 启动项目
set csproj=MyMvcWeb\MyMvcWeb.csproj  
:: [ -- 自定义-- ] 本地暂存盘,建议发布相关的操作目录都在此盘符下,避免不断用命令切盘符 
set DriveLetterLocal=D:
:: [ -- 自定义-- ] Web发布包输出文件夹根目录
set OutRoot=%DriveLetterLocal%\ci-web-pkgs\
:: [ -- 自定义-- ] Web 发布包目录,这个包最终会传输至发布服务器进行发布
set OutDir=%OutRoot%%PrjName%\

:: [ -- 自定义-- ] SSH地址  ↓↓↓ 远程服务器SSH信息设置
set SshAddress=远程服务器IP
:: [ -- 自定义-- ] SSH账号
set SshUser=SSH账号
:: [ -- 自定义-- ] SSH端口
set SshPort=SSH端口,通常是 22
:: [ -- 自定义-- ] SSH证书 - 私钥路径
set SshKeyPath=C:\Users\自己电脑的用户名\.ssh\id_rsa

:: [ -- 自定义-- ] REM 服务端的CD脚本路径 ↓↓↓ 远程服务器其它设置
set ServerCD=C:\web-release\MyMvcWeb\CD.bat
:: [ -- 自定义-- ] REM 服务端的临时发布包目录
set ServerTempPubPkgs=C:\web-release\temp-publish-pkgs

:: ---------- 1. 自定义设置 finished ...


:: ---------- 2.clear history start ...
%DriveLetterLocal%
cd %OutRoot%
echo clear history Start	...... 
echo %OutDir%
REM 清理掉Web发布包输出文件夹目录
rmdir /s /q %OutDir%
echo clear history Finished	...... 

:: ---------- 2.clear history finished ...


:: ---------- 3. publish start ...

REM 进入本地发布盘符
%DriveLetterLocal%

if not exist %OutRoot% (
    mkdir %OutRoot%
    echo %OutRoot% created successfully.
) else (
    echo %OutRoot% already exists.
)



if not exist %OutDir% (
    mkdir %OutDir%
    echo %OutDir% created successfully.
) else (
    echo %OutDir% already exists.
)


echo publish Start	...... 
cd %SlnDir%
dotnet publish "%csproj%" --no-self-contained -c Release /p:EnvironmentName=%Env% -o %OutDir%
echo publish Finished	...... 

:: ---------- 3. publish project finished ...

:: ---------- 4. delete *.pdb temp files & compress & Upload Publish Pkgs start ...

REM 进入本地发布目录   	↓↓↓ delete *.pdb temp files
cd %OutDir%
:: 检查是否存在以 .pdb 为后缀的文仿
dir /B *.pdb > nul 2>&1
REM 当检测出需要处理的文件后进行处琿
if %errorlevel% equ 0 (
:: 存在仿.pdb 为后缀的文件,删除它们
    del /Q *.pdb
    echo delete all rar file success
) else (
    echo rar file not found
)

:: ↓↓↓ compress - 把发布的文件压缩
cd %OutDir%
echo compress Start	......
:: 设置要打包的研所包文件夹 OutDir 上边已经有变釿
"%zip7%" a -tzip "%PrjName%.7z" "%OutDir%" -mx9
echo compress Finished	.....

:: ↓↓↓ Upload Publish Pkgs - 把压缩包上传到远程目录
:: 发送到服务端的临时发布包目录
scp "%OutDir%%PrjName%.7z" %SshUser%@%SshAddress%:%ServerTempPubPkgs%

:: ---------- 4. delete *.pdb temp files & compress & Upload Publish Pkgs finished ...

:: ---------- 时间统计输出 start
set CIEndTime=%time%
set CIEndTimeTxt=CI结束时间是%time:~0,2%点%time:~3,2%分%time:~6,2%秒
call :ColorText 0a "%CIEndTimeTxt%"
echo.
call :ColorText 0a "CD执行开始"
echo.
:: ---------- 时间统计输出  end

:: ---------- 5. execute server cd.bat start ...

:: SSH 执行远程服务器的CD命令
echo execute cd.bat Start	......
ssh %SshUser%@%SshAddress%  -p %SshPort% -i "%SshKeyPath%" %ServerCD%
echo execute cd.bat End	......
:: ---------- 5. execute server cd.bat finished ...

:: 打开发布的网站
start http://106.15.74.25:80

:: 时间统计输出-----------------------------------------------------start-----------------------------------------------------
:: 这里更换编码格式为了改变字体颜色
chcp 936
set CDEndTime=%time%
set CDEndTimeTxt=CD结束时间是%time:~0,2%点%time:~3,2%分%time:~6,2%秒
call :ColorText 0a "%CDEndTimeTxt%"
echo.
echo.
call :ColorText 0a "%StartTimeTxt%"
echo.
call :ColorText 0a "%CIEndTimeTxt%"
echo.
call :ColorText 0a "%CDEndTimeTxt%"
echo.
echo.


set StartTimeH=%StartTime:~0,2%
set CIEndTimeH=%CIEndTime:~0,2%
set CDEndTimeH=%CDEndTime:~0,2%
set StartTimeM=%StartTime:~3,2%
set CIEndTimeM=%CIEndTime:~3,2%
set CDEndTimeM=%CDEndTime:~3,2%
set StartTimeS=%StartTime:~6,2%
set CIEndTimeS=%CIEndTime:~6,2%
set CDEndTimeS=%CDEndTime:~6,2%

if %StartTimeH:~0,1%==0 set /a StartTimeH=%StartTimeH:~1,1%*1
if %CIEndTimeH:~0,1%==0 set /a CIEndTimeH=%CIEndTimeH:~1,1%*1
if %CDEndTimeH:~0,1%==0 set /a CDEndTimeH=%CDEndTimeH:~1,1%*1
if %StartTimeM:~0,1%==0 set /a StartTimeM=%StartTimeM:~1,1%*1
if %CIEndTimeM:~0,1%==0 set /a CIEndTimeM=%CIEndTimeM:~1,1%*1
if %CDEndTimeM:~0,1%==0 set /a CDEndTimeM=%CDEndTimeM:~1,1%*1
if %StartTimeS:~0,1%==0 set /a StartTimeS=%StartTimeS:~1,1%*1
if %CIEndTimeS:~0,1%==0 set /a CIEndTimeS=%CIEndTimeS:~1,1%*1
if %CDEndTimeS:~0,1%==0 set /a CDEndTimeS=%CDEndTimeS:~1,1%*1

set /a StartTimeSecond=%StartTimeH%*3600+%StartTimeM%*60+%StartTimeS%  
set /a CIEndTimeSecond=%CIEndTimeH%*3600+%CIEndTimeM%*60+%CIEndTimeS%
set /a CDEndTimeSecond=%CDEndTimeH%*3600+%CDEndTimeM%*60+%CDEndTimeS%

set /a StartTimeDiff=%CIEndTimeSecond%-%StartTimeSecond%
set /a CIEndTimeDiff=%CDEndTimeSecond%-%CIEndTimeSecond%
set /a CDEndTimeDiff=%CDEndTimeSecond%-%StartTimeSecond%


set /a StartTimeDiffH=%StartTimeDiff%/3600
set /a CIEndTimeDiffH=%CIEndTimeDiff%/3600
set /a CDEndTimeDiffH=%CDEndTimeDiff%/3600

set /a StartTimeDiffM=(%StartTimeDiff%-%StartTimeDiffH%*3600)/60  
set /a CIEndTimeDiffM=(%CIEndTimeDiff%-%CIEndTimeDiffH%*3600)/60  
set /a CDEndTimeDiffM=(%CDEndTimeDiff%-%CDEndTimeDiffH%*3600)/60  

set /a StartTimeDiffS=%StartTimeDiff%-%StartTimeDiffH%*3600-%StartTimeDiffM%*60
set /a CIEndTimeDiffS=%CIEndTimeDiff%-%CIEndTimeDiffH%*3600-%CIEndTimeDiffM%*60
set /a CDEndTimeDiffS=%CDEndTimeDiff%-%CDEndTimeDiffH%*3600-%CDEndTimeDiffM%*60

if %StartTimeDiffH% LSS 10 set StartTimeDiffH=0%StartTimeDiffH%
if %CIEndTimeDiffH% LSS 10 set CIEndTimeDiffH=0%CIEndTimeDiffH%
if %CDEndTimeDiffH% LSS 10 set CDEndTimeDiffH=0%CDEndTimeDiffH%
if %StartTimeDiffM% LSS 10 set StartTimeDiffM=0%StartTimeDiffM%
if %CIEndTimeDiffM% LSS 10 set CIEndTimeDiffM=0%CIEndTimeDiffM%
if %CDEndTimeDiffM% LSS 10 set CDEndTimeDiffM=0%CDEndTimeDiffM%
if %StartTimeDiffS% LSS 10 set StartTimeDiffS=0%StartTimeDiffS%
if %CIEndTimeDiffS% LSS 10 set CIEndTimeDiffS=0%CIEndTimeDiffS%
if %CDEndTimeDiffS% LSS 10 set CDEndTimeDiffS=0%CDEndTimeDiffS%

call :ColorText 0a "CI耗时%StartTimeDiffH%时%StartTimeDiffM%分%StartTimeDiffS%秒"
echo.                                     
call :ColorText 0a "CD耗时%CIEndTimeDiffH%时%CIEndTimeDiffM%分%CIEndTimeDiffS%秒"
echo.                                     
call :ColorText 0a "总耗时%CDEndTimeDiffH%时%CDEndTimeDiffM%分%CDEndTimeDiffS%秒"
echo.
echo.

:: 时间统计输出-----------------------------------------------------end-----------------------------------------------------

if not %errorlevel%==0 goto fail
if %errorlevel%==0 goto success
:fail
call :ColorText 0c "执行失败,请检查"
pause
exit
:success
call :ColorText 0a "执行成功,当前窗口会在3秒钟自动关闭"
TIMEOUT /T 3

:: 时间统计输出-----------------------------------------------------start-----------------------------------------------------
goto :eof
:ColorText
echo off
<nul set /p ".=%DEL%" > "%~2"
findstr /v /a:%1 /R "^$" "%~2" nul
del "%~2" > nul 2>&1
goto :eof
:: 时间统计输出-----------------------------------------------------end-----------------------------------------------------




pause

CD.bat 参照(中文乱码时,文件要用GB2312 格式):

chcp 65001

REM @echo off
REM SETLOCAL EnableDelayedExpansion

::切换到当前目录
cd /d %~dp0
:: ------------------------------------------- 工具相关配置 
:: 7z安装目录
set zip7=C:\Program Files\7-Zip\7z.exe

:: ------------------------------------------- 项目发布相关配置 
:: 项目名称 和 CI中的项目名称一致
set ProjectName=MyMvcWeb
:: IIS 部署目录
set IISWebSiteDir=%~dp0
:: Web 发布包目录
set PublishcPkgsDir=C:\web-release\temp-publish-pkgs


:: ------------------------------------------- IIS相关配置 
:: Web站点名称
set WebSiteName="CICD-MyWebSite"
:: 站点端口
set WebSitePort="80"

:: Web应用程序池名称
set WebSitePoolName="CICD-MyWebSitePool"
:: 程序池版本
set WebSitePoolVersion=""
:: 是否开启32位
set Enable32BitAppOnWin64="false"

:: 获取应用程序池列表
C:\Windows\System32\inetsrv\appcmd.exe list apppool /apppool.name:%WebSitePoolName%
:: 如果不存在程序池就新建
IF ERRORLEVEL 0 (
	C:\Windows\System32\inetsrv\appcmd.exe add apppool /name:%WebSitePoolName% /managedRuntimeVersion:%WebSitePoolVersion% /Enable32BitAppOnWin64:%Enable32BitAppOnWin64%
)

:: 获取Web站点列表
C:\Windows\System32\inetsrv\appcmd.exe list site /site.name:%WebSiteName%
:: 如果不存在站点就新建
IF ERRORLEVEL 0 (
	C:\Windows\System32\inetsrv\appcmd.exe add site /name:%WebSiteName% /bindings:http/*:%WebSitePort%: /applicationDefaults.applicationPool:%WebSitePoolName% /physicalPath:%~dp0
)

:: 发布前  停止一下IIS站点
@echo stop WebSite start...
@C:\Windows\System32\inetsrv\appcmd.exe stop site %WebSiteName%
@echo stop WebSite finished...

:: 停止应用程序池
@echo stop WebSite start...
C:\Windows\System32\inetsrv\appcmd.exe stop apppool /apppool.name:%WebSitePoolName%
@echo stop WebSite finished... 

:: 等待几秒 确保所有文件都不被占用
echo 等待1秒,确保所有文件都不被占用 ...
timeout /t 1 /nobreak
echo 1秒已过,继续执行。

:: 解压前,删除临时发布目录
rmdir /s /q "%PublishcPkgsDir%\%ProjectName%
::  用7z 解压文件到发布包临时目录,x 解压文件 -o指定解压目的地
"%zip7%" x -o"%PublishcPkgsDir%" "%PublishcPkgsDir%\%ProjectName%.7z"

::  从发布包临时目录 Copy 发布文件到 IIS Web站点目录
xcopy "%PublishcPkgsDir%\%ProjectName%\*.*" "%IISWebSiteDir%" /s /e /y

:: 启动应用程序池
@echo stop WebSite start...
C:\Windows\System32\inetsrv\appcmd.exe start apppool /apppool.name:%WebSitePoolName%
@echo stop WebSite finished...

:: 启动IIS站点
@echo Restart WebSite start...
@C:\Windows\System32\inetsrv\appcmd.exe start site %WebSiteName%
@echo Restart WebSite finished...

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

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

相关文章

金蝶云星空协同平台业务对象下同时存在未加载未引入对象的原因分析和处理方式

文章目录 问题截图原因分析&#xff0c;解决方式 问题截图 原因分析&#xff0c;解决方式 未加载是 别的账套提交的数据&#xff0c;本账套不存在&#xff0c;点击加载则回、会同步到当前数据中心 未引入&#xff0c;则是在A账套删除后提交到应用&#xff0c;在B账套则显示未…

使用go语言获取海南七星彩历史开奖记录并打印输出

效果如下 : 1.引用json与http模块 import ("encoding/json""fmt""github.com/nahid/gohttp" ) 2.创建请求: req := gohttp.NewRequest()resp, err := req.Get("这里填写请求地址")if err != nil {panic(err)} 3.处理响应结果 : if…

数据恢复工具,电脑+手机双端,十分好用!

哈喽&#xff0c;各位小伙伴们好&#xff0c;我是给大家带来各类黑科技与前沿资讯的小武。 今天给大家安利两款数据恢复工具&#xff0c;分别为电脑手机双端&#xff0c;无论是因为格式化误操作、设备损坏还是其他意外情况&#xff0c;都能轻松找回重要的文件、照片、视频等数…

JavaScript编程语言的学习

一、JavaScript介绍 JavaScript 是一种轻量级的脚本语言。所谓“脚本语言”&#xff0c;指的是它不具备开发操作系统的能力&#xff0c;而是只用来编写控制其他大型应用程序的“脚本”。 JavaScript 是一种嵌入式&#xff08;embedded&#xff09;语言。它本身提供的核心语法不…

【流式输出】LangChain流式输出的概念

&#x1f601; 作者简介&#xff1a;一名大四的学生&#xff0c;致力学习前端开发技术 ⭐️个人主页&#xff1a;夜宵饽饽的主页 ❔ 系列专栏&#xff1a;JavaScript小贴士 &#x1f450;学习格言&#xff1a;成功不是终点&#xff0c;失败也并非末日&#xff0c;最重要的是继续…

Visual Studio提示‘缺少MSVXXXX.dll文件’和‘应用程序无法正常启动0xc000007b’的解决办法

vs调试bug记录 1提示&#xff1a;缺失MSVCR120D.dll 在该地址下载dll文件&#xff1a; https://cn.dll-files.com/search/?qMSVCR120D.dll 下载之后放入本地C:\Windows\System32文件夹里面&#xff0c;缺失MSVCR120D.dll的错误信息消失 2提示&#xff1a;应用程序无法正常启…

深入解析Linux轻量级进程:线程的概念、原理、优缺点及其与进程的关系与区别

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;Linux从入门到进阶 欢迎大家点赞收藏评论&#x1f60a; 目录 &#x1f4da;Linux线程&#x1f4d5;什么是线程*可以使用多进程去并发的执行一个进程的代码&#xff0c;那为什么要由线程呢&#x…

Dev C++:简单步骤下载与安装指南

1. 前言 在当今这个数字化时代&#xff0c;编程已成为连接创意与技术的桥梁&#xff0c;它不仅推动着科技的进步&#xff0c;也深刻地改变着我们的生活方式。对于初学者而言&#xff0c;选择一款合适且易于上手的集成开发环境&#xff08;IDE&#xff09;是学习编程旅程中的重…

Vmware虚拟机断电重启后无法正常启动报Unmount and run xfs_repair

目录 一、问题描述二、解决方法 一、问题描述 Vmware虚拟机断电重启后无法正常启动&#xff0c;报错信息如下&#xff1a; 二、解决方法 执行以下命令&#xff1a; umount /dev/sda5 xfs_repair -L /dev/sda5 reboot

jmeter响应断言、json断言、断言持续时间、大小断言操作

在jmeter断言当中、常用的有响应断言、json断言、断言持续时间&#xff0c;大小断言等 一、响应断言 Apply to&#xff1a;断言应用的范围&#xff0c;这里默认&#xff0c;通常发出一个请求只触发一个服务器测试字段 响应文本&#xff0c;response响应体内的信息响应代码&am…

awk详解

文章目录 一、概述二、工作原理三、工作流程3.1 运行模式3.2 执行流程 四、基本语法4.1 命令格式 五、实战案例5.1 开始块&#xff08;BEGIN block&#xff09;5.1.1print 5.2 内置变量5.3 BEGIN END 运算5.3.1 扩展生产&#xff1a;网卡的ip、流量5.3.2 根分区的可用量5.3.3 a…

python与pytroch相关

1.pytroch模型类 PyTorch 是一个易学且清晰明了的深度学习库。本节讲解如何查看一个模型的结构。 首先&#xff0c;最简单创建模型的方式如下&#xff1a; #导入必要的库 import torch.nn as nn myNetnn.Sequential(nn.Linear(2,10),#第一层&#xff08;全连接层&#xff09;&…

Leetcode236经典题目二叉树的最近公共祖先

本次为大家带来的题目是leetcode236二叉树的最近公共祖先 本道题的直观思路是自底向上进行寻找&#xff0c;如果存在的话那么向上返回&#xff0c;如何能够自底向上遍历呢&#xff1f;我们可以利用回溯进行处理&#xff0c;那么需要注意的是进行回溯的时候一定要使用后序遍历来…

Centos7安装FFmpeg详细步骤(已验证成功)

最近我们需要使用FFmpeg来合成视频功能&#xff0c;这就需要用到服务器必须安装FFmpeg了。 FFmpeg 是一款功能强大的跨平台命令行工具&#xff0c;可以处理各种音频和视频文件&#xff0c;包括转换视频和音频格式、剪辑、合并视频和音频、提取音频、添加字幕、添加水印、调整视…

读书学习笔记入门 # Datawhale X 李宏毅苹果书 AI夏令营

文章目录 学习目标&#xff1a;学习内容&#xff1a;Task 1 通过案例了解机器学习机器学习&#xff08;Machine Learning&#xff0c;ML&#xff09;和深度学习&#xff08;Deep Learning&#xff0c;DL&#xff09;的基本概念什么是回归&#xff08;regression&#xff09;什么…

【机器学习】表示学习的基本概念和方法以及编解码结构的基本概念

引言 表示学习&#xff08;Representation Learning&#xff09;是机器学习的一个子领域&#xff0c;它专注于学习数据的表示形式&#xff0c;即数据的高层特征或抽象概念 文章目录 引言一、表示学习1.1 表示学习的重要性1.2 表示学习的方法1.3 应用场景1.4 挑战1.5 总结 二、如…

AUTOSAR_EXP_ARAComAPI的5章笔记(2)

返回目录 5.3 Proxy Class Proxy Class从AutoSar元模型的服务接口描述中生成。 ara::com确实标准化了生成的Proxy Class的接口。一个AP产品供应商的工具链将生成一个代理实现类来精确地实现这个接口。 注意: 因为Proxy Class必须提供的接口是由ara::com定义的&#xff0c;所…

教你手机投屏到电视方法,用电视屏幕让家庭蛋糕制作更有趣

心血来潮&#xff0c;我突然想要尝试跟着手机视频制作蛋糕。当我向老妈提起这个想法时&#xff0c;她也表示出了浓厚的兴趣&#xff0c;想要一起学习如何制作蛋糕。 然而&#xff0c;我们很快意识到一个问题&#xff1a;如果我们俩都挤在狭小的厨房里&#xff0c;一边看手机一…

51单片机-LED点阵屏介绍

作者&#xff1a;Whappy 时间&#xff1a;2024.9.3 目的&#xff1a;手撕51 74HC595&#xff0c;原理很简单&#xff0c;就是通过串行输入端SER&#xff0c;将一个字节的数据一位一位的传送到我们的移位寄存器中&#xff0c;图左边第一个区域&#xff0c;则SERCLK就是给移位节…

[STM32]从零开始的STM32 LED教程(小白向)

一、为什么LED会作为第一个例程 大家可能已经发现了&#xff0c;我们大部分的STM32教程都将LED作为教程中的第一个例程。为什么呢&#xff1f;在我看来&#xff0c;之所以把LED作为教程的第一个例程&#xff0c;因为这个实验能够让新手直观的看到实验现象&#xff0c;在操作GPI…