Skip to content

技术架构

Think Site Manager 采用前后端分离架构,后端基于 Spring Boot 提供 REST API,前端基于 UmiJS Max 构建管理界面。


总体架构

┌─────────────────────────────────────────────────────────────┐
│                      用户浏览器                              │
│  ┌──────────────────────┐    ┌──────────────────────────┐  │
│  │  管理平台 (UmiJS Max) │    │ 文档站点 (VitePress)      │  │
│  │  React + Ant Design  │    │  + 认证插件               │  │
│  └──────────┬───────────┘    └────────────┬─────────────┘  │
└─────────────┼──────────────────────────────┼────────────────┘
              │ HTTP/REST                    │ HTTP/REST
              ▼                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    Spring Boot (Port 8300)                   │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐  │
│  │ JWT 认证  │ │ License  │ │ 业务逻辑  │ │ 插件生成器    │  │
│  │ Filter   │ │ Filter   │ │ Services │ │ Plugin Gen   │  │
│  └──────────┘ └──────────┘ └────┬─────┘ └──────────────┘  │
│                                 │                            │
│                          ┌──────▼──────┐                    │
│                          │  MyBatis-Plus│                    │
│                          └──────┬──────┘                    │
└─────────────────────────────────┼───────────────────────────┘


                    ┌─────────────────────┐
                    │    MySQL 8.x        │
                    │ think_site_management│
                    └─────────────────────┘

技术栈

后端

技术版本用途
JDK17运行环境
Spring Boot3.3.2应用框架
Spring Security6.3.1安全认证
MyBatis-Plus3.5.7ORM 框架
Knife4j4.4.0API 文档 (OpenAPI 3)
jjwt / java-jwt0.9.1 / 3.11.0JWT Token 处理
Hutool5.7.0工具库
Apache MINA SSHD2.13.2SSH 客户端 + 服务端(native NIO,长连接复用)
sshd-scp2.13.2SCP 文件传输协议
I2P eddsa0.3.0ed25519 算法 provider(JDK 17 没自带)
BouncyCastle1.78.1通用 JCA 兜底(bcprov-jdk18on + bcpkix-jdk18on)
Apache Commons Compress1.26.0tar.gz 打包(UTF-8 跨平台,中文文件名不乱码)
Flyway10.x数据库迁移(V20260619_xxx__*.sql)
Maven3.x构建工具

前端

技术版本用途
Node.js18+运行环境
UmiJS Max^4.6.57React 应用框架
React18.xUI 框架
Ant Design^5.4.0UI 组件库
ProComponents^2.4.4高级业务组件
@ant-design/charts^2.6.7数据可视化
pnpmlatest包管理器

中间件

技术版本用途
MySQL8.x关系数据库

后端项目结构

backend/
├── pom.xml                    # 父 POM,统一依赖管理
├── admin/                     # 主应用模块
│   ├── pom.xml
│   └── src/main/java/cool/webstudy/admin/
│       ├── AdminApplication.java          # Spring Boot 启动类
│       ├── configuration/                 # 配置类 (Knife4j, Security, MyBatis-Plus)
│       ├── controller/                    # REST Controller
│       │   ├── auth/                      # 认证接口
│       │   ├── dashboard/                 # 数据看板接口
│       │   ├── invite/                    # 邀请码接口
│       │   ├── site/                      # 站点/文章/绑定/插件接口
│       │   ├── system/                    # License 接口
│       │   └── user/                      # 用户接口
│       ├── filter/security/               # JWT + License + SiteToken 过滤器
│       ├── mapper/                        # MyBatis-Plus Mapper 接口
│       ├── model/
│       │   ├── dto/                       # 请求 DTO
│       │   ├── po/                        # 持久化对象 (PO)
│       │   └── vo/                        # 响应 VO
│       ├── service/                       # 业务服务接口 + 实现
│       └── utils/                         # 工具类 (JWT, AES, License)
├── common/                     # 共享模块
│   └── src/main/java/cool/webstudy/common/
│       ├── constant/enums/                # 通用枚举
│       ├── model/                         # 共享 PO/DTO
│       └── utils/                         # 通用工具 (UUID)
└── license-gen/                # License 生成 CLI 工具

Maven 多模块设计

common 模块不依赖 Spring,可独立被其他 Java 项目引用。admin 模块依赖 common,包含全部业务逻辑。license-gen 是独立 JAR,用于离线生成 .lic 授权文件。


前端项目结构

frontend/
├── .umirc.ts                  # UmiJS 配置 (路由、代理、插件)
├── package.json
├── src/
│   ├── app.tsx                # 运行时配置 (初始化、Layout、请求拦截)
│   ├── access.ts              # 权限定义
│   ├── pages/                 # 页面组件
│   │   ├── Home/              # 首页数据看板
│   │   ├── Site/              # 站点管理 (含 Detail)
│   │   ├── Article/           # 文章管理
│   │   ├── User/              # 人员管理
│   │   ├── InviteCode/        # 邀请码管理
│   │   ├── Profile/           # 个人信息
│   │   ├── Login/             # 登录页
│   │   ├── Register/          # 注册页
│   │   └── Activate/          # License 激活页
│   ├── components/            # 共享组件
│   ├── services/site/         # API 请求服务层
│   ├── models/                # 全局状态 (Umi plugin-model)
│   └── constants/             # 常量定义
└── mock/                      # 开发 Mock 数据

页面路由

路由组件权限说明
/homeHome已登录数据看板
/siteSite站点管理权限站点列表
/site/:unCodeSite/Detail站点管理权限站点详情
/articleArticle站点管理权限文章管理
/userUser用户管理权限人员管理
/invite-codeInviteCode站点管理权限邀请码管理
/profileProfile已登录个人信息
/loginLogin公开登录页
/registerRegister公开注册页
/activateActivate公开License 激活

数据库设计

数据库名称:think_site_management,共 5 张业务表

设计特点

  • 🔑 业务主键 + 自增主键un_code (UUID) 作为对外暴露的业务标识,id 作为内部自增主键
  • ♻️ 逻辑删除:所有表通过 del_flag 字段标记删除(0=正常,1=已删),数据不可逆
  • 🔒 密码加密:用户密码使用 BCrypt 加密存储
  • 🔗 软关联:表之间通过 un_code 字段关联,而非数据库外键

安全体系

多层过滤链

请求 → LicenseFilter → SiteTokenFilter → JWTAuthenticationFilter → Controller
过滤器优先级职责
LicenseFilter最高拦截所有请求,验证 License 有效性,无效则返回激活提示
SiteTokenAuthenticationFilter通过 X-Site-Token 头校验第三方站点身份
JWTAuthenticationFilter最低校验 Bearer Token,解析用户身份写入 SecurityContext

JWT 认证流程

  1. 用户通过 /api/user/login 登录,返回加密 JWT Token
  2. 前端存储 Token 到 localStorage
  3. 后续请求通过 Authorization: Bearer <token> 头携带
  4. JWTAuthenticationFilter 解析 Token,获取用户信息注入 Spring Security Context
  5. JWT Payload 中的用户标识通过 AES 加密保护

License 授权系统

  • 🔑 RSA 签名:License 文件包含 RSA 数字签名,防止伪造
  • 💻 硬件绑定:支持绑定服务器 MAC 地址和 IP 地址
  • 定时校验:每小时自动重新验证 License 有效期
  • 过期保护:License 失效后所有接口返回 LICENSE_INVALID

主机凭据 AES-256-GCM 加密

SSH 密码 / 私钥 / passphrase 等敏感凭据,用 AES-256-GCM 加密存 host 表(详见 主机管理):

  • 主密钥 THINK_HOST_CRYPTO_KEY(环境变量,32 字节 hex)启动校验 fail-fast
  • IV 12 字节随机,每条记录独立
  • 密文格式 base64(IV || ciphertext || GCM tag)
  • 解密点 内存中解密,绝不写日志 / 响应
  • 算法 AES-256-GCM(GCM 提供认证加密,防篡改)

主机管理与发布

平台通过 Apache MINA SSHD(异步 NIO SSH 客户端)与目标主机通信,围绕 Host / HostDeployHistory 两张表展开。

核心组件

组件职责
HostCryptoServiceAES-256-GCM 加解密,启动校验 THINK_HOST_CRYPTO_KEY
SecurityProviderInitializer注册 I2P EdDSA (pos 1) + BouncyCastle (pos 2)
SshConnectionMINA SSHD 封装,长连接复用,暴露 exec / scpClient / openShellChannel
HostService主机 CRUD + 密文存取 + 连通性状态回写
HostProbeServiceSSH 探测 OS / nginx 状态,3 段鲁棒判断 not-installed / active / inactive
NginxInitService9 步流水线(SSH→装包→启服务→校验→平台主动 HTTP 探测→防火墙→放行→重测),SSE 实时推
HostDeployService7 步发布流水线(build→SCP→解压→reload),ReentrantLock 串行化同 host+site 并发,ReentrantLock 跨子线程复制 SecurityContext
HostDeployProgressHub复用 BuildProgressHub SSE,额外封装 emitProgress / emitDone / emitFailed
HostShellWebSocketHandlerxterm.js 端 WebSocket 升级处理,PTY 透传,query token 鉴权
PlatformHttpProbejava.net.http.HttpClient 主动 GET,模拟外部用户访问,验证 nginx 是否真的对外暴露

9 步初始化流程

CONNECT → PROBE_OS → INSTALL_NGINX → ENABLE_NGINX → VERIFY_NGINX
   → PROBE_HTTP(平台主动) → CHECK_FIREWALL → OPEN_FIREWALL → REPROBE_HTTP
   → SUCCESS / PARTIAL / ERROR

关键设计: HTTP 连通性探测走"平台主动 HTTP GET http://<host>:80/",而不是 SSH 内 curl 127.0.0.1:80这才验证了「外部用户能不能访问」,而非「主机自己能不能访问」。详见 nginx 初始化 9 步详解

7 步发布流程

启动 → SSH 预检 → 复用/构建 → SCP 上传 → 解压 webRoot → reload nginx → 清理临时
   → SUCCESS

简化部署模型: 不维护多版本目录 + current 软链 + think-sites.conf,直接解压到主机 webRoot(/var/www/html)覆盖原内容,nginx 默认 server 的 root 就是这个目录,reload 即可生效。详见 站点发布到主机

跨平台中文文件名

构建产物(VitePress 输出)可能含中文文件名(快速开始.mdguide/入门/)。平台在 Windows 上跑,默认 GBK 编码,Java ZipOutputStream 写入 zip 时如果 entry name 是 GBK char 序列,会被双重编码,Linux 主机 unzip 拿到错的字节,显示乱码。

修法: 改用 Apache Commons Compresstar.gz:

java
new TarArchiveOutputStream(gzipOut, "UTF-8")  // 构造器第 4 参数显式 UTF-8 编码
    .setAddPaxHeadersForNonAsciiNames(true)  // 对非 ASCII entry 加 pax extended header

任何版本 GNU tar 都能正确解码(旧版读 pax,新版直接读 UTF-8 字节)。旧 .zip 产物走 unzip -O UTF-8 兜底。

SSH 资源约束

Linux server 默认 MaxSessions=10(ubuntu/centos/rocky)。整个 init 流程的 SSH 命令合并为最少 channel(9 个左右):

优化channel 数
prepareNginxDirs(合并 webRoot + conf.d + include 校验)1
openFirewallPorts(80, 443)(合并放行 + reload)1
diagnostics()(合并 IP + 监听 + 防火墙端口,用 ---LABEL--- 分段)1

避免触发 SshChannelOpenException: open failed调大 MaxSessions: sudo sed -i 's/^#MaxSessions 10/MaxSessions 50/' /etc/ssh/sshd_config && sudo systemctl restart sshd


API 设计规范

统一响应格式

所有 API 返回统一格式:

json
{
  "success": true,
  "code": "00000",
  "message": "操作成功",
  "data": { }
}

分页响应

json
{
  "success": true,
  "data": {
    "records": [],
    "current": 1,
    "pages": 10,
    "size": 20,
    "total": 200
  }
}

API 文档

开发环境启动后端后,可通过 Knife4j 访问在线 API 文档:

  • Swagger UI:http://localhost:8300/api/doc.html
  • OpenAPI JSON:http://localhost:8300/api/v3/api-docs

代码规范体系

项目目录 rules/ 下包含完整的开发规范文档:

规范覆盖范围
project-structure.md总体架构、模块划分、目录结构
naming-conventions.md类名、方法名、变量名、包名规范
database-design.md表设计、字段类型、索引、逻辑删除
backend-standards.mdController/Service/Mapper 分层规范
frontend-standards.md组件、服务、路由、状态管理规范
api-design.mdREST 风格、请求/响应格式、错误码

下一步

了解了技术架构后,可以继续阅读 部署说明 开始部署平台。

基于 VitePress 构建