#!/bin/bash # ============================================================ # 一键部署脚本 # 用法: ./deploy.sh [admin|miniapp|all] [--skip-frontend] # 调试: bash -x ./deploy.sh # ============================================================ APP_DIR="/data/app" CODE_DIR="/data/code/car-wash-java" BACKUP_DIR="/data/backup" LOG_DIR="/data/logs" HISTORY_FILE="/data/history" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' log() { echo -e "[$(date '+%H:%M:%S')] $1"; } info() { log "${GREEN}INFO${NC} $1"; } warn() { log "${YELLOW}WARN${NC} $1"; } error() { log "${RED}ERROR${NC} $1"; } mkdir -p "$LOG_DIR" "$BACKUP_DIR" info "开始部署..." # ---- 参数解析 ---- TARGET="${1:-all}" SKIP_FRONTEND=false [ "$2" = "--skip-frontend" ] || [ "$1" = "--skip-frontend" ] && SKIP_FRONTEND=true # ---- 拉取最新代码 ---- info "拉取最新代码..." cd "$CODE_DIR" || { error "无法进入 $CODE_DIR"; exit 1; } git pull origin master || { error "git pull 失败"; exit 1; } # ---- 前端构建 ---- if [ "$SKIP_FRONTEND" = false ] && [ "$TARGET" != "miniapp" ]; then info "构建管理后台前端 (admin-web)..." (cd "$CODE_DIR/admin-web" && npm run build) || { error "admin-web 构建失败"; exit 1; } info "构建 H5 前端 (admin-h5)..." (cd "$CODE_DIR/admin-h5" && npm run build) || { error "admin-h5 构建失败"; exit 1; } info "前端构建完成" fi # ---- Maven 打包 ---- if [ "$TARGET" = "miniapp" ]; then info "Maven 打包 (仅 miniapp)..." (cd "$CODE_DIR" && mvn clean package -DskipTests -pl car-wash-miniapp -am) || { error "Maven 打包失败"; exit 1; } else info "Maven 打包..." (cd "$CODE_DIR" && mvn clean package -DskipTests) || { error "Maven 打包失败"; exit 1; } fi # ---- 备份并复制 jar ---- backup_and_copy() { local module=$1 local jar_src="$CODE_DIR/$module/target/${module}-0.0.1-SNAPSHOT.jar" local jar_dst="$APP_DIR/${module}-0.0.1-SNAPSHOT.jar" if [ ! -f "$jar_src" ]; then error "未找到 jar 文件: $jar_src" exit 1 fi if [ -f "$jar_dst" ]; then cp "$jar_dst" "$BACKUP_DIR/${module}-0.0.1-SNAPSHOT.jar.$(date +%Y%m%d_%H%M%S)" info "已备份 $module (保留最近 5 个)" ls -t "$BACKUP_DIR/${module}"-*.jar 2>/dev/null | tail -n +6 | xargs -r rm -f fi cp "$jar_src" "$jar_dst" info "$module jar 已复制到 $APP_DIR" } # ---- 重启服务 (使用原版 wash-restart.sh 的 PID 检测逻辑) ---- restart_service() { local module=$1 local jar_file="${module}-0.0.1-SNAPSHOT.jar" local start_log="$LOG_DIR/${module}.log" info "正在停止 $module ..." # 用原版脚本的 grep 方式: grep java | grep 模块名 local pid=$(ps -ef | grep java | grep "$module" | grep -v grep | awk '{print $2}') if [ -n "$pid" ]; then # 多 pid 情况:逐个处理 for p in $pid; do info "终止进程 $module (pid=$p)..." kill "$p" 2>/dev/null # 等待 10 秒 for i in $(seq 1 10); do if ! kill -0 "$p" 2>/dev/null; then info "进程 $p 已退出" break fi sleep 1 done # 没退出就强制 kill if kill -0 "$p" 2>/dev/null; then warn "强制终止 $p" kill -9 "$p" 2>/dev/null sleep 1 fi done else info "$module 未在运行" fi # 确认端口释放 info "启动 $module ..." local cert_arg="" if [ "$module" = "car-wash-admin" ]; then cert_arg="-Dwechat.payment.certPath=/data/wash-pem/apiclient_cert.pem -Dwechat.payment.keyPath=/data/wash-pem/apiclient_key.pem" fi cd "$APP_DIR" nohup java -jar -Dspring.profiles.active=prod $cert_arg "$jar_file" > "$start_log" 2>&1 & sleep 5 local new_pid=$(ps -ef | grep java | grep "$module" | grep -v grep | awk '{print $2}') if [ -n "$new_pid" ]; then info "$module 启动成功 (pid=$new_pid)" echo "$(date) $module restarted" >> "$HISTORY_FILE" else error "$module 可能启动失败,查看日志:" echo "--- $start_log ---" tail -30 "$start_log" echo "--- end ---" exit 1 fi } # ---- 执行部署 ---- case "$TARGET" in admin) backup_and_copy "car-wash-admin" restart_service "car-wash-admin" ;; miniapp) backup_and_copy "car-wash-miniapp" restart_service "car-wash-miniapp" ;; all) backup_and_copy "car-wash-admin" backup_and_copy "car-wash-miniapp" restart_service "car-wash-admin" restart_service "car-wash-miniapp" ;; *) error "未知模块: $TARGET (可选: admin | miniapp | all)" exit 1 ;; esac echo "========================================" info "部署完成" echo "========================================"