@echo off chcp 65001 >nul setlocal enabledelayedexpansion title IoT SaaS 一键重新构建并部署(后端 4 服务 + 前端后台) REM 非交互部署(CI/自动化):运行前先 set NONINTERACTIVE=1,例如 REM cmd /c "set NONINTERACTIVE=1 & f:\work\iotsaas\deploy-all.bat" REM 可跳过末尾 pause,避免在自动化环境(非 TTY)用管道喂入干扰 plink。 :: ============ 环境配置(按本机实际路径修改) ============ set JAVA_HOME=C:\Program Files\Eclipse Adoptium\jdk-17.0.19.10-hotspot set PATH=%JAVA_HOME%\bin;D:\dev\apache-maven-3.9.16\bin;%PATH% set PLINK="C:\Program Files\PuTTY\plink.exe" set PLINK_OPTS=-pw Tonzou@888 -hostkey aa:01:8c:1d:95:36:68:6d:c6:ad:d1:c5:45:0b:05:46 -batch tonzou@192.168.3.3 set SRV_JARS=/opt/iotsaas/backend/jars set SRV_DIST=/opt/iotsaas/frontend/dist set BACKEND_DIR=f:\work\iotsaas\backend set ADMIN_DIR=f:\work\iotsaas\frontend\admin :: iot-device 带 exec classifier,其余为 fat jar 原名 set JAR_DEV=iot-device-1.0.0-exec.jar set JAR_DATA=iot-data-1.0.0.jar set JAR_RULE=iot-rule-1.0.0.jar set JAR_ALARM=iot-alarm-1.0.0.jar :: ============ 1) 后端构建(含共享模块 iot-common) ============ cd /d %BACKEND_DIR% echo ============================================ echo [1/7] Maven 重新构建 4 个服务(含共享模块 iot-common) echo ============================================ call mvn clean package -pl iot-device,iot-data,iot-rule,iot-alarm -am -DskipTests if %ERRORLEVEL% NEQ 0 ( echo [错误] 后端构建失败,已中止。 & pause & exit /b 1 ) echo [OK] 后端构建成功。 :: ============ 2) 上传 4 个 jar ============ echo ============================================ echo [2/7] 上传 4 个 jar 到服务器 %SRV_JARS% echo ============================================ tar cf - -C %BACKEND_DIR%\iot-device\target %JAR_DEV% -C %BACKEND_DIR%\iot-data\target %JAR_DATA% -C %BACKEND_DIR%\iot-rule\target %JAR_RULE% -C %BACKEND_DIR%\iot-alarm\target %JAR_ALARM% | %PLINK% %PLINK_OPTS% tar xf - -C %SRV_JARS% if %ERRORLEVEL% NEQ 0 ( echo [错误] jar 上传失败。 & pause & exit /b 1 ) echo [OK] jar 上传完成。 :: ============ 2.5) 数据库迁移(Flyway 在本环境未启用,按 DB 内 tracking 表应用未执行的 V 迁移) ============ echo ============================================ echo [3/7] 应用未执行的 SQL 迁移(%BACKEND_DIR%\sql\V*.sql,按 db_migrations_applied 去重) echo ============================================ set MIG_DIR=%BACKEND_DIR%\sql set CHK_FILE=%TEMP%\_mig_chk.txt %PLINK% %PLINK_OPTS% "docker exec -i iot-mysql mysql -uroot -p'IoT.p2026.Xk9Qm' iot_platform -e \"CREATE TABLE IF NOT EXISTS db_migrations_applied (name VARCHAR(80) NOT NULL PRIMARY KEY, applied_at DATETIME DEFAULT CURRENT_TIMESTAMP)\"" 2>nul REM 首次使用(tracking 表为空)则标记当前所有 V 文件为已应用:假定目标库已手工迁移到最新。 REM 全新库请先手动执行 sql/ 下全部 V 迁移,再运行本脚本(或清空 db_migrations_applied 让其补跑,需迁移文件幂等)。 %PLINK% %PLINK_OPTS% "docker exec -i iot-mysql mysql -uroot -p'IoT.p2026.Xk9Qm' iot_platform -N -e \"SELECT COUNT(*) FROM db_migrations_applied\"" 2>nul > "%CHK_FILE%" set /p MIG_CNT=<"%CHK_FILE%" if "!MIG_CNT!"=="0" ( echo 首次使用:标记当前所有 V 迁移为已应用(假定库已迁移到最新) for /f "delims=" %%F in ('dir /b /on "%MIG_DIR%\V*.sql"') do call :mig_seed "%%F" ) REM 应用未记录的 V 迁移(新增迁移文件会自动在此补跑,无需改本脚本) for /f "delims=" %%F in ('dir /b /on "%MIG_DIR%\V*.sql"') do call :mig_apply "%%F" echo [OK] 迁移步骤完成。 :: ============ 3) 重启 4 个后端服务 ============ echo ============================================ echo [4/7] 重启 4 个后端服务(systemd) echo ============================================ %PLINK% %PLINK_OPTS% "echo 'Tonzou@888' | sudo -S -p '' systemctl restart iot-device iot-data iot-rule iot-alarm" 2>nul if %ERRORLEVEL% NEQ 0 ( echo [错误] 服务重启失败。 & pause & exit /b 1 ) echo [OK] 重启命令已下发。 :: ============ 4) 构建前端后台(admin) ============ cd /d %ADMIN_DIR% echo ============================================ echo [5/7] 构建前端后台(admin)— 跳过 vue-tsc 类型检查,直接 vite build echo ============================================ where node >nul 2>nul || ( echo [错误] 未找到 node,请将其加入 PATH。 & pause & exit /b 1 ) call npx vite build if %ERRORLEVEL% NEQ 0 ( echo [错误] 前端构建失败。 & pause & exit /b 1 ) echo [OK] 前端构建成功(dist 已生成)。 :: ============ 5) 上传前端 dist(先清空旧文件再解包,避免残留旧 hash 资源) ============ echo ============================================ echo [6/7] 上传前端 dist 到服务器 %SRV_DIST% echo ============================================ %PLINK% %PLINK_OPTS% "echo 'Tonzou@888' | sudo -S -p '' rm -rf %SRV_DIST% && mkdir -p %SRV_DIST%" if %ERRORLEVEL% NEQ 0 ( echo [错误] 清空远端 dist 失败。 & pause & exit /b 1 ) tar cf - -C %ADMIN_DIR%\dist . | %PLINK% %PLINK_OPTS% tar xf - -C %SRV_DIST% if %ERRORLEVEL% NEQ 0 ( echo [错误] dist 上传失败。 & pause & exit /b 1 ) echo [OK] dist 上传完成。 :: ============ 6) 确认状态 ============ echo ============================================ echo [7/7] 等待启动并确认服务状态 echo ============================================ timeout /t 20 /nobreak >nul %PLINK% %PLINK_OPTS% "echo 'Tonzou@888' | sudo -S -p '' systemctl is-active iot-device iot-data iot-rule iot-alarm" 2>nul echo. echo 部署完成!冒烟测试地址: echo http://192.168.3.3:9081/doc.html (设备/鉴权/授权对接接口) echo http://192.168.3.3/ (后台管理,含「系统管理 - 应用管理」) echo http://192.168.3.3/api/doc/partner.html (授权对接接入指南) echo. REM 非交互部署(如 CI/自动化)设 set NONINTERACTIVE=1 可跳过等待按键,避免管道喂入干扰 plink if not defined NONINTERACTIVE pause goto :eof :: ============ 迁移子例程(顶层执行,避开括号块内转义问题) ============ :mig_seed %PLINK% %PLINK_OPTS% "docker exec -i iot-mysql mysql -uroot -p'IoT.p2026.Xk9Qm' iot_platform -e \"INSERT IGNORE INTO db_migrations_applied(name) VALUES('%1')\"" 2>nul goto :eof :mig_apply set CHK=0 %PLINK% %PLINK_OPTS% "docker exec -i iot-mysql mysql -uroot -p'IoT.p2026.Xk9Qm' iot_platform -N -e \"SELECT COUNT(*) FROM db_migrations_applied WHERE name='%1'\"" 2>nul > "%CHK_FILE%" set /p CHK=<"%CHK_FILE%" if not "!CHK!"=="0" ( echo 跳过已应用 %1 goto :eof ) echo 应用 %1 ... REM --force: 迁移脚本中"已存在"的 DDL(重复列/索引)属正常情况,不应中断整体部署 type "%MIG_DIR%\%1" | %PLINK% %PLINK_OPTS% "docker exec -i iot-mysql mysql --force -uroot -p'IoT.p2026.Xk9Qm' iot_platform" if !ERRORLEVEL! NEQ 0 ( echo [错误] 迁移 %1 执行失败。 & pause & exit /b 1 ) %PLINK% %PLINK_OPTS% "docker exec -i iot-mysql mysql -uroot -p'IoT.p2026.Xk9Qm' iot_platform -e \"INSERT IGNORE INTO db_migrations_applied(name) VALUES('%1')\"" 2>nul goto :eof