This commit is contained in:
binghuai
2025-11-20 19:01:30 +08:00
parent 98e8831d3b
commit 2430c0e683
49 changed files with 1204 additions and 25 deletions

View File

@@ -1 +1 @@
{"月度/8月/8月.md":{"scroll":150.7352,"cursor":{"from":{"ch":20,"line":164},"to":{"ch":20,"line":164}}},"材料/服务器.md":{"scroll":20.5975,"cursor":{"from":{"ch":17,"line":31},"to":{"ch":29,"line":31}}},"月度/9月/9月.md":{"scroll":378.1023,"cursor":{"from":{"ch":26,"line":389},"to":{"ch":26,"line":389}}},"月度/7月/7月.md":{"scroll":0,"cursor":{"from":{"ch":29,"line":147},"to":{"ch":29,"line":147}}},"月度/6月/6月.md":{"scroll":0,"cursor":{"from":{"ch":23,"line":120},"to":{"ch":23,"line":120}}},"月度/5月/5月.md":{"scroll":93.1957,"cursor":{"from":{"ch":20,"line":105},"to":{"ch":20,"line":105}}},"月度/4月/4月.md":{"scroll":120.1806,"cursor":{"from":{"ch":20,"line":139},"to":{"ch":20,"line":139}}},"月度/3月/3月.md":{"scroll":31.0412,"cursor":{"from":{"ch":6,"line":39},"to":{"ch":6,"line":39}}},"月度/7月/7月工作总结及8月工作计划.md":{"scroll":0,"cursor":{"from":{"ch":0,"line":0},"to":{"ch":0,"line":0}}},"月度/6月/6月份晨午检bug修复.md":{"scroll":307.9981,"cursor":{"from":{"ch":0,"line":0},"to":{"ch":0,"line":0}}},"月度/7月/设备管理中心研发记录.md":{"scroll":108.9598,"cursor":{"from":{"ch":0,"line":0},"to":{"ch":0,"line":0}}},"月度/8月/CA身份认证app/CA身份认证app流程图.md":{"scroll":5.8654,"cursor":{"from":{"ch":0,"line":0},"to":{"ch":0,"line":0}}},"月度/9月/常见病/20250903常见病优化沟通.md":{"scroll":0.7205,"cursor":{"from":{"ch":0,"line":0},"to":{"ch":0,"line":0}}},"月度/9月/汇海/对接主机/不登录模式接口文档.md":{"scroll":0,"cursor":{"from":{"ch":5,"line":8},"to":{"ch":5,"line":8}}},"月度/9月/汇海/对接主机/登录算法和密钥.md":{"scroll":0,"cursor":{"from":{"ch":0,"line":0},"to":{"ch":0,"line":0}}},"月度/9月/汇海/对接主机/华夏汇海接口文档.md":{"scroll":1133.8083,"cursor":{"from":{"ch":96,"line":1670},"to":{"ch":96,"line":1670}}},"材料/配置/Obsidian快捷键.md":{"scroll":0,"cursor":{"from":{"ch":18,"line":16},"to":{"ch":18,"line":16}}},"材料/配置/工具.md":{"scroll":0,"cursor":{"from":{"ch":50,"line":0},"to":{"ch":50,"line":0}}},"月度/9月/石榴籽-家校通/家校通需求.md":{"scroll":22.9513,"cursor":{"from":{"ch":13,"line":37},"to":{"ch":13,"line":37}}},"月度/9月/汇海/体质测试数据上传接口文档.md":{"scroll":64.4749,"cursor":{"from":{"ch":0,"line":0},"to":{"ch":0,"line":0}}},"月度/9月/汇海/解析汇海设备请求.md":{"scroll":1331.4598,"cursor":{"from":{"ch":0,"line":0},"to":{"ch":0,"line":0}}},"月度/9月/156中 中考模拟 初三.md":{"scroll":8.0497,"cursor":{"from":{"ch":0,"line":20},"to":{"ch":0,"line":20}}},"月度/10月/10月.md":{"scroll":0,"cursor":{"from":{"ch":12,"line":0},"to":{"ch":0,"line":0}}},"月度/11月/11月.md":{"scroll":579.7556,"cursor":{"from":{"ch":7,"line":600},"to":{"ch":7,"line":600}}},"月度/10月/第86届中国教育装备展/智慧体育.md":{"scroll":0.0271,"cursor":{"from":{"ch":0,"line":0},"to":{"ch":0,"line":0}}},"月度/11月/家校协同/11.11家校协同会议.md":{"scroll":49.3825,"cursor":{"from":{"ch":0,"line":77},"to":{"ch":0,"line":77}}}}
{"月度/8月/8月.md":{"scroll":150.7352,"cursor":{"from":{"ch":20,"line":164},"to":{"ch":20,"line":164}}},"材料/服务器.md":{"scroll":20.5975,"cursor":{"from":{"ch":17,"line":31},"to":{"ch":29,"line":31}}},"月度/9月/9月.md":{"scroll":378.1023,"cursor":{"from":{"ch":26,"line":389},"to":{"ch":26,"line":389}}},"月度/7月/7月.md":{"scroll":0,"cursor":{"from":{"ch":29,"line":147},"to":{"ch":29,"line":147}}},"月度/6月/6月.md":{"scroll":0,"cursor":{"from":{"ch":23,"line":120},"to":{"ch":23,"line":120}}},"月度/5月/5月.md":{"scroll":93.1957,"cursor":{"from":{"ch":20,"line":105},"to":{"ch":20,"line":105}}},"月度/4月/4月.md":{"scroll":120.1806,"cursor":{"from":{"ch":20,"line":139},"to":{"ch":20,"line":139}}},"月度/3月/3月.md":{"scroll":31.0412,"cursor":{"from":{"ch":6,"line":39},"to":{"ch":6,"line":39}}},"月度/7月/7月工作总结及8月工作计划.md":{"scroll":0,"cursor":{"from":{"ch":0,"line":0},"to":{"ch":0,"line":0}}},"月度/6月/6月份晨午检bug修复.md":{"scroll":307.9981,"cursor":{"from":{"ch":0,"line":0},"to":{"ch":0,"line":0}}},"月度/7月/设备管理中心研发记录.md":{"scroll":108.9598,"cursor":{"from":{"ch":0,"line":0},"to":{"ch":0,"line":0}}},"月度/8月/CA身份认证app/CA身份认证app流程图.md":{"scroll":5.8654,"cursor":{"from":{"ch":0,"line":0},"to":{"ch":0,"line":0}}},"月度/9月/常见病/20250903常见病优化沟通.md":{"scroll":0.7205,"cursor":{"from":{"ch":0,"line":0},"to":{"ch":0,"line":0}}},"月度/9月/汇海/对接主机/不登录模式接口文档.md":{"scroll":0,"cursor":{"from":{"ch":5,"line":8},"to":{"ch":5,"line":8}}},"月度/9月/汇海/对接主机/登录算法和密钥.md":{"scroll":0,"cursor":{"from":{"ch":0,"line":0},"to":{"ch":0,"line":0}}},"月度/9月/汇海/对接主机/华夏汇海接口文档.md":{"scroll":1133.8083,"cursor":{"from":{"ch":96,"line":1670},"to":{"ch":96,"line":1670}}},"材料/配置/Obsidian快捷键.md":{"scroll":0,"cursor":{"from":{"ch":18,"line":16},"to":{"ch":18,"line":16}}},"材料/配置/工具.md":{"scroll":0,"cursor":{"from":{"ch":50,"line":0},"to":{"ch":50,"line":0}}},"月度/9月/石榴籽-家校通/家校通需求.md":{"scroll":22.9513,"cursor":{"from":{"ch":13,"line":37},"to":{"ch":13,"line":37}}},"月度/9月/汇海/体质测试数据上传接口文档.md":{"scroll":64.4749,"cursor":{"from":{"ch":0,"line":0},"to":{"ch":0,"line":0}}},"月度/9月/汇海/解析汇海设备请求.md":{"scroll":1331.4598,"cursor":{"from":{"ch":0,"line":0},"to":{"ch":0,"line":0}}},"月度/9月/156中 中考模拟 初三.md":{"scroll":8.0497,"cursor":{"from":{"ch":0,"line":20},"to":{"ch":0,"line":20}}},"月度/10月/10月.md":{"scroll":0,"cursor":{"from":{"ch":12,"line":0},"to":{"ch":0,"line":0}}},"月度/11月/11月.md":{"scroll":639.0128,"cursor":{"from":{"ch":33,"line":659},"to":{"ch":33,"line":659}}},"月度/10月/第86届中国教育装备展/智慧体育.md":{"scroll":0.0271,"cursor":{"from":{"ch":0,"line":0},"to":{"ch":0,"line":0}}},"月度/11月/家校协同/11.11家校协同会议.md":{"scroll":49.3825,"cursor":{"from":{"ch":0,"line":77},"to":{"ch":0,"line":77}}}}

View File

@@ -190,32 +190,32 @@
},
"active": "d042930aea8ec533",
"lastOpenFiles": [
"月度/11月/家校协同/方老师谈技术部运营与团队建设.docx",
"月度/11月/家校协同/石榴籽家校协同平台上线总结.docx",
"月度/11月/家校协同/晨午检_slices/mipmap-xxxhdpi/Frame_427319603.png",
"月度/11月/家校协同/晨午检_slices/mipmap-xxxhdpi/Frame_427319603(2).png",
"月度/11月/家校协同/晨午检_slices/mipmap-xxxhdpi/Frame_427319603(1).png",
"月度/11月/家校协同/晨午检_slices/mipmap-xxxhdpi/Frame_427319602.png",
"月度/11月/家校协同/晨午检_slices/mipmap-xxxhdpi/Frame_427319602(2).png",
"月度/11月/家校协同/晨午检_slices/mipmap-xxxhdpi/Frame_427319602(1).png",
"月度/11月/家校协同/晨午检_slices/mipmap-xxxhdpi/Frame_427319601.png",
"月度/11月/家校协同/晨午检_slices/mipmap-xxxhdpi/Frame_427319601(2).png",
"月度/11月/家校协同/晨午检_slices/mipmap-xxxhdpi/Frame_427319601(1).png",
"月度/11月/家校协同/晨午检_slices/mipmap-xxxhdpi",
"月度/11月/家校协同/晨午检_slices/mipmap-xxhdpi/Frame_427319603.png",
"月度/11月/家校协同/晨午检_slices/mipmap-xxhdpi/Frame_427319603(2).png",
"月度/11月/家校协同/晨午检_slices/mipmap-xxhdpi",
"月度/11月/家校协同/晨午检_slices/mipmap-mdpi",
"月度/11月/家校协同/晨午检_slices/mipmap-xhdpi",
"月度/11月/家校协同/晨午检_slices/mipmap-hdpi",
"月度/11月/家校协同/晨午检_slices",
"月度/11月/家校协同/晨午检_slices.zip",
"月度/11月/晨午检脚本/oom_monitor.sh",
"月度/11月/晨午检脚本/新建 文本文档.sh",
"月度/11月/晨午检脚本/新建 文本文档.txt",
"月度/11月/11月.md",
"材料/服务器.md",
"月度/11月/家校协同/静态资源/积分图片/书包.png",
"月度/11月/家校协同/静态资源/积分图片/a2b56bd9e659e81e5e2f885874eb1343.png",
"月度/11月/家校协同/静态资源/积分图片/笔记本.png",
"月度/11月/家校协同/静态资源/积分图片/07bd0ac6326212be1805bd13eb56c034.png",
"月度/11月/家校协同/静态资源/积分图片/笔记本.jpg",
"月度/11月/家校协同/静态资源/积分图片/5ab4d653712a5dace75499f357586b32.jpg",
"月度/11月/家校协同/静态资源/积分图片/书包.jpg",
"月度/11月/家校协同/静态资源/积分图片/8cbd0acc7aa5f88c9a70866c68988193(1).jpg",
"月度/11月/家校协同/静态资源/积分图片/水杯.jpg",
"月度/11月/家校协同/静态资源/积分图片/1dc829b8fa3ed234288b053bc67343e2(1).jpg",
"月度/11月/家校协同/静态资源/积分图片",
"月度/11月/家校协同/静态资源/新建文件夹",
"月度/11月/家校协同/11.11家校协同会议.md",
"月度/8月/8月.md",
"月度/9月/9月.md",
"月度/11月/家校协同/静态资源/轮播图",
"月度/11月/家校协同/静态资源/首页图标",
"月度/11月/家校协同/静态资源",
"月度/11月/家校协同/新建文件夹",
"月度/11月/家校协同/家校协同功能列表~C7D9E.tmp",
"月度/11月/家校协同/数据要素获奖名单.pdf",
"月度/11月/家校协同/25年“数据要素×”大赛新疆分赛闭幕式通知.pdf",
"月度/9月/156中 中考模拟 初三.md",
"月度/7月/设备管理中心研发记录.md",
"月度/8月/8.8技术部研讨会议纪要.md",

View File

@@ -614,3 +614,54 @@ feat(food): 新增菜谱推荐功能
- 添加小贴士展示功能
- 优化菜谱描述文本清理逻辑
- 更新页面标题文字统一为“食物营养查询”
2.<span style="color:#3EC1D3 !important;">巴州常见病</span>手动导入学生
2.<span style="color:#3EC1D3 !important;">石榴籽</span>
feat(yyjk): 新增学生菜谱推荐及详情页面
- 新增菜谱详情页面 (pages/yyjk/detail.vue),展示三餐详情及饮食建议
- 实现菜谱数据获取接口 (getRecipe) 并在首页集成
- 新增菜谱详情页路由配置及页面结构
- 移除食谱推荐中的图片展示简化UI并增加加载状态
- 增加AI生成菜谱的异步处理与缓存逻辑
- 完成菜谱数据结构解析与前端展示适配
- 引入fastjson2依赖以支持菜谱数据解析
- 添加菜谱服务端缓存机制,提升性能与用户体验
- 修复学生数据查询空指针异常
# 11.20
1.<span style="color:#3EC1D3 !important;">巴州常见病</span>手动导入学生进行修复
[[和硕县幼儿园学生信息导入模板 修改名单110120.xls]]
2.优化<span style="color:#3EC1D3 !important;">晨午检</span>启动脚本
![[tomcat.sh]]
增加<span style="color:#3EC1D3 !important;">晨午检</span>oom监测脚本
![[oom_monitor.sh]]
3.<span style="color:#3EC1D3 !important;">石榴籽</span>
**小程序**
食物营养查询底部按钮增加图标
feat(components): 添加全局底部导航组件并集成到食物相关页面
- 创建 BottomNav 组件,包含分类、搜索、推荐三个导航项
- 为导航项添加激活状态样式及图标切换逻辑
- 在 food 相关页面中引入并使用 BottomNav 组件
- 移除原有重复的底部导航代码
- 调整搜索页面列表高度以适配底部导航
**后端前端**
feat(ops): 新增书籍管理功能模块
- 添加书籍实体类 Book 及其相关字段和方法
- 添加章节实体类 BookChapter 及其相关字段和方法
- 添加小节实体类 BookSection 及其相关字段和方法
- 添加文本内容实体类 SectionText 及其相关字段和方法
- 创建书籍、章节、小节和文本内容的 Mapper 接口
- 实现书籍完整数据查询服务 selectBookWithDetails
- 添加事务支持以确保数据一致性
- 配置 MyBatis 映射文件及 SQL 查询逻辑

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 872 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 875 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 875 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 791 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1020 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,512 @@
#!/bin/bash
# OOM监控配置
readonly MONITOR_INTERVAL=30 # 检查间隔(秒)
readonly OOM_KEYWORDS=("java.lang.OutOfMemoryError" "OutOfMemoryError" "java.lang.OutOfMemory")
readonly MAX_RESTART_ATTEMPTS=3 # 最大重启尝试次数
readonly RESTART_COOLDOWN=300 # 重启冷却时间(秒)
# 内存阈值配置(根据您的实际情况调整)
readonly MEMORY_THRESHOLD_GB=6 # 内存阈值GB超过此值才认为是内存使用过高
readonly MEMORY_THRESHOLD_KB=$((MEMORY_THRESHOLD_GB * 1024 * 1024)) # 转换为KB
# 日志配置
readonly LOG_FILE="/home/chenwujian2/script/logs/oom_monitor.log"
readonly STATUS_FILE="/home/chenwujian2/script/logs/oom_status.json"
# Tomcat实例配置 (端口:基础路径)
declare -A TOMCAT_INSTANCES=(
[90105]="/home/chenwujian"
[90106]="/home/chenwujian"
[90107]="/home/chenwujian2"
[90108]="/home/chenwujian2"
)
# 颜色定义
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly CYAN='\033[0;36m'
readonly NC='\033[0m'
# 获取Tomcat完整路径
get_tomcat_path() {
local port=$1
local base_path="${TOMCAT_INSTANCES[$port]}"
echo "${base_path}/tomcat${port}"
}
# 获取所有监控的端口
get_monitor_ports() {
echo "${!TOMCAT_INSTANCES[@]}"
}
# 日志函数
log() {
local message="$1"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo -e "${GREEN}[${timestamp}] $message${NC}"
echo "[${timestamp}] $message" >> "$LOG_FILE"
}
warn() {
local message="$1"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo -e "${YELLOW}[${timestamp}] 警告: $message${NC}"
echo "[${timestamp}] 警告: $message" >> "$LOG_FILE"
}
error() {
local message="$1"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo -e "${RED}[${timestamp}] 错误: $message${NC}"
echo "[${timestamp}] 错误: $message" >> "$LOG_FILE"
}
info() {
local message="$1"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo -e "${BLUE}[${timestamp}] $message${NC}"
echo "[${timestamp}] $message" >> "$LOG_FILE"
}
# 初始化状态文件
init_status_file() {
if [ ! -f "$STATUS_FILE" ]; then
cat > "$STATUS_FILE" << EOF
{
"monitor_start_time": "$(date '+%Y-%m-%d %H:%M:%S')",
"restart_records": {}
}
EOF
fi
# 创建日志目录
local log_dir=$(dirname "$LOG_FILE")
mkdir -p "$log_dir"
}
# 获取Tomcat进程PID
get_tomcat_pid() {
local port=$1
local tomcat_path=$(get_tomcat_path "$port")
# 方法1: 通过catalina.base路径查找
local pid=$(ps -ef | grep java | grep "catalina.base=${tomcat_path}" | grep -v grep | awk '{print $2}')
# 方法2: 如果方法1没找到通过端口查找
if [ -z "$pid" ]; then
pid=$(netstat -tlnp 2>/dev/null | grep ":${port} " | awk '{print $7}' | cut -d'/' -f1 | grep -v '^-$' | grep -v '^$')
fi
echo "$pid"
}
# 检查Tomcat是否运行
is_tomcat_running() {
local port=$1
local pid=$(get_tomcat_pid "$port")
if [ -n "$pid" ] && ps -p "$pid" > /dev/null 2>&1; then
return 0
else
return 1
fi
}
# 检查OOM错误
check_oom_error() {
local port=$1
local tomcat_path=$(get_tomcat_path "$port")
local log_file="${tomcat_path}/logs/catalina.out"
if [ ! -f "$log_file" ]; then
return 1
fi
# 检查最近的日志中是否有OOM错误最近1000行
for keyword in "${OOM_KEYWORDS[@]}"; do
if tail -n 1000 "$log_file" | grep -i "$keyword" > /dev/null 2>&1; then
# 获取OOM错误的具体信息
local oom_line=$(tail -n 1000 "$log_file" | grep -i "$keyword" | tail -1)
log "检测到Tomcat $port OOM错误: $oom_line"
return 0
fi
done
return 1
}
# 检查系统dmesg中的OOM killer
check_dmesg_oom() {
local port=$1
local pid=$(get_tomcat_pid "$port")
if [ -n "$pid" ]; then
# 检查dmesg中是否有该进程被OOM killer杀死的记录
if dmesg | grep -i "killed process.*java.*$pid" > /dev/null 2>&1; then
local oom_info=$(dmesg | grep -i "killed process.*java.*$pid" | tail -1)
log "检测到系统OOM Killer杀死了Tomcat $port (PID: $pid): $oom_info"
return 0
fi
fi
return 1
}
# 检查内存使用情况(改进版)
check_memory_usage() {
local port=$1
local pid=$(get_tomcat_pid "$port")
if [ -z "$pid" ]; then
return 1
fi
# 获取Java进程内存使用情况
local mem_info=$(ps -o pid,rss,vsz,pmem,comm -p "$pid" 2>/dev/null | grep java)
if [ -n "$mem_info" ]; then
local rss=$(echo "$mem_info" | awk '{print $2}') # 物理内存(KB)
local vsz=$(echo "$mem_info" | awk '{print $3}') # 虚拟内存(KB)
local rss_gb=$((rss / 1024 / 1024))
local vsz_gb=$((vsz / 1024 / 1024))
# 记录内存使用情况(不触发重启)
info "Tomcat $port 内存使用: RSS=${rss_gb}GB (${rss}KB) VSZ=${vsz_gb}GB (${vsz}KB)"
# 如果RSS超过阈值认为内存使用过高
if [ "$rss" -gt "$MEMORY_THRESHOLD_KB" ]; then
warn "Tomcat $port 内存使用过高: RSS=${rss_gb}GB (超过${MEMORY_THRESHOLD_GB}GB阈值)"
return 0
fi
fi
return 1
}
# 重启Tomcat
restart_tomcat() {
local port=$1
local reason="$2"
local tomcat_path=$(get_tomcat_path "$port")
log "准备重启Tomcat $port,原因: $reason"
log "Tomcat路径: $tomcat_path"
# 停止Tomcat
if [ -f "${tomcat_path}/bin/shutdown.sh" ]; then
info "停止Tomcat $port..."
if sh "${tomcat_path}/bin/shutdown.sh"; then
log "Tomcat $port 停止命令已发送"
else
warn "Tomcat $port 停止过程中可能出现问题"
fi
else
error "Tomcat $port 停止脚本不存在: ${tomcat_path}/bin/shutdown.sh"
return 1
fi
# 等待停止
sleep 5
# 强制杀死残留进程
local pid=$(get_tomcat_pid "$port")
if [ -n "$pid" ]; then
warn "强制杀死Tomcat $port 残留进程: $pid"
kill -9 "$pid" 2>/dev/null
sleep 2
fi
# 备份OOM日志只有在真正OOM时才备份
if [ "$reason" = "应用层OOM错误" ] || [ "$reason" = "系统OOM Killer" ]; then
local log_file="${tomcat_path}/logs/catalina.out"
if [ -f "$log_file" ]; then
local backup_name="${log_file}.oom.$(date +%Y%m%d_%H%M%S)"
cp "$log_file" "$backup_name"
log "OOM日志已备份: $backup_name"
# 清空原日志文件
> "$log_file"
fi
fi
# 启动Tomcat
if [ -f "${tomcat_path}/bin/startup.sh" ]; then
info "启动Tomcat $port..."
if sh "${tomcat_path}/bin/startup.sh"; then
log "Tomcat $port 启动命令已执行"
# 等待启动
sleep 10
# 验证是否启动成功
if is_tomcat_running "$port"; then
log "Tomcat $port 重启成功"
return 0
else
error "Tomcat $port 启动后未运行"
return 1
fi
else
error "Tomcat $port 启动失败"
return 1
fi
else
error "Tomcat $port 启动脚本不存在"
return 1
fi
}
# 更新重启记录
update_restart_record() {
local port=$1
local reason="$2"
local success="$3"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
local temp_file="${STATUS_FILE}.tmp"
# 使用jq更新JSON文件如果没有jq则使用sed
if command -v jq >/dev/null 2>&1; then
jq --arg port "$port" \
--arg timestamp "$timestamp" \
--arg reason "$reason" \
--arg success "$success" \
'.restart_records[$port] += [{"time": $timestamp, "reason": $reason, "success": $success}]' \
"$STATUS_FILE" > "$temp_file" && mv "$temp_file" "$STATUS_FILE"
else
# 简单的文本处理如果没有jq
echo "重启记录 - 端口: $port, 时间: $timestamp, 原因: $reason, 成功: $success" >> "$LOG_FILE"
fi
}
# 检查重启频率
can_restart() {
local port=$1
local current_time=$(date +%s)
# 检查冷却时间
if [ -f "/tmp/tomcat_${port}_restart_time" ]; then
local last_restart=$(cat "/tmp/tomcat_${port}_restart_time")
local time_diff=$((current_time - last_restart))
if [ $time_diff -lt $RESTART_COOLDOWN ]; then
local remaining=$((RESTART_COOLDOWN - time_diff))
warn "Tomcat $port 在冷却期内,${remaining}秒后可重启"
return 1
fi
fi
# 检查重启次数
local restart_count_file="/tmp/tomcat_${port}_restart_count"
local restart_count=0
if [ -f "$restart_count_file" ]; then
restart_count=$(cat "$restart_count_file")
fi
# 每天重置计数
local today=$(date +%Y%m%d)
local count_date_file="/tmp/tomcat_${port}_restart_date"
if [ -f "$count_date_file" ]; then
local last_date=$(cat "$count_date_file")
if [ "$last_date" != "$today" ]; then
restart_count=0
echo "$restart_count" > "$restart_count_file"
echo "$today" > "$count_date_file"
fi
else
echo "$today" > "$count_date_file"
fi
if [ $restart_count -ge $MAX_RESTART_ATTEMPTS ]; then
error "Tomcat $port 今日重启次数已达上限($MAX_RESTART_ATTEMPTS次),不再自动重启"
return 1
fi
return 0
}
# 更新重启计数
update_restart_count() {
local port=$1
local restart_count_file="/tmp/tomcat_${port}_restart_count"
local restart_count=0
if [ -f "$restart_count_file" ]; then
restart_count=$(cat "$restart_count_file")
fi
restart_count=$((restart_count + 1))
echo "$restart_count" > "$restart_count_file"
echo "$(date +%s)" > "/tmp/tomcat_${port}_restart_time"
}
# 监控单个Tomcat实例
monitor_tomcat() {
local port=$1
if ! is_tomcat_running "$port"; then
warn "Tomcat $port 未运行"
return
fi
local oom_detected=false
local oom_reason=""
# 检查OOM错误最高优先级
if check_oom_error "$port"; then
oom_detected=true
oom_reason="应用层OOM错误"
elif check_dmesg_oom "$port"; then
oom_detected=true
oom_reason="系统OOM Killer"
elif check_memory_usage "$port"; then
oom_detected=true
oom_reason="内存使用过高"
fi
if [ "$oom_detected" = true ]; then
warn "检测到Tomcat $port 需要重启: $oom_reason"
if can_restart "$port"; then
info "开始重启Tomcat $port..."
if restart_tomcat "$port" "$oom_reason"; then
log "Tomcat $port 重启成功"
update_restart_record "$port" "$oom_reason" "true"
update_restart_count "$port"
else
error "Tomcat $port 重启失败"
update_restart_record "$port" "$oom_reason" "false"
fi
fi
fi
}
# 显示监控状态
show_monitor_status() {
log "=== Tomcat OOM监控状态 ==="
log "监控节点: $(get_monitor_ports | tr '\n' ' ')"
log "检查间隔: ${MONITOR_INTERVAL}"
log "内存阈值: ${MEMORY_THRESHOLD_GB}GB"
log "日志文件: $LOG_FILE"
log "状态文件: $STATUS_FILE"
echo
for port in $(get_monitor_ports); do
local base_path="${TOMCAT_INSTANCES[$port]}"
if is_tomcat_running "$port"; then
local pid=$(get_tomcat_pid "$port")
# 显示内存使用情况
local mem_info=$(ps -o rss -p "$pid" 2>/dev/null | tail -1)
local rss_gb=$((mem_info / 1024 / 1024))
echo -e "${GREEN}Tomcat $port: 运行中 (PID: $pid, 内存: ~${rss_gb}GB, 路径: ${base_path}/tomcat${port})${NC}"
else
echo -e "${RED}Tomcat $port: 未运行 (路径: ${base_path}/tomcat${port})${NC}"
fi
done
echo
}
# 主监控循环
start_monitor() {
log "启动Tomcat OOM监控服务..."
log "监控端口: $(get_monitor_ports | tr '\n' ' ')"
log "检查间隔: ${MONITOR_INTERVAL}"
log "内存阈值: ${MEMORY_THRESHOLD_GB}GB"
log "按 Ctrl+C 停止监控"
echo
# 显示初始状态
show_monitor_status
# 主循环
while true; do
for port in $(get_monitor_ports); do
monitor_tomcat "$port"
done
# 等待下一次检查
sleep $MONITOR_INTERVAL
done
}
# 停止监控
stop_monitor() {
log "停止Tomcat OOM监控服务..."
pkill -f "tomcat.*oom.*monitor" || true
}
# 显示帮助
show_usage() {
echo "使用方法: $0 {start|stop|status|restart|once}"
echo
echo "命令说明:"
echo " start 启动OOM监控服务"
echo " stop 停止OOM监控服务"
echo " status 查看监控状态"
echo " restart 重启监控服务"
echo " once 执行一次检查(不持续监控)"
echo
echo "监控配置:"
echo " 监控端口和路径:"
for port in $(get_monitor_ports); do
local base_path="${TOMCAT_INSTANCES[$port]}"
echo " $port -> ${base_path}/tomcat${port}"
done
echo " 检查间隔: ${MONITOR_INTERVAL}"
echo " 内存阈值: ${MEMORY_THRESHOLD_GB}GB"
echo " 日志文件: $LOG_FILE"
}
# 执行单次检查
run_once() {
log "执行单次OOM检查..."
for port in $(get_monitor_ports); do
monitor_tomcat "$port"
done
log "单次检查完成"
}
# 主函数
main() {
local command="${1:-start}"
# 初始化
init_status_file
case "$command" in
start)
start_monitor
;;
stop)
stop_monitor
;;
status)
show_monitor_status
;;
restart)
stop_monitor
sleep 2
start_monitor
;;
once)
run_once
;;
help|--help|-h)
show_usage
;;
*)
error "未知命令: $command"
show_usage
exit 1
;;
esac
}
# 脚本入口
if [ $# -eq 0 ]; then
show_usage
exit 1
fi
main "$@"

View File

@@ -0,0 +1,616 @@
#!/bin/bash
# 配置区域 - 便于修改
readonly TOMCAT_PORTS=(90107 90108)
readonly TOMCAT_BASE_PATH="/home/chenwujian2"
readonly DIST_PATH="/home/stxt/cwj2/"
readonly CONFIG_SOURCE_PATH="/home/chenwujian/tomcat90105/webapps"
readonly CLEANUP_PATHS=(
"/home/chenwujian2/script/2025/"
"/home/chenwujian2/script/logs/app.log"
)
# 颜色定义
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly CYAN='\033[0;36m'
readonly PURPLE='\033[0;35m'
readonly NC='\033[0m' # No Color
# 获取Tomcat完整路径
get_tomcat_path() {
local port=$1
echo "${TOMCAT_BASE_PATH}/tomcat${port}"
}
# 日志函数
log() {
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] $1${NC}"
}
warn() {
echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')] 警告: $1${NC}"
}
error() {
echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] 错误: $1${NC}"
}
info() {
echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')] $1${NC}"
}
# 显示菜单
show_menu() {
clear
echo -e "${CYAN}"
echo "================================================"
echo " Tomcat 服务管理菜单"
echo "================================================"
echo -e "${NC}"
echo -e "${GREEN}1. 启动 Tomcat 服务${NC}"
echo -e "${GREEN}2. 停止 Tomcat 服务${NC}"
echo -e "${GREEN}3. 重启 Tomcat 服务${NC}"
echo -e "${YELLOW}4. 部署应用到 Tomcat${NC}"
echo -e "${YELLOW}5. 分发配置文件${NC}"
echo -e "${BLUE}6. 查看服务状态${NC}"
echo -e "${PURPLE}7. 查看 Tomcat 日志${NC}"
echo -e "${RED}8. 清理所有文件(包括日志)${NC}"
echo -e "${RED}9. 仅清理 Tomcat 日志${NC}"
echo -e "${CYAN}a. 完整部署流程${NC}"
echo -e "${RED}0. 退出脚本${NC}"
echo "================================================"
}
# 检查必要目录是否存在
check_dependencies() {
if [ ! -d "$TOMCAT_BASE_PATH" ]; then
error "基础路径不存在: $TOMCAT_BASE_PATH"
return 1
fi
for port in "${TOMCAT_PORTS[@]}"; do
local tomcat_path=$(get_tomcat_path "$port")
if [ ! -d "$tomcat_path" ]; then
error "Tomcat实例路径不存在: $tomcat_path"
return 1
fi
done
return 0
}
# 显示Tomcat日志实时输出
show_tomcat_logs() {
local port=$1
local tomcat_path=$(get_tomcat_path "$port")
local log_file="${tomcat_path}/logs/catalina.out"
if [ ! -f "$log_file" ]; then
warn "日志文件不存在: $log_file"
echo "可能的原因:"
echo "1. Tomcat 尚未启动"
echo "2. 日志文件路径不正确"
echo "3. 没有读取权限"
return 1
fi
info "开始显示 Tomcat $port 日志 (按 Ctrl+C 退出)..."
echo -e "${CYAN}================================================${NC}"
echo -e "${CYAN}日志文件: $log_file${NC}"
echo -e "${CYAN}================================================${NC}"
# 显示文件大小
local file_size=$(du -h "$log_file" | cut -f1)
echo -e "${BLUE}日志文件大小: $file_size${NC}"
echo ""
# 使用 trap 来捕获 Ctrl+C 信号
trap 'kill $tail_pid $stat_pid 2>/dev/null; echo ""; info "已退出日志查看"; exit 0' INT TERM
# 显示最后50行日志然后实时跟踪新日志
tail -n 50 -f "$log_file" &
local tail_pid=$!
# 等待 tail 进程结束
wait $tail_pid 2>/dev/null
trap - INT TERM # 清理 trap
}
# 查看日志菜单
view_logs_menu() {
local choice
while true; do
clear
echo -e "${PURPLE}"
echo "================================================"
echo " 查看 Tomcat 日志"
echo "================================================"
echo -e "${NC}"
# 显示各Tomcat状态
for i in "${!TOMCAT_PORTS[@]}"; do
local port="${TOMCAT_PORTS[$i]}"
local tomcat_path=$(get_tomcat_path "$port")
local log_file="${tomcat_path}/logs/catalina.out"
if [ -f "$log_file" ]; then
local file_size=$(du -h "$log_file" | cut -f1)
local line_count=$(wc -l < "$log_file" 2>/dev/null || echo "0")
echo -e "${CYAN}$((i+1)). Tomcat $port 日志${NC}"
echo -e " 文件: $log_file"
echo -e " 大小: $file_size, 行数: $line_count"
else
echo -e "${YELLOW}$((i+1)). Tomcat $port 日志${NC}"
echo -e " 状态: ${RED}日志文件不存在${NC}"
fi
echo ""
done
echo -e "${CYAN}c. 查看所有 Tomcat 日志(多窗口)${NC}"
echo -e "${CYAN}b. 返回主菜单${NC}"
echo "================================================"
read -p "请选择要查看的日志 (1-${#TOMCAT_PORTS[@]}/c/b): " choice
case $choice in
[1-9])
local index=$((choice-1))
if [ $index -lt ${#TOMCAT_PORTS[@]} ]; then
local port="${TOMCAT_PORTS[$index]}"
show_tomcat_logs "$port"
read -p "按回车键继续..." dummy
else
error "无效选择,请重新输入!"
sleep 1
fi
;;
c|C)
view_all_logs
;;
b|B)
return
;;
*)
error "无效选择,请重新输入!"
sleep 1
;;
esac
done
}
# 查看所有Tomcat日志多窗口方式
view_all_logs() {
info "即将在新窗口中打开所有Tomcat日志..."
echo "这将为每个Tomcat打开一个独立的终端窗口查看日志"
echo "关闭日志窗口后,按回车键返回菜单"
echo ""
for port in "${TOMCAT_PORTS[@]}"; do
local tomcat_path=$(get_tomcat_path "$port")
local log_file="${tomcat_path}/logs/catalina.out"
if [ -f "$log_file" ]; then
info "为 Tomcat $port 打开日志窗口..."
# 使用 gnome-terminal, xterm 或 screen 来打开新窗口
if command -v gnome-terminal >/dev/null 2>&1; then
gnome-terminal --title="Tomcat $port 日志" -- bash -c "echo '正在显示 Tomcat $port 日志...'; echo '文件: $log_file'; echo '按 Ctrl+C 退出'; echo '================================'; tail -n 50 -f '$log_file'; exec bash"
elif command -v xterm >/dev/null 2>&1; then
xterm -title "Tomcat $port 日志" -e bash -c "echo '正在显示 Tomcat $port 日志...'; echo '文件: $log_file'; echo '按 Ctrl+C 退出'; echo '================================'; tail -n 50 -f '$log_file'; read -p '按回车键关闭...'"
else
warn "未找到可用的终端程序,无法打开多窗口"
info "将在当前终端依次显示日志..."
show_tomcat_logs "$port"
fi
else
warn "Tomcat $port 日志文件不存在: $log_file"
fi
done
read -p "所有日志窗口已启动,按回车键返回菜单..." dummy
}
# 启动Tomcat并显示日志
start_tomcats_with_logs() {
log "启动Tomcat服务..."
# 首先启动所有Tomcat
for port in "${TOMCAT_PORTS[@]}"; do
local tomcat_path=$(get_tomcat_path "$port")
if [ -f "${tomcat_path}/bin/startup.sh" ]; then
info "启动Tomcat $port..."
if sh "${tomcat_path}/bin/startup.sh"; then
log "Tomcat $port 启动命令执行完成"
else
error "Tomcat $port 启动失败"
fi
else
error "启动脚本不存在: ${tomcat_path}/bin/startup.sh"
fi
done
# 等待一段时间让Tomcat开始启动
info "等待Tomcat启动..."
sleep 5
# 显示启动状态
show_tomcat_status
# 询问是否查看日志
echo
read -p "是否查看Tomcat启动日志(y/n, 默认y): " view_logs
view_logs=${view_logs:-y}
if [[ $view_logs =~ ^[Yy]$ ]]; then
for port in "${TOMCAT_PORTS[@]}"; do
echo
read -p "是否查看 Tomcat $port 的启动日志?(y/n): " view_single
if [[ $view_single =~ ^[Yy]$ ]]; then
show_tomcat_logs "$port"
fi
done
fi
}
# 清理Tomcat日志
clean_tomcat_logs() {
log "开始清理Tomcat日志..."
for port in "${TOMCAT_PORTS[@]}"; do
local tomcat_path=$(get_tomcat_path "$port")
local logs_path="${tomcat_path}/logs"
if [ -d "$logs_path" ]; then
info "清理Tomcat $port 日志..."
# 清理catalina.out清空内容而不是删除文件
if [ -f "${logs_path}/catalina.out" ]; then
> "${logs_path}/catalina.out"
log "Tomcat $port - 已清空 catalina.out"
fi
# 删除旧的日志文件,但保留最近的一些
local log_files=("catalina." "localhost." "manager." "host-manager." "localhost_access_log.")
for log_prefix in "${log_files[@]}"; do
# 删除7天前的日志文件
find "$logs_path" -name "${log_prefix}*" -type f -mtime +7 -delete 2>/dev/null
# 统计清理结果
local remaining_count=$(find "$logs_path" -name "${log_prefix}*" -type f | wc -l)
log "Tomcat $port - ${log_prefix}* 剩余文件: $remaining_count"
done
# 清理temp目录
local temp_path="${tomcat_path}/temp"
if [ -d "$temp_path" ]; then
rm -rf "${temp_path}"/*
log "Tomcat $port - 已清空 temp 目录"
fi
else
warn "Tomcat $port 日志路径不存在: $logs_path"
fi
done
}
# 清理文件函数
cleanup_files() {
log "开始清理文件..."
for path in "${CLEANUP_PATHS[@]}"; do
if [[ "$path" == */ ]]; then
# 如果是目录,删除目录下所有文件但保留目录
if [ -d "$path" ]; then
rm -rf "${path}"*
log "已清空目录: $path"
else
warn "目录不存在: $path"
fi
else
# 如果是文件,清空内容或删除
if [ -f "$path" ]; then
> "$path" # 清空文件内容
log "已清空文件: $path"
else
warn "文件不存在: $path"
fi
fi
done
# 清理Tomcat日志
clean_tomcat_logs
}
# 启动Tomcat
start_tomcats() {
log "启动Tomcat服务..."
for port in "${TOMCAT_PORTS[@]}"; do
local tomcat_path=$(get_tomcat_path "$port")
if [ -f "${tomcat_path}/bin/startup.sh" ]; then
info "启动Tomcat $port..."
if sh "${tomcat_path}/bin/startup.sh"; then
log "Tomcat $port 启动完成"
else
error "Tomcat $port 启动失败"
fi
else
error "启动脚本不存在: ${tomcat_path}/bin/startup.sh"
fi
done
show_tomcat_status
}
# 停止Tomcat精确停止指定端口的Tomcat
stop_tomcats() {
log "停止Tomcat服务..."
# 首先使用正常关闭方式
for port in "${TOMCAT_PORTS[@]}"; do
local tomcat_path=$(get_tomcat_path "$port")
if [ -f "${tomcat_path}/bin/shutdown.sh" ]; then
info "停止Tomcat $port..."
if sh "${tomcat_path}/bin/shutdown.sh"; then
log "Tomcat $port 已发送停止命令"
else
warn "Tomcat $port 停止过程中可能出现问题"
fi
else
error "停止脚本不存在: ${tomcat_path}/bin/shutdown.sh"
fi
done
# 等待正常关闭
info "等待正常关闭..."
sleep 5
# 精确杀死指定端口的进程
for port in "${TOMCAT_PORTS[@]}"; do
# 查找监听指定端口的Java进程
local pids=$(netstat -tlnp 2>/dev/null | grep ":${port} " | awk '{print $7}' | cut -d'/' -f1 | grep -v '^-$' | grep -v '^$')
if [ -n "$pids" ]; then
warn "发现端口 $port 的残留进程,强制杀死: $pids"
kill -9 $pids 2>/dev/null
fi
# 另外通过进程参数查找对应的Tomcat进程
local tomcat_pids=$(ps -ef | grep java | grep "catalina.base=/home/chenwujian2/tomcat${port}" | grep -v grep | awk '{print $2}')
if [ -n "$tomcat_pids" ]; then
warn "发现Tomcat${port}的残留进程,强制杀死: $tomcat_pids"
kill -9 $tomcat_pids 2>/dev/null
fi
done
show_tomcat_status
}
# 重启Tomcat
restart_tomcats() {
log "重启Tomcat服务..."
stop_tomcats
sleep 2
start_tomcats_with_logs
}
# 分发配置文件
distribute_config() {
log "分发配置文件..."
if [ ! -d "$CONFIG_SOURCE_PATH" ]; then
error "配置文件源路径不存在: $CONFIG_SOURCE_PATH"
return 1
fi
for port in "${TOMCAT_PORTS[@]}"; do
local tomcat_path=$(get_tomcat_path "$port")
local target_path="${tomcat_path}/webapps/ROOT/WEB-INF/classes"
# 创建目标目录(如果不存在)
mkdir -p "${target_path}/properties"
# 复制配置文件
if \cp -rf "${CONFIG_SOURCE_PATH}/jeeplus.properties" "${target_path}/properties/"; then
log "Tomcat $port - jeeplus.properties 复制完成"
else
error "Tomcat $port - jeeplus.properties 复制失败"
fi
if \cp -rf "${CONFIG_SOURCE_PATH}/fdfs_client.conf" "${target_path}/"; then
log "Tomcat $port - fdfs_client.conf 复制完成"
else
error "Tomcat $port - fdfs_client.conf 复制失败"
fi
done
}
# 显示Tomcat状态
show_tomcat_status() {
log "Tomcat进程状态:"
# 精确显示指定Tomcat的进程通过catalina.base路径匹配
local found_process=0
for port in "${TOMCAT_PORTS[@]}"; do
local tomcat_path=$(get_tomcat_path "$port")
local process=$(ps -ef | grep java | grep "catalina.base=${tomcat_path}" | grep -v grep)
if [ -n "$process" ]; then
echo -e "${GREEN}Tomcat $port 运行中:${NC}"
echo -e "${GREEN}$process${NC}"
echo ""
found_process=1
else
echo -e "${YELLOW}Tomcat $port: 未运行${NC}"
echo ""
fi
done
if [ $found_process -eq 0 ]; then
info "所有指定的Tomcat实例均未运行"
fi
# 显示端口占用情况(更精确的端口检测)
log "端口占用情况:"
for port in "${TOMCAT_PORTS[@]}"; do
# 使用更精确的端口检测
if ss -tlnp 2>/dev/null | grep ":${port} " >/dev/null || \
netstat -tlnp 2>/dev/null | grep ":${port} " >/dev/null; then
# 获取占用该端口的进程信息
local port_info=""
if command -v ss >/dev/null 2>&1; then
port_info=$(ss -tlnp | grep ":${port} " | head -1)
local pid=$(echo "$port_info" | grep -o 'pid=[0-9]*' | cut -d= -f2)
else
port_info=$(netstat -tlnp 2>/dev/null | grep ":${port} " | head -1)
local pid=$(echo "$port_info" | awk '{print $7}' | cut -d'/' -f1)
fi
if [ -n "$pid" ] && [ "$pid" != "-" ]; then
# 检查该进程是否是我们管理的Tomcat
local tomcat_path=$(get_tomcat_path "$port")
if ps -p "$pid" -o command= 2>/dev/null | grep -q "catalina.base=${tomcat_path}"; then
echo -e "${GREEN}端口 $port: 被本脚本管理的Tomcat占用 (PID: $pid)${NC}"
else
echo -e "${YELLOW}端口 $port: 被其他进程占用 (PID: $pid)${NC}"
fi
else
echo -e "${YELLOW}端口 $port: 被占用 (无法获取PID)${NC}"
fi
else
echo -e "${RED}端口 $port: 未被占用${NC}"
fi
done
}
# 部署应用
deploy_app() {
log "开始部署应用..."
local today=$(date +"%Y%m%d%H%M")
if [ ! -f "${DIST_PATH}ROOT.tar.gz" ]; then
error "部署包不存在: ${DIST_PATH}ROOT.tar.gz"
return 1
fi
for port in "${TOMCAT_PORTS[@]}"; do
local tomcat_path=$(get_tomcat_path "$port")
local webapps_path="${tomcat_path}/webapps"
# 停止当前Tomcat
info "停止Tomcat $port..."
sh "${tomcat_path}/bin/shutdown.sh" 2>/dev/null
sleep 2
# 清理旧应用
rm -f "${webapps_path}/ROOT.tar.gz"
rm -rf "${webapps_path}/ROOT"
# 部署新应用
if cp "${DIST_PATH}ROOT.tar.gz" "${webapps_path}/"; then
if tar -zxf "${webapps_path}/ROOT.tar.gz" -C "${webapps_path}/"; then
log "Tomcat $port 部署完成"
else
error "Tomcat $port 解压失败"
fi
else
error "Tomcat $port 复制部署包失败"
fi
done
# 备份部署包
if mv "${DIST_PATH}/ROOT.tar.gz" "${DIST_PATH}/ROOT.${today}.tar.gz"; then
log "部署包已备份: ${DIST_PATH}/ROOT.${today}.tar.gz"
else
error "部署包备份失败"
fi
}
# 完整流程
full_process() {
log "开始执行完整流程..."
cleanup_files
stop_tomcats
deploy_app
distribute_config
start_tomcats_with_logs
log "完整流程执行完毕!"
}
# 执行选择的操作
execute_choice() {
local choice=$1
case $choice in
1)
start_tomcats_with_logs
;;
2)
stop_tomcats
;;
3)
restart_tomcats
;;
4)
deploy_app
read -p "部署完成是否启动Tomcat服务(y/n, 默认y): " start_after_deploy
start_after_deploy=${start_after_deploy:-y}
if [[ $start_after_deploy =~ ^[Yy]$ ]]; then
start_tomcats_with_logs
fi
;;
5)
distribute_config
;;
6)
show_tomcat_status
;;
7)
view_logs_menu
;;
8)
cleanup_files
;;
9)
clean_tomcat_logs
;;
a|A)
full_process
;;
0)
log "再见!"
exit 0
;;
*)
error "无效选择,请重新输入!"
;;
esac
}
# 主函数
main() {
# 检查依赖
if ! check_dependencies; then
error "环境检查失败,请检查配置"
exit 1
fi
while true; do
show_menu
echo
read -p "请选择操作 (0-9/a): " choice
case $choice in
[0-9aA])
execute_choice "$choice"
;;
*)
error "无效输入,请输入数字 0-9 或 a"
;;
esac
echo
read -p "按回车键继续..." dummy
done
}
# 脚本入口
main "$@"

View File

@@ -10,8 +10,8 @@ auth.token = "token123456"
[[proxies]]
name = "web-tcp" # 代理名称(自定义,唯一即可)
type = "tcp" # 类型为 tcp
localIP = "127.0.0.1" # 本地服务 IP
localPort = 802 # 本地服务端口(您要暴露的服务)
localIP = "192.168.2.40" # 本地服务 IP
localPort = 80 # 本地服务端口(您要暴露的服务)
remotePort = 8081 # 服务器映射端口
# 2.http://frps.binghuai.xyz:8088/