四零语境后端代码仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

989 lines
27 KiB

  1. #!/bin/bash
  2. # ========================================
  3. # Java应用启动/重启脚本
  4. # 使用方法: ./restart-java-app.sh
  5. # ========================================
  6. # 全局配置
  7. JAR_NAME="" # JAR文件名(为空时自动检测)
  8. JAVA_OPTS="" # JVM参数(为空时使用默认值,节省内存)
  9. LOG_FILE="" # 日志文件名(自动生成)
  10. # 运行时配置常量
  11. STOP_TIMEOUT=15 # 停止超时时间(秒)
  12. STARTUP_WAIT=3 # 启动等待时间(秒)
  13. FORCE_KILL_WAIT=2 # 强制终止等待时间(秒)
  14. # 颜色定义
  15. RED='\033[0;31m'
  16. GREEN='\033[0;32m'
  17. YELLOW='\033[1;33m'
  18. BLUE='\033[0;34m'
  19. CYAN='\033[0;36m'
  20. NC='\033[0m' # No Color
  21. # 全局变量(用于交互式选择和批量操作)
  22. SELECTED_JARS=() # 用户选择的JAR包数组
  23. MULTI_JAR_MODE=false # 是否为多JAR包模式
  24. PARSED_ACTION="" # 解析出的操作命令
  25. PARSED_JARS=() # 解析出的JAR包列表
  26. # ========================================
  27. # 工具函数
  28. # ========================================
  29. # 打印错误消息
  30. print_error() {
  31. echo -e "${RED}错误: $1${NC}" >&2
  32. }
  33. # 打印警告消息
  34. print_warning() {
  35. echo -e "${YELLOW}$1${NC}"
  36. }
  37. # 打印成功消息
  38. print_success() {
  39. echo -e "${GREEN}$1${NC}"
  40. }
  41. # 打印信息消息
  42. print_info() {
  43. echo -e "${BLUE}$1${NC}"
  44. }
  45. # 验证Java环境的详细检查
  46. validate_java_environment() {
  47. # 检查Java是否安装
  48. if ! command -v java >/dev/null 2>&1; then
  49. print_error "Java未安装或不在PATH中"
  50. print_info "请安装Java运行环境(JRE)或Java开发工具包(JDK)"
  51. return 1
  52. fi
  53. # 检查Java版本
  54. local java_version
  55. java_version=$(java -version 2>&1 | head -n 1 | cut -d'"' -f2)
  56. if [ -z "$java_version" ]; then
  57. print_error "无法获取Java版本信息"
  58. return 1
  59. fi
  60. print_info "检测到Java版本: $java_version"
  61. # 检查Java是否能正常运行
  62. if ! java -version >/dev/null 2>&1; then
  63. print_error "Java环境异常,无法正常运行"
  64. return 1
  65. fi
  66. return 0
  67. }
  68. # 检查磁盘空间
  69. check_disk_space() {
  70. local required_space_mb="${1:-100}" # 默认需要100MB空间
  71. # 获取当前目录的可用空间(MB)
  72. local available_space
  73. if command -v df >/dev/null 2>&1; then
  74. available_space=$(df . | awk 'NR==2 {print int($4/1024)}')
  75. if [ "$available_space" -lt "$required_space_mb" ]; then
  76. print_warning "磁盘空间不足,可用空间: ${available_space}MB,建议至少: ${required_space_mb}MB"
  77. return 1
  78. fi
  79. else
  80. print_warning "无法检查磁盘空间(df命令不可用)"
  81. fi
  82. return 0
  83. }
  84. # 检查文件权限
  85. check_file_permissions() {
  86. local file_path="$1"
  87. # 检查文件是否存在
  88. if [ ! -f "$file_path" ]; then
  89. print_error "文件不存在: $file_path"
  90. return 1
  91. fi
  92. # 检查文件是否可读
  93. if [ ! -r "$file_path" ]; then
  94. print_error "文件不可读: $file_path"
  95. return 1
  96. fi
  97. return 0
  98. }
  99. # 验证JAR文件名的安全性
  100. validate_jar_name() {
  101. local jar_name="$1"
  102. # 检查是否为空
  103. if [ -z "$jar_name" ]; then
  104. print_error "JAR文件名不能为空"
  105. return 1
  106. fi
  107. # 检查文件名长度(防止过长的文件名)
  108. if [ ${#jar_name} -gt 255 ]; then
  109. print_error "JAR文件名过长(超过255个字符)"
  110. return 1
  111. fi
  112. # 检查是否包含危险字符(路径遍历攻击)
  113. if [[ "$jar_name" == *".."* ]] || [[ "$jar_name" == *"/"* ]] || [[ "$jar_name" == *"\\"* ]]; then
  114. print_error "JAR文件名包含非法字符(不允许路径分隔符或相对路径)"
  115. return 1
  116. fi
  117. # 检查是否以.jar结尾
  118. if [[ ! "$jar_name" == *.jar ]]; then
  119. print_error "文件必须是.jar格式"
  120. return 1
  121. fi
  122. # 检查文件名是否包含特殊字符(可能导致命令注入)
  123. if [[ "$jar_name" =~ [\;\|\&\$\`\<\>\(\)\{\}\[\]\"\'*\?\~] ]]; then
  124. print_error "JAR文件名包含特殊字符,可能存在安全风险"
  125. return 1
  126. fi
  127. return 0
  128. }
  129. # 验证用户输入的安全性
  130. validate_user_input() {
  131. local input="$1"
  132. local input_type="${2:-general}"
  133. # 检查输入长度
  134. if [ ${#input} -gt 1000 ]; then
  135. print_error "输入内容过长"
  136. return 1
  137. fi
  138. # 根据输入类型进行不同的验证
  139. case "$input_type" in
  140. "number")
  141. # 验证数字输入
  142. if [[ ! "$input" =~ ^[0-9,[:space:]]+$ ]] && [ "$input" != "all" ]; then
  143. print_error "输入格式错误,只允许数字、逗号、空格或'all'"
  144. return 1
  145. fi
  146. ;;
  147. "action")
  148. # 验证操作命令
  149. if [[ ! "$input" =~ ^(start|stop|restart|status|help|-h|--help)$ ]]; then
  150. print_error "无效的操作命令: $input"
  151. return 1
  152. fi
  153. ;;
  154. "general")
  155. # 通用输入验证,检查危险字符
  156. if [[ "$input" =~ [\;\|\&\$\`\<\>\(\)\{\}*\?\~] ]]; then
  157. print_error "输入包含特殊字符,可能存在安全风险"
  158. return 1
  159. fi
  160. ;;
  161. esac
  162. return 0
  163. }
  164. # 检查Java环境
  165. check_java_environment() {
  166. if ! command -v java &> /dev/null; then
  167. print_error "Java未安装或不在PATH中"
  168. return 1
  169. fi
  170. # 使用更详细的Java环境验证
  171. if ! validate_java_environment; then
  172. return 1
  173. fi
  174. # 检查磁盘空间
  175. if ! check_disk_space; then
  176. print_warning "磁盘空间不足可能影响应用运行"
  177. fi
  178. return 0
  179. }
  180. # 设置JAR包相关变量
  181. setup_jar_variables() {
  182. local jar_name="$1"
  183. if [ -z "$jar_name" ]; then
  184. jar_name="$JAR_NAME"
  185. fi
  186. # 设置日志文件名(添加时间戳)
  187. local jar_basename=$(basename "$jar_name" .jar)
  188. local timestamp=$(date +"%Y%m%d_%H%M%S")
  189. # 创建日志目录结构:log/jar包名称/
  190. local log_dir="log/${jar_basename}"
  191. # 确保日志目录存在
  192. if [ ! -d "$log_dir" ]; then
  193. mkdir -p "$log_dir" 2>/dev/null
  194. if [ $? -ne 0 ]; then
  195. print_warning "无法创建日志目录 $log_dir,使用当前目录"
  196. LOG_FILE="${jar_basename}_${timestamp}.log"
  197. else
  198. LOG_FILE="${log_dir}/${jar_basename}_${timestamp}.log"
  199. fi
  200. else
  201. LOG_FILE="${log_dir}/${jar_basename}_${timestamp}.log"
  202. fi
  203. }
  204. # 等待进程停止
  205. wait_for_process_stop() {
  206. local pid="$1"
  207. local timeout="${2:-$STOP_TIMEOUT}"
  208. local count=0
  209. while [ $count -lt $timeout ]; do
  210. if ! ps -p $pid > /dev/null 2>&1; then
  211. return 0
  212. fi
  213. sleep 1
  214. count=$((count + 1))
  215. done
  216. return 1
  217. }
  218. # 根据昵称匹配JAR文件
  219. find_jar_by_nickname() {
  220. local nickname="$1"
  221. local found_jars=()
  222. # 如果昵称是 "all",返回所有JAR文件
  223. if [ "$nickname" = "all" ]; then
  224. for jar in *.jar; do
  225. if [ -f "$jar" ]; then
  226. found_jars+=("$jar")
  227. fi
  228. done
  229. else
  230. # 模糊匹配JAR文件名
  231. for jar in *.jar; do
  232. if [ -f "$jar" ] && [[ "$jar" == *"$nickname"* ]]; then
  233. found_jars+=("$jar")
  234. fi
  235. done
  236. fi
  237. # 输出匹配的JAR文件
  238. printf '%s\n' "${found_jars[@]}"
  239. }
  240. # 解析JAR包参数列表
  241. parse_jar_arguments() {
  242. local args=("$@")
  243. local jar_list=()
  244. local action=""
  245. # 如果没有参数,使用默认行为
  246. if [ ${#args[@]} -eq 0 ]; then
  247. action="restart"
  248. PARSED_ACTION="$action"
  249. return
  250. fi
  251. # 检查第一个参数是否是操作命令
  252. case "${args[0]}" in
  253. "start"|"stop"|"restart"|"status"|"help"|"-h"|"--help")
  254. action="${args[0]}"
  255. # 验证操作命令
  256. if ! validate_user_input "$action" "action"; then
  257. return 1
  258. fi
  259. # 如果只有操作命令,使用原有逻辑
  260. if [ ${#args[@]} -eq 1 ]; then
  261. PARSED_ACTION="$action"
  262. return
  263. fi
  264. # 其余参数作为JAR包昵称
  265. for ((i=1; i<${#args[@]}; i++)); do
  266. # 验证JAR包昵称输入
  267. if ! validate_user_input "${args[i]}" "general"; then
  268. return 1
  269. fi
  270. jar_list+=("${args[i]}")
  271. done
  272. ;;
  273. *)
  274. # 第一个参数不是操作命令,默认为restart操作
  275. action="restart"
  276. # 所有参数都作为JAR包昵称
  277. for arg in "${args[@]}"; do
  278. # 验证JAR包昵称输入
  279. if ! validate_user_input "$arg" "general"; then
  280. return 1
  281. fi
  282. jar_list+=("$arg")
  283. done
  284. ;;
  285. esac
  286. # 设置全局变量
  287. PARSED_ACTION="$action"
  288. PARSED_JARS=("${jar_list[@]}")
  289. }
  290. # 检查JAR文件是否存在
  291. check_jar_exists() {
  292. # 如果JAR_NAME为空,自动检测当前目录下的JAR文件
  293. if [ -z "$JAR_NAME" ]; then
  294. local jar_files=(*.jar)
  295. # 检查是否存在JAR文件
  296. if [ ! -e "${jar_files[0]}" ]; then
  297. print_error "当前目录下没有找到JAR文件!"
  298. print_warning "请将JAR文件放在脚本同一目录下,或在脚本中指定JAR_NAME"
  299. return 1
  300. fi
  301. # 如果只有一个JAR文件,自动使用
  302. if [ ${#jar_files[@]} -eq 1 ]; then
  303. JAR_NAME="${jar_files[0]}"
  304. # 验证JAR文件名的安全性
  305. if ! validate_jar_name "$JAR_NAME"; then
  306. return 1
  307. fi
  308. print_info "自动检测到JAR文件: $JAR_NAME"
  309. else
  310. # 多个JAR文件时,让用户选择
  311. print_info "检测到多个JAR文件,请选择要启动的应用:"
  312. echo ""
  313. # 显示选项列表
  314. local i=1
  315. for jar in "${jar_files[@]}"; do
  316. echo -e "${GREEN}[$i]${NC} $jar"
  317. ((i++))
  318. done
  319. echo ""
  320. # 提示用户输入
  321. echo -e "${YELLOW}输入选项:${NC}"
  322. echo -e " - 单个序号: ${GREEN}1${NC} (选择第1个JAR包)"
  323. echo -e " - 多个序号: ${GREEN}1,3,5${NC}${GREEN}1 3 5${NC} (选择多个JAR包)"
  324. echo -e " - 全部选择: ${GREEN}all${NC} (选择所有JAR包)"
  325. echo ""
  326. echo -n -e "${YELLOW}请输入选择: ${NC}"
  327. read -r choice
  328. # 验证用户输入
  329. if ! validate_user_input "$choice" "number"; then
  330. return 1
  331. fi
  332. # 处理输入
  333. local selected_jars=()
  334. if [ "$choice" = "all" ]; then
  335. # 选择所有JAR包
  336. selected_jars=("${jar_files[@]}")
  337. print_success "已选择所有JAR包 (${#selected_jars[@]}个)"
  338. else
  339. # 解析序号输入(支持逗号分隔和空格分隔)
  340. local numbers
  341. if [[ "$choice" == *","* ]]; then
  342. # 逗号分隔
  343. IFS=',' read -ra numbers <<< "$choice"
  344. else
  345. # 空格分隔
  346. read -ra numbers <<< "$choice"
  347. fi
  348. # 验证并收集选中的JAR包
  349. local valid_selection=true
  350. for num in "${numbers[@]}"; do
  351. # 去除空格
  352. num=$(echo "$num" | tr -d ' ')
  353. if [[ "$num" =~ ^[0-9]+$ ]] && [ "$num" -ge 1 ] && [ "$num" -le ${#jar_files[@]} ]; then
  354. selected_jars+=("${jar_files[$((num-1))]}")
  355. else
  356. print_error "无效的序号 '$num'!请输入1到${#jar_files[@]}之间的数字"
  357. valid_selection=false
  358. break
  359. fi
  360. done
  361. if [ "$valid_selection" = false ]; then
  362. return 1
  363. fi
  364. # 去重
  365. selected_jars=($(printf '%s\n' "${selected_jars[@]}" | sort -u))
  366. print_success "已选择 ${#selected_jars[@]} 个JAR包:"
  367. for jar in "${selected_jars[@]}"; do
  368. echo -e " - $jar"
  369. done
  370. fi
  371. # 验证所有选中的JAR文件名
  372. for jar in "${selected_jars[@]}"; do
  373. if ! validate_jar_name "$jar"; then
  374. return 1
  375. fi
  376. done
  377. echo ""
  378. # 如果选择了多个JAR包,设置全局变量供批量操作使用
  379. if [ ${#selected_jars[@]} -gt 1 ]; then
  380. SELECTED_JARS=("${selected_jars[@]}")
  381. MULTI_JAR_MODE=true
  382. # 设置第一个JAR作为默认JAR_NAME(兼容性)
  383. JAR_NAME="${selected_jars[0]}"
  384. else
  385. # 单个JAR包
  386. JAR_NAME="${selected_jars[0]}"
  387. MULTI_JAR_MODE=false
  388. fi
  389. fi
  390. fi
  391. # 检查指定的JAR文件是否存在
  392. if [ ! -f "$JAR_NAME" ]; then
  393. print_error "JAR文件 '$JAR_NAME' 不存在!"
  394. print_warning "请检查JAR_NAME配置是否正确,或确保JAR文件在当前目录下"
  395. return 1
  396. fi
  397. # 检查文件权限
  398. if ! check_file_permissions "$JAR_NAME"; then
  399. return 1
  400. fi
  401. return 0
  402. }
  403. # 获取运行中的应用PID
  404. get_app_pid() {
  405. local jar_name="$1"
  406. if [ -z "$jar_name" ]; then
  407. jar_name="$JAR_NAME"
  408. fi
  409. # 通过进程名查找(更可靠的方法)
  410. pgrep -f "$jar_name" | head -1
  411. }
  412. # 检查应用是否正在运行
  413. is_running() {
  414. local jar_name="$1"
  415. local pid=$(get_app_pid "$jar_name")
  416. if [ -n "$pid" ]; then
  417. return 0 # 正在运行
  418. else
  419. return 1 # 未运行
  420. fi
  421. }
  422. # 启动应用
  423. start_app() {
  424. local jar_name="$1"
  425. if [ -z "$jar_name" ]; then
  426. jar_name="$JAR_NAME"
  427. fi
  428. if ! check_java_environment; then
  429. return 1
  430. fi
  431. setup_jar_variables "$jar_name"
  432. if is_running "$jar_name"; then
  433. print_warning "应用 $jar_name 已在运行中 (PID: $(get_app_pid "$jar_name"))"
  434. return 0
  435. fi
  436. print_info "正在启动应用: $jar_name"
  437. print_info "日志文件: $LOG_FILE"
  438. # 启动应用
  439. nohup java $JAVA_OPTS -jar "$jar_name" > "$LOG_FILE" 2>&1 &
  440. # 等待启动
  441. sleep "$STARTUP_WAIT"
  442. # 验证启动状态
  443. if is_running "$jar_name"; then
  444. local actual_pid=$(get_app_pid "$jar_name")
  445. print_success "应用 $jar_name 启动成功 (PID: $actual_pid)"
  446. print_info "查看日志: tail -f $LOG_FILE"
  447. return 0
  448. else
  449. print_error "应用 $jar_name 启动失败"
  450. print_warning "请检查日志文件: $LOG_FILE"
  451. return 1
  452. fi
  453. }
  454. # 停止应用
  455. stop_app() {
  456. local jar_name="$1"
  457. if [ -z "$jar_name" ]; then
  458. jar_name="$JAR_NAME"
  459. fi
  460. local pid=$(get_app_pid "$jar_name")
  461. if [ -z "$pid" ]; then
  462. print_warning "应用 $jar_name 未运行"
  463. return 0
  464. fi
  465. setup_jar_variables "$jar_name"
  466. print_info "正在停止应用 $jar_name (PID: $pid)..."
  467. # 发送TERM信号
  468. kill "$pid" 2>/dev/null
  469. # 等待进程停止
  470. if wait_for_process_stop "$pid"; then
  471. print_success "应用 $jar_name 已成功停止"
  472. return 0
  473. else
  474. print_warning "应用 $jar_name 未在 ${STOP_TIMEOUT} 秒内停止,强制终止..."
  475. kill -9 "$pid" 2>/dev/null
  476. sleep "$FORCE_KILL_WAIT"
  477. # 再次检查
  478. if [ -z "$(get_app_pid "$jar_name")" ]; then
  479. print_success "应用 $jar_name 已强制停止"
  480. return 0
  481. else
  482. print_error "无法停止应用 $jar_name"
  483. return 1
  484. fi
  485. fi
  486. }
  487. # 重启应用
  488. restart_app() {
  489. local jar_name="$1"
  490. if [ -z "$jar_name" ]; then
  491. jar_name="$JAR_NAME"
  492. fi
  493. if ! check_java_environment; then
  494. return 1
  495. fi
  496. setup_jar_variables "$jar_name"
  497. print_info "正在重启应用: $jar_name"
  498. if is_running "$jar_name"; then
  499. print_info "正在停止应用..."
  500. stop_app "$jar_name"
  501. else
  502. print_info "应用未运行,直接启动"
  503. fi
  504. print_info "正在启动应用..."
  505. start_app "$jar_name"
  506. }
  507. # 显示应用状态
  508. show_status() {
  509. local jar_name="$1"
  510. if [ -z "$jar_name" ]; then
  511. jar_name="$JAR_NAME"
  512. fi
  513. setup_jar_variables "$jar_name"
  514. print_info "=== 应用状态 ==="
  515. echo "JAR包: $jar_name"
  516. echo "JVM参数: $JAVA_OPTS"
  517. echo "日志文件: $LOG_FILE"
  518. echo ""
  519. local pid=$(get_app_pid "$jar_name")
  520. if [ -n "$pid" ]; then
  521. print_success "✓ 应用正在运行 (PID: $pid)"
  522. # 显示进程信息
  523. if command -v ps >/dev/null 2>&1; then
  524. echo ""
  525. echo "进程详情:"
  526. ps -p "$pid" -o pid,ppid,cmd --no-headers 2>/dev/null || echo " 无法获取进程详情"
  527. fi
  528. else
  529. print_warning "✗ 应用未运行"
  530. fi
  531. }
  532. # 批量启动应用
  533. batch_start_app() {
  534. local jar_files=("$@")
  535. local success_count=0
  536. local total_count=${#jar_files[@]}
  537. if [ $total_count -eq 0 ]; then
  538. print_error "没有指定要启动的JAR包"
  539. return 1
  540. fi
  541. if ! check_java_environment; then
  542. return 1
  543. fi
  544. print_info "=== 批量启动应用 ==="
  545. print_info "准备启动 $total_count 个JAR包..."
  546. echo ""
  547. for jar_file in "${jar_files[@]}"; do
  548. print_info "正在启动: $jar_file"
  549. # 检查JAR文件是否存在
  550. if [ ! -f "$jar_file" ]; then
  551. print_error " JAR文件不存在: $jar_file"
  552. continue
  553. fi
  554. setup_jar_variables "$jar_file"
  555. # 检查是否已经在运行
  556. if is_running "$jar_file"; then
  557. print_warning " $jar_file 已经在运行"
  558. ((success_count++))
  559. continue
  560. fi
  561. # 启动应用
  562. echo " JAR包: $jar_file"
  563. echo " JVM参数: $JAVA_OPTS"
  564. echo " 日志文件: $LOG_FILE"
  565. nohup java $JAVA_OPTS -jar "$jar_file" > "$LOG_FILE" 2>&1 &
  566. sleep "$STARTUP_WAIT"
  567. if is_running "$jar_file"; then
  568. local pid=$(get_app_pid "$jar_file")
  569. print_success " $jar_file 启动成功 (PID: $pid)"
  570. ((success_count++))
  571. else
  572. print_error " $jar_file 启动失败"
  573. print_warning " 请检查日志文件: $LOG_FILE"
  574. fi
  575. echo ""
  576. done
  577. print_info "=== 批量启动完成 ==="
  578. if [ $success_count -eq $total_count ]; then
  579. print_success "成功启动: $success_count/$total_count"
  580. else
  581. print_warning "成功启动: $success_count/$total_count"
  582. fi
  583. }
  584. # 批量停止应用
  585. batch_stop_app() {
  586. local jar_files=("$@")
  587. local success_count=0
  588. local total_count=${#jar_files[@]}
  589. if [ $total_count -eq 0 ]; then
  590. print_error "没有指定要停止的JAR包"
  591. return 1
  592. fi
  593. print_info "=== 批量停止应用 ==="
  594. print_info "准备停止 $total_count 个JAR包..."
  595. echo ""
  596. for jar_file in "${jar_files[@]}"; do
  597. print_info "正在停止: $jar_file"
  598. local pid=$(get_app_pid "$jar_file")
  599. if [ -z "$pid" ]; then
  600. print_warning " $jar_file 未运行"
  601. ((success_count++))
  602. continue
  603. fi
  604. setup_jar_variables "$jar_file"
  605. echo " 正在停止进程 (PID: $pid)..."
  606. kill "$pid" 2>/dev/null
  607. # 等待进程停止
  608. if wait_for_process_stop "$pid"; then
  609. print_success " $jar_file 停止成功"
  610. ((success_count++))
  611. else
  612. print_warning " 强制停止进程..."
  613. kill -9 "$pid" 2>/dev/null
  614. sleep "$FORCE_KILL_WAIT"
  615. if [ -z "$(get_app_pid "$jar_file")" ]; then
  616. print_success " $jar_file 强制停止成功"
  617. ((success_count++))
  618. else
  619. print_error " $jar_file 停止失败"
  620. fi
  621. fi
  622. echo ""
  623. done
  624. print_info "=== 批量停止完成 ==="
  625. if [ $success_count -eq $total_count ]; then
  626. print_success "成功停止: $success_count/$total_count"
  627. else
  628. print_warning "成功停止: $success_count/$total_count"
  629. fi
  630. }
  631. # 批量重启应用
  632. batch_restart_app() {
  633. local jar_files=("$@")
  634. if [ ${#jar_files[@]} -eq 0 ]; then
  635. print_error "没有指定要重启的JAR包"
  636. return 1
  637. fi
  638. if ! check_java_environment; then
  639. return 1
  640. fi
  641. print_info "=== 批量重启应用 ==="
  642. print_info "准备重启 ${#jar_files[@]} 个JAR包..."
  643. echo ""
  644. # 先停止所有应用
  645. batch_stop_app "${jar_files[@]}"
  646. echo ""
  647. sleep "$STARTUP_WAIT"
  648. # 再启动所有应用
  649. batch_start_app "${jar_files[@]}"
  650. }
  651. # 批量显示状态
  652. batch_show_status() {
  653. local jar_files=("$@")
  654. if [ ${#jar_files[@]} -eq 0 ]; then
  655. print_error "没有指定要查看状态的JAR包"
  656. return 1
  657. fi
  658. print_info "=== 批量应用状态 ==="
  659. echo ""
  660. local running_count=0
  661. local total_count=${#jar_files[@]}
  662. for jar_file in "${jar_files[@]}"; do
  663. echo -e "${CYAN}--- $jar_file ---${NC}"
  664. setup_jar_variables "$jar_file"
  665. echo "JAR包: $jar_file"
  666. echo "JVM参数: $JAVA_OPTS"
  667. echo "日志文件: $LOG_FILE"
  668. local pid=$(get_app_pid "$jar_file")
  669. if [ -n "$pid" ]; then
  670. print_success "✓ 正在运行 (PID: $pid)"
  671. ((running_count++))
  672. else
  673. print_warning "✗ 未运行"
  674. fi
  675. echo ""
  676. done
  677. print_info "=== 状态统计 ==="
  678. if [ $running_count -eq $total_count ]; then
  679. print_success "运行中: $running_count/$total_count (全部运行)"
  680. elif [ $running_count -eq 0 ]; then
  681. print_warning "运行中: $running_count/$total_count (全部停止)"
  682. else
  683. print_warning "运行中: $running_count/$total_count (部分运行)"
  684. fi
  685. }
  686. # 显示帮助信息
  687. show_help() {
  688. cat << 'EOF'
  689. Java应用管理脚本
  690. 用法:
  691. ./restart-java-app.sh {start|stop|restart|status|help} [jar昵称1] [jar昵称2] ...
  692. ./restart-java-app.sh [jar昵称1] [jar昵称2] ... # 默认执行restart操作
  693. 命令说明:
  694. start - 启动应用
  695. stop - 停止应用
  696. restart - 重启应用(默认操作)
  697. status - 查看应用状态
  698. help - 显示帮助信息
  699. JAR包昵称说明:
  700. • 支持模糊匹配:输入JAR包名称的一部分即可匹配
  701. • 支持多个昵称:可以同时指定多个JAR包昵称进行批量操作
  702. • 支持 'all' 参数:使用 'all' 可以对所有JAR包进行操作
  703. • 自动检测:如果不指定昵称,脚本会自动检测当前目录下的JAR包
  704. 使用示例:
  705. # 单JAR包操作
  706. ./restart-java-app.sh start # 启动(自动检测JAR包)
  707. ./restart-java-app.sh restart myapp # 重启包含"myapp"的JAR包
  708. ./restart-java-app.sh status user-service # 查看user-service状态
  709. # 多JAR包批量操作
  710. ./restart-java-app.sh start user order # 启动user和order相关的JAR包
  711. ./restart-java-app.sh stop all # 停止所有JAR包
  712. ./restart-java-app.sh restart user order pay # 重启多个服务
  713. # 默认重启操作(省略restart命令)
  714. ./restart-java-app.sh myapp # 重启myapp
  715. ./restart-java-app.sh user order # 重启user和order服务
  716. 配置说明:
  717. • JAR_NAME: JAR文件名(留空自动检测)
  718. • JAVA_OPTS: JVM参数(默认: -Xms512m -Xmx1024m)
  719. • 日志文件: 自动生成为 {jar名称}.log
  720. 注意事项:
  721. • 脚本需要在JAR文件所在目录运行
  722. • 确保有足够的权限启动/停止进程
  723. • 日志文件会在同一目录下生成
  724. • 支持优雅停止,超时后会强制终止进程
  725. EOF
  726. }
  727. # 执行命令的统一处理函数
  728. execute_command() {
  729. local action="$1"
  730. shift
  731. local jar_files=("$@")
  732. case "$action" in
  733. "start")
  734. if [ ${#jar_files[@]} -gt 1 ]; then
  735. batch_start_app "${jar_files[@]}"
  736. else
  737. start_app "${jar_files[0]}"
  738. fi
  739. ;;
  740. "stop")
  741. if [ ${#jar_files[@]} -gt 1 ]; then
  742. batch_stop_app "${jar_files[@]}"
  743. else
  744. stop_app "${jar_files[0]}"
  745. fi
  746. ;;
  747. "restart")
  748. if [ ${#jar_files[@]} -gt 1 ]; then
  749. batch_restart_app "${jar_files[@]}"
  750. else
  751. restart_app "${jar_files[0]}"
  752. fi
  753. ;;
  754. "status")
  755. if [ ${#jar_files[@]} -gt 1 ]; then
  756. batch_show_status "${jar_files[@]}"
  757. else
  758. show_status "${jar_files[0]}"
  759. fi
  760. ;;
  761. "help"|"-h"|"--help")
  762. show_help
  763. ;;
  764. *)
  765. print_error "未知命令 '$action'"
  766. show_help
  767. exit 1
  768. ;;
  769. esac
  770. }
  771. # ========================================
  772. # 主程序
  773. # ========================================
  774. # 解析命令行参数
  775. parse_jar_arguments "$@"
  776. # 如果解析出了JAR包参数,执行批量操作
  777. if [ ${#PARSED_JARS[@]} -gt 0 ]; then
  778. # 收集所有匹配的JAR文件
  779. all_jar_files=()
  780. for nickname in "${PARSED_JARS[@]}"; do
  781. matched_jars=($(find_jar_by_nickname "$nickname"))
  782. if [ ${#matched_jars[@]} -eq 0 ]; then
  783. print_error "未找到匹配昵称 '$nickname' 的JAR文件"
  784. exit 1
  785. fi
  786. # 添加到总列表
  787. all_jar_files+=("${matched_jars[@]}")
  788. done
  789. # 去重
  790. unique_jars=($(printf '%s\n' "${all_jar_files[@]}" | sort -u))
  791. print_info "找到 ${#unique_jars[@]} 个JAR文件:"
  792. for jar in "${unique_jars[@]}"; do
  793. echo " - $jar"
  794. done
  795. echo ""
  796. execute_command "$PARSED_ACTION" "${unique_jars[@]}"
  797. else
  798. # 检查JAR文件是否存在(可能触发交互式选择)
  799. if ! check_jar_exists; then
  800. exit 1
  801. fi
  802. # 处理命令行参数
  803. ACTION="${PARSED_ACTION:-restart}"
  804. # 检查是否在check_jar_exists中选择了多个JAR包
  805. if [ "$MULTI_JAR_MODE" = true ] && [ ${#SELECTED_JARS[@]} -gt 0 ]; then
  806. print_info "检测到多JAR包模式,将对 ${#SELECTED_JARS[@]} 个JAR包执行 '$ACTION' 操作"
  807. echo ""
  808. execute_command "$ACTION" "${SELECTED_JARS[@]}"
  809. else
  810. # 单JAR包操作
  811. execute_command "$ACTION" "$JAR_NAME"
  812. fi
  813. fi