#!/bin/bash # ============================================== # Java应用管理脚本 v2.0 # 功能:启动/停止/重启/状态检查/日志查看/升级/备份 # ============================================== # -------------------------- # 配置区(请根据实际情况修改) # -------------------------- APP_NAME="snailjob-server" # 应用名称 APP_DIR="../lib" # 应用目录(支持绝对路径) JAR_NAME="ruoyi-snailjob-server.jar" # JAR文件名 JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseG1GC -Dfile.encoding=UTF-8" # JVM参数 LOG_FILE="${APP_DIR}/app.log" # 日志文件路径 PID_FILE="${APP_DIR}/app.pid" # PID文件路径 MAX_LOG_SIZE=10 # 日志轮转大小(MB) BACKUP_DIR="${APP_DIR}/backup" # 备份目录 WAIT_STOP_TIMEOUT=30 # 停止等待超时(秒) # -------------------------- # 初始化检查 # -------------------------- init_check() { # 检查Java环境 if ! command -v java &> /dev/null; then echo "[ERROR] Java未安装!请先安装JDK" exit 1 fi # 检查目录是否存在 if [ ! -d "$APP_DIR" ]; then echo "[ERROR] 应用目录不存在: $APP_DIR" exit 1 fi # 检查JAR文件是否存在 if [ ! -f "${APP_DIR}/${JAR_NAME}" ]; then echo "[ERROR] JAR文件不存在: ${APP_DIR}/${JAR_NAME}" exit 1 fi # 创建备份目录 mkdir -p "$BACKUP_DIR" } # -------------------------- # 日志轮转 # -------------------------- rotate_log() { if [ -f "$LOG_FILE" ]; then log_size=$(du -m "$LOG_FILE" | cut -f1) if [ "$log_size" -gt "$MAX_LOG_SIZE" ]; then echo "正在轮转日志文件..." timestamp=$(date +%Y%m%d%H%M%S) mv "$LOG_FILE" "${LOG_FILE}.$timestamp" gzip "${LOG_FILE}.$timestamp" -f mv "${LOG_FILE}.$timestamp.gz" "$BACKUP_DIR/" touch "$LOG_FILE" fi fi } # -------------------------- # 获取应用状态 # -------------------------- status() { if [ -f "$PID_FILE" ]; then pid=$(cat "$PID_FILE") if ps -p "$pid" > /dev/null; then echo "[INFO] $APP_NAME 正在运行 (PID: $pid)" return 0 else echo "[WARN] PID文件存在但进程未运行,可能存在异常退出" return 1 fi else echo "[INFO] $APP_NAME 未运行" return 3 fi } # -------------------------- # 启动应用 # -------------------------- start() { init_check status >/dev/null 2>&1 local running=$? if [ $running -eq 0 ]; then echo "[WARN] $APP_NAME 已经在运行中 (PID: $(cat "$PID_FILE"))" return 1 fi # 清理无效PID文件 if [ $running -eq 1 ]; then rm -f "$PID_FILE" fi rotate_log echo "正在启动 $APP_NAME..." cd "$APP_DIR" || exit 1 # 使用exec启动以便获取正确的PID nohup java $JAVA_OPTS -jar "$JAR_NAME" >> "$LOG_FILE" 2>&1 & local pid=$! echo $pid > "$PID_FILE" echo "[SUCCESS] $APP_NAME 已启动 (PID: $pid)" echo "日志文件: $LOG_FILE" } # -------------------------- # 停止应用 # -------------------------- stop() { status >/dev/null 2>&1 local running=$? if [ $running -ne 0 ]; then echo "[WARN] $APP_NAME 未运行" return 1 fi local pid=$(cat "$PID_FILE") echo "正在停止 $APP_NAME (PID: $pid)..." # 先尝试优雅关闭 kill $pid # 等待进程退出 local count=0 while [ $count -lt $WAIT_STOP_TIMEOUT ]; do if ! ps -p $pid > /dev/null; then break fi sleep 1 ((count++)) done # 强制终止 if ps -p $pid > /dev/null; then echo "[WARN] 优雅关闭失败,尝试强制终止..." kill -9 $pid sleep 1 fi rm -f "$PID_FILE" echo "[SUCCESS] $APP_NAME 已停止" } # -------------------------- # 重启应用 # -------------------------- restart() { stop sleep 2 start } # -------------------------- # 查看日志 # -------------------------- tail_log() { if [ ! -f "$LOG_FILE" ]; then echo "[ERROR] 日志文件不存在: $LOG_FILE" return 1 fi echo "正在显示日志: $LOG_FILE (Ctrl+C 退出)" echo "--------------------------------------------------" tail -f "$LOG_FILE" } # -------------------------- # 备份应用 # -------------------------- backup() { local timestamp=$(date +%Y%m%d%H%M%S) local backup_file="${BACKUP_DIR}/${JAR_NAME%.*}_${timestamp}.jar" echo "正在备份应用到: $backup_file" cp "${APP_DIR}/${JAR_NAME}" "$backup_file" if [ $? -eq 0 ]; then echo "[SUCCESS] 备份完成" return 0 else echo "[ERROR] 备份失败" return 1 fi } # -------------------------- # 升级应用 # -------------------------- upgrade() { local new_jar="$JAR_NAME" local lib_dir="$APP_DIR" local backup_dir="${BACKUP_DIR}/lib" # 检查新的JAR文件是否存在 if [ ! -f "$new_jar" ]; then echo "[ERROR] 新的JAR文件不存在: $new_jar" return 1 fi # 检查lib目录是否存在 if [ ! -d "$lib_dir" ]; then echo "[ERROR] lib目录不存在: $lib_dir" return 1 fi # 检查backup目录是否存在,不存在则创建 mkdir -p "$backup_dir" # 获取lib目录下原有的JAR文件名 local old_jar=$(ls "$lib_dir" | grep -E "^${JAR_NAME%.jar}-[0-9]{14}\.jar$") if [ -z "$old_jar" ]; then old_jar="$JAR_NAME" fi # 备份原有的JAR文件 local timestamp=$(date +%Y%m%d%H%M%S) local backup_file="${backup_dir}/${old_jar%.jar}_${timestamp}.jar" cp "${lib_dir}/${old_jar}" "$backup_file" if [ $? -eq 0 ]; then echo "[SUCCESS] 备份原有JAR文件到: $backup_file" else echo "[ERROR] 备份原有JAR文件失败" return 1 fi # 复制新的JAR文件到lib目录 cp "$new_jar" "$lib_dir/" if [ $? -eq 0 ]; then echo "[SUCCESS] 升级JAR文件到: $lib_dir/$new_jar" else echo "[ERROR] 升级JAR文件失败" return 1 fi # 删除旧的JAR文件(可选,如果保留旧版本则不需要删除) # rm -f "${lib_dir}/${old_jar}" # if [ $? -eq 0 ]; then # echo "[SUCCESS] 删除旧的JAR文件: ${lib_dir}/${old_jar}" # else # echo "[ERROR] 删除旧的JAR文件失败" # return 1 # fi } # -------------------------- # 主程序 # -------------------------- case "$1" in start) start ;; stop) stop ;; restart) restart ;; status) status ;; log) tail_log ;; backup) backup ;; upgrade) upgrade ;; *) echo "用法: $0 {start|stop|restart|status|log|backup|upgrade}" echo " start 启动应用" echo " stop 停止应用" echo " restart 重启应用" echo " status 查看状态" echo " log 查看实时日志" echo " backup 备份应用" echo " upgrade 升级应用" exit 1 ;; esac exit 0