From 68f830c75c3e9dd93fe7585c4203ad170dd97012 Mon Sep 17 00:00:00 2001 From: renjianbo <18691577328@163.com> Date: Sun, 17 May 2026 01:18:22 +0800 Subject: [PATCH] docs: add cloud server deployment guide and update improvement log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New: 云服务器部署实操手册.md covering Docker, database, frontend deployment, Git sync, paramiko, API testing, menu management, and troubleshooting - Update: 改进完成记录.md with Issue #18, #21, and order_view fix Co-Authored-By: Claude Opus 4.6 --- docs/云服务器部署实操手册.md | 540 +++++++++++++++++++++++++++++++++++ docs/改进完成记录.md | 23 ++ 2 files changed, 563 insertions(+) create mode 100644 docs/云服务器部署实操手册.md diff --git a/docs/云服务器部署实操手册.md b/docs/云服务器部署实操手册.md new file mode 100644 index 0000000..6a67364 --- /dev/null +++ b/docs/云服务器部署实操手册.md @@ -0,0 +1,540 @@ +# 云服务器部署实操手册 + +> 更新日期:2026-05-17 +> 基于 101.43.95.130 (腾讯云 2核/7.5GB) 实际部署经验编写 + +--- + +## 一、服务器基本信息 + +| 项目 | 详情 | +|------|------| +| IP | `101.43.95.130` | +| 系统 | CentOS 7 / Ubuntu | +| 内存 | 7.5GB(可用约 762MB,仅跑一个 Java 实例) | +| SSH | `renjianbo:123456` | +| Git 服务 | Gitea `http://101.43.95.130:3001` (admin/123456) | +| CI/CD | Drone CI `http://101.43.95.130:3002` | +| 管理后台 | `http://101.43.95.130:8050` | +| 后端 API | `http://101.43.95.130:8039` | + +### 项目路径 + +| 位置 | 路径 | +|------|------| +| 服务器代码 | `/home/renjianbo/saars/rlz/` | +| Docker Compose | `/home/renjianbo/saars/rlz/docker-compose.yml` | +| 前端 Nginx | Docker 容器 `rlz-ui-server` | +| 本地代码 | `D:\androidPj\rlz\` | + +--- + +## 二、Docker 容器架构 + +``` +┌─────────────────────────────────────────────────┐ +│ Docker Host (101.43.95.130) │ +│ │ +│ ┌───────────┐ ┌────────────┐ ┌──────────────┐ │ +│ │rlz-backend│ │rlz-ui-server│ │ rlz-redis │ │ +│ │ :8039 │ │ :8050 │ │ :6379 │ │ +│ │ Spring │ │ Nginx + │ │ Redis 7 │ │ +│ │ Boot │ │ 前端 dist │ │ │ │ +│ └───────────┘ └────────────┘ └──────────────┘ │ +│ │ +│ ┌───────────┐ ┌────────────┐ ┌──────────────┐ │ +│ │ Gitea │ │ Drone │ │ Drone Runner│ │ +│ │ :3001 │ │ :3002/3003 │ │ │ │ +│ └───────────┘ └────────────┘ └──────────────┘ │ +└─────────────────────────────────────────────────┘ + │ + ▼ + ┌──────────────────────┐ + │ 腾讯云 CynosDB MySQL│ + │ gz-...sql.tencentcdb.com:24936 │ + │ 库: rlz (生产) │ + │ 库: rlz_dev (开发) │ + └──────────────────────┘ +``` + +### 常用 Docker 命令 + +```bash +# 查看所有容器状态 +docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" + +# 重建后端(代码改动后) +cd /home/renjianbo/saars/rlz +docker compose build --no-cache backend +docker compose up -d backend + +# 查看后端日志 +docker logs --tail 100 rlz-backend + +# 重启前端 Nginx +docker restart rlz-ui-server + +# 进入 Redis +docker exec -it rlz-redis redis-cli +``` + +--- + +## 三、数据库操作 + +### 连接信息 + +``` +Host: gz-cynosdbmysql-grp-d26pzce5.sql.tencentcdb.com +Port: 24936 +User: root +Password: !Rjb12191 +Databases: rlz (生产), rlz_dev (开发) +``` + +### 通过服务器 Python 脚本操作数据库 + +由于服务器 Docker 容器内没有 `mysql` 客户端,需要用 `pymysql`: + +```python +import pymysql + +conn = pymysql.connect( + host='gz-cynosdbmysql-grp-d26pzce5.sql.tencentcdb.com', + port=24936, + user='root', + password='!Rjb12191', + database='rlz', + charset='utf8mb4' +) +cur = conn.cursor() +cur.execute("YOUR SQL HERE") +conn.commit() +cur.close() +conn.close() +``` + +### 复制表结构到开发库 + +```sql +-- 先禁用外键检查(避免表依赖顺序问题) +SET FOREIGN_KEY_CHECKS = 0; + +-- 逐表 CREATE TABLE ... LIKE + INSERT ... SELECT +CREATE TABLE rlz_dev.sys_xxx LIKE rlz.sys_xxx; +INSERT INTO rlz_dev.sys_xxx SELECT * FROM rlz.sys_xxx; + +-- 视图需要等到所有基表创建完成后才能创建 +-- 恢复外键检查 +SET FOREIGN_KEY_CHECKS = 1; +``` + +### 修复视图(常见问题) + +视图引用的列在基表中不存在时会导致 SQL 错误。例如 `order_view` 引用了 `sys_user` 不存在的 `age`/`nation` 列: + +```sql +-- 用 NULL 占位缺失的列 +CREATE OR REPLACE VIEW `order_view` AS +SELECT + o.order_id, + ub.user_id AS userb_id, + NULL AS userb_age, -- sys_user 表暂无此列 + NULL AS userb_nation, -- sys_user 表暂无此列 + ... +FROM rlz_order o +LEFT JOIN sys_user ub ON o.b_id = ub.user_id +... +``` + +### 备份生产库 + +在对 `rlz` 做结构变更前务必备份: + +```sql +-- 通过 pymysql 导出 +-- 或使用云数据库自带的备份功能 +``` + +--- + +## 四、前端部署 + +### 本地构建 + +```bash +# Windows 环境,Node 17+ 需要 OpenSSL legacy 兼容 +cd D:\androidPj\rlz\rlz-ui + +# 设置兼容模式 +set NODE_OPTIONS=--openssl-legacy-provider + +# 构建 +npm run build:prod +``` + +### 上传到服务器(SFTP) + +构建产物较大(约 3MB tar),不能用 base64 echo 方式传输(会导致 SSH 连接重置),必须用 SFTP: + +```python +import paramiko + +client = paramiko.SSHClient() +client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +client.connect('101.43.95.130', 22, 'renjianbo', '123456') + +sftp = client.open_sftp() +sftp.put('local_dist.tar', '/tmp/dist.tar') +sftp.close() + +# 部署 +stdin, stdout, stderr = client.exec_command( + 'cd /tmp && tar xf dist.tar && cp -r dist/* /home/renjianbo/saars/rlz/rlz-ui/dist/ && docker restart rlz-ui-server' +) +client.close() +``` + +### 通过服务器直接构建(不推荐,服务器资源紧张) + +```bash +cd /home/renjianbo/saars/rlz/rlz-ui +npm install +NODE_OPTIONS=--openssl-legacy-provider npm run build:prod +# 确保 nginx 指向 dist 目录 +``` + +--- + +## 五、Git 代码同步 + +### 仓库地址 + +``` +http://101.43.95.130:3001/admin/rlz.git +``` + +### 本地 ↔ Gitea ↔ 服务器 三方同步 + +```bash +# === 本地 === +cd D:/androidPj/rlz +git checkout dev +git add +git commit -m "message" +git push origin dev + +# === 服务器 === +cd /home/renjianbo/saars/rlz +git pull origin dev + +# 如果服务器有未跟踪文件冲突 +git stash --include-untracked +git pull origin dev +git stash drop +``` + +### 解决 push 被拒绝 + +```bash +# 如果远程有本地没有的提交 +git pull origin dev --no-edit +git push origin dev +``` + +### 服务器有本地修改时提交 + +```bash +cd /home/renjianbo/saars/rlz +git add +git commit -m "message" +git push origin dev +``` + +--- + +## 六、Python paramiko 远程操作 + +### 基础连接 + +```python +import paramiko + +client = paramiko.SSHClient() +client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +client.connect('101.43.95.130', 22, 'renjianbo', '123456') + +# 执行命令 +stdin, stdout, stderr = client.exec_command('command') +output = stdout.read().decode('utf-8', errors='replace') +error = stderr.read().decode('utf-8', errors='replace') +exit_code = stdout.channel.recv_exit_status() + +client.close() +``` + +### 大文件传输(必须用 SFTP) + +```python +sftp = client.open_sftp() +sftp.put('/local/path/file', '/remote/path/file') # 上传 +sftp.get('/remote/path/file', '/local/path/file') # 下载 +sftp.close() +``` + +### 编码处理(处理中文日志) + +```python +import sys, io +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace') +``` + +### 通过 heredoc 执行 Python 脚本 + +```python +# 注意:复杂的 f-string 和花括号会导致 bash heredoc 转义问题 +# 推荐用 SFTP 上传 .py 文件代替 heredoc + +# 简单脚本可以用 heredoc: +script = ''' +import json +data = {"key": "value"} +print(json.dumps(data)) +''' +# 危险的字符需要转义:$ → \$, ` → \`, \ → \\ +``` + +--- + +## 七、API 测试与 JWT 认证 + +### 获取有效 Token + +RuoYi 框架使用 Redis 存储验证码,需要先获取 captcha 再登录: + +```python +import json, subprocess + +# Step 1: 获取验证码 UUID +result = subprocess.run(['curl', '-s', 'http://localhost:8039/captchaImage'], + capture_output=True, text=True) +captcha = json.loads(result.stdout) +uuid = captcha['uuid'] + +# Step 2: 从 Redis 读取验证码答案 +result = subprocess.run(['docker', 'exec', 'rlz-redis', 'redis-cli', + 'GET', f'captcha_codes:{uuid}'], + capture_output=True, text=True) +code = result.stdout.strip().strip('"') + +# Step 3: 登录获取 token +import urllib.request +data = json.dumps({'username': 'admin', 'password': 'admin123', + 'code': code, 'uuid': uuid}) +req = urllib.request.Request('http://localhost:8039/login', + data=data.encode(), + headers={'Content-Type': 'application/json'}) +resp = json.loads(urllib.request.urlopen(req).read().decode()) +token = resp['token'] +``` + +### 带 Token 调用 API + +```python +req = urllib.request.Request('http://localhost:8039/system/renzheng/list', + headers={'Authorization': f'Bearer {token}'}) +resp = urllib.request.urlopen(req) +data = json.loads(resp.read().decode()) +``` + +### 管理员默认账号 + +- 用户名: `admin` +- 密码: `admin123` + +--- + +## 八、RuoYi 菜单管理 + +### 菜单是数据库驱动的 + +前端侧边栏菜单由 `sys_menu` 表动态加载,不需要修改前端代码。 + +### sys_menu 表结构 + +| 字段 | 说明 | +|------|------| +| `menu_id` | 主键,建议新菜单用 2000+ 避免冲突 | +| `menu_name` | 菜单名称 | +| `parent_id` | 父菜单ID,`0` 表示顶级菜单 | +| `menu_type` | `M`=目录, `C`=菜单(页面), `F`=按钮(权限) | +| `path` | 路由路径,对应 `@/views/` 下的组件路径 | +| `component` | 组件路径,如 `system/hospital/index` | +| `perms` | 权限标识,如 `system:hospital:list` | +| `icon` | 图标名称(Element UI 图标) | +| `visible` | `0`=可见, `1`=隐藏 | +| `status` | `0`=启用, `1`=停用 | +| `order_num` | 排序 | + +### 添加新菜单的完整流程 + +```sql +-- 1. 添加菜单项 +INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, + component, menu_type, perms, icon, create_by, create_time, + visible, status, is_frame, is_cache) +VALUES (2001, '医院管理', 2000, 1, 'system/hospital', + 'system/hospital/index', 'C', 'system:hospital:list', + 'build', 'admin', NOW(), '0', '0', 1, 0); + +-- 2. 添加权限按钮(F 类型) +INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, + menu_type, perms, create_by, create_time) +VALUES (2002, '医院查询', 2001, 1, 'F', 'system:hospital:list', + 'admin', NOW()); + +-- 3. 授权给管理员角色(role_id=1) +INSERT INTO sys_role_menu (role_id, menu_id) VALUES (1, 2001); +INSERT INTO sys_role_menu (role_id, menu_id) VALUES (1, 2002); +``` + +### 菜单结构调整示例 + +``` +调整前: 调整后: +系统管理 业务管理 + ├── 用户管理 ├── 医院管理 + ├── 服务类型 ├── 订单管理 + └── ... ├── 认证管理 + └── 服务类型 ← 从系统管理移过来 + + 财务管理 + ├── 退款审核 + ├── 结算管理 + └── 收入统计 + + 系统管理(下移) + ├── 用户管理 + └── ... +``` + +只需 `UPDATE sys_menu SET parent_id=2000 WHERE menu_id=1060` 即可移动菜单。 + +--- + +## 九、常见问题与解决 + +### MyBatis XML 解析错误 + +**错误**: `SAXParseException: 元素内容必须由正确的字符数据或标记组成` + +**原因**: XML 文件中有不可见字符(如 `\x01` SOH)或行首多余字符 + +**修复**: +```bash +# 检查 XML 里是否有 BOM 或控制字符 +cat -A mapper.xml | head -5 + +# 移除 SOH 字符 +sed -i "s/\x01//g" mapper.xml + +# 或通过 Python 二进制方式清理 +with open(file, 'rb') as f: + content = f.read() +with open(file, 'wb') as f: + f.write(content.replace(b'\x01', b'').replace(b'^t', b'')) +``` + +### Docker 构建不生效 + +**现象**: `docker compose up -d --build` 后代码未更新 + +**修复**: 使用 `--no-cache` 强制重建 +```bash +docker compose build --no-cache backend +docker compose up -d backend +``` + +### 外键约束导致建表失败 + +**现象**: `Cannot add foreign key constraint` + +**修复**: +```sql +SET FOREIGN_KEY_CHECKS = 0; +-- 执行建表 SQL +SET FOREIGN_KEY_CHECKS = 1; +``` + +### 视图创建失败 + +**原因**: 视图引用的表尚未创建 + +**修复**: 等所有基表建完后再创建视图(放到第二遍执行) + +### SSH heredoc 转义问题 + +**现象**: bash heredoc 中 Python f-string 的花括号被 bash 错误解析 + +**修复**: 用 SFTP 上传 `.py` 文件代替 heredoc 内联脚本 + +### Node.js 构建 OpenSSL 错误 + +**现象**: `Error: error:0308010C:digital envelope routines::unsupported` + +**修复**: Node 17+ 不兼容旧版 webpack 插件 +```bash +export NODE_OPTIONS="--openssl-legacy-provider" +npm run build:prod +``` + +### Python GBK 编码错误 + +**现象**: `UnicodeEncodeError` 处理中文服务器日志时 + +**修复**: +```python +import sys, io +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace') +``` + +### 云数据库密码特殊字符 + +密码 `!Rjb12191` 中的 `!` 在 bash heredoc 中会被解释。用 base64 编码传递或通过 Python 变量直接引用。 + +--- + +## 十、部署检查清单 + +每次部署后确认: + +```bash +# 1. 后端健康检查 +curl -s -o /dev/null -w "%{http_code}" http://localhost:8039 + +# 2. 前端健康检查 +curl -s -o /dev/null -w "%{http_code}" http://localhost:8050 + +# 3. 容器状态 +docker ps --format "table {{.Names}}\t{{.Status}}" + +# 4. 数据库连接(通过 API 间接验证) +# 调用任意一个 list 接口确认能正常返回数据 + +# 5. Redis 连接 +docker exec rlz-redis redis-cli PING +# 预期返回: PONG +``` + +--- + +## 十一、关键密码与地址速查 + +| 项目 | 值 | +|------|-----| +| 服务器 SSH | `ssh renjianbo@101.43.95.130` 密码 `123456` | +| Gitea | `http://101.43.95.130:3001` admin/123456 | +| 云 MySQL | `gz-cynosdbmysql-grp-d26pzce5.sql.tencentcdb.com:24936` root/!Rjb12191 | +| 管理后台 | `http://101.43.95.130:8050` admin/admin123 | +| Redis CLI | `docker exec -it rlz-redis redis-cli` | +| Drone CI | `http://101.43.95.130:3002` | diff --git a/docs/改进完成记录.md b/docs/改进完成记录.md index eb25f9a..75ffc1a 100644 --- a/docs/改进完成记录.md +++ b/docs/改进完成记录.md @@ -53,6 +53,29 @@ --- +### 8. 认证管理增强 (Issue #18) — 2026-05-17 + +- 后端新增 `PUT /system/renzheng/approve/{id}` 审核通过接口 +- 后端新增 `PUT /system/renzheng/reject/{id}` 审核驳回接口 +- 前端重写认证管理页面:状态筛选、彩色标签、通过/驳回操作、驳回原因弹窗、详情弹窗 +- 创建 `sys_user_renzheng` 表(rlz 和 rlz_dev 两库) +- 补充 `renzheng.js` API 模块(approveRenzheng / rejectRenzheng) + +### 9. 菜单结构调整 (Issue #21) — 2026-05-17 + +- 新增顶级菜单 **业务管理**(医院管理 / 订单管理 / 认证管理 / 服务类型) +- 新增顶级菜单 **财务管理**(退款审核 / 结算管理 / 收入统计) +- 服务类型从系统管理移至业务管理 +- 为医院管理、订单管理、认证管理添加完整权限按钮 +- 所有菜单授权给管理员角色 + +### 10. order_view 修复 — 2026-05-17 + +- `order_view` 缺少 `userb_age`/`userb_nation`/`userc_age`/`userc_nation` 列导致订单 API 500 错误 +- 通过 `CREATE OR REPLACE VIEW` 用 `NULL AS` 占位缺失列,两库均已修复 + +--- + ## 后续需要手动完成的 | 事项 | 操作 |