前后端目录重命名: - reading-platform-java/ → lesingle-edu-reading-platform-backend/ - reading-platform-frontend/ → lesingle-edu-reading-platform-frontend/ 更新相关文件: - 所有 shell 脚本中的目录引用 - pom.xml 和 application.yml 中的项目名称 - package.json 中的项目名称 - .claude/CLAUDE.md 中的路径引用 - README 文档中的路径引用
409 lines
11 KiB
Bash
409 lines
11 KiB
Bash
#!/bin/bash
|
||
|
||
#===============================================================================
|
||
# 幼儿阅读教学服务平台 - 一键部署到宝塔面板
|
||
#
|
||
# 使用前请配置:
|
||
# 1. 远程服务器信息(IP、用户名、密码/密钥)
|
||
# 2. 宝塔面板信息(面板地址、API 密钥)
|
||
# 3. 数据库信息
|
||
#===============================================================================
|
||
|
||
set -e
|
||
|
||
#============================== 配置区域 ==============================
|
||
|
||
# 远程服务器配置
|
||
REMOTE_HOST="8.148.151.56" # 服务器 IP
|
||
REMOTE_USER="root" # SSH 用户名
|
||
REMOTE_PORT="22" # SSH 端口
|
||
# 推荐使用 SSH 密钥,如无密钥将使用密码认证
|
||
REMOTE_PASSWORD="" # SSH 密码(可选)
|
||
SSH_KEY_FILE="~/.ssh/id_rsa" # SSH 密钥文件
|
||
|
||
# 部署路径配置
|
||
REMOTE_BASE_DIR="/www/wwwroot/reading-platform" # 后端部署目录
|
||
REMOTE_FRONTEND_DIR="/www/wwwroot/reading.ycapp.cn" # 前端部署目录(宝塔站点目录)
|
||
|
||
# 宝塔面板配置
|
||
BAOTA_PANEL_URL="http://${REMOTE_HOST}:8888" # 宝塔面板地址
|
||
BAOTA_API_KEY="" # 宝塔 API 密钥(在宝塔面板 → 设置 → API 获取)
|
||
BAOTA_SECRET_KEY="" # 宝塔 API 密钥
|
||
|
||
# 数据库配置(宝塔中创建的数据库)
|
||
DB_HOST="localhost"
|
||
DB_PORT="3306"
|
||
DB_NAME="lesingle-edu-reading-platform"
|
||
DB_USER="reading_platform"
|
||
DB_PASSWORD="" # 数据库密码
|
||
|
||
# JWT 配置(生产环境必须修改)
|
||
JWT_SECRET="your-production-jwt-secret-change-this"
|
||
JWT_EXPIRATION="86400000"
|
||
|
||
# Redis 配置
|
||
REDIS_HOST="localhost"
|
||
REDIS_PORT="6379"
|
||
REDIS_PASSWORD=""
|
||
|
||
# OSS 配置(生产环境)
|
||
OSS_ACCESS_KEY_ID="LTAI5tKZhPofbThbSzDSiWoK"
|
||
OSS_ACCESS_KEY_SECRET="FtcsC7oQX3T0NaChaa9FYq2aoysQFM"
|
||
OSS_BUCKET_NAME="lesingle-kid-course"
|
||
OSS_ENDPOINT="oss-cn-shenzhen.aliyuncs.com"
|
||
|
||
#============================== 脚本主体 ==============================
|
||
|
||
# 颜色定义
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# 日志函数
|
||
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||
log_step() { echo -e "${BLUE}[STEP]${NC} $1"; }
|
||
|
||
# 检查配置
|
||
check_config() {
|
||
log_step "检查配置..."
|
||
|
||
if [ -z "$REMOTE_HOST" ]; then
|
||
log_error "请配置 REMOTE_HOST(服务器 IP)"
|
||
exit 1
|
||
fi
|
||
|
||
# 检查本地是否有 JAR 包
|
||
JAR_FILE="lesingle-edu-reading-platform-backend/target/reading-platform-1.0.0.jar"
|
||
if [ ! -f "$JAR_FILE" ]; then
|
||
log_warn "未找到 JAR 包,将先执行构建..."
|
||
BUILD_NEEDED=true
|
||
fi
|
||
|
||
# 检查前端是否有 dist
|
||
if [ ! -d "lesingle-edu-reading-platform-frontend/dist" ]; then
|
||
log_warn "未找到前端构建文件,将先执行构建..."
|
||
BUILD_FRONTEND_NEEDED=true
|
||
fi
|
||
}
|
||
|
||
# 构建后端
|
||
build_backend() {
|
||
if [ "$BUILD_NEEDED" != "true" ]; then
|
||
return
|
||
fi
|
||
|
||
log_step "构建后端服务..."
|
||
cd "lesingle-edu-reading-platform-backend"
|
||
|
||
# 检查 JDK 版本
|
||
if command -v java &> /dev/null; then
|
||
JAVA_VERSION=$(java -version 2>&1 | head -n 1 | cut -d'"' -f2 | cut -d'.' -f1)
|
||
if [ "$JAVA_VERSION" != "17" ]; then
|
||
log_warn "当前 Java 版本为 $JAVA_VERSION,建议 JDK 17"
|
||
fi
|
||
fi
|
||
|
||
# Maven 构建
|
||
if command -v mvn &> /dev/null; then
|
||
mvn clean package -DskipTests
|
||
else
|
||
log_error "未找到 Maven,请先安装"
|
||
exit 1
|
||
fi
|
||
|
||
cd ..
|
||
|
||
if [ -f "$JAR_FILE" ]; then
|
||
log_info "后端构建成功:$JAR_FILE"
|
||
else
|
||
log_error "后端构建失败"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# 构建前端
|
||
build_frontend() {
|
||
if [ "$BUILD_FRONTEND_NEEDED" != "true" ]; then
|
||
return
|
||
fi
|
||
|
||
log_step "构建前端..."
|
||
cd "reading-platform-frontend"
|
||
|
||
# 检查 Node.js
|
||
if ! command -v node &> /dev/null; then
|
||
log_error "未找到 Node.js,请先安装"
|
||
exit 1
|
||
fi
|
||
|
||
# 安装依赖(如果 node_modules 不存在)
|
||
if [ ! -d "node_modules" ]; then
|
||
log_info "安装前端依赖..."
|
||
npm install
|
||
fi
|
||
|
||
# 构建
|
||
npm run build
|
||
|
||
cd ..
|
||
|
||
if [ -d "lesingle-edu-reading-platform-frontend/dist" ]; then
|
||
log_info "前端构建成功"
|
||
else
|
||
log_error "前端构建失败"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# SSH 上传文件
|
||
upload_files() {
|
||
log_step "上传文件到远程服务器..."
|
||
|
||
# 创建 SSH 命令别名(根据是否有密码)
|
||
if [ -n "$REMOTE_PASSWORD" ]; then
|
||
SSH_PASS="sshpass -p '$REMOTE_PASSWORD'"
|
||
SCP_PASS="sshpass -p '$REMOTE_PASSWORD'"
|
||
else
|
||
SSH_PASS=""
|
||
SCP_PASS=""
|
||
fi
|
||
|
||
# 测试 SSH 连接
|
||
log_info "测试 SSH 连接..."
|
||
if ! ssh -o StrictHostKeyChecking=no -p "$REMOTE_PORT" "$REMOTE_USER@$REMOTE_HOST" "echo '连接成功'" 2>/dev/null; then
|
||
log_error "SSH 连接失败,请检查服务器配置"
|
||
exit 1
|
||
fi
|
||
log_info "SSH 连接成功"
|
||
|
||
# 创建远程目录
|
||
log_info "创建远程目录..."
|
||
ssh -o StrictHostKeyChecking=no -p "$REMOTE_PORT" "$REMOTE_USER@$REMOTE_HOST" << 'ENDSSH'
|
||
mkdir -p /www/wwwroot/reading-platform
|
||
mkdir -p /www/wwwroot/reading-platform/logs
|
||
ENDSSH
|
||
|
||
# 上传 JAR 包
|
||
log_info "上传后端 JAR 包..."
|
||
scp -o StrictHostKeyChecking=no -P "$REMOTE_PORT" \
|
||
"lesingle-edu-reading-platform-backend/target/reading-platform-1.0.0.jar" \
|
||
"$REMOTE_USER@$REMOTE_HOST:/www/wwwroot/reading-platform/app.jar"
|
||
|
||
# 上传启动脚本
|
||
log_info "上传启动脚本..."
|
||
cat > /tmp/deploy-start.sh << 'EOF'
|
||
#!/bin/bash
|
||
# 阅读平台后端启动脚本
|
||
|
||
APP_DIR="/www/wwwroot/reading-platform"
|
||
JAR_FILE="$APP_DIR/app.jar"
|
||
PID_FILE="$APP_DIR/app.pid"
|
||
LOG_FILE="$APP_DIR/logs/application.log"
|
||
|
||
# 环境变量
|
||
export SPRING_PROFILES_ACTIVE=prod
|
||
export SERVER_PORT=8480
|
||
export DB_HOST=${DB_HOST:-localhost}
|
||
export DB_PASSWORD=${DB_PASSWORD}
|
||
export JWT_SECRET=${JWT_SECRET}
|
||
|
||
# 检查是否已在运行
|
||
if [ -f "$PID_FILE" ]; then
|
||
OLD_PID=$(cat "$PID_FILE")
|
||
if kill -0 "$OLD_PID" 2>/dev/null; then
|
||
echo "停止旧进程 (PID: $OLD_PID)..."
|
||
kill "$OLD_PID"
|
||
sleep 3
|
||
fi
|
||
rm -f "$PID_FILE"
|
||
fi
|
||
|
||
# 启动应用
|
||
echo "启动阅读平台后端..."
|
||
nohup java -jar \
|
||
-Xms512m \
|
||
-Xmx1024m \
|
||
-XX:+UseG1GC \
|
||
-XX:MaxGCPauseMillis=200 \
|
||
-XX:+HeapDumpOnOutOfMemoryError \
|
||
-XX:HeapDumpPath="$APP_DIR/logs/heapdump.hprof" \
|
||
"$JAR_FILE" \
|
||
--spring.profiles.active=prod \
|
||
> "$LOG_FILE" 2>&1 &
|
||
|
||
NEW_PID=$!
|
||
echo $NEW_PID > "$PID_FILE"
|
||
echo "应用已启动 (PID: $NEW_PID)"
|
||
echo "日志文件:$LOG_FILE"
|
||
|
||
# 等待启动
|
||
echo "等待应用启动..."
|
||
for i in {1..60}; do
|
||
if curl -s http://localhost:8480/actuator/health > /dev/null 2>&1; then
|
||
echo "应用启动成功!"
|
||
exit 0
|
||
fi
|
||
sleep 2
|
||
done
|
||
|
||
echo "应用启动超时,请检查日志"
|
||
tail -100 "$LOG_FILE"
|
||
exit 1
|
||
EOF
|
||
|
||
scp -o StrictHostKeyChecking=no -P "$REMOTE_PORT" \
|
||
/tmp/deploy-start.sh \
|
||
"$REMOTE_USER@$REMOTE_HOST:/www/wwwroot/reading-platform/start.sh"
|
||
|
||
# 上传停止脚本
|
||
cat > /tmp/deploy-stop.sh << 'EOF'
|
||
#!/bin/bash
|
||
PID_FILE="/www/wwwroot/reading-platform/app.pid"
|
||
if [ -f "$PID_FILE" ]; then
|
||
PID=$(cat "$PID_FILE")
|
||
if kill -0 "$PID" 2>/dev/null; then
|
||
echo "停止应用 (PID: $PID)..."
|
||
kill "$PID"
|
||
sleep 3
|
||
fi
|
||
rm -f "$PID_FILE"
|
||
fi
|
||
# 确保进程已停止
|
||
pkill -f "reading-platform-1.0.0.jar" 2>/dev/null || true
|
||
echo "应用已停止"
|
||
EOF
|
||
|
||
scp -o StrictHostKeyChecking=no -P "$REMOTE_PORT" \
|
||
/tmp/deploy-stop.sh \
|
||
"$REMOTE_USER@$REMOTE_HOST:/www/wwwroot/reading-platform/stop.sh"
|
||
|
||
# 设置执行权限
|
||
ssh -o StrictHostKeyChecking=no -p "$REMOTE_PORT" "$REMOTE_USER@$REMOTE_HOST" \
|
||
"chmod +x /www/wwwroot/reading-platform/start.sh /www/wwwroot/reading-platform/stop.sh"
|
||
|
||
log_info "文件上传完成"
|
||
}
|
||
|
||
# 上传前端文件
|
||
upload_frontend() {
|
||
log_step "上传前端文件..."
|
||
|
||
# 确保前端目录存在
|
||
ssh -o StrictHostKeyChecking=no -p "$REMOTE_PORT" "$REMOTE_USER@$REMOTE_HOST" \
|
||
"mkdir -p $REMOTE_FRONTEND_DIR"
|
||
|
||
# 上传 dist 目录
|
||
log_info "上传前端构建文件..."
|
||
scp -o StrictHostKeyChecking=no -r -P "$REMOTE_PORT" \
|
||
"lesingle-edu-reading-platform-frontend/dist/" \
|
||
"$REMOTE_USER@$REMOTE_HOST:$REMOTE_FRONTEND_DIR/"
|
||
|
||
log_info "前端文件上传完成"
|
||
}
|
||
|
||
# 创建配置文件
|
||
create_config() {
|
||
log_step "创建生产环境配置..."
|
||
|
||
# 创建环境变量文件
|
||
cat > /tmp/remote-env << EOF
|
||
# 数据库配置
|
||
DB_HOST=$DB_HOST
|
||
DB_PASSWORD=$DB_PASSWORD
|
||
|
||
# JWT 配置
|
||
JWT_SECRET=$JWT_SECRET
|
||
JWT_EXPIRATION=$JWT_EXPIRATION
|
||
|
||
# Redis 配置
|
||
REDIS_HOST=$REDIS_HOST
|
||
REDIS_PORT=$REDIS_PORT
|
||
REDIS_PASSWORD=$REDIS_PASSWORD
|
||
|
||
# OSS 配置
|
||
OSS_ACCESS_KEY_ID=$OSS_ACCESS_KEY_ID
|
||
OSS_ACCESS_KEY_SECRET=$OSS_ACCESS_KEY_SECRET
|
||
OSS_BUCKET_NAME=$OSS_BUCKET_NAME
|
||
OSS_ENDPOINT=$OSS_ENDPOINT
|
||
EOF
|
||
|
||
scp -o StrictHostKeyChecking=no -P "$REMOTE_PORT" \
|
||
/tmp/remote-env \
|
||
"$REMOTE_USER@$REMOTE_HOST:/www/wwwroot/reading-platform/.env"
|
||
|
||
log_info "配置文件创建完成"
|
||
}
|
||
|
||
# 远程部署
|
||
remote_deploy() {
|
||
log_step "执行远程部署..."
|
||
|
||
ssh -o StrictHostKeyChecking=no -p "$REMOTE_PORT" "$REMOTE_USER@$REMOTE_HOST" << 'ENDSSH'
|
||
cd /www/wwwroot/reading-platform
|
||
|
||
# 停止旧服务
|
||
echo "停止旧服务..."
|
||
bash stop.sh
|
||
|
||
# 启动新服务
|
||
echo "启动新服务..."
|
||
bash start.sh
|
||
ENDSSH
|
||
|
||
log_info "远程部署完成"
|
||
}
|
||
|
||
# 显示部署信息
|
||
show_deploy_info() {
|
||
echo ""
|
||
echo "=============================================="
|
||
echo " 部署完成!"
|
||
echo "=============================================="
|
||
echo ""
|
||
echo "后端 API 地址:http://${REMOTE_HOST}:8480"
|
||
echo "前端访问地址:http://${REMOTE_HOST}"
|
||
echo "API 文档地址:http://${REMOTE_HOST}:8480/swagger-ui.html"
|
||
echo ""
|
||
echo "远程目录:"
|
||
echo " 后端:/www/wwwroot/reading-platform"
|
||
echo " 前端:$REMOTE_FRONTEND_DIR"
|
||
echo ""
|
||
echo "管理命令:"
|
||
echo " ssh $REMOTE_USER@$REMOTE_HOST"
|
||
echo " cd /www/wwwroot/reading-platform"
|
||
echo " ./start.sh # 启动"
|
||
echo " ./stop.sh # 停止"
|
||
echo " ./restart.sh # 重启"
|
||
echo ""
|
||
echo "日志查看:"
|
||
echo " tail -f /www/wwwroot/reading-platform/logs/application.log"
|
||
echo ""
|
||
echo "=============================================="
|
||
}
|
||
|
||
# 主函数
|
||
main() {
|
||
echo ""
|
||
echo "=============================================="
|
||
echo " 幼儿阅读教学服务平台"
|
||
echo " 一键部署到宝塔面板"
|
||
echo "=============================================="
|
||
echo ""
|
||
|
||
check_config
|
||
build_backend
|
||
build_frontend
|
||
upload_files
|
||
upload_frontend
|
||
create_config
|
||
remote_deploy
|
||
show_deploy_info
|
||
}
|
||
|
||
# 执行
|
||
main "$@"
|