# QH-MES 部署与热部署方案 > 本文档记录 QH-MES(jeecg-boot 3.9.2)在 Windows Server 上的部署方案,包含后端、前端的一键发版流程、关键配置、踩过的坑,以及未来上线客户正式服务器的规划。 > 最后更新:2026-06-17 --- ## 一、环境概况 ### 测试服务器(当前) - **系统**:Windows Server 2016 Standard - **JDK**:17.0.11(`C:\Program Files\Java\jdk-17`,注意 `JAVA_HOME` 要指根目录,**不能带 `\bin`**) - **Maven**:3.9.8(`D:\apache-maven-3.9.8`,从本地 Win11 拷过去的,因服务器网络受限无法在线下载) - **Git**:已装在 `C:\Program Files\Git`,但不在 PATH(用完整路径 `"C:\Program Files\Git\cmd\git.exe"` 调用) - **Gitea**:跑在**同一台机器**,裸仓库在 `D:\gitea\data\gitea-repositories\chenx\qhmes.git`,Web 地址 `http://27.223.88.102:33000/chenx/qhmes` - **Nginx**:1.30.1,装在 `D:\qhmes\nginx-1.30.1\`,前端文件目录 `D:\qhmes\nginx-1.30.1\html\jeecg\` - **Node/pnpm/npm**:**服务器上没装**(前端不在服务器构建) ### 关键路径 | 用途 | 路径 | |------|------| | 后端运行目录(jar + WinSW 服务) | `D:\qhmes\` | | 后端运行 jar | `D:\qhmes\jeecg-system-start-3.9.2.jar` | | 服务器源码工作副本 | `D:\qhmes-src\`(从本地裸仓库 clone,分支 `main`) | | 前端 nginx 目录 | `D:\qhmes\nginx-1.30.1\html\jeecg\` | | WinSW 服务程序/配置 | `D:\qhmes\qhmes-service.exe` / `qhmes-service.xml` | | 后端发版脚本 | `D:\deploy-server.bat`(放源码目录外,避免 git pull 自我覆盖) | ### 本地开发机(Win11) - 项目路径:`D:\XSL-PROJECT\QH-MES\qhmes` - 后端模块:`jeecg-boot/`,前端:`jeecgboot-vue3/`(同一个 git 仓库) - 传文件到服务器的方式:**向日葵远程传输**(只能手动,不能脚本化) --- ## 二、后端部署(已跑通 ✅) ### 2.1 后端做成 Windows 服务(WinSW) 后端不再手动 `java -jar`(关窗口/断 RDP 就掉),改用 **WinSW** 注册成 Windows 服务,开机自启、崩溃自动重启。 - 服务 id:`qhmes`,名称:`QH-MES Backend` - 配置文件 `D:\qhmes\qhmes-service.xml` 关键内容: ```xml java -Xms1g -Xmx2g -jar "D:\qhmes\jeecg-system-start-3.9.2.jar" D:\qhmes D:\qhmes\logs ``` - **注意**:`` 里**不加** `--spring.profiles.active`,因为 profile 已在打包时烤进 jar(见第四节)。 - 常用命令(管理员): ``` D:\qhmes\qhmes-service.exe install # 安装服务(一次性) D:\qhmes\qhmes-service.exe start # 启动 D:\qhmes\qhmes-service.exe stop # 停止 ``` - 查日志: ```powershell Get-Content D:\qhmes\logs\qhmes-service.out.log -Wait -Tail 60 ``` 启动成功标志:`Started JeecgSystemApplication in xx seconds`,Tomcat 监听 8888。 ### 2.2 一键发版脚本 `D:\deploy-server.bat` 流程:`git pull → mvn 打包(prod) → 停服务 → 换 jar → 启服务`。脚本自带 `git pull`,**双击即自动拉最新代码**。 ```bat @echo off setlocal set SRC=D:\qhmes-src set GIT="C:\Program Files\Git\cmd\git.exe" set DEPLOY_DIR=D:\qhmes set JAR_NAME=jeecg-system-start-3.9.2.jar set SVC=D:\qhmes\qhmes-service.exe set BUILT_JAR=%SRC%\jeecg-boot\jeecg-module-system\jeecg-system-start\target\%JAR_NAME% echo [1/5] git pull ... cd /d %SRC% %GIT% pull if errorlevel 1 ( echo [ERROR] git pull failed & pause & exit /b 1 ) echo [2/5] maven package with prod profile ... cd /d %SRC%\jeecg-boot call mvn clean package -pl jeecg-module-system/jeecg-system-start -am -DskipTests -P prod -T 1C if errorlevel 1 ( echo [ERROR] build failed & pause & exit /b 1 ) if not exist "%BUILT_JAR%" ( echo [ERROR] built jar not found & pause & exit /b 1 ) echo [3/5] stop service ... "%SVC%" stop timeout /t 6 /nobreak >nul echo [4/5] copy new jar ... copy /Y "%BUILT_JAR%" "%DEPLOY_DIR%\%JAR_NAME%" if errorlevel 1 ( echo [ERROR] copy failed, jar locked? & pause & exit /b 1 ) echo [5/5] start service ... "%SVC%" start echo ===== DEPLOY DONE ===== endlocal pause ``` ### 2.3 后端发版流程 1. 本地改代码 → `git push`(推到 `main`) 2. RDP/向日葵到服务器 → 双击 `D:\deploy-server.bat` 3. 看日志确认 `Started ... in xx seconds` > 首次构建会下载几百 MB 依赖(约 8 分钟),缓存在 `D:\maven-repo`,之后每次只需 1~3 分钟。 --- ## 三、前端部署(脚本已就绪) 前端 `jeecgboot-vue3` 用 **pnpm** 构建,产物 `dist/`,放到 nginx 的 `html\jeecg\`。 因服务器没 Node 且网络受限,**前端不在服务器构建**,而是:**本地构建 → dist 走 git → 服务器拉取替换**。 > `jeecgboot-vue3/dist` 被 `.gitignore` 忽略,所以构建后复制到根目录 **`web-dist`** 文件夹(未被忽略)再提交。 ### 3.1 本地构建脚本 `build-frontend.bat`(本地 Win11 双击) 核心构建步骤与官网一致:`pnpm install` + `pnpm run build`,之后自动复制 dist 到 web-dist 并 git push。 ```bat @echo off setlocal set REPO=%~dp0 set WEBDIST=%REPO%web-dist echo [1/4] build frontend (pnpm install + build) ... cd /d %REPO%jeecgboot-vue3 call pnpm install if errorlevel 1 ( echo [ERROR] pnpm install failed & pause & exit /b 1 ) call pnpm run build if errorlevel 1 ( echo [ERROR] frontend build failed & pause & exit /b 1 ) if not exist "%REPO%jeecgboot-vue3\dist\index.html" ( echo [ERROR] dist/index.html not found & pause & exit /b 1 ) echo [2/4] refresh web-dist folder ... if exist "%WEBDIST%" rmdir /S /Q "%WEBDIST%" mkdir "%WEBDIST%" xcopy "%REPO%jeecgboot-vue3\dist\*" "%WEBDIST%\" /E /Y /I >nul echo [3/4] git add and commit web-dist ... cd /d %REPO% git add web-dist git commit -m "frontend build dist update" echo [4/4] git push ... git push if errorlevel 1 ( echo [ERROR] git push failed & pause & exit /b 1 ) echo ===== FRONTEND BUILT AND PUSHED ===== endlocal pause ``` ### 3.2 服务器部署脚本 `D:\deploy-frontend.bat`(服务器双击) ```bat @echo off setlocal set SRC=D:\qhmes-src set GIT="C:\Program Files\Git\cmd\git.exe" set WEB=D:\qhmes\nginx-1.30.1\html\jeecg set NGINX_DIR=D:\qhmes\nginx-1.30.1 echo [1/3] git pull ... cd /d %SRC% %GIT% pull if errorlevel 1 ( echo [ERROR] git pull failed & pause & exit /b 1 ) if not exist "%SRC%\web-dist\index.html" ( echo [ERROR] web-dist not found, run build-frontend.bat first & pause & exit /b 1 ) echo [2/3] replace nginx frontend files ... if exist "%WEB%" rmdir /S /Q "%WEB%" mkdir "%WEB%" xcopy "%SRC%\web-dist\*" "%WEB%\" /E /Y /I >nul if errorlevel 1 ( echo [ERROR] copy failed & pause & exit /b 1 ) echo [3/3] reload nginx (ignore error if not running) ... cd /d %NGINX_DIR% nginx.exe -s reload echo ===== FRONTEND DEPLOY DONE ===== endlocal pause ``` > **nginx 不用重启**:静态文件替换后自动生效。`nginx -s reload` 是平滑重载,**不要直接跑 `nginx.exe`**(会报端口占用)。 ### 3.3 前端发版流程(两步双击) 1. 本地双击 `build-frontend.bat`(构建 + 推送 web-dist) 2. 服务器双击 `D:\deploy-frontend.bat`(拉取 + 替换 + reload) 3. 刷新浏览器 --- ## 四、配置(profile)说明 —— 重点 ### 4.1 哪个配置生效,由打包时的 Maven `-P` 决定 `application.yml` 里 `spring.profiles.active: '@profile.name@'` 是 Maven 占位符,打包时填入: | 打包命令 | 生效配置 | |---------|---------| | `mvn package`(不带 -P) | **dev**(默认,`` 在 dev 上) | | `mvn package -P prod` | **prod** | | `mvn package -P test` | test | > 发版脚本用的是 **`-P prod`**,所以烤进 jar 的是 prod 配置,运行时无需再加 `--spring.profiles.active`。 ### 4.2 判断一个 jar 用的哪个配置 - 看启动日志:`The following 1 profile is active: "prod"` - 解压 jar 看 `BOOT-INF/classes/application.yml` 里 `active` 的实际值 - 运行时 `--spring.profiles.active=xxx` 可强制覆盖 ### 4.3 dev vs prod 的区别(本项目) | 项 | dev | prod(当前测试服务器用) | |----|-----|------| | 端口 | 8888 | 8888(已改成与现网一致) | | MySQL | `xsl.qdxsl.top:50768`(公网绕一圈) | `127.0.0.1:3306`(本机直连) | | MySQL 密码 | 123456 | 123456(已改,原为 root) | > **重要事实**:`xsl.qdxsl.top:50768` 与本机 `127.0.0.1:3306` 是**同一个生产库**(公网域名+端口转发到本机)。prod 走本机直连更快更稳。 > prod 配置的修改在 `application-prod.yml`,已带 `update-begin/update-end` 痕迹注释。 --- ## 五、踩过的坑(避免重复) 1. **bat 文件乱码/无法执行**:bat 里写中文 + 存成 UTF-8,cmd 按 GBK 读会乱码,连 `@echo off` 都坏。→ **bat 只用英文 ASCII,不带 BOM**。 2. **WinSW 报 `Invalid character in encoding`**:xml 里中文存成了 ANSI/GBK。→ 用 UTF-8 保存,或描述改英文。 3. **服务用 prod 启动报 `Access denied for user 'root'`**:prod 密码原写的 `root`,实际应为 `123456`。 4. **PowerShell 下载报 `未能创建 SSL/TLS 安全通道`**:Server 2016 默认 TLS 1.0。→ 先 `[Net.ServicePointManager]::SecurityProtocol = ... -bor 3072` 开启 TLS 1.2。 5. **服务器下载被 `127.0.0.1:10080` 的本机 Apache 拦截 404**:服务器网络有本机代理/DNS 劫持,外网下载不通。→ Maven/Node 等**在本地下好,向日葵拷过去**。 6. **`mvn` 报 `JAVA_HOME not defined correctly`**:`JAVA_HOME` 误设成了 `...\jdk-17\bin`。→ 应为根目录 `...\jdk-17`。 7. **`git clone D:\gitea\...qhmes.git` 拿到的没有源码**:那是 Gitea 裸仓库(只有 git 底层数据)。→ `git clone` 它到 `D:\qhmes-src` 得到工作副本。 8. **cmd 里 `cd D:\xxx` 不切盘**:要用 `cd /d D:\xxx`;`&` 是 PowerShell 语法,cmd 里不能用。 9. **PowerShell 粘贴 here-string 卡在 `>>`**:终止符 `'@` 没识别。→ 大段内容改用**记事本**另存为(All Files + ANSI),或写进 git 拉取。 --- ## 六、未来上线客户正式服务器的规划(待落地) **核心原则:测试服务器可以 git 拉源码+构建;客户正式服务器只部署"已构建的成品",不放源码、不装构建工具、不依赖我方 gitea。** ### 6.1 目标流程 ``` 我方(测试服务器/开发机):打包出成品(jar + 前端dist)并测好 ↓ 向日葵/U盘/网盘 传过去 客户正式服务器:双击 deploy.bat → 停服务 → 换jar → 换前端 → 启服务 ``` ### 6.2 必做改造:配置外置(同一 jar 走天下) 现在 prod 配置(数据库/IP/密码)烤死在 jar 里,是测试服务器的。客户的库不同,需把配置挪到 jar 外: ``` D:\qhmes\ ├── jeecg-system-start-3.9.2.jar ← 所有环境通用,不用为每个客户重打 └── config\ └── application-prod.yml ← 本机专属:客户的数据库/IP/密码 ``` Spring Boot 自动优先读 jar 同级 `config\` 目录的配置(外部 > jar 内 classpath)。 ### 6.3 待办(上线时找 Claude 做) 1. 把 prod 配置从 jar 内挪到外部 `config\`,jar 变环境无关 2. 写"打 release 包"脚本:一键产出 `jar + 前端dist + deploy.bat` 发布包 3. 写客户服务器 `deploy.bat`:只"换文件+重启",不构建、不拉源码 4. (建议)测试服务器也提前切到外置配置,与客户环境保持一致,上线零改动 --- ## 七、快速命令速查 ```powershell # 后端发版 D:\deploy-server.bat # 服务器双击 # 前端发版 build-frontend.bat # 本地 Win11 双击 D:\deploy-frontend.bat # 服务器双击 # 看后端日志 Get-Content D:\qhmes\logs\qhmes-service.out.log -Wait -Tail 60 # 后端服务控制(管理员) D:\qhmes\qhmes-service.exe stop|start|status # nginx 平滑重载(在 nginx 目录下) cd /d D:\qhmes\nginx-1.30.1 nginx.exe -s reload ```