chore: 更新应用配置和数据库迁移脚本

- 更新 application-dev/test/prod.yml 环境配置
- 更新 V35 清理旧套餐表的迁移脚本
- 添加部署相关文档和脚本
- 移除 CLEAN_V10_FAILED.sql 临时文件
This commit is contained in:
En 2026-03-25 18:05:02 +08:00
parent abfbe35d3a
commit 9d76e178de
14 changed files with 1739 additions and 100 deletions

36
.env.prod.template Normal file
View File

@ -0,0 +1,36 @@
# 生产环境配置模板
# 复制此文件为 .env.prod 并填入实际值
#==============================
# 数据库配置
#==============================
DB_HOST=localhost
DB_PORT=3306
DB_USERNAME=reading_platform
DB_PASSWORD=你的数据库密码
#==============================
# Redis 配置
#==============================
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
#==============================
# JWT 配置(生产环境必须修改)
#==============================
JWT_SECRET=你的-production-jwt-secret-至少-32-字符
JWT_EXPIRATION=86400000
#==============================
# 阿里云 OSS 配置
#==============================
OSS_ENDPOINT=oss-cn-shenzhen.aliyuncs.com
OSS_ACCESS_KEY_ID=LTAI5tKZhPofbThbSzDSiWoK
OSS_ACCESS_KEY_SECRET=FtcsC7oQX3T0NaChaa9FYq2aoysQFM
OSS_BUCKET_NAME=lesingle-kid-course
#==============================
# 服务器配置
#==============================
SERVER_PORT=8480

310
DEPLOY_BAOTA.md Normal file
View File

@ -0,0 +1,310 @@
# 宝塔面板部署指南
## 快速开始
### 方式一:使用部署脚本(推荐)
```bash
# 1. 配置环境变量
export REMOTE_HOST=你的服务器 IP
export REMOTE_USER=root
# 2. 部署后端
./deploy-backend.sh
# 3. 部署前端
./deploy-frontend.sh
```
### 方式二:手动部署
---
## 第一步:在宝塔安装基础服务
1. 登录宝塔面板(`http://你的IP:8888`
2. 安装 LNMP 套件:
- Nginx 1.24+
- MySQL 8.0+
- PHP 纯静态(前端不需要 PHP
- Redis 7.x
3. 安装 JDK 17
- 软件商店 → 搜索 "Java"
- 安装 JDK 17 版本
---
## 第二步:创建数据库
1. 宝塔面板 → 数据库 → 添加
2. 填写信息:
- 数据库名:`lesingle-edu-reading-platform`
- 用户名:`reading_platform`
- 密码:设置一个强密码(保存好)
- 权限:全部
3. 记录数据库信息,后面要用
---
## 第三步:部署后端
### 3.1 上传 JAR 包
```bash
# 本地构建
cd /f/LesingleProject/lesingle-kindergarten-course/kindergarten_java/reading-platform-java
mvn clean package -DskipTests
# 上传到服务器
scp target/reading-platform-1.0.0.jar root@你的 IP:/www/wwwroot/reading-platform/app.jar
```
### 3.2 创建启动脚本
在服务器上创建 `/www/wwwroot/reading-platform/start.sh`
```bash
#!/bin/bash
export SPRING_PROFILES_ACTIVE=prod
export SERVER_PORT=8480
export DB_HOST=localhost
export DB_PASSWORD=你的数据库密码
export JWT_SECRET=你的 JWT 密钥
nohup java -jar -Xms512m -Xmx1024m /www/wwwroot/reading-platform/app.jar \
--spring.profiles.active=prod > /www/wwwroot/reading-platform/logs/app.log 2>&1 &
echo $! > /www/wwwroot/reading-platform/app.pid
```
```bash
chmod +x /www/wwwroot/reading-platform/start.sh
```
### 3.3 创建环境变量文件
`/www/wwwroot/reading-platform/.env`
```bash
# 数据库
DB_HOST=localhost
DB_PASSWORD=你的数据库密码
# JWT
JWT_SECRET=你的-production-jwt-secret-至少-32-字符
JWT_EXPIRATION=86400000
# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
# OSS
OSS_ACCESS_KEY_ID=LTAI5tKZhPofbThbSzDSiWoK
OSS_ACCESS_KEY_SECRET=FtcsC7oQX3T0NaChaa9FYq2aoysQFM
OSS_BUCKET_NAME=lesingle-kid-course
```
### 3.4 启动后端
```bash
cd /www/wwwroot/reading-platform
./start.sh
# 查看日志
tail -f logs/app.log
```
---
## 第四步:部署前端
### 4.1 本地构建
```bash
cd /f/LesingleProject/lesingle-kindergarten-course/kindergarten_java/reading-platform-frontend
npm run build
```
### 4.2 上传到服务器
```bash
# 上传到宝塔站点目录
scp -r dist/* root@你的 IP:/www/wwwroot/你的域名/
```
---
## 第五步:配置 Nginx 反向代理
1. 宝塔面板 → 网站 → 添加站点
2. 填写域名,根目录设为 `/www/wwwroot/你的域名`
3. 确定后,点击网站 → 设置 → 配置文件
4. 添加以下配置:
```nginx
# 前端页面
location / {
try_files $uri $uri/ /index.html;
}
# 后端 API 反向代理
location /api {
proxy_pass http://localhost:8480;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# 文件上传代理
location /uploads {
proxy_pass http://localhost:8480;
}
```
5. 保存配置
---
## 第六步:配置防火墙
1. 宝塔面板 → 安全 → 放行端口
2. 放行以下端口:
- 80HTTP
- 443HTTPS如果用 SSL
- 8480后端 API可选如果通过 Nginx 代理就不需要)
---
## 第七步:验证部署
```bash
# 检查后端健康状态
curl http://localhost:8480/actuator/health
# 访问前端
curl http://localhost
# 测试 API
curl http://localhost:8480/api/v1
```
---
## 第八步:申请 SSL 证书(可选)
1. 宝塔面板 → 网站 → 点击对应网站 → SSL
2. 选择 "Let's Encrypt" 免费证书
3. 填写邮箱,点击申请
4. 申请成功后,开启"强制 HTTPS"
---
## 管理命令
### 后端管理
```bash
# 启动
cd /www/wwwroot/reading-platform && ./start.sh
# 停止
cd /www/wwwroot/reading-platform && ./stop.sh
# 重启
cd /www/wwwroot/reading-platform && ./stop.sh && ./start.sh
# 查看日志
tail -f /www/wwwroot/reading-platform/logs/app.log
# 查看进程
ps aux | grep reading-platform
```
### 前端更新
```bash
# 本地重新构建并上传
cd reading-platform-frontend
npm run build
scp -r dist/* root@你的 IP:/www/wwwroot/你的域名/
```
---
## 常见问题
### 1. 后端启动失败
检查日志:
```bash
tail -100 /www/wwwroot/reading-platform/logs/app.log
```
常见原因:
- JDK 版本不对(必须是 17
- 数据库连接失败
- 端口被占用
### 2. 前端页面空白
- 检查 Nginx 配置是否正确
- 打开浏览器 Console 查看错误
- 检查 API 请求是否 404
### 3. API 请求失败
- 检查 Nginx 反向代理配置
- 确认后端服务是否运行
- 检查防火墙端口
### 4. 文件上传失败
- 检查 OSS 配置
- 检查 Nginx 上传大小限制
- 查看后端日志
---
## 性能优化
### JVM 优化参数
```bash
java -jar \
-Xms1g \
-Xmx2g \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:+HeapDumpOnOutOfMemoryError \
app.jar
```
### Nginx 优化
```nginx
# 开启 gzip 压缩
gzip on;
gzip_types text/plain text/css application/json application/javascript;
# 上传大小限制
client_max_body_size 100M;
```
---
## 备份与恢复
### 数据库备份
```bash
# 宝塔面板 → 数据库 → 备份
# 或命令行
mysqldump -u reading_platform -p lesingle-edu-reading-platform > backup.sql
```
### 文件备份
```bash
tar -czf backup-$(date +%Y%m%d).tar.gz /www/wwwroot/reading-platform
```

170
README-BAOTA-DEPLOY.md Normal file
View File

@ -0,0 +1,170 @@
# 宝塔部署快速配置指南
## 第一次部署前,请在宝塔面板完成以下操作:
### 1. 安装基础服务
登录宝塔面板 → 软件商店 → 安装以下软件:
| 软件 | 版本 | 说明 |
|------|------|------|
| Nginx | 1.24+ | Web 服务器 |
| MySQL | 8.0+ | 数据库 |
| Redis | 7.x | 缓存 |
| Java | JDK 17 | 运行环境 |
### 2. 创建数据库
宝塔面板 → 数据库 → 添加:
```
数据库名lesingle-edu-reading-platform
用户名reading_platform
密码:[设置一个强密码,记下来]
权限:全部
```
### 3. 配置环境变量
复制配置文件模板:
```bash
cp .env.prod.template .env.prod
```
编辑 `.env.prod`,填入实际值:
```bash
# 数据库密码(从宝塔获取)
DB_PASSWORD=你的数据库密码
# JWT 密钥(必须修改)
JWT_SECRET=你的-production-jwt-secret-至少-32-字符
# Redis 密码(如果宝塔设置了)
REDIS_PASSWORD=
```
### 4. 修改部署脚本配置
编辑 `deploy-backend.sh`,找到环境变量部分,填入你的配置:
```bash
# 在启动脚本中添加环境变量
export DB_PASSWORD=你的数据库密码
export JWT_SECRET=你的 JWT 密钥
```
或者在服务器上创建 `/www/wwwroot/reading-platform/.env` 文件。
---
## 一键部署
```bash
# 方式 1使用主部署脚本
./deploy.sh root@你的服务器 IP
# 方式 2分别部署
export REMOTE_HOST=你的服务器 IP
./deploy-backend.sh # 部署后端
./deploy-frontend.sh # 部署前端
```
---
## 部署后配置
### 1. 配置 Nginx 反向代理
宝塔面板 → 网站 → 你的网站 → 设置 → 配置文件:
粘贴 `nginx-baota.conf` 中的配置。
### 2. 验证部署
```bash
# SSH 登录服务器
ssh root@你的服务器 IP
# 检查后端健康状态
curl http://localhost:8480/actuator/health
# 查看后端日志
tail -f /www/wwwroot/reading-platform/logs/app.log
```
### 3. 访问应用
- 前端http://你的服务器 IP
- API 文档http://你的服务器 IP:8480/swagger-ui.html
---
## 常用命令
### 后端管理
```bash
# 登录服务器
ssh root@你的服务器 IP
# 进入目录
cd /www/wwwroot/reading-platform
# 启动
./start.sh
# 停止
./stop.sh
# 查看日志
tail -f logs/app.log
# 查看进程
ps aux | grep app.jar
```
### 前端更新
```bash
# 本地重新构建并部署
./deploy-frontend.sh root@你的服务器 IP
```
---
## 问题排查
### 后端启动失败
```bash
# 查看详细日志
tail -100 /www/wwwroot/reading-platform/logs/app.log
# 检查 Java 版本
java -version
# 检查端口占用
netstat -tlnp | grep 8480
```
### 前端页面空白
1. 打开浏览器 ConsoleF12
2. 查看 Network 标签,检查 API 请求
3. 确认 Nginx 反向代理配置正确
### 数据库连接失败
1. 确认数据库已创建
2. 确认数据库密码正确
3. 确认 MySQL 服务运行中
---
## 需要帮助?
- 详细部署文档:`DEPLOY_BAOTA.md`
- Nginx 配置:`nginx-baota.conf`
- 环境变量模板:`.env.prod.template`

191
deploy-backend.sh Normal file
View File

@ -0,0 +1,191 @@
#!/bin/bash
#===============================================================================
# 后端生产环境部署脚本
#
# 使用方法:
# ./deploy-backend.sh user@host
# 或
# export REMOTE_USER=root
# export REMOTE_HOST=8.148.151.56
# ./deploy-backend.sh
#===============================================================================
set -e
# 配置
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BACKEND_DIR="$SCRIPT_DIR/reading-platform-java"
REMOTE_BASE_DIR="/www/wwwroot/reading-platform"
# SSH 配置
REMOTE_USER="${REMOTE_USER:-root}"
REMOTE_HOST="${REMOTE_HOST:-}"
REMOTE_PORT="${REMOTE_PORT:-22}"
# 颜色
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
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"; }
# 检查参数
if [ -n "$1" ]; then
if [[ "$1" == *"@"* ]]; then
REMOTE_USER=$(echo "$1" | cut -d'@' -f1)
REMOTE_HOST=$(echo "$1" | cut -d'@' -f2)
fi
fi
if [ -z "$REMOTE_HOST" ]; then
log_error "请提供远程主机:$0 user@host 或设置 REMOTE_HOST 环境变量"
exit 1
fi
echo ""
echo "=============================================="
echo " 后端部署到宝塔"
echo "=============================================="
echo ""
echo " 远程主机:$REMOTE_USER@$REMOTE_HOST"
echo " 部署目录:$REMOTE_BASE_DIR"
echo ""
# 步骤 1: 构建 JAR
log_step "构建后端..."
cd "$BACKEND_DIR"
if ! command -v mvn &> /dev/null; then
log_error "未找到 Maven"
exit 1
fi
# 检查 Java 版本
java_ver=$(java -version 2>&1 | head -n 1 | cut -d'"' -f2 | cut -d'.' -f1)
if [ "$java_ver" != "17" ]; then
log_warn "当前 Java 版本:$java_ver,建议使用 JDK 17"
fi
mvn clean package -DskipTests
JAR_FILE="$BACKEND_DIR/target/reading-platform-1.0.0.jar"
if [ ! -f "$JAR_FILE" ]; then
log_error "构建失败,未找到 JAR 包"
exit 1
fi
log_info "构建成功:$JAR_FILE"
# 步骤 2: 上传到服务器
log_step "上传到远程服务器..."
# 创建目录
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
scp -o StrictHostKeyChecking=no -P "$REMOTE_PORT" \
"$JAR_FILE" \
"$REMOTE_USER@$REMOTE_HOST:$REMOTE_BASE_DIR/app.jar"
# 步骤 3: 创建启动脚本
log_step "创建启动脚本..."
cat > /tmp/baota-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
# 停止旧进程
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
pkill -f "app.jar" 2>/dev/null || true
# 启动
echo "启动应用..."
nohup java -jar \
-Xms512m \
-Xmx1024m \
-XX:+UseG1GC \
"$JAR_FILE" \
--spring.profiles.active=prod \
> "$LOG_FILE" 2>&1 &
NEW_PID=$!
echo $NEW_PID > "$PID_FILE"
echo "已启动 (PID: $NEW_PID)"
# 等待启动
for i in {1..30}; do
if curl -s http://localhost:8480/actuator/health 2>/dev/null; then
echo "启动成功!"
exit 0
fi
sleep 2
done
echo "启动超时检查日志tail -100 $LOG_FILE"
exit 1
EOF
scp -o StrictHostKeyChecking=no -P "$REMOTE_PORT" \
/tmp/baota-start.sh \
"$REMOTE_USER@$REMOTE_HOST:$REMOTE_BASE_DIR/start.sh"
# 步骤 4: 创建停止脚本
cat > /tmp/baota-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
kill "$PID"
echo "已停止 (PID: $PID)"
fi
rm -f "$PID_FILE"
fi
pkill -f "app.jar" 2>/dev/null || true
echo "已停止"
EOF
scp -o StrictHostKeyChecking=no -P "$REMOTE_PORT" \
/tmp/baota-stop.sh \
"$REMOTE_USER@$REMOTE_HOST:$REMOTE_BASE_DIR/stop.sh"
# 设置权限
ssh -o StrictHostKeyChecking=no -p "$REMOTE_PORT" "$REMOTE_USER@$REMOTE_HOST" \
"chmod +x $REMOTE_BASE_DIR/start.sh $REMOTE_BASE_DIR/stop.sh"
log_info "部署完成"
echo ""
echo "=============================================="
echo " 后端部署完成!"
echo "=============================================="
echo ""
echo " 远程登录ssh $REMOTE_USER@$REMOTE_HOST"
echo " 启动服务cd $REMOTE_BASE_DIR && ./start.sh"
echo " 停止服务cd $REMOTE_BASE_DIR && ./stop.sh"
echo " 查看日志tail -f $REMOTE_BASE_DIR/logs/application.log"
echo ""
echo " 健康检查curl http://localhost:8480/actuator/health"
echo ""

120
deploy-frontend.sh Normal file
View File

@ -0,0 +1,120 @@
#!/bin/bash
#===============================================================================
# 前端生产环境构建并部署脚本
#
# 使用方法:
# ./deploy-frontend.sh user@host
# 或
# export REMOTE_USER=root
# export REMOTE_HOST=8.148.151.56
# ./deploy-frontend.sh
#===============================================================================
set -e
# 配置
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
FRONTEND_DIR="$SCRIPT_DIR/reading-platform-frontend"
REMOTE_DIR="/www/wwwroot/reading.ycapp.cn"
# SSH 配置(可通过环境变量覆盖)
REMOTE_USER="${REMOTE_USER:-root}"
REMOTE_HOST="${REMOTE_HOST:-}"
REMOTE_PORT="${REMOTE_PORT:-22}"
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
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"; }
# 检查参数
if [ -n "$1" ]; then
if [[ "$1" == *"@"* ]]; then
REMOTE_USER=$(echo "$1" | cut -d'@' -f1)
REMOTE_HOST=$(echo "$1" | cut -d'@' -f2)
fi
fi
if [ -z "$REMOTE_HOST" ]; then
log_error "请提供远程主机:$0 user@host 或设置 REMOTE_HOST 环境变量"
exit 1
fi
echo ""
echo "=============================================="
echo " 前端部署到宝塔"
echo "=============================================="
echo ""
echo " 远程主机:$REMOTE_USER@$REMOTE_HOST"
echo " 部署目录:$REMOTE_DIR"
echo ""
cd "$FRONTEND_DIR"
# 步骤 1: 检查 Node.js
log_step "检查环境..."
if ! command -v node &> /dev/null; then
log_error "未找到 Node.js"
exit 1
fi
node_version=$(node -v)
npm_version=$(npm -v)
log_info "Node.js: $node_version, npm: $npm_version"
# 步骤 2: 安装依赖
log_step "安装依赖..."
if [ ! -d "node_modules" ]; then
npm install
else
log_info "node_modules 已存在,跳过依赖安装"
fi
# 步骤 3: 构建
log_step "构建前端..."
npm run build
if [ ! -d "dist" ]; then
log_error "构建失败,未找到 dist 目录"
exit 1
fi
log_info "构建成功"
# 步骤 4: 上传到服务器
log_step "上传到远程服务器..."
# 创建远程目录
ssh -o StrictHostKeyChecking=no -p "$REMOTE_PORT" "$REMOTE_USER@$REMOTE_HOST" \
"mkdir -p $REMOTE_DIR"
# 上传文件
scp -o StrictHostKeyChecking=no -r -P "$REMOTE_PORT" \
dist/ \
"$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/"
log_info "上传完成"
# 步骤 5: 设置权限
log_step "设置文件权限..."
ssh -o StrictHostKeyChecking=no -p "$REMOTE_PORT" "$REMOTE_USER@$REMOTE_HOST" << 'ENDSSH'
chown -R www:www /www/wwwroot/reading.ycapp.cn
chmod -R 755 /www/wwwroot/reading.ycapp.cn
ENDSSH
echo ""
echo "=============================================="
echo " 前端部署完成!"
echo "=============================================="
echo ""
echo " 访问地址http://${REMOTE_HOST}"
echo ""
echo " 下一步:在宝塔面板配置 Nginx 反向代理"
echo " /api -> http://localhost:8480"
echo ""

408
deploy-to-baota.sh Normal file
View File

@ -0,0 +1,408 @@
#!/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="reading-platform-java/target/reading-platform-1.0.0.jar"
if [ ! -f "$JAR_FILE" ]; then
log_warn "未找到 JAR 包,将先执行构建..."
BUILD_NEEDED=true
fi
# 检查前端是否有 dist
if [ ! -d "reading-platform-frontend/dist" ]; then
log_warn "未找到前端构建文件,将先执行构建..."
BUILD_FRONTEND_NEEDED=true
fi
}
# 构建后端
build_backend() {
if [ "$BUILD_NEEDED" != "true" ]; then
return
fi
log_step "构建后端服务..."
cd "reading-platform-java"
# 检查 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 "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" \
"reading-platform-java/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" \
"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 "$@"

161
deploy.sh Normal file
View File

@ -0,0 +1,161 @@
#!/bin/bash
#===============================================================================
# 幼儿阅读教学服务平台 - 一键部署到宝塔面板
#
# 使用方法:
# ./deploy.sh your-server-ip
# 或
# ./deploy.sh root@your-server-ip
#===============================================================================
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# 颜色
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
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"; }
# 检查参数
if [ -z "$1" ]; then
echo ""
echo "=============================================="
echo " 幼儿阅读教学服务平台"
echo " 一键部署到宝塔面板"
echo "=============================================="
echo ""
echo "使用方法:"
echo " $0 your-server-ip"
echo " $0 root@your-server-ip"
echo ""
echo "示例:"
echo " $0 8.148.151.56"
echo " $0 root@8.148.151.56"
echo ""
exit 1
fi
# 解析参数
REMOTE_HOST="$1"
REMOTE_USER="root"
if [[ "$1" == *"@"* ]]; then
REMOTE_USER=$(echo "$1" | cut -d'@' -f1)
REMOTE_HOST=$(echo "$1" | cut -d'@' -f2)
fi
echo ""
echo "=============================================="
echo " 一键部署到宝塔面板"
echo "=============================================="
echo ""
echo " 服务器:$REMOTE_USER@$REMOTE_HOST"
echo ""
# 检查 SSH 连接
log_step "检查 SSH 连接..."
if ! ssh -o StrictHostKeyChecking=no "$REMOTE_USER@$REMOTE_HOST" "echo '连接成功'" 2>/dev/null; then
log_error "SSH 连接失败,请检查:"
echo " 1. 服务器 IP 是否正确"
echo " 2. SSH 是否启用(默认端口 22"
echo " 3. 密码/密钥是否正确"
echo ""
echo " 如果是密码登录,请先执行:"
echo " ssh-copy-id $REMOTE_USER@$REMOTE_HOST"
exit 1
fi
log_info "SSH 连接成功"
# 检查远程服务器
log_step "检查远程服务器..."
ssh "$REMOTE_USER@$REMOTE_HOST" << 'ENDSSH'
# 检查是否安装了宝塔
if [ -d "/www/server/panel" ]; then
echo "宝塔面板:已安装"
else
echo "警告:未检测到宝塔面板"
fi
# 检查 JDK
if command -v java &> /dev/null; then
java_version=$(java -version 2>&1 | head -n 1)
echo "Java: $java_version"
else
echo "警告:未安装 Java"
fi
# 检查 MySQL
if command -v mysql &> /dev/null; then
echo "MySQL: 已安装"
else
echo "警告:未安装 MySQL"
fi
# 检查 Nginx
if command -v nginx &> /dev/null; then
echo "Nginx: 已安装"
fi
# 检查磁盘空间
disk_used=$(df -h / | tail -1 | awk '{print $5}')
echo "磁盘使用:$disk_used"
ENDSSH
echo ""
echo "=============================================="
echo " 部署前检查完成"
echo "=============================================="
echo ""
echo " 请确认:"
echo " 1. 宝塔面板已安装并可以访问"
echo " 2. 已在宝塔中安装 MySQL、Redis、Nginx"
echo " 3. 已创建数据库和用户(见 DEPLOY_BAOTA.md"
echo " 4. JDK 17 已安装(或通过宝塔安装)"
echo ""
read -p "是否继续部署?(y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
# 部署后端
log_step "部署后端..."
export REMOTE_USER
export REMOTE_HOST
bash "$SCRIPT_DIR/deploy-backend.sh"
# 部署前端
log_step "部署前端..."
bash "$SCRIPT_DIR/deploy-frontend.sh"
echo ""
echo "=============================================="
echo " 部署完成!"
echo "=============================================="
echo ""
echo " 下一步操作:"
echo ""
echo " 1. 在宝塔面板配置 Nginx 反向代理"
echo " 网站 → 设置 → 配置文件"
echo " 参考 nginx-baota.conf 中的配置"
echo ""
echo " 2. 验证后端服务"
echo " ssh $REMOTE_USER@$REMOTE_HOST"
echo " curl http://localhost:8480/actuator/health"
echo ""
echo " 3. 访问前端页面"
echo " http://$REMOTE_HOST"
echo ""
echo " 4. 查看日志"
echo " 后端tail -f /www/wwwroot/reading-platform/logs/app.log"
echo " Nginx: tail -f /www/wwwlogs/你的域名.error.log"
echo ""
echo "=============================================="

123
nginx-baota.conf Normal file
View File

@ -0,0 +1,123 @@
# Nginx 配置 - 幼儿阅读教学服务平台
# 在宝塔面板中配置此反向代理
#==============================
# 在宝塔面板的操作步骤:
# 1. 网站 → 添加站点 → 创建站点
# 2. 域名:输入你的域名(如 reading.ycapp.cn
# 3. 根目录:/www/wwwroot/reading.ycapp.cn
# 4. 数据库PHP 纯静态(前端已构建好)
# 5. 确定后,点击网站 → 设置 → 配置文件
# 6. 将以下配置粘贴到配置文件中
#==============================
server {
listen 80;
server_name reading.ycapp.cn; # 修改为你的域名
# 前端静态文件根目录
root /www/wwwroot/reading.ycapp.cn;
index index.html;
# 前端页面路由Vue Router history 模式支持)
location / {
try_files $uri $uri/ /index.html;
}
# 后端 API 反向代理
location /api {
proxy_pass http://localhost:8480;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 跨域支持(如果需要)
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
add_header Access-Control-Allow-Headers 'Content-Type, Authorization';
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
add_header Access-Control-Allow-Headers 'Content-Type, Authorization';
add_header Content-Type 'text/plain; charset=utf-8';
add_header Content-Length 0;
return 204;
}
}
# 文件上传代理
location /uploads {
proxy_pass http://localhost:8480;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|svg|ico|css|js|woff|woff2|ttf|eot)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# 禁止访问隐藏文件
location ~ /\. {
deny all;
}
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}
#==============================
# HTTPS 配置(启用 SSL 后使用此配置)
#==============================
# 在宝塔面板 → 网站 → SSL → Let's Encrypt 免费申请证书
# 申请成功后会自动生成以下配置
# server {
# listen 443 ssl http2;
# server_name reading.ycapp.cn;
# ssl_certificate /www/server/panel/vhost/certs/reading.ycapp.cn/fullchain.pem;
# ssl_certificate_key /www/server/panel/vhost/certs/reading.ycapp.cn/privkey.pem;
#
# # SSL 优化
# ssl_protocols TLSv1.2 TLSv1.3;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# ssl_session_cache shared:SSL:10m;
# ssl_session_timeout 10m;
#
# root /www/wwwroot/reading.ycapp.cn;
# index index.html;
#
# location / {
# try_files $uri $uri/ /index.html;
# }
#
# location /api {
# proxy_pass http://localhost:8480;
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto $scheme;
# }
#
# location /uploads {
# proxy_pass http://localhost:8480;
# }
# }
#
# # HTTP 自动跳转 HTTPS
# server {
# listen 80;
# server_name reading.ycapp.cn;
# return 301 https://$server_name$request_uri;
# }

View File

@ -11,6 +11,29 @@ spring:
username: ${DB_USERNAME:reading_platform}
password: ${DB_PASSWORD:reading_platform_pwd}
type: com.alibaba.druid.pool.DruidDataSource
druid:
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 60000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: SELECT 1
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
stat-view-servlet:
enabled: true
url-pattern: /druid/*
reset-enable: false
login-username: admin
login-password: admin
web-stat-filter:
enabled: true
url-pattern: /*
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
data:
redis:
# host: ${REDIS_HOST:8.148.151.56}
@ -36,32 +59,7 @@ spring:
clean-on-validation-error: true
out-of-order: true
# Druid 连接池配置(开发环境)
druid:
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 60000ms
time-between-eviction-runs-millis: 60000ms
min-evictable-idle-time-millis: 300000ms
validation-query: SELECT 1
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
stat-view-servlet:
enabled: true
url-pattern: /druid/*
reset-enable: false
login-username: admin
login-password: admin
web-stat-filter:
enabled: true
url-pattern: /*
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
# MyBatis-Plus 配置(开发环境 - 开启 SQL 日志)
# MyBatis-Plus 配置
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

View File

@ -6,39 +6,17 @@ spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/reading_platform?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=true&allowPublicKeyRetrieval=true
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
url: jdbc:mysql://${DB_HOST:47.106.92.245}:${DB_PORT:3306}/lesingle-edu-reading-platform?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=true&allowPublicKeyRetrieval=true
username: ${DB_USERNAME:reading_platform}
password: ${DB_PASSWORD:WawfXxrMRENydksk}
type: com.alibaba.druid.pool.DruidDataSource
data:
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASSWORD}
database: 0
timeout: 10000ms
lettuce:
pool:
max-active: 16
max-wait: -1ms
max-idle: 8
min-idle: 2
flyway:
enabled: true
locations: classpath:db/migration
clean-disabled: true
validate-on-migrate: true
# Druid 连接池配置(生产环境)
druid:
druid:
initial-size: 10
min-idle: 10
max-active: 50
max-wait: 30000ms
time-between-eviction-runs-millis: 60000ms
min-evictable-idle-time-millis: 300000ms
max-wait: 30000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: SELECT 1
test-while-idle: true
test-on-borrow: false
@ -56,7 +34,28 @@ druid:
url-pattern: /*
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
# MyBatis-Plus 配置(生产环境 - 关闭 SQL 日志)
data:
redis:
host: ${REDIS_HOST:127.0.0.1}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASSWORD:laomo_redis123}
database: 7
timeout: 10000ms
lettuce:
pool:
max-active: 16
max-wait: -1ms
max-idle: 8
min-idle: 2
flyway:
enabled: true
locations: classpath:db/migration
clean-disabled: true
validate-on-migrate: true
skip-patterns: V7_,V8_,V10_,V43_
# MyBatis-Plus 配置
mybatis-plus:
configuration:
map-underscore-to-camel-case: true

View File

@ -10,6 +10,29 @@ spring:
username: ${DB_USERNAME:reading_platform}
password: ${DB_PASSWORD:reading_platform_pwd}
type: com.alibaba.druid.pool.DruidDataSource
druid:
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 60000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: SELECT 1
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
stat-view-servlet:
enabled: true
url-pattern: /druid/*
reset-enable: false
login-username: admin
login-password: admin
web-stat-filter:
enabled: true
url-pattern: /*
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
data:
redis:
@ -31,32 +54,7 @@ spring:
clean-disabled: true
validate-on-migrate: true
# Druid 连接池配置(测试环境)
druid:
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 60000ms
time-between-eviction-runs-millis: 60000ms
min-evictable-idle-time-millis: 300000ms
validation-query: SELECT 1
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
stat-view-servlet:
enabled: true
url-pattern: /druid/*
reset-enable: false
login-username: admin
login-password: admin
web-stat-filter:
enabled: true
url-pattern: /*
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
# MyBatis-Plus 配置(测试环境)
# MyBatis-Plus 配置
mybatis-plus:
configuration:
map-underscore-to-camel-case: true

View File

@ -1,12 +0,0 @@
-- =====================================================
-- 清理 V10 失败的 Flyway 迁移记录
-- 使用方法:在 MySQL 客户端中执行此脚本
-- =====================================================
-- 删除 V10 失败记录
DELETE FROM flyway_schema_history WHERE version = '10';
-- 验证清理结果
SELECT * FROM flyway_schema_history ORDER BY installed_rank DESC LIMIT 5;
-- 确认后重启应用Flyway 将重新执行 V10 迁移

View File

@ -0,0 +1,141 @@
# Flyway 迁移脚本部署说明
## 正式环境部署指南
### 1. Flyway 配置确认
生产环境配置 `application-prod.yml` 已正确设置:
```yaml
spring:
flyway:
enabled: true # ✅ 必须设置为 true
locations: classpath:db/migration
clean-disabled: true # ✅ 禁止清理数据库
validate-on-migrate: true # ✅ 迁移前验证
skip-patterns: V7_,V8_,V10_,V43_ # ✅ 跳过测试数据脚本
```
### 2. 测试数据脚本处理
生产环境通过 `skip-patterns` 配置跳过以下测试数据脚本:
| 脚本文件 | 内容 | 状态 |
|---------|------|------|
| `V7__add_test_data.sql` | 测试课程、套餐、教师、家长、学生数据 | ⚠️ 生产环境跳过 |
| `V8__add_tenant_package_test_data.sql` | 测试租户套餐数据 | ⚠️ 生产环境跳过 |
| `V10__add_relation_test_data.sql` | 测试关联数据(课程资源、活动、任务等) | ⚠️ 生产环境跳过 |
| `V43__add_student_class_history_data.sql` | 测试学生班级关联数据 | ⚠️ 生产环境跳过 |
**注意**
- 开发和测试环境**不受影响**,会继续执行所有脚本
- 生产环境通过 `skip-patterns` 配置自动跳过带 `V7_`、`V8_`、`V10_`、`V43_` 前缀的脚本
### 3. 正式环境迁移执行顺序
Flyway 将按以下顺序执行迁移脚本(生产环境跳过 V7, V8, V10, V43
```
V1 → V2 → V3 → V4 → V5 → V6 → V9 → V11 → V12 → V13 → V14 → V15 → V16
→ V26 → V27 → V28 → V29 → V31 → V32 → V33 → V34 → V35 → V36 → V37
→ V38 → V39 → V40 → V41 → V42 → V44 → V45 → V46 → V47 → V48 → V49 → V50
```
**跳过的脚本**V7, V8, V10, V43测试数据
### 4. 部署步骤
#### 步骤 1准备数据库
```sql
-- 创建数据库(如未创建)
CREATE DATABASE IF NOT EXISTS `lesingle-edu-reading-platform`
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
-- 创建数据库用户(推荐使用专用用户)
CREATE USER 'reading_platform'@'%' IDENTIFIED BY '强密码';
GRANT ALL PRIVILEGES ON `lesingle-edu-reading-platform`.* TO 'reading_platform'@'%';
FLUSH PRIVILEGES;
```
#### 步骤 2配置环境变量
```bash
# 数据库配置
export DB_HOST=你的数据库主机
export DB_PORT=3306
export DB_USERNAME=reading_platform
export DB_PASSWORD=强密码
# Redis 配置
export REDIS_HOST=你的 Redis 主机
export REDIS_PORT=6379
# JWT 密钥(必须设置)
export JWT_SECRET=你的 JWT 密钥(建议 32 位以上随机字符串)
# OSS 配置(可选,使用默认值或设置)
export OSS_ENDPOINT=oss-cn-shenzhen.aliyuncs.com
export OSS_ACCESS_KEY_ID=你的 AccessKey
export OSS_ACCESS_KEY_SECRET=你的 AccessKey 密钥
export OSS_BUCKET_NAME=lesingle-kid-course
```
#### 步骤 3启动应用
```bash
# 使用生产环境配置启动
java -jar reading-platform.jar --spring.profiles.active=prod
```
#### 步骤 4验证迁移
启动后检查日志,确认 Flyway 迁移成功:
```
Flyway migration completed successfully
Applied X migrations to database
```
检查数据库中的迁移历史表:
```sql
USE `lesingle-edu-reading-platform`;
SELECT * FROM flyway_schema_history ORDER BY installed_rank;
```
### 5. 初始化超管账号
迁移完成后,数据库中没有超管账号,需要通过超管端创建第一个超管账号。
### 6. 注意事项
1. **测试数据脚本跳过** - 生产环境通过 `skip-patterns` 配置跳过 V7, V8, V10, V43
2. **开发和测试环境不受影响** - 其他环境继续执行所有脚本(包括测试数据)
3. **JWT 密钥必须设置** - 生产环境必须通过环境变量设置 JWT_SECRET
4. **数据库权限最小化** - 建议使用专用数据库用户,仅授予必要权限
5. **备份数据库** - 部署前建议备份数据库
6. **Flyway 历史记录** - `flyway_schema_history` 表记录了所有迁移历史,不要手动修改
### 7. 迁移脚本清单
| 版本号 | 脚本文件 | 描述 |
| --- | --- | --- |
| V1 | `V1__init_schema.sql` | 初始化基础表结构 |
| V2 | `V2__add_course_tables.sql` | 添加课程相关表 |
| V3 | `V3__add_business_tables.sql` | 添加业务表 |
| V4 | `V4__add_resource_tables.sql` | 添加资源表 |
| V5 | `V5__fix_password.sql` | 修复密码字段 |
| V6 | `V6__fix_status.sql` | 修复状态字段 |
| V9 | `V9__fix_resource_and_tenant_tables.sql` | 修复资源和租户表 |
| V11-V16 | `V11-V16__*.sql` | 自增 ID、字段修复 |
| V26-V29 | `V26-V29__*.sql` | 添加集体课型、排课引用数据等 |
| V31-V35 | `V31-V35__*.sql` | 删除废弃字段、套餐结构重构 |
| V36-V42 | `V36-V42__*.sql` | 重命名表、清理旧表、优化关联表 |
| V44-V50 | `V44-V50__*.sql` | 添加阅读任务功能、主题色、操作日志扩展 |
---
**最后更新**: 2026-03-25
**适用版本**: 生产环境部署

View File

@ -15,10 +15,6 @@ SET FOREIGN_KEY_CHECKS = 0;
SELECT
'=== 检查 course_package 表中需要迁移的数据 ===' as info;
-- 如果有需要保留的数据,可以先备份
CREATE TABLE IF NOT EXISTS course_package_backup AS
SELECT * FROM course_package WHERE 1=0;
-- =====================================================
-- 第二步:删除旧的关联表
-- =====================================================