kindergarten_java/deploy-to-baota.sh
En de264d3298 refactor(后端): 重构包名从 com.reading.platform 到 com.lesingle.edu
- 修改 pom.xml 中的 groupId
- 移动所有 Java 文件到新包路径 com/lesingle/edu
- 更新所有 Java 文件的 package 和 import 语句 (438 个文件)
- 更新配置文件中的日志包名引用 (application-*.yml, logback-spring.xml)
- 更新 @MapperScan 注解路径
- 更新 CLAUDE.md 文档中的目录结构说明

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 12:02:20 +08:00

409 lines
11 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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 "$@"