四零语境后端代码仓库
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.

974 lines
27 KiB

  1. #!/bin/bash
  2. # ========================================
  3. # Java应用启动/重启脚本
  4. # 使用方法: ./restart-java-app.sh
  5. # ========================================
  6. # 全局配置
  7. JAR_NAME="" # JAR文件名(为空时自动检测)
  8. JAVA_OPTS="-Xms512m -Xmx1024m" # 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_FILE="${jar_basename}_${timestamp}.log"
  190. }
  191. # 等待进程停止
  192. wait_for_process_stop() {
  193. local pid="$1"
  194. local timeout="${2:-$STOP_TIMEOUT}"
  195. local count=0
  196. while [ $count -lt $timeout ]; do
  197. if ! ps -p $pid > /dev/null 2>&1; then
  198. return 0
  199. fi
  200. sleep 1
  201. count=$((count + 1))
  202. done
  203. return 1
  204. }
  205. # 根据昵称匹配JAR文件
  206. find_jar_by_nickname() {
  207. local nickname="$1"
  208. local found_jars=()
  209. # 如果昵称是 "all",返回所有JAR文件
  210. if [ "$nickname" = "all" ]; then
  211. for jar in *.jar; do
  212. if [ -f "$jar" ]; then
  213. found_jars+=("$jar")
  214. fi
  215. done
  216. else
  217. # 模糊匹配JAR文件名
  218. for jar in *.jar; do
  219. if [ -f "$jar" ] && [[ "$jar" == *"$nickname"* ]]; then
  220. found_jars+=("$jar")
  221. fi
  222. done
  223. fi
  224. # 输出匹配的JAR文件
  225. printf '%s\n' "${found_jars[@]}"
  226. }
  227. # 解析JAR包参数列表
  228. parse_jar_arguments() {
  229. local args=("$@")
  230. local jar_list=()
  231. local action=""
  232. # 如果没有参数,使用默认行为
  233. if [ ${#args[@]} -eq 0 ]; then
  234. action="restart"
  235. PARSED_ACTION="$action"
  236. return
  237. fi
  238. # 检查第一个参数是否是操作命令
  239. case "${args[0]}" in
  240. "start"|"stop"|"restart"|"status"|"help"|"-h"|"--help")
  241. action="${args[0]}"
  242. # 验证操作命令
  243. if ! validate_user_input "$action" "action"; then
  244. return 1
  245. fi
  246. # 如果只有操作命令,使用原有逻辑
  247. if [ ${#args[@]} -eq 1 ]; then
  248. PARSED_ACTION="$action"
  249. return
  250. fi
  251. # 其余参数作为JAR包昵称
  252. for ((i=1; i<${#args[@]}; i++)); do
  253. # 验证JAR包昵称输入
  254. if ! validate_user_input "${args[i]}" "general"; then
  255. return 1
  256. fi
  257. jar_list+=("${args[i]}")
  258. done
  259. ;;
  260. *)
  261. # 第一个参数不是操作命令,默认为restart操作
  262. action="restart"
  263. # 所有参数都作为JAR包昵称
  264. for arg in "${args[@]}"; do
  265. # 验证JAR包昵称输入
  266. if ! validate_user_input "$arg" "general"; then
  267. return 1
  268. fi
  269. jar_list+=("$arg")
  270. done
  271. ;;
  272. esac
  273. # 设置全局变量
  274. PARSED_ACTION="$action"
  275. PARSED_JARS=("${jar_list[@]}")
  276. }
  277. # 检查JAR文件是否存在
  278. check_jar_exists() {
  279. # 如果JAR_NAME为空,自动检测当前目录下的JAR文件
  280. if [ -z "$JAR_NAME" ]; then
  281. local jar_files=(*.jar)
  282. # 检查是否存在JAR文件
  283. if [ ! -e "${jar_files[0]}" ]; then
  284. print_error "当前目录下没有找到JAR文件!"
  285. print_warning "请将JAR文件放在脚本同一目录下,或在脚本中指定JAR_NAME"
  286. return 1
  287. fi
  288. # 如果只有一个JAR文件,自动使用
  289. if [ ${#jar_files[@]} -eq 1 ]; then
  290. JAR_NAME="${jar_files[0]}"
  291. # 验证JAR文件名的安全性
  292. if ! validate_jar_name "$JAR_NAME"; then
  293. return 1
  294. fi
  295. print_info "自动检测到JAR文件: $JAR_NAME"
  296. else
  297. # 多个JAR文件时,让用户选择
  298. print_info "检测到多个JAR文件,请选择要启动的应用:"
  299. echo ""
  300. # 显示选项列表
  301. local i=1
  302. for jar in "${jar_files[@]}"; do
  303. echo -e "${GREEN}[$i]${NC} $jar"
  304. ((i++))
  305. done
  306. echo ""
  307. # 提示用户输入
  308. echo -e "${YELLOW}输入选项:${NC}"
  309. echo -e " - 单个序号: ${GREEN}1${NC} (选择第1个JAR包)"
  310. echo -e " - 多个序号: ${GREEN}1,3,5${NC}${GREEN}1 3 5${NC} (选择多个JAR包)"
  311. echo -e " - 全部选择: ${GREEN}all${NC} (选择所有JAR包)"
  312. echo ""
  313. echo -n -e "${YELLOW}请输入选择: ${NC}"
  314. read -r choice
  315. # 验证用户输入
  316. if ! validate_user_input "$choice" "number"; then
  317. return 1
  318. fi
  319. # 处理输入
  320. local selected_jars=()
  321. if [ "$choice" = "all" ]; then
  322. # 选择所有JAR包
  323. selected_jars=("${jar_files[@]}")
  324. print_success "已选择所有JAR包 (${#selected_jars[@]}个)"
  325. else
  326. # 解析序号输入(支持逗号分隔和空格分隔)
  327. local numbers
  328. if [[ "$choice" == *","* ]]; then
  329. # 逗号分隔
  330. IFS=',' read -ra numbers <<< "$choice"
  331. else
  332. # 空格分隔
  333. read -ra numbers <<< "$choice"
  334. fi
  335. # 验证并收集选中的JAR包
  336. local valid_selection=true
  337. for num in "${numbers[@]}"; do
  338. # 去除空格
  339. num=$(echo "$num" | tr -d ' ')
  340. if [[ "$num" =~ ^[0-9]+$ ]] && [ "$num" -ge 1 ] && [ "$num" -le ${#jar_files[@]} ]; then
  341. selected_jars+=("${jar_files[$((num-1))]}")
  342. else
  343. print_error "无效的序号 '$num'!请输入1到${#jar_files[@]}之间的数字"
  344. valid_selection=false
  345. break
  346. fi
  347. done
  348. if [ "$valid_selection" = false ]; then
  349. return 1
  350. fi
  351. # 去重
  352. selected_jars=($(printf '%s\n' "${selected_jars[@]}" | sort -u))
  353. print_success "已选择 ${#selected_jars[@]} 个JAR包:"
  354. for jar in "${selected_jars[@]}"; do
  355. echo -e " - $jar"
  356. done
  357. fi
  358. # 验证所有选中的JAR文件名
  359. for jar in "${selected_jars[@]}"; do
  360. if ! validate_jar_name "$jar"; then
  361. return 1
  362. fi
  363. done
  364. echo ""
  365. # 如果选择了多个JAR包,设置全局变量供批量操作使用
  366. if [ ${#selected_jars[@]} -gt 1 ]; then
  367. SELECTED_JARS=("${selected_jars[@]}")
  368. MULTI_JAR_MODE=true
  369. # 设置第一个JAR作为默认JAR_NAME(兼容性)
  370. JAR_NAME="${selected_jars[0]}"
  371. else
  372. # 单个JAR包
  373. JAR_NAME="${selected_jars[0]}"
  374. MULTI_JAR_MODE=false
  375. fi
  376. fi
  377. fi
  378. # 检查指定的JAR文件是否存在
  379. if [ ! -f "$JAR_NAME" ]; then
  380. print_error "JAR文件 '$JAR_NAME' 不存在!"
  381. print_warning "请检查JAR_NAME配置是否正确,或确保JAR文件在当前目录下"
  382. return 1
  383. fi
  384. # 检查文件权限
  385. if ! check_file_permissions "$JAR_NAME"; then
  386. return 1
  387. fi
  388. return 0
  389. }
  390. # 获取运行中的应用PID
  391. get_app_pid() {
  392. local jar_name="$1"
  393. if [ -z "$jar_name" ]; then
  394. jar_name="$JAR_NAME"
  395. fi
  396. # 通过进程名查找(更可靠的方法)
  397. pgrep -f "$jar_name" | head -1
  398. }
  399. # 检查应用是否正在运行
  400. is_running() {
  401. local jar_name="$1"
  402. local pid=$(get_app_pid "$jar_name")
  403. if [ -n "$pid" ]; then
  404. return 0 # 正在运行
  405. else
  406. return 1 # 未运行
  407. fi
  408. }
  409. # 启动应用
  410. start_app() {
  411. local jar_name="$1"
  412. if [ -z "$jar_name" ]; then
  413. jar_name="$JAR_NAME"
  414. fi
  415. if ! check_java_environment; then
  416. return 1
  417. fi
  418. setup_jar_variables "$jar_name"
  419. if is_running "$jar_name"; then
  420. print_warning "应用 $jar_name 已在运行中 (PID: $(get_app_pid "$jar_name"))"
  421. return 0
  422. fi
  423. print_info "正在启动应用: $jar_name"
  424. print_info "日志文件: $LOG_FILE"
  425. # 启动应用
  426. nohup java $JAVA_OPTS -jar "$jar_name" > "$LOG_FILE" 2>&1 &
  427. # 等待启动
  428. sleep "$STARTUP_WAIT"
  429. # 验证启动状态
  430. if is_running "$jar_name"; then
  431. local actual_pid=$(get_app_pid "$jar_name")
  432. print_success "应用 $jar_name 启动成功 (PID: $actual_pid)"
  433. print_info "查看日志: tail -f $LOG_FILE"
  434. return 0
  435. else
  436. print_error "应用 $jar_name 启动失败"
  437. print_warning "请检查日志文件: $LOG_FILE"
  438. return 1
  439. fi
  440. }
  441. # 停止应用
  442. stop_app() {
  443. local jar_name="$1"
  444. if [ -z "$jar_name" ]; then
  445. jar_name="$JAR_NAME"
  446. fi
  447. local pid=$(get_app_pid "$jar_name")
  448. if [ -z "$pid" ]; then
  449. print_warning "应用 $jar_name 未运行"
  450. return 0
  451. fi
  452. setup_jar_variables "$jar_name"
  453. print_info "正在停止应用 $jar_name (PID: $pid)..."
  454. # 发送TERM信号
  455. kill "$pid" 2>/dev/null
  456. # 等待进程停止
  457. if wait_for_process_stop "$pid"; then
  458. print_success "应用 $jar_name 已成功停止"
  459. return 0
  460. else
  461. print_warning "应用 $jar_name 未在 ${STOP_TIMEOUT} 秒内停止,强制终止..."
  462. kill -9 "$pid" 2>/dev/null
  463. sleep "$FORCE_KILL_WAIT"
  464. # 再次检查
  465. if [ -z "$(get_app_pid "$jar_name")" ]; then
  466. print_success "应用 $jar_name 已强制停止"
  467. return 0
  468. else
  469. print_error "无法停止应用 $jar_name"
  470. return 1
  471. fi
  472. fi
  473. }
  474. # 重启应用
  475. restart_app() {
  476. local jar_name="$1"
  477. if [ -z "$jar_name" ]; then
  478. jar_name="$JAR_NAME"
  479. fi
  480. if ! check_java_environment; then
  481. return 1
  482. fi
  483. setup_jar_variables "$jar_name"
  484. print_info "正在重启应用: $jar_name"
  485. if is_running "$jar_name"; then
  486. print_info "正在停止应用..."
  487. stop_app "$jar_name"
  488. else
  489. print_info "应用未运行,直接启动"
  490. fi
  491. print_info "正在启动应用..."
  492. start_app "$jar_name"
  493. }
  494. # 显示应用状态
  495. show_status() {
  496. local jar_name="$1"
  497. if [ -z "$jar_name" ]; then
  498. jar_name="$JAR_NAME"
  499. fi
  500. setup_jar_variables "$jar_name"
  501. print_info "=== 应用状态 ==="
  502. echo "JAR包: $jar_name"
  503. echo "JVM参数: $JAVA_OPTS"
  504. echo "日志文件: $LOG_FILE"
  505. echo ""
  506. local pid=$(get_app_pid "$jar_name")
  507. if [ -n "$pid" ]; then
  508. print_success "✓ 应用正在运行 (PID: $pid)"
  509. # 显示进程信息
  510. if command -v ps >/dev/null 2>&1; then
  511. echo ""
  512. echo "进程详情:"
  513. ps -p "$pid" -o pid,ppid,cmd --no-headers 2>/dev/null || echo " 无法获取进程详情"
  514. fi
  515. else
  516. print_warning "✗ 应用未运行"
  517. fi
  518. }
  519. # 批量启动应用
  520. batch_start_app() {
  521. local jar_files=("$@")
  522. local success_count=0
  523. local total_count=${#jar_files[@]}
  524. if [ $total_count -eq 0 ]; then
  525. print_error "没有指定要启动的JAR包"
  526. return 1
  527. fi
  528. if ! check_java_environment; then
  529. return 1
  530. fi
  531. print_info "=== 批量启动应用 ==="
  532. print_info "准备启动 $total_count 个JAR包..."
  533. echo ""
  534. for jar_file in "${jar_files[@]}"; do
  535. print_info "正在启动: $jar_file"
  536. # 检查JAR文件是否存在
  537. if [ ! -f "$jar_file" ]; then
  538. print_error " JAR文件不存在: $jar_file"
  539. continue
  540. fi
  541. setup_jar_variables "$jar_file"
  542. # 检查是否已经在运行
  543. if is_running "$jar_file"; then
  544. print_warning " $jar_file 已经在运行"
  545. ((success_count++))
  546. continue
  547. fi
  548. # 启动应用
  549. echo " JAR包: $jar_file"
  550. echo " JVM参数: $JAVA_OPTS"
  551. echo " 日志文件: $LOG_FILE"
  552. nohup java $JAVA_OPTS -jar "$jar_file" > "$LOG_FILE" 2>&1 &
  553. sleep "$STARTUP_WAIT"
  554. if is_running "$jar_file"; then
  555. local pid=$(get_app_pid "$jar_file")
  556. print_success " $jar_file 启动成功 (PID: $pid)"
  557. ((success_count++))
  558. else
  559. print_error " $jar_file 启动失败"
  560. print_warning " 请检查日志文件: $LOG_FILE"
  561. fi
  562. echo ""
  563. done
  564. print_info "=== 批量启动完成 ==="
  565. if [ $success_count -eq $total_count ]; then
  566. print_success "成功启动: $success_count/$total_count"
  567. else
  568. print_warning "成功启动: $success_count/$total_count"
  569. fi
  570. }
  571. # 批量停止应用
  572. batch_stop_app() {
  573. local jar_files=("$@")
  574. local success_count=0
  575. local total_count=${#jar_files[@]}
  576. if [ $total_count -eq 0 ]; then
  577. print_error "没有指定要停止的JAR包"
  578. return 1
  579. fi
  580. print_info "=== 批量停止应用 ==="
  581. print_info "准备停止 $total_count 个JAR包..."
  582. echo ""
  583. for jar_file in "${jar_files[@]}"; do
  584. print_info "正在停止: $jar_file"
  585. local pid=$(get_app_pid "$jar_file")
  586. if [ -z "$pid" ]; then
  587. print_warning " $jar_file 未运行"
  588. ((success_count++))
  589. continue
  590. fi
  591. setup_jar_variables "$jar_file"
  592. echo " 正在停止进程 (PID: $pid)..."
  593. kill "$pid" 2>/dev/null
  594. # 等待进程停止
  595. if wait_for_process_stop "$pid"; then
  596. print_success " $jar_file 停止成功"
  597. ((success_count++))
  598. else
  599. print_warning " 强制停止进程..."
  600. kill -9 "$pid" 2>/dev/null
  601. sleep "$FORCE_KILL_WAIT"
  602. if [ -z "$(get_app_pid "$jar_file")" ]; then
  603. print_success " $jar_file 强制停止成功"
  604. ((success_count++))
  605. else
  606. print_error " $jar_file 停止失败"
  607. fi
  608. fi
  609. echo ""
  610. done
  611. print_info "=== 批量停止完成 ==="
  612. if [ $success_count -eq $total_count ]; then
  613. print_success "成功停止: $success_count/$total_count"
  614. else
  615. print_warning "成功停止: $success_count/$total_count"
  616. fi
  617. }
  618. # 批量重启应用
  619. batch_restart_app() {
  620. local jar_files=("$@")
  621. if [ ${#jar_files[@]} -eq 0 ]; then
  622. print_error "没有指定要重启的JAR包"
  623. return 1
  624. fi
  625. if ! check_java_environment; then
  626. return 1
  627. fi
  628. print_info "=== 批量重启应用 ==="
  629. print_info "准备重启 ${#jar_files[@]} 个JAR包..."
  630. echo ""
  631. # 先停止所有应用
  632. batch_stop_app "${jar_files[@]}"
  633. echo ""
  634. sleep "$STARTUP_WAIT"
  635. # 再启动所有应用
  636. batch_start_app "${jar_files[@]}"
  637. }
  638. # 批量显示状态
  639. batch_show_status() {
  640. local jar_files=("$@")
  641. if [ ${#jar_files[@]} -eq 0 ]; then
  642. print_error "没有指定要查看状态的JAR包"
  643. return 1
  644. fi
  645. print_info "=== 批量应用状态 ==="
  646. echo ""
  647. local running_count=0
  648. local total_count=${#jar_files[@]}
  649. for jar_file in "${jar_files[@]}"; do
  650. echo -e "${CYAN}--- $jar_file ---${NC}"
  651. setup_jar_variables "$jar_file"
  652. echo "JAR包: $jar_file"
  653. echo "JVM参数: $JAVA_OPTS"
  654. echo "日志文件: $LOG_FILE"
  655. local pid=$(get_app_pid "$jar_file")
  656. if [ -n "$pid" ]; then
  657. print_success "✓ 正在运行 (PID: $pid)"
  658. ((running_count++))
  659. else
  660. print_warning "✗ 未运行"
  661. fi
  662. echo ""
  663. done
  664. print_info "=== 状态统计 ==="
  665. if [ $running_count -eq $total_count ]; then
  666. print_success "运行中: $running_count/$total_count (全部运行)"
  667. elif [ $running_count -eq 0 ]; then
  668. print_warning "运行中: $running_count/$total_count (全部停止)"
  669. else
  670. print_warning "运行中: $running_count/$total_count (部分运行)"
  671. fi
  672. }
  673. # 显示帮助信息
  674. show_help() {
  675. cat << 'EOF'
  676. Java应用管理脚本
  677. 用法:
  678. ./restart-java-app.sh {start|stop|restart|status|help} [jar昵称1] [jar昵称2] ...
  679. ./restart-java-app.sh [jar昵称1] [jar昵称2] ... # 默认执行restart操作
  680. 命令说明:
  681. start - 启动应用
  682. stop - 停止应用
  683. restart - 重启应用(默认操作)
  684. status - 查看应用状态
  685. help - 显示帮助信息
  686. JAR包昵称说明:
  687. • 支持模糊匹配:输入JAR包名称的一部分即可匹配
  688. • 支持多个昵称:可以同时指定多个JAR包昵称进行批量操作
  689. • 支持 'all' 参数:使用 'all' 可以对所有JAR包进行操作
  690. • 自动检测:如果不指定昵称,脚本会自动检测当前目录下的JAR包
  691. 使用示例:
  692. # 单JAR包操作
  693. ./restart-java-app.sh start # 启动(自动检测JAR包)
  694. ./restart-java-app.sh restart myapp # 重启包含"myapp"的JAR包
  695. ./restart-java-app.sh status user-service # 查看user-service状态
  696. # 多JAR包批量操作
  697. ./restart-java-app.sh start user order # 启动user和order相关的JAR包
  698. ./restart-java-app.sh stop all # 停止所有JAR包
  699. ./restart-java-app.sh restart user order pay # 重启多个服务
  700. # 默认重启操作(省略restart命令)
  701. ./restart-java-app.sh myapp # 重启myapp
  702. ./restart-java-app.sh user order # 重启user和order服务
  703. 配置说明:
  704. • JAR_NAME: JAR文件名(留空自动检测)
  705. • JAVA_OPTS: JVM参数(默认: -Xms512m -Xmx1024m)
  706. • 日志文件: 自动生成为 {jar名称}.log
  707. 注意事项:
  708. • 脚本需要在JAR文件所在目录运行
  709. • 确保有足够的权限启动/停止进程
  710. • 日志文件会在同一目录下生成
  711. • 支持优雅停止,超时后会强制终止进程
  712. EOF
  713. }
  714. # 执行命令的统一处理函数
  715. execute_command() {
  716. local action="$1"
  717. shift
  718. local jar_files=("$@")
  719. case "$action" in
  720. "start")
  721. if [ ${#jar_files[@]} -gt 1 ]; then
  722. batch_start_app "${jar_files[@]}"
  723. else
  724. start_app "${jar_files[0]}"
  725. fi
  726. ;;
  727. "stop")
  728. if [ ${#jar_files[@]} -gt 1 ]; then
  729. batch_stop_app "${jar_files[@]}"
  730. else
  731. stop_app "${jar_files[0]}"
  732. fi
  733. ;;
  734. "restart")
  735. if [ ${#jar_files[@]} -gt 1 ]; then
  736. batch_restart_app "${jar_files[@]}"
  737. else
  738. restart_app "${jar_files[0]}"
  739. fi
  740. ;;
  741. "status")
  742. if [ ${#jar_files[@]} -gt 1 ]; then
  743. batch_show_status "${jar_files[@]}"
  744. else
  745. show_status "${jar_files[0]}"
  746. fi
  747. ;;
  748. "help"|"-h"|"--help")
  749. show_help
  750. ;;
  751. *)
  752. print_error "未知命令 '$action'"
  753. show_help
  754. exit 1
  755. ;;
  756. esac
  757. }
  758. # ========================================
  759. # 主程序
  760. # ========================================
  761. # 解析命令行参数
  762. parse_jar_arguments "$@"
  763. # 如果解析出了JAR包参数,执行批量操作
  764. if [ ${#PARSED_JARS[@]} -gt 0 ]; then
  765. # 收集所有匹配的JAR文件
  766. all_jar_files=()
  767. for nickname in "${PARSED_JARS[@]}"; do
  768. matched_jars=($(find_jar_by_nickname "$nickname"))
  769. if [ ${#matched_jars[@]} -eq 0 ]; then
  770. print_error "未找到匹配昵称 '$nickname' 的JAR文件"
  771. exit 1
  772. fi
  773. # 添加到总列表
  774. all_jar_files+=("${matched_jars[@]}")
  775. done
  776. # 去重
  777. unique_jars=($(printf '%s\n' "${all_jar_files[@]}" | sort -u))
  778. print_info "找到 ${#unique_jars[@]} 个JAR文件:"
  779. for jar in "${unique_jars[@]}"; do
  780. echo " - $jar"
  781. done
  782. echo ""
  783. execute_command "$PARSED_ACTION" "${unique_jars[@]}"
  784. else
  785. # 检查JAR文件是否存在(可能触发交互式选择)
  786. if ! check_jar_exists; then
  787. exit 1
  788. fi
  789. # 处理命令行参数
  790. ACTION="${PARSED_ACTION:-restart}"
  791. # 检查是否在check_jar_exists中选择了多个JAR包
  792. if [ "$MULTI_JAR_MODE" = true ] && [ ${#SELECTED_JARS[@]} -gt 0 ]; then
  793. print_info "检测到多JAR包模式,将对 ${#SELECTED_JARS[@]} 个JAR包执行 '$ACTION' 操作"
  794. echo ""
  795. execute_command "$ACTION" "${SELECTED_JARS[@]}"
  796. else
  797. # 单JAR包操作
  798. execute_command "$ACTION" "$JAR_NAME"
  799. fi
  800. fi