初始化代码

This commit is contained in:
lpd
2026-01-19 18:54:03 +08:00
commit 423975df96
4386 changed files with 375663 additions and 0 deletions

54
.gitignore vendored Normal file
View File

@@ -0,0 +1,54 @@
######################################################################
# Build Tools
.gradle
/build/
!gradle/wrapper/gradle-wrapper.jar
target/
!.mvn/wrapper/maven-wrapper.jar
.flattened-pom.xml
######################################################################
# IDE
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
nbproject/private/
build/*
nbbuild/
dist/
nbdist/
.nb-gradle/
######################################################################
# Others
*.log
*.xml.versionsBackup
*.swp
!*/build/*.java
!*/build/*.html
!*/build/*.xml
### JRebel ###
rebel.xml
application-my.yaml
/lyzsys-ui-app/unpackage/
**/.DS_Store

BIN
.image/Java监控.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

BIN
.image/MySQL.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

BIN
.image/OA请假-列表.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

BIN
.image/OA请假-发起.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
.image/OA请假-详情.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
.image/Redis.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

BIN
.image/admin-uniapp/01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
.image/admin-uniapp/02.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
.image/admin-uniapp/03.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
.image/admin-uniapp/04.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

BIN
.image/admin-uniapp/05.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
.image/admin-uniapp/06.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
.image/admin-uniapp/07.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
.image/admin-uniapp/08.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
.image/admin-uniapp/09.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
.image/个人中心.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
.image/代码生成.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

BIN
.image/令牌管理.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

BIN
.image/任务日志.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

BIN
.image/商户信息.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
.image/在线用户.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
.image/字典数据.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

BIN
.image/字典类型.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

BIN
.image/定时任务.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
.image/岗位管理.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
.image/应用管理.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
.image/操作日志.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
.image/支付订单.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

BIN
.image/敏感词.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
.image/数据库文档.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

BIN
.image/文件管理.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
.image/文件管理2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

BIN
.image/文件配置.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

BIN
.image/日志中心.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

BIN
.image/流程表单.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

BIN
.image/生成效果.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

BIN
.image/用户分组.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
.image/用户管理.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

BIN
.image/登录.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
.image/登录日志.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
.image/短信日志.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
.image/短信模板.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

BIN
.image/短信渠道.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
.image/租户套餐.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

BIN
.image/租户管理.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

BIN
.image/系统接口.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
.image/菜单管理.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

BIN
.image/表单构建.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

BIN
.image/角色管理.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
.image/访问日志.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
.image/退款订单.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

BIN
.image/通知公告.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
.image/部门管理.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

BIN
.image/配置管理.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

BIN
.image/链路追踪.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
.image/错误日志.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

BIN
.image/错误码管理.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

BIN
.image/首页.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

20
LICENSE Normal file
View File

@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2021 ruoyi-vue-pro
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

0
README.md Normal file
View File

1464
doc/前端开发文档.md Normal file

File diff suppressed because it is too large Load Diff

866
doc/后端开发文档.md Normal file
View File

@@ -0,0 +1,866 @@
# Lyzsys 后端开发文档
## 目录
- [项目概述](#项目概述)
- [技术栈](#技术栈)
- [项目架构](#项目架构)
- [模块说明](#模块说明)
- [开发指南](#开发指南)
- [核心功能](#核心功能)
- [部署指南](#部署指南)
---
## 项目概述
Lyzsys 是一个基于 Spring Boot 的企业级后台管理系统采用模块化单体架构支持多租户、工作流、权限管理、AI 集成等企业级功能。
### 核心特性
- **模块化架构**: 基于 Maven 多模块的清晰分层设计
- **多租户支持**: 原生支持 SaaS 多租户场景
- **权限管理**: 基于 RBAC 的动态权限和数据权限
- **工作流引擎**: 集成 Flowable 实现业务流程管理
- **AI 集成**: 支持多个 AI 服务提供商集成
- **微服务就绪**: 模块化设计便于未来微服务化改造
---
## 技术栈
### 核心框架
| 技术 | 版本 | 说明 |
|------|------|------|
| Spring Boot | 2.7.18 | 应用开发框架 |
| Spring Security | 5.8.16 | 安全框架 |
| MyBatis Plus | 3.5.15 | ORM 增强框架 |
| Flowable | 6.8.0 | 工作流引擎 |
| Redisson | 3.52.0 | 分布式锁客户端 |
### 数据存储
| 技术 | 版本 | 说明 |
|------|------|------|
| MySQL | 5.7+ | 主数据库 |
| Redis | 5.0+ | 缓存数据库 |
| 支持数据库 | - | MySQL、PostgreSQL、Oracle、SQL Server、H2 等 |
### 工具库
| 技术 | 版本 | 说明 |
|------|------|------|
| Lombok | 1.18.34 | 简化 Java 代码 |
| MapStruct | 1.6.3 | 对象映射 |
| Jackson | 2.13.5 | JSON 处理 |
| Hibernate Validator | 6.2.5 | 参数校验 |
| Knife4j | 3.0.3 | API 文档 |
---
## 项目架构
### 整体架构
Lyzsys 后端采用**模块化单体架构**,基于 **Controller-Service-DAL** 三层架构模式:
```
┌─────────────────────────────────────────────────────────────┐
│ 前端应用 │
│ (lyzsys-ui-admin / lyzsys-ui-admin-uniapp) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ lyzsys-server │
│ (应用启动入口) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────┼─────────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────────┐ ┌──────────────┐
│ lyzsys-framework│ │ lyzsys-module-xxx│ │lyzsys-dependencies│
│ (框架层) │ │ (业务模块) │ │ (依赖管理) │
└──────────────┘ └──────────────────┘ └──────────────┘
```
### 分层架构
每个业务模块都遵循标准的三层架构:
```
controller/ # 控制层 - 接收 HTTP 请求
├── admin/ # 管理后台 API
└── app/ # 用户 App API
service/ # 服务层 - 业务逻辑处理
├── IxxxService.java # 服务接口
└── xxxServiceImpl.java # 服务实现
dal/ # 数据访问层
├── dataobject/ # 数据对象 (DO)
├── mysql/ # MyBatis Mapper
└── redis/ # Redis 操作
```
### 架构设计原则
1. **依赖倒置**: Controller 依赖 Service 接口,而非实现
2. **单一职责**: 每层只负责自己的职责
3. **开闭原则**: 通过接口扩展,而非修改
4. **非严格分层**: 允许跨层访问(如 Service 直接调用多个 Mapper
---
## 模块说明
### Maven 模块分类
项目共有四类 Maven Module
#### 1. lyzsys-dependencies
**作用**: Maven 依赖版本管理 (BOM)
**说明**: 定义项目中所有 Maven 依赖的版本号,解决依赖冲突问题。
**关键文件**:
- `pom.xml`: 依赖版本定义
#### 2. lyzsys-framework
**作用**: Java 框架拓展
**说明**: 提供项目的基础框架能力,分为技术组件和业务组件。
**技术组件**:
| 模块 | 作用 |
|------|------|
| lyzsys-common | 基础 pojo 类、枚举、工具类 |
| lyzsys-spring-boot-starter-web | Web 封装,全局异常、访问日志 |
| lyzsys-spring-boot-starter-security | 认证授权,基于 Spring Security |
| lyzsys-spring-boot-starter-mybatis | 数据库操作,基于 MyBatis Plus |
| lyzsys-spring-boot-starter-redis | 缓存操作,基于 Spring Data Redis + Redisson |
| lyzsys-spring-boot-starter-mq | 消息队列,基于 Redis 实现 |
| lyzsys-spring-boot-starter-job | 定时任务,基于 Quartz 实现 |
| lyzsys-spring-boot-starter-protection | 服务保障,幂等、分布式锁、限流、熔断 |
| lyzsys-spring-boot-starter-excel | Excel 导入导出,基于 EasyExcel |
| lyzsys-spring-boot-starter-monitor | 服务监控,链路追踪、日志服务 |
| lyzsys-spring-boot-starter-websocket | WebSocket 封装,支持 Token 认证 |
**业务组件**:
| 模块 | 作用 |
|------|------|
| lyzsys-spring-boot-starter-biz-tenant | SaaS 多租户 |
| lyzsys-spring-boot-starter-biz-data-permission | 数据权限 |
| lyzsys-spring-boot-starter-biz-ip | 地区 & IP 库 |
#### 3. lyzsys-module-xxx
**作用**: 业务功能模块
**核心模块**:
| 模块 | 说明 | 是否必须 |
|------|------|----------|
| lyzsys-module-system | 系统功能模块 | √ |
| lyzsys-module-infra | 基础设施模块 | √ |
| lyzsys-module-ai | AI 大模型集成 | × |
| lyzsys-module-bpm | 业务流程管理 | × |
| lyzsys-module-crm | 客户关系管理 | × |
| lyzsys-module-erp | 企业资源规划 | × |
| lyzsys-module-iot | 物联网平台 | × |
| lyzsys-module-mall | 商城系统 | × |
| lyzsys-module-member | 会员中心 | × |
| lyzsys-module-mp | 微信公众号 | × |
| lyzsys-module-pay | 支付系统 | × |
| lyzsys-module-report | 报表系统 | × |
#### 4. lyzsys-server
**作用**: 管理后台 + 用户 App 的服务端
**说明**: 后端 Server 的主项目,通过引入需要的 lyzsys-module-xxx 业务模块,提供 RESTful API。
### 模块标准结构
每个业务模块采用统一的目录结构:
```
lyzsys-module-xxx/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── cn/iocoder/lyzsys/module/xxx/
│ │ │ ├── api/ # 对外 API 接口
│ │ │ │ ├── xxxApi.java
│ │ │ │ └── xxxApiImpl.java
│ │ │ ├── controller/ # 控制层
│ │ │ │ ├── admin/ # 管理后台 Controller
│ │ │ │ │ ├── xxxController.java
│ │ │ │ │ └── vo/ # 视图对象
│ │ │ │ │ ├── xxxReqVO.java
│ │ │ │ │ └── xxxRespVO.java
│ │ │ │ └── app/ # 用户 App Controller
│ │ │ ├── service/ # 服务层
│ │ │ │ ├── xxxService.java
│ │ │ │ └── xxxServiceImpl.java
│ │ │ ├── dal/ # 数据访问层
│ │ │ │ ├── dataobject/ # 数据对象
│ │ │ │ │ └── xxxDO.java
│ │ │ │ ├── mysql/ # MyBatis Mapper
│ │ │ │ │ └── xxxMapper.java
│ │ │ │ └── redis/ # Redis 操作
│ │ │ │ └── xxxRedisDAO.java
│ │ │ ├── convert/ # 对象转换器
│ │ │ │ └── xxxConvert.java
│ │ │ ├── enums/ # 枚举类
│ │ │ │ └── xxxEnum.java
│ │ │ └── framework/ # 模块框架配置
│ │ └── resources/
│ │ └── mapper/ # MyBatis XML
│ └── test/
│ └── java/
└── pom.xml
```
---
## 开发指南
### 环境准备
#### 必需软件
| 软件 | 版本要求 | 下载地址 |
|------|----------|----------|
| JDK | 8+ | https://www.oracle.com/java/technologies/downloads/ |
| MySQL | 5.7+ | https://dev.mysql.com/downloads/mysql/ |
| Redis | 5.0+ | https://redis.io/download |
| Maven | 3.6+ | https://maven.apache.org/download.cgi |
| IDE | IntelliJ IDEA 推荐 | https://www.jetbrains.com/idea/ |
#### 配置数据库
1. 创建数据库:
```sql
CREATE DATABASE lyzsys CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
```
2. 导入 SQL 脚本(位置:`sql/` 目录)
3. 修改配置文件 `lyzsys-server/src/main/resources/application.yaml`
### 快速开始
#### 1. 克隆项目
```bash
git clone https://github.com/your-org/lyzsys.git
cd lyzsys/lyzsys_backend
```
#### 2. 导入 IDE
将项目导入 IntelliJ IDEA
```
File → Open → 选择 lyzsys_backend 目录
```
等待 Maven 依赖下载完成。
#### 3. 启动 Redis
```bash
redis-server
```
#### 4. 运行主类
找到 `lyzsys-server/src/main/java/cn/iocoder/lyzsys/server/LyzsysServerApplication.java`
右键 → Run 'LyzsysServerApplication'
#### 5. 访问应用
- 应用地址: http://localhost:48080
- API 文档: http://localhost:48080/doc.html
- 用户名: admin
- 密码: admin123
### 开发规范
#### 命名规范
**包命名**: 全小写,使用点分隔
```
cn.iocoder.lyzsys.module.system.controller.admin
```
**类命名**: 大驼峰
```
UserController, UserService, UserDO
```
**方法命名**: 小驼峰
```
getUserById(), createUser(), deleteUser()
```
**变量命名**: 小驼峰
```
userName, userAge, isAdmin
```
**常量命名**: 全大写,下划线分隔
```
MAX_SIZE, DEFAULT_PAGE_SIZE, ERROR_CODE
```
#### 注释规范
**类注释**:
```java
/**
* 用户 Controller
*
* @author 芋道源码
*/
@RestController
@RequestMapping("/system/user")
public class UserController {
}
```
**方法注释**:
```java
/**
* 创建用户
*
* @param createReqVO 创建信息
* @return 用户 ID
*/
@PostMapping("/create")
public CommonResult<Long> createUser(@Valid @RequestBody UserCreateReqVO createReqVO) {
return success(userService.createUser(createReqVO));
}
```
#### 代码规范
1. **使用 Lombok 简化代码**:
```java
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserDO extends TenantBaseDO {
private Long id;
private String username;
}
```
2. **使用 MapStruct 进行对象转换**:
```java
@Mapper
public interface UserConvert {
UserConvert INSTANCE = Mappers.getMapper(UserConvert.class);
UserDO convert(UserCreateReqVO bean);
UserRespVO convert(UserDO bean);
}
```
3. **异常处理**:
```java
// 使用全局异常处理器
throw new ServiceException(USER_USERNAME_EXISTS);
// 或使用工具方法
throw exception(USER_USERNAME_EXISTS);
```
### 接口开发
#### Controller 层
```java
@Tag(name = "管理后台 - 用户")
@RestController
@RequestMapping("/system/user")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@PostMapping("/create")
@Operation(summary = "创建用户")
@PreAuthorize("@ss.hasPermission('system:user:create')")
public CommonResult<Long> createUser(@Valid @RequestBody UserCreateReqVO createReqVO) {
return success(userService.createUser(createReqVO));
}
@GetMapping("/get")
@Operation(summary = "获取用户详情")
@Parameter(name = "id", description = "用户 ID", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:user:query')")
public CommonResult<UserRespVO> getUser(@RequestParam("id") Long id) {
return success(userService.getUser(id));
}
}
```
#### Service 层
```java
public interface UserService {
Long createUser(UserCreateReqVO createReqVO);
UserRespVO getUser(Long id);
void deleteUser(Long id);
}
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final UserMapper userMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createUser(UserCreateReqVO createReqVO) {
// 1. 参数校验
validateUserExists(null, createReqVO.getUsername());
// 2. 插入用户
UserDO user = UserConvert.INSTANCE.convert(createReqVO);
user.setPassword(encodePassword(createReqVO.getPassword()));
userMapper.insert(user);
// 3. 返回 ID
return user.getId();
}
@Override
public UserRespVO getUser(Long id) {
UserDO user = userMapper.selectById(id);
return UserConvert.INSTANCE.convert(user);
}
}
```
#### Mapper 层
```java
@Mapper
public interface UserMapper extends BaseMapperX<UserDO> {
default UserDO selectByUsername(String username) {
return selectOne("username", username);
}
default List<UserDO> selectListByDeptIds(Collection<Long> deptIds) {
return selectList(new LambdaQueryWrapperX<UserDO>()
.in(UserDO::getDeptId, deptIds));
}
default PageResult<UserDO> selectPage(UserPageReqVO pageReqVO) {
return selectPage(pageReqVO, new LambdaQueryWrapperX<UserDO>()
.likeIfPresent(UserDO::getUsername, pageReqVO.getUsername())
.likeIfPresent(UserDO::getMobile, pageReqVO.getMobile())
.betweenIfPresent(UserDO::getCreateTime, pageReqVO.getCreateTime())
.orderByDesc(UserDO::getId));
}
}
```
---
## 核心功能
### 认证授权
#### 认证流程
1. **登录认证**:
```
用户输入用户名密码 → 后端验证 → 生成 JWT Token → 返回 Token
```
2. **Token 验证**:
```
请求携带 Token → 后端解析 Token → 验证有效性 → 允许访问
```
3. **Token 刷新**:
```
Token 即将过期 → 使用刷新令牌 → 获取新 Token
```
#### 权限模型
**RBAC (基于角色的访问控制)**:
```
用户 (User)
角色 (Role)
权限 (Permission)
资源 (Resource)
```
**数据权限**:
- 全部数据权限
- 本部门数据权限
- 本部门及以下数据权限
- 仅本人数据权限
- 自定义数据权限
### 多租户
#### 租户隔离
1. **数据库隔离**: 通过 `tenant_id` 字段隔离
2. **自动过滤**: MyBatis Plus 拦截器自动添加租户条件
3. **租户上下文**: `TenantContextHolder` 管理当前租户
#### 使用示例
```java
// 继承租户基类
@TableName("system_user")
public class UserDO extends TenantBaseDO {
private Long id;
private String username;
// tenant_id 由 TenantBaseDO 提供
}
// 查询自动过滤租户
List<UserDO> users = userMapper.selectList();
// SQL: SELECT * FROM system_user WHERE tenant_id = ?
```
### 工作流 (Flowable)
#### 流程定义
```java
@Service
public class ProcessDefinitionService {
public String createProcessDefinition(ProcessDefinitionCreateReqVO createReqVO) {
// 1. 校验流程模型
validateProcessModel(createReqVO.getModelId());
// 2. 部署流程定义
Deployment deployment = repositoryService.createDeployment()
.name(createReqVO.getName())
.addBytes(createReqVO.getBpmnBytes())
.deploy();
// 3. 返回流程定义 ID
return deployment.getId();
}
}
```
#### 流程实例
```java
@Service
public class ProcessInstanceService {
public String startProcessInstance(ProcessInstanceStartReqVO startReqVO) {
// 1. 启动流程实例
ProcessInstance instance = runtimeService.startProcessInstanceByKey(
startReqVO.getProcessDefinitionKey(),
startReqVO.getBusinessKey()
);
// 2. 完成第一个任务
taskService.complete(instance.getId());
// 3. 返回实例 ID
return instance.getId();
}
}
```
### 缓存管理
#### Redis 缓存
```java
// 使用 RedisTemplate
@Service
@RequiredArgsConstructor
public class UserServiceImpl {
private final RedisTemplate<String, UserDO> redisTemplate;
public UserDO getUser(Long id) {
String key = "user:" + id;
UserDO user = redisTemplate.opsForValue().get(key);
if (user == null) {
user = userMapper.selectById(id);
redisTemplate.opsForValue().set(key, user, 1, TimeUnit.HOURS);
}
return user;
}
}
```
#### 缓存注解
```java
@Cacheable(value = "user", key = "#id")
public UserDO getUser(Long id) {
return userMapper.selectById(id);
}
@CachePut(value = "user", key = "#user.id")
public UserDO updateUser(UserDO user) {
userMapper.updateById(user);
return user;
}
@CacheEvict(value = "user", key = "#id")
public void deleteUser(Long id) {
userMapper.deleteById(id);
}
```
### 消息队列
#### Redis 消息队列
```java
@Component
@RequiredArgsConstructor
public class SmsProducer {
private final RedisTemplate<String, Object> redisTemplate;
public void sendSmsSendMessage(Long userId, String mobile, String content) {
SmsSendMessage message = new SmsSendMessage()
.setUserId(userId)
.setMobile(mobile)
.setContent(content);
redisTemplate.convertAndSend("sms_send", message);
}
}
@Component
@RequiredArgsConstructor
public class SmsSendConsumer {
private final SmsService smsService;
@RedisStreamListener(stream = "sms_send", consumerGroup = "sms_send_group")
public void consumeSmsSendMessage(SmsSendMessage message) {
smsService.sendSms(message.getMobile(), message.getContent());
}
}
```
### 定时任务
#### Quartz 定时任务
```java
@Component
public class DemoJob extends QuartzJobBean {
@Autowired
private UserService userService;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
// 定时清理过期用户
userService.cleanExpiredUsers();
}
}
```
### 文件管理
#### 文件上传
```java
@RestController
@RequestMapping("/infra/file")
public class FileController {
@PostMapping("/upload")
public CommonResult<String> uploadFile(@RequestParam("file") MultipartFile file) {
// 1. 上传文件
String url = fileService.uploadFile(file);
// 2. 返回 URL
return success(url);
}
}
```
#### 文件存储
支持多种存储方式:
- 本地存储
- 阿里云 OSS
- 腾讯云 COS
- MinIO
- FTP / SFTP
### Excel 操作
#### 导入
```java
@PostMapping("/import")
public CommonResult<Integer> importUsers(@RequestParam("file") MultipartFile file) {
List<UserImportExcelVO> list = ExcelUtils.read(file, UserImportExcelVO.class);
return success(userService.importUsers(list));
}
```
#### 导出
```java
@GetMapping("/export")
public void exportUsers(HttpServletResponse response, UserPageReqVO pageReqVO) {
List<UserDO> list = userService.getUserList(pageReqVO);
ExcelUtils.write(response, "用户数据.xls", "用户列表", UserRespVO.class,
BeanConvertUtils.convertList(list, UserRespVO.class));
}
```
---
## 部署指南
### 本地部署
#### 1. 打包项目
```bash
cd lyzsys_backend
mvn clean package -DskipTests
```
#### 2. 上传文件
`lyzsys-server/target/lyzsys-server.jar` 上传到服务器
#### 3. 启动应用
```bash
java -jar lyzsys-server.jar --spring.profiles.active=prod
```
### Docker 部署
#### 1. 构建镜像
```bash
docker build -t lyzsys/lyzsys-server:latest .
```
#### 2. 运行容器
```bash
docker run -d \
--name lyzsys-server \
-p 48080:48080 \
-e SPRING_PROFILES_ACTIVE=prod \
-e SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/lyzsys \
-e SPRING_DATASOURCE_USERNAME=root \
-e SPRING_DATASOURCE_PASSWORD=password \
-e SPRING_DATA_REDIS_HOST=redis \
lyzsys/lyzsys-server:latest
```
### 配置说明
#### application.yaml
```yaml
spring:
# 数据源配置
datasource:
url: jdbc:mysql://127.0.0.1:3306/lyzsys?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
# Redis 配置
redis:
host: 127.0.0.1
port: 6379
database: 1
password:
timeout: 0
# 项目配置
lyzsys:
info:
base-package: cn.iocoder.lyzsys
web:
api-prefix: /admin-api
security:
mock-enable: true
upload:
base-url: http://127.0.0.1:48080
```
---
## 附录
### 常见问题
#### Q1: 如何添加新的业务模块?
1.`lyzsys-module-xxx` 目录下创建新模块
2. 按照标准模块结构创建包和类
3.`lyzsys-server/pom.xml` 中添加模块依赖
4.`application.yaml` 中配置模块扫描路径
#### Q2: 如何自定义异常?
1.`module-system/enums/ErrorCodeConstants.java` 中添加错误码
2. 使用 `throw exception(ERROR_CODE)` 抛出异常
3. 全局异常处理器会自动处理并返回统一格式
#### Q3: 如何实现数据权限?
1.`@Table` 注解中配置 `dataPermission` 属性
2. 使用 `@DataPermission` 注解标记需要数据权限的方法
3. 框架会自动添加数据权限过滤条件
### 参考资源
- [Spring Boot 官方文档](https://spring.io/projects/spring-boot)
- [MyBatis Plus 官方文档](https://baomidou.com/)
- [Flowable 官方文档](https://www.flowable.com/open-source/docs)
- [Redis 官方文档](https://redis.io/documentation)
- [芋道源码文档](https://doc.iocoder.cn/)
---
**文档版本**: v1.0.0
**最后更新**: 2025-01-19
**维护团队**: Lyzsys 开发团队

804
doc/常见问题.md Normal file
View File

@@ -0,0 +1,804 @@
# Lyzsys 常见问题 (FAQ)
## 📖 目录
- [快速导航](#快速导航)
- [后端开发问题](#后端开发问题)
- [前端开发问题](#前端开发问题)
- [部署运维问题](#部署运维问题)
- [性能优化问题](#性能优化问题)
- [功能定制问题](#功能定制问题)
- [故障排查问题](#故障排查问题)
---
## 快速导航
### 新手入门
- [如何快速开始?](#如何快速开始)
- [项目运行需要什么环境?](#项目运行需要什么环境)
- [如何获取项目源码?](#如何获取项目源码)
### 开发相关
- [如何添加新的业务模块?](#如何添加新的业务模块)
- [如何修改前端页面?](#如何修改前端页面)
- [如何自定义接口?](#如何自定义接口)
- [如何实现权限控制?](#如何实现权限控制)
### 部署相关
- [如何部署到生产环境?](#如何部署到生产环境)
- [如何配置数据库连接?](#如何配置数据库连接)
- [如何配置 SSL 证书?](#如何配置-ssl-证书)
- [如何进行性能优化?](#如何进行性能优化)
---
## 后端开发问题
### Q1: 如何快速开始?
**A**: 按照以下步骤操作:
1. **克隆项目**
```bash
git clone https://github.com/your-org/lyzsys.git
cd lyzsys/lyzsys_backend
```
2. **导入数据库**
```bash
mysql -u root -p < sql/lyzsys.sql
```
3. **修改配置**
```yaml
# application.yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/lyzsys
username: root
password: your_password
```
4. **启动项目**
```bash
mvn spring-boot:run
```
5. **访问系统**
- 后端地址: http://localhost:48080
- API 文档: http://localhost:48080/doc.html
### Q2: 如何添加新的业务模块?
**A**: 按照以下步骤创建新模块:
1. **创建模块目录**
```
lyzsys-module-xxx/
├── src/
│ └── main/
│ ├── java/
│ └── resources/
└── pom.xml
```
2. **创建模块 pom.xml**
```xml
<parent>
<groupId>cn.iocoder</groupId>
<artifactId>lyzsys-backend</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>lyzsys-module-xxx</artifactId>
<packaging>jar</packaging>
<dependencies>
<!-- 依赖其他模块 -->
</dependencies>
```
3. **创建标准包结构**
```
cn.iocoder.lyzsys.module.xxx/
├── api/
├── controller/
│ ├── admin/
│ └── app/
├── service/
├── dal/
│ ├── dataobject/
│ ├── mysql/
│ └── redis/
├── convert/
└── enums/
```
4. **在主 pom.xml 中添加模块**
```xml
<modules>
<module>lyzsys-module-xxx</module>
</modules>
```
5. **在 lyzsys-server 中引入**
```xml
<dependency>
<groupId>cn.iocoder</groupId>
<artifactId>lyzsys-module-xxx</artifactId>
</dependency>
```
### Q3: 如何实现权限控制?
**A**: Lyzsys 提供了多层次的权限控制:
#### 1. 接口权限
使用 `@PreAuthorize` 注解:
```java
@PostMapping("/create")
@PreAuthorize("@ss.hasPermission('system:user:create')")
public CommonResult<Long> createUser(@Valid @RequestBody UserCreateReqVO reqVO) {
return success(userService.createUser(reqVO));
}
```
#### 2. 数据权限
使用 `@DataScope` 注解:
```java
@DataScope(deptAlias = "d", userAlias = "u")
public List<UserDO> getUserList() {
return userMapper.selectList();
}
```
#### 3. 前端权限
使用权限指令:
```vue
<!-- 有权限时显示 -->
<el-button v-hasPermi="['system:user:create']">创建</el-button>
<!-- 有角色时显示 -->
<el-button v-hasRole="['admin']">管理员操作</el-button>
```
### Q4: 如何使用代码生成器?
**A**: 代码生成器使用步骤:
1. **访问代码生成**
- 登录系统后,进入「基础设施」→「代码生成」
2. **导入数据库表**
- 点击「导入」按钮
- 选择要生成的表
3. **配置生成信息**
- 基本信息:模块名、业务名、功能名
- 生成信息:包路径、模块名、业务名
- 字段信息:字段显示、查询条件、必填项
4. **生成代码**
- 点击「生成代码」按钮
- 下载代码压缩包
5. **导入项目**
- 解压代码到对应模块
- 创建菜单和权限
### Q5: 如何实现文件上传?
**A**: 文件上传实现步骤:
#### 1. 配置文件存储
```yaml
lyzsys:
upload:
base-url: http://your-domain.com
storage:
minio:
endpoint: http://localhost:9000
access-key: your_access_key
secret-key: your_secret_key
bucket-name: lyzsys
```
#### 2. 后端上传
```java
@PostMapping("/upload")
public CommonResult<String> uploadFile(@RequestParam("file") MultipartFile file) {
String url = fileService.uploadFile(file);
return success(url);
}
```
#### 3. 前端上传
```vue
<el-upload
:action="uploadUrl"
:headers="uploadHeaders"
:on-success="handleSuccess"
>
<el-button type="primary">上传文件</el-button>
</el-upload>
```
### Q6: 如何使用 Redis 缓存?
**A**: Redis 缓存使用方法:
#### 1. 使用 Spring Cache
```java
@Cacheable(value = "user", key = "#id")
public UserDO getUser(Long id) {
return userMapper.selectById(id);
}
@CachePut(value = "user", key = "#user.id")
public UserDO updateUser(UserDO user) {
userMapper.updateById(user);
return user;
}
@CacheEvict(value = "user", key = "#id")
public void deleteUser(Long id) {
userMapper.deleteById(id);
}
```
#### 2. 使用 RedisTemplate
```java
@Autowired
private RedisTemplate<String, UserDO> redisTemplate;
public UserDO getUser(Long id) {
String key = "user:" + id;
UserDO user = redisTemplate.opsForValue().get(key);
if (user == null) {
user = userMapper.selectById(id);
redisTemplate.opsForValue().set(key, user, 1, TimeUnit.HOURS);
}
return user;
}
```
---
## 前端开发问题
### Q7: 如何修改前端页面?
**A**: 前端页面修改步骤:
1. **找到页面文件**
- 页面文件位于 `src/views/` 目录
- 按照模块分类,如 `src/views/system/user/`
2. **修改页面内容**
```vue
<template>
<div class="user-list">
<!-- 页面内容 -->
</div>
</template>
<script setup lang="ts">
// 脚本逻辑
</script>
<style scoped lang="scss">
// 样式
</style>
```
3. **热更新**
- 修改后自动热更新,无需重启
4. **构建测试**
```bash
pnpm build:prod
```
### Q8: 如何调用后端 API
**A**: API 调用方法:
#### 1. 定义 API
```typescript
// src/api/system/user/index.ts
import request from '@/utils/request'
export function getUserPage(params: UserPageReqVO) {
return request.get({ url: '/system/user/page', params })
}
export function createUser(data: UserCreateReqVO) {
return request.post({ url: '/system/user/create', data })
}
```
#### 2. 调用 API
```vue
<script setup lang="ts">
import { ref } from 'vue'
import { getUserPage } from '@/api/system/user'
const loading = ref(false)
const tableData = ref([])
async function fetchUsers() {
loading.value = true
try {
const { data } = await getUserPage({
pageNo: 1,
pageSize: 10
})
tableData.value = data.list
} finally {
loading.value = false
}
}
</script>
```
### Q9: 如何实现国际化?
**A**: 国际化实现步骤:
#### 1. 添加语言文件
```typescript
// src/locales/zh-CN/common.ts
export default {
title: 'Lyzsys 管理系统',
logout: '退出登录'
}
```
```typescript
// src/locales/en/common.ts
export default {
title: 'Lyzsys Admin',
logout: 'Logout'
}
```
#### 2. 使用翻译
```vue
<template>
<h1>{{ $t('common.title') }}</h1>
</template>
<script setup lang="ts">
import { useI18n } from '@/hooks/web/useI18n'
const { t } = useI18n()
const title = t('common.title')
</script>
```
### Q10: 如何自定义主题?
**A**: 主题定制方法:
#### 1. 修改主题色
```scss
// styles/variables.scss
$primary-color: #409eff;
$success-color: #67c23a;
$warning-color: #e6a23c;
$danger-color: #f56c6c;
```
#### 2. 动态切换主题
```typescript
import { useAppStore } from '@/store/modules/app'
const appStore = useAppStore()
// 切换暗黑模式
function toggleDarkMode() {
appStore.setDarkMode(!appStore.getDarkMode)
}
```
### Q11: 如何使用 Element Plus 组件?
**A**: Element Plus 组件使用:
#### 1. 表格组件
```vue
<el-table :data="tableData" border>
<el-table-column prop="name" label="姓名" />
<el-table-column prop="email" label="邮箱" />
<el-table-column label="操作">
<template #default="{ row }">
<el-button link @click="handleEdit(row)">编辑</el-button>
</template>
</el-table-column>
</el-table>
```
#### 2. 表单组件
```vue
<el-form :model="form" :rules="rules" ref="formRef">
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSubmit">提交</el-button>
</el-form-item>
</el-form>
```
#### 3. 对话框组件
```vue
<el-dialog v-model="visible" title="提示">
<span>这是一段内容</span>
<template #footer>
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="visible = false">确定</el-button>
</template>
</el-dialog>
```
---
## 部署运维问题
### Q12: 如何部署到生产环境?
**A**: 生产部署步骤:
#### 后端部署
1. **打包项目**
```bash
mvn clean package -DskipTests
```
2. **上传到服务器**
```bash
scp lyzsys-server.jar user@server:/opt/lyzsys/
```
3. **启动服务**
```bash
java -jar lyzsys-server.jar --spring.profiles.active=prod
```
#### 前端部署
1. **构建项目**
```bash
pnpm build:prod
```
2. **部署到 Nginx**
```bash
scp -r dist/* user@server:/var/www/lyzsys/
```
3. **配置 Nginx**
```nginx
server {
listen 80;
server_name your-domain.com;
root /var/www/lyzsys;
location / {
try_files $uri $uri/ /index.html;
}
location /admin-api/ {
proxy_pass http://localhost:48080/admin-api/;
}
}
```
### Q13: 如何配置数据库连接?
**A**: 数据库连接配置:
```yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/lyzsys?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
# 连接池配置
hikari:
minimum-idle: 5
maximum-pool-size: 20
idle-timeout: 30000
connection-timeout: 30000
```
### Q14: 如何配置 SSL 证书?
**A**: SSL 证书配置步骤:
1. **获取证书**
```bash
certbot certonly --standalone -d your-domain.com
```
2. **配置 Nginx**
```nginx
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
}
server {
listen 80;
server_name your-domain.com;
return 301 https://$server_name$request_uri;
}
```
### Q15: 如何进行备份和恢复?
**A**: 备份恢复方法:
#### 数据库备份
```bash
# 备份
mysqldump -u root -p lyzsys > lyzsys_backup.sql
# 恢复
mysql -u root -p lyzsys < lyzsys_backup.sql
```
#### 文件备份
```bash
# 备份
tar -czf lyzsys_backup.tar.gz /var/www/lyzsys
# 恢复
tar -xzf lyzsys_backup.tar.gz -C /
```
---
## 性能优化问题
### Q16: 如何进行性能优化?
**A**: 性能优化建议:
#### 后端优化
1. **数据库优化**
- 添加索引
- 优化 SQL
- 使用缓存
2. **代码优化**
- 批量操作
- 异步处理
- 减少数据库查询
3. **JVM 优化**
```bash
java -Xms2g -Xmx2g \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-jar lyzsys-server.jar
```
#### 前端优化
1. **代码分割**
```typescript
const UserList = defineAsyncComponent(() => import('./views/system/user/index.vue'))
```
2. **资源优化**
- 压缩代码
- 使用 CDN
- 图片优化
3. **缓存优化**
- 浏览器缓存
- 本地存储
- Service Worker
### Q17: 如何处理高并发?
**A**: 高并发处理方案:
1. **水平扩展**
- 应用集群
- 负载均衡
- 数据库主从
2. **缓存策略**
- Redis 缓存
- 本地缓存
- 缓存预热
3. **异步处理**
- 消息队列
- 异步任务
- 线程池
4. **限流降级**
- 接口限流
- 服务降级
- 熔断保护
---
## 功能定制问题
### Q18: 如何修改 Logo 和标题?
**A**: 品牌定制方法:
#### 1. 修改前端
```typescript
// src/config/index.ts
export default {
title: '你的系统名称',
logo: '/logo.png'
}
```
#### 2. 修改后端
```yaml
lyzsys:
info:
name: '你的系统名称'
version: '1.0.0'
```
### Q19: 如何集成第三方服务?
**A**: 第三方集成方法:
#### 1. 短信集成
```java
@Service
public class SmsServiceImpl implements SmsService {
@Autowired
private SmsClient smsClient;
public void sendSms(String mobile, String content) {
SmsSendReqDTO req = new SmsSendReqDTO();
req.setMobile(mobile);
req.setContent(content);
smsClient.send(req);
}
}
```
#### 2. 支付集成
```java
@Service
public class PayServiceImpl implements PayService {
@Autowired
private PayClient payClient;
public String createOrder(PayOrderCreateReqDTO req) {
return payClient.createOrder(req);
}
}
```
---
## 故障排查问题
### Q20: 如何查看错误日志?
**A**: 日志查看方法:
#### 后端日志
```bash
# 查看应用日志
tail -f logs/lyzsys.log
# 查看错误日志
grep ERROR logs/lyzsys.log
# 查看 Nginx 日志
tail -f /var/log/nginx/error.log
```
#### 前端日志
```javascript
// 浏览器控制台
console.log('日志信息')
console.error('错误信息')
// 网络请求
// Network 标签查看请求详情
```
### Q21: 常见错误及解决方案
#### 1. 数据库连接失败
**错误**: `Could not get JDBC Connection`
**解决方案**:
- 检查数据库是否启动
- 检查连接信息是否正确
- 检查防火墙是否开放端口
#### 2. Redis 连接失败
**错误**: `Unable to connect to Redis`
**解决方案**:
- 检查 Redis 是否启动
- 检查 Redis 密码是否正确
- 检查 Redis 地址是否正确
#### 3. 前端页面空白
**错误**: 页面无法显示
**解决方案**:
- 检查 Nginx 配置
- 检查前端路由配置
- 检查浏览器控制台错误
#### 4. API 请求失败
**错误**: `Network Error`
**解决方案**:
- 检查后端服务是否启动
- 检查 API 地址是否正确
- 检查跨域配置
---
**文档版本**: v1.0.0
**最后更新**: 2025-01-19
**维护团队**: Lyzsys 开发团队

697
doc/数据库设计.md Normal file
View File

@@ -0,0 +1,697 @@
# Lyzsys 数据库设计文档
## 📖 目录
- [数据库概述](#数据库概述)
- [设计规范](#设计规范)
- [核心表设计](#核心表设计)
- [索引设计](#索引设计)
- [数据字典](#数据字典)
- [多租户设计](#多租户设计)
- [数据库优化](#数据库优化)
- [数据库管理](#数据库管理)
---
## 数据库概述
### 技术选型
| 特性 | 说明 |
|------|------|
| 数据库 | MySQL 5.7+ / 8.0+ |
| 字符集 | utf8mb4 |
| 排序规则 | utf8mb4_unicode_ci |
| 引擎 | InnoDB |
| 时区 | Asia/Shanghai |
### 支持的数据库
- MySQL 5.7、8.0+
- PostgreSQL 9.6+
| Oracle 11g+
| SQL Server 2012+
| H2 2.x (开发测试)
### 数据库特点
1. **多数据库支持**: 通过 MyBatis Plus 实现
2. **租户隔离**: 支持多租户数据隔离
3. **逻辑删除**: 支持软删除
4. **数据权限**: 支持行级数据权限
5. **审计日志**: 完整的创建、更新日志
---
## 设计规范
### 命名规范
#### 数据库命名
- 格式: `lyzsys`
- 示例: `lyzsys`
#### 表命名
- 格式: `{模块}_{业务}_{实体}`
- 规则: 小写字母 + 下划线
- 示例:
- `system_users` - 系统用户表
- `system_roles` - 系统角色表
- `mall_orders` - 商城订单表
- `bpm_process_instance` - 工作流实例表
#### 字段命名
- 格式: 小写字母 + 下划线
- 规则: 使用有意义的单词组合
- 示例:
- `user_id` - 用户 ID
- `user_name` - 用户名
- `create_time` - 创建时间
- `update_time` - 更新时间
#### 索引命名
- 主键索引: `PRIMARY`
- 唯一索引: `uniq_{字段名}`
- 普通索引: `idx_{字段名}`
- 示例:
- `uniq_username` - 用户名唯一索引
- `idx_dept_id` - 部门 ID 普通索引
### 字段类型
#### 整数类型
| 类型 | 字节 | 范围 | 用途 |
|------|------|------|------|
| TINYINT | 1 | -128 ~ 127 | 状态、标识 |
| SMALLINT | 2 | -32768 ~ 32767 | 枚举值 |
| INT | 4 | -21亿 ~ 21亿 | 数量、序号 |
| BIGINT | 8 | 极大数值 | 主键、外键 |
#### 字符串类型
| 类型 | 长度 | 用途 |
|------|------|------|
| CHAR | 0-255 | 固定长度字符串 |
| VARCHAR | 0-65535 | 变长字符串 |
| TEXT | 0-65535 | 长文本 |
| LONGTEXT | 0-4294967295 | 超长文本 |
#### 日期时间类型
| 类型 | 格式 | 用途 |
|------|------|------|
| DATE | YYYY-MM-DD | 日期 |
| DATETIME | YYYY-MM-DD HH:MM:SS | 日期时间 |
| TIMESTAMP | 时间戳 | 时间戳 |
#### 小数类型
| 类型 | 用途 |
|------|------|
| DECIMAL(M,D) | 金额、精度数值 |
### 通用字段
每张表都包含以下通用字段:
```sql
-- 主键
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键'
-- 创建信息
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
creator VARCHAR(64) COMMENT '创建人'
-- 更新信息
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
updater VARCHAR(64) COMMENT '更新人'
-- 删除标记
deleted BIT NOT NULL DEFAULT FALSE COMMENT '是否删除'
-- 租户 ID (多租户表)
tenant_id BIGINT NOT NULL COMMENT '租户 ID'
```
---
## 核心表设计
### 系统管理模块
#### 1. 用户表 (system_users)
```sql
CREATE TABLE `system_users` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`username` VARCHAR(30) NOT NULL COMMENT '用户账号',
`password` VARCHAR(100) NOT NULL COMMENT '密码',
`nickname` VARCHAR(30) NOT NULL COMMENT '用户昵称',
`remark` VARCHAR(500) COMMENT '备注',
`dept_id` BIGINT NOT NULL COMMENT '部门ID',
`post_ids` VARCHAR(255) COMMENT '岗位编号数组',
`email` VARCHAR(50) COMMENT '用户邮箱',
`mobile` VARCHAR(11) COMMENT '手机号码',
`sex` TINYINT COMMENT '用户性别',
`avatar` VARCHAR(100) COMMENT '头像地址',
`status` TINYINT NOT NULL DEFAULT 0 COMMENT '帐号状态0正常 1停用',
`login_ip` VARCHAR(50) COMMENT '最后登录IP',
`login_date` DATETIME COMMENT '最后登录时间',
`tenant_id` BIGINT NOT NULL COMMENT '租户 ID',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`creator` VARCHAR(64) COMMENT '创建人',
`updater` VARCHAR(64) COMMENT '更新人',
`deleted` BIT NOT NULL DEFAULT FALSE COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `uniq_username` (`username`, `update_time`, `tenant_id`, `deleted`)
) ENGINE=InnoDB COMMENT='用户信息表';
```
#### 2. 角色表 (system_roles)
```sql
CREATE TABLE `system_roles` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '角色ID',
`name` VARCHAR(30) NOT NULL COMMENT '角色名称',
`code` VARCHAR(100) NOT NULL COMMENT '角色权限字符串',
`sort` INT NOT NULL COMMENT '显示顺序',
`data_scope` TINYINT NOT NULL DEFAULT 1 COMMENT '数据范围1全部数据权限 2本部门及以下数据权限 3本部门数据权限 4仅本人数据权限',
`data_scope_dept_ids` VARCHAR(500) COMMENT '数据范围-部门数组',
`status` TINYINT NOT NULL COMMENT '角色状态0正常 1停用',
`type` TINYINT NOT NULL COMMENT '角色类型1系统内置 2自定义',
`remark` VARCHAR(500) COMMENT '备注',
`tenant_id` BIGINT NOT NULL COMMENT '租户 ID',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`creator` VARCHAR(64) COMMENT '创建人',
`updater` VARCHAR(64) COMMENT '更新人',
`deleted` BIT NOT NULL DEFAULT FALSE COMMENT '是否删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='角色信息表';
```
#### 3. 菜单表 (system_menu)
```sql
CREATE TABLE `system_menu` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '菜单ID',
`name` VARCHAR(50) NOT NULL COMMENT '菜单名称',
`permission` VARCHAR(100) NOT NULL COMMENT '权限标识',
`type` TINYINT NOT NULL COMMENT '菜单类型1目录 2菜单 3按钮',
`sort` INT NOT NULL DEFAULT 0 COMMENT '显示顺序',
`parent_id` BIGINT NOT NULL DEFAULT 0 COMMENT '父菜单ID',
`path` VARCHAR(200) COMMENT '路由地址',
`icon` VARCHAR(100) COMMENT '菜单图标',
`component` VARCHAR(255) COMMENT '组件路径',
`component_name` VARCHAR(255) COMMENT '组件名',
`status` TINYINT NOT NULL DEFAULT 0 COMMENT '菜单状态0正常 1停用',
`visible` BIT NOT NULL DEFAULT TRUE COMMENT '是否可见',
`keep_alive` BIT NOT NULL DEFAULT FALSE COMMENT '是否缓存',
`always_show` BIT NOT NULL DEFAULT FALSE COMMENT '是否总是显示',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`creator` VARCHAR(64) COMMENT '创建人',
`updater` VARCHAR(64) COMMENT '更新人',
`deleted` BIT NOT NULL DEFAULT FALSE COMMENT '是否删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='菜单权限表';
```
#### 4. 部门表 (system_dept)
```sql
CREATE TABLE `system_dept` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '部门id',
`parent_id` BIGINT NOT NULL DEFAULT 0 COMMENT '父部门id',
`name` VARCHAR(30) NOT NULL COMMENT '部门名称',
`sort` INT NOT NULL DEFAULT 0 COMMENT '显示顺序',
`leader_user_id` BIGINT COMMENT '负责人',
`phone` VARCHAR(11) COMMENT '联系电话',
`email` VARCHAR(64) COMMENT '邮箱',
`status` TINYINT NOT NULL COMMENT '部门状态0正常 1停用',
`tenant_id` BIGINT NOT NULL COMMENT '租户 ID',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`creator` VARCHAR(64) COMMENT '创建人',
`updater` VARCHAR(64) COMMENT '更新人',
`deleted` BIT NOT NULL DEFAULT FALSE COMMENT '是否删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='部门表';
```
#### 5. 字典表 (system_dict_type)
```sql
CREATE TABLE `system_dict_type` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '字典主键',
`name` VARCHAR(100) NOT NULL COMMENT '字典名称',
`type` VARCHAR(100) NOT NULL COMMENT '字典类型',
`status` TINYINT NOT NULL DEFAULT 0 COMMENT '状态0正常 1停用',
`remark` VARCHAR(500) COMMENT '备注',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`creator` VARCHAR(64) COMMENT '创建人',
`updater` VARCHAR(64) COMMENT '更新人',
`deleted` BIT NOT NULL DEFAULT FALSE COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `uniq_type` (`type`, `update_time`, `deleted`)
) ENGINE=InnoDB COMMENT='字典类型表';
```
### 基础设施模块
#### 6. 代码生成表 (infra_codegen_column)
```sql
CREATE TABLE `infra_codegen_column` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '编号',
`table_id` BIGINT NOT NULL COMMENT '表编号',
`column_name` VARCHAR(200) NOT NULL COMMENT '字段名',
`data_type` VARCHAR(100) NOT NULL COMMENT '字段类型',
`column_comment` VARCHAR(500) COMMENT '字段描述',
`nullable` BIT NOT NULL COMMENT '是否允许为空',
`pk` BIT NOT NULL COMMENT '是否主键',
`ordinal_position` INT NOT NULL COMMENT '排序',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`creator` VARCHAR(64) COMMENT '创建人',
`updater` VARCHAR(64) COMMENT '更新人',
`deleted` BIT NOT NULL DEFAULT FALSE COMMENT '是否删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='代码生成字段表';
```
#### 7. 定时任务表 (infra_job)
```sql
CREATE TABLE `infra_job` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '任务ID',
`name` VARCHAR(200) NOT NULL COMMENT '任务名称',
`status` TINYINT NOT NULL COMMENT '任务状态',
`handler_name` VARCHAR(200) NOT NULL COMMENT '处理器的名字',
`handler_param` VARCHAR(500) COMMENT '处理器的参数',
`cron_expression` VARCHAR(100) NOT NULL COMMENT 'Cron 表达式',
`retry_count` INT NOT NULL DEFAULT 0 COMMENT '重试次数',
`retry_interval` INT NOT NULL DEFAULT 0 COMMENT '重试间隔',
`monitor_timeout` INT NOT NULL DEFAULT 0 COMMENT '监控超时时间',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`creator` VARCHAR(64) COMMENT '创建人',
`updater` VARCHAR(64) COMMENT '更新人',
`deleted` BIT NOT NULL DEFAULT FALSE COMMENT '是否删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='定时任务表';
```
### 工作流模块
#### 8. 流程实例表 (bpm_process_instance)
```sql
CREATE TABLE `bpm_process_instance` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '编号',
`process_definition_id` VARCHAR(64) NOT NULL COMMENT '流程定义的编号',
`process_instance_id` VARCHAR(64) NOT NULL COMMENT '流程实例的编号',
`start_user_id` BIGINT NOT NULL COMMENT '发起人的用户编号',
`name` VARCHAR(255) COMMENT '流程实例的名字',
`business_key` VARCHAR(64) COMMENT '业务标识',
`status` TINYINT NOT NULL COMMENT '流程实例的状态',
`tenant_id` BIGINT NOT NULL COMMENT '租户 ID',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`creator` VARCHAR(64) COMMENT '创建人',
`updater` VARCHAR(64) COMMENT '更新人',
`deleted` BIT NOT NULL DEFAULT FALSE COMMENT '是否删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='流程实例表';
```
### 商城模块
#### 9. 商品表 (mall_product)
```sql
CREATE TABLE `mall_product` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '商品编号',
`name` VARCHAR(200) NOT NULL COMMENT '商品名称',
`sell_point` VARCHAR(500) COMMENT '卖点',
`description` VARCHAR(2000) COMMENT '商品详情',
`category_id` BIGINT NOT NULL COMMENT '分类编号',
`brand_id` BIGINT COMMENT '品牌编号',
`price` BIGINT NOT NULL COMMENT '价格,单位:分',
`stock` INT NOT NULL COMMENT '库存',
`pic_url` VARCHAR(500) COMMENT '商品主图',
`status` TINYINT NOT NULL COMMENT '商品状态',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`creator` VARCHAR(64) COMMENT '创建人',
`updater` VARCHAR(64) COMMENT '更新人',
`deleted` BIT NOT NULL DEFAULT FALSE COMMENT '是否删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='商品表';
```
#### 10. 订单表 (mall_order)
```sql
CREATE TABLE `mall_order` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '订单编号',
`user_id` BIGINT NOT NULL COMMENT '用户编号',
`order_no` VARCHAR(64) NOT NULL COMMENT '订单号',
`total_price` BIGINT NOT NULL COMMENT '订单总价,单位:分',
`status` TINYINT NOT NULL COMMENT '订单状态',
`pay_time` DATETIME COMMENT '付款时间',
`delivery_time` DATETIME COMMENT '发货时间',
`receiver_time` DATETIME COMMENT '收货时间',
`comment_time` DATETIME COMMENT '评论时间',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`creator` VARCHAR(64) COMMENT '创建人',
`updater` VARCHAR(64) COMMENT '更新人',
`deleted` BIT NOT NULL DEFAULT FALSE COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `uniq_order_no` (`order_no`)
) ENGINE=InnoDB COMMENT='订单表';
```
---
## 索引设计
### 索引类型
#### 1. 主键索引 (PRIMARY KEY)
每张表都有主键索引:
```sql
PRIMARY KEY (`id`)
```
#### 2. 唯一索引 (UNIQUE)
用于保证字段的唯一性:
```sql
UNIQUE KEY `uniq_username` (`username`, `update_time`, `tenant_id`, `deleted`)
```
#### 3. 普通索引 (INDEX)
用于提升查询性能:
```sql
KEY `idx_dept_id` (`dept_id`)
```
#### 4. 联合索引
用于多字段查询:
```sql
KEY `idx_user_id_status` (`user_id`, `status`)
```
### 索引规范
1. **主键索引**: 使用自增 BIGINT
2. **唯一索引**: 业务唯一字段
3. **普通索引**: 频繁查询的字段
4. **联合索引**: 多字段组合查询,遵循最左前缀原则
5. **索引数量**: 单表索引不超过 5 个
### 索引示例
```sql
-- 用户表索引
PRIMARY KEY (`id`)
UNIQUE KEY `uniq_username` (`username`, `update_time`, `tenant_id`, `deleted`)
KEY `idx_dept_id` (`dept_id`)
KEY `idx_status` (`status`)
-- 订单表索引
PRIMARY KEY (`id`)
UNIQUE KEY `uniq_order_no` (`order_no`)
KEY `idx_user_id` (`user_id`)
KEY `idx_status` (`status`)
KEY `idx_create_time` (`create_time`)
```
---
## 数据字典
### 通用数据字典
#### 1. 用户性别 (system_user_sex)
| 字典值 | 字典标签 | 颜色 |
|--------|----------|------|
| 1 | 男 | blue |
| 2 | 女 | pink |
| 3 | 未知 | gray |
#### 2. 用户状态 (system_common_status)
| 字典值 | 字典标签 | 颜色 |
|--------|----------|------|
| 0 | 启用 | success |
| 1 | 停用 | danger |
#### 3. 菜单类型 (system_menu_type)
| 字典值 | 字典标签 | 颜色 |
|--------|----------|------|
| 1 | 目录 | |
| 2 | 菜单 | |
| 3 | 按钮 | |
#### 4. 数据范围 (system_data_scope)
| 字典值 | 字典标签 |
|--------|----------|
| 1 | 全部数据权限 |
| 2 | 本部门及以下数据权限 |
| 3 | 本部门数据权限 |
| 4 | 仅本人数据权限 |
#### 5. 流程实例状态 (bpm_process_instance_status)
| 字典值 | 字典标签 | 颜色 |
|--------|----------|------|
| 1 | 进行中 | primary |
| 2 | 已结束 | success |
---
## 多租户设计
### 租户隔离策略
#### 1. 共享数据库、共享 Schema
所有租户共享同一个数据库,通过 `tenant_id` 字段隔离。
#### 2. 自动过滤
MyBatis Plus 拦截器自动添加租户条件:
```java
// 查询时自动添加租户条件
List<UserDO> users = userMapper.selectList();
// 实际 SQL
SELECT * FROM system_users
WHERE deleted = 0
AND tenant_id = 1
```
### 租户表设计
#### 租户表 (system_tenant)
```sql
CREATE TABLE `system_tenant` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '租户编号',
`name` VARCHAR(30) NOT NULL COMMENT '租户名',
`contact_user_id` BIGINT NOT NULL COMMENT '联系人的用户编号',
`contact_name` VARCHAR(30) NOT NULL COMMENT '联系人',
`contact_mobile` VARCHAR(11) COMMENT '联系手机',
`status` TINYINT NOT NULL COMMENT '租户状态',
`website` VARCHAR(256) COMMENT '绑定域名',
`package_id` BIGINT NOT NULL COMMENT '租户套餐编号',
`expire_time` DATETIME NOT NULL COMMENT '过期时间',
`account_count` INT NOT NULL COMMENT '账号数量',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`creator` VARCHAR(64) COMMENT '创建人',
`updater` VARCHAR(64) COMMENT '更新人',
`deleted` BIT NOT NULL DEFAULT FALSE COMMENT '是否删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='租户表';
```
#### 租户套餐表 (system_tenant_package)
```sql
CREATE TABLE `system_tenant_package` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '套餐编号',
`name` VARCHAR(30) NOT NULL COMMENT '套餐名',
`status` TINYINT NOT NULL COMMENT '套餐状态',
`remark` VARCHAR(500) COMMENT '备注',
`menu_ids` VARCHAR(500) NOT NULL COMMENT '关联的菜单编号',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`creator` VARCHAR(64) COMMENT '创建人',
`updater` VARCHAR(64) COMMENT '更新人',
`deleted` BIT NOT NULL DEFAULT FALSE COMMENT '是否删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='租户套餐表';
```
---
## 数据库优化
### SQL 优化
#### 1. 避免全表扫描
```sql
-- 不推荐
SELECT * FROM system_users
-- 推荐
SELECT id, username, nickname FROM system_users
```
#### 2. 使用索引
```sql
-- 不推荐
SELECT * FROM system_users WHERE SUBSTRING(username, 1, 3) = 'adm'
-- 推荐
SELECT * FROM system_users WHERE username LIKE 'adm%'
```
#### 3. 分页查询
```sql
-- 使用分页插件
SELECT * FROM system_users
LIMIT 10 OFFSET 0
```
### 表结构优化
#### 1. 字段类型选择
```sql
-- 不推荐
VARCHAR(1000) -- 过长
-- 推荐
VARCHAR(200) -- 合理长度
```
#### 2. 字段数量控制
单表字段数量不超过 50 个。
#### 3. 表分区
大表可以采用分区策略:
```sql
-- 按时间分区
CREATE TABLE `system_operate_log` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`create_time` DATETIME NOT NULL,
PRIMARY KEY (`id`, `create_time`)
) ENGINE=InnoDB
PARTITION BY RANGE (TO_DAYS(create_time)) (
PARTITION p202301 VALUES LESS THAN (TO_DAYS('2023-02-01')),
PARTITION p202302 VALUES LESS THAN (TO_DAYS('2023-03-01'))
);
```
---
## 数据库管理
### 数据库备份
#### 1. 逻辑备份
```bash
# 备份
mysqldump -u root -p lyzsys > lyzsys_backup.sql
# 恢复
mysql -u root -p lyzsys < lyzsys_backup.sql
```
#### 2. 物理备份
```bash
# 复制数据文件
cp -r /var/lib/mysql/lyzsys /backup/lyzsys
```
### 数据库监控
#### 1. 慢查询日志
```sql
-- 开启慢查询日志
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 2;
```
#### 2. 性能监控
```sql
-- 查看连接数
SHOW PROCESSLIST;
-- 查看状态
SHOW STATUS;
```
### 数据库维护
#### 1. 表优化
```sql
-- 优化表
OPTIMIZE TABLE system_users;
-- 分析表
ANALYZE TABLE system_users;
-- 修复表
REPAIR TABLE system_users;
```
#### 2. 索引优化
```sql
-- 查看索引使用情况
SHOW INDEX FROM system_users;
-- 删除无用索引
DROP INDEX idx_unused ON system_users;
```
---
**文档版本**: v1.0.0
**最后更新**: 2025-01-19
**维护团队**: Lyzsys 数据库团队

734
doc/架构设计.md Normal file
View File

@@ -0,0 +1,734 @@
# Lyzsys 架构设计文档
## 📖 目录
- [架构概述](#架构概述)
- [架构设计原则](#架构设计原则)
- [分层架构](#分层架构)
- [模块化设计](#模块化设计)
- [数据架构](#数据架构)
- [安全架构](#安全架构)
- [技术架构](#技术架构)
- [部署架构](#部署架构)
- [性能优化](#性能优化)
- [扩展性设计](#扩展性设计)
---
## 架构概述
### 整体架构
Lyzsys 采用**前后端分离**的**模块化单体架构**,基于**领域驱动设计DDD**思想进行模块划分,支持未来向微服务架构演进。
```
┌─────────────────────────────────────────────────────────────────┐
│ 客户端层 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Web 浏览器 │ │ 移动 App │ │ 小程序 │ │
│ │ (Vue3) │ │ (UniApp) │ │ (UniApp) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 接入层 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Nginx / │ │ API 网关 │ │ 负载均衡 │ │
│ │ CDN │ │ (可选) │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 应用层 │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ lyzsys-server │ │
│ │ (Spring Boot 应用) │ │
│ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │
│ │ │ Controller │ │ Service │ │ DAL │ │ │
│ │ │ 层 │ │ 层 │ │ 层 │ │ │
│ │ └────────────┘ └────────────┘ └────────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────┼─────────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────────┐ ┌──────────────┐
│lyzsys-module-│ │lyzsys-module-xxx │ │lyzsys-module-│
│ system │ │ (业务模块) │ │ infra │
└──────────────┘ └──────────────────┘ └──────────────┘
┌─────────────────────┼─────────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────────┐ ┌──────────────┐
│lyzsys- │ │lyzsys-framework │ │lyzsys- │
│dependencies │ │ (框架组件) │ │common │
└──────────────┘ └──────────────────┘ └──────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 数据层 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ MySQL │ │ Redis │ │ MinIO │ │
│ │ (主数据库) │ │ (缓存) │ │ (文件存储) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 外部服务 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ AI 服务 │ │ 短信服务 │ │ 支付服务 │ │
│ │ (OpenAI等) │ │ (阿里云等) │ │ (微信等) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
### 架构特点
1. **前后端分离**: 前端和后端独立开发、部署、扩展
2. **模块化设计**: 业务模块独立,低耦合、高内聚
3. **分层架构**: 清晰的分层,职责明确
4. **微服务就绪**: 模块化设计便于微服务化改造
5. **多租户支持**: 原生支持 SaaS 多租户场景
6. **高可用**: 支持集群部署,无状态设计
---
## 架构设计原则
### 1. 单一职责原则 (SRP)
每个模块、每个类只负责一个职责。
**示例**:
- `UserController` 只负责接收 HTTP 请求
- `UserService` 只负责业务逻辑处理
- `UserMapper` 只负责数据库操作
### 2. 开闭原则 (OCP)
对扩展开放,对修改关闭。
**示例**:
- 通过实现接口扩展功能,而非修改原有代码
- 使用策略模式实现不同的支付方式
### 3. 里氏替换原则 (LSP)
子类可以替换父类。
**示例**:
- `UserServiceImpl` 可以替换 `UserService`
- `BaseMapperX` 可以替换 `BaseMapper`
### 4. 接口隔离原则 (ISP)
使用多个细粒度的接口,而非单一的总接口。
**示例**:
- `UserService``RoleService``MenuService` 各司其职
- 前端 API 按模块划分(`/system/user``/system/role`
### 5. 依赖倒置原则 (DIP)
高层模块不依赖低层模块,都依赖于抽象。
**示例**:
- Controller 依赖 Service 接口,而非实现
- Service 依赖 Mapper 接口,而非实现
### 6. 迪米特法则 (LoD)
最少知识原则,模块之间尽量少交互。
**示例**:
- 模块之间通过 API 接口交互
- 避免跨层调用(如 Controller 直接调用 Mapper
---
## 分层架构
### 应用分层
```
┌─────────────────────────────────────────────────────────────┐
│ Controller 层 │
│ • 接收 HTTP 请求 │
│ • 参数校验 │
│ • 调用 Service 层 │
│ • 返回响应 │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Service 层 │
│ • 业务逻辑处理 │
│ • 事务控制 │
│ • 调用 DAL 层 │
│ • 返回处理结果 │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ DAL 层 │
│ • 数据访问 │
│ • 数据库操作 │
│ • 缓存操作 │
│ • 返回数据对象 │
└─────────────────────────────────────────────────────────────┘
```
### 层次交互规则
1. **自上而下调用**: Controller → Service → DAL
2. **跨层访问**: 允许 Service 直接调用多个 DAL
3. **禁止反向调用**: 下层不能调用上层
4. **同层交互**: 同层之间通过接口交互
### 分层示例
#### Controller 层
```java
@RestController
@RequestMapping("/system/user")
@Tag(name = "管理后台 - 用户")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/create")
@Operation(summary = "创建用户")
public CommonResult<Long> createUser(@Valid @RequestBody UserCreateReqVO reqVO) {
return success(userService.createUser(reqVO));
}
@GetMapping("/get")
@Operation(summary = "获取用户详情")
public CommonResult<UserRespVO> getUser(@RequestParam("id") Long id) {
return success(userService.getUser(id));
}
}
```
#### Service 层
```java
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private DeptMapper deptMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createUser(UserCreateReqVO reqVO) {
// 业务逻辑
UserDO user = UserConvert.INSTANCE.convert(reqVO);
userMapper.insert(user);
return user.getId();
}
@Override
public UserRespVO getUser(Long id) {
UserDO user = userMapper.selectById(id);
DeptDO dept = deptMapper.selectById(user.getDeptId());
return UserConvert.INSTANCE.convert(user, dept);
}
}
```
#### DAL 层
```java
@Mapper
public interface UserMapper extends BaseMapperX<UserDO> {
default UserDO selectByUsername(String username) {
return selectOne("username", username);
}
default PageResult<UserDO> selectPage(UserPageReqVO pageReqVO) {
return selectPage(pageReqVO, new LambdaQueryWrapperX<UserDO>()
.likeIfPresent(UserDO::getUsername, pageReqVO.getUsername())
.betweenIfPresent(UserDO::getCreateTime, pageReqVO.getCreateTime())
.orderByDesc(UserDO::getId));
}
}
```
---
## 模块化设计
### 模块划分
项目按照**领域驱动设计DDD**思想进行模块划分。
#### 基础模块
| 模块 | 职责 |
|------|------|
| lyzsys-dependencies | 依赖版本管理 |
| lyzsys-framework | 框架组件封装 |
| lyzsys-server | 应用启动入口 |
#### 业务模块
| 模块 | 领域 | 职责 |
|------|------|------|
| lyzsys-module-system | 系统管理 | 用户、角色、菜单、部门、字典等 |
| lyzsys-module-infra | 基础设施 | 代码生成、文件、配置、任务等 |
| lyzsys-module-bpm | 工作流 | 流程定义、流程实例、任务管理 |
| lyzsys-module-pay | 支付 | 支付订单、退款、回调 |
| lyzsys-module-member | 会员 | 会员、积分、等级 |
| lyzsys-module-mall | 商城 | 商品、订单、营销 |
| lyzsys-module-crm | CRM | 客户、商机、合同 |
| lyzsys-module-erp | ERP | 采购、销售、库存 |
| lyzsys-module-ai | AI | AI 聊天、绘图、知识库 |
| lyzsys-module-mp | 微信公众号 | 公众号管理、粉丝、消息 |
| lyzsys-module-iot | IoT | 设备、产品、数据采集 |
| lyzsys-module-report | 报表 | 报表设计、大屏设计 |
### 模块结构
每个业务模块都遵循统一的结构:
```
lyzsys-module-xxx/
├── api/ # 对外 API
│ ├── xxxApi.java
│ └── xxxApiImpl.java
├── controller/ # 控制器
│ ├── admin/ # 管理后台 API
│ │ ├── xxxController.java
│ │ └── vo/
│ │ ├── xxxReqVO.java
│ │ └── xxxRespVO.java
│ └── app/ # 用户 App API
│ └── xxxController.java
├── service/ # 服务层
│ ├── xxxService.java
│ └── xxxServiceImpl.java
├── dal/ # 数据访问层
│ ├── dataobject/ # 数据对象
│ │ └── xxxDO.java
│ ├── mysql/ # MySQL Mapper
│ │ └── xxxMapper.java
│ └── redis/ # Redis DAO
│ └── xxxRedisDAO.java
├── convert/ # 对象转换
│ └── xxxConvert.java
├── enums/ # 枚举
│ └── xxxEnum.java
└── framework/ # 框架配置
└── xxxConfiguration.java
```
### 模块交互
#### 模块间调用规则
1. **禁止直接依赖**: 模块之间不能直接依赖
2. **通过 API 调用**: 通过 API 接口进行调用
3. **事件驱动**: 通过消息队列进行异步通信
#### 示例
```java
// mall 模块调用 pay 模块
@DubboReference
private PayOrderApi payOrderApi;
public void createOrder(OrderCreateReqVO reqVO) {
// 创建订单
OrderDO order = createOrder(reqVO);
// 调用支付模块
PayOrderCreateReqDTO payReq = new PayOrderCreateReqDTO();
payReq.setOrderId(order.getId());
payOrderApi.createOrder(payReq);
}
```
---
## 数据架构
### 数据存储
```
┌─────────────────────────────────────────────────────────────┐
│ 数据层 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ MySQL │ │ Redis │ │ MinIO │ │
│ │ (主数据库) │ │ (缓存) │ │ (文件存储) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
### 数据库设计
#### 表命名规范
- 格式: `{模块}_{业务}_{实体}`
- 示例: `system_users``system_roles``mall_orders`
#### 字段命名规范
- 小写字母 + 下划线
- 示例: `user_id``user_name``create_time`
#### 通用字段
每张表都包含以下通用字段:
```sql
id BIGINT 主键
create_time DATETIME 创建时间
update_time DATETIME 更新时间
creator VARCHAR(64) 创建人
updater VARCHAR(64) 更新人
deleted BIT 是否删除
tenant_id BIGINT 租户 ID (多租户表)
```
### 多租户数据隔离
#### 策略
- **共享数据库、共享 Schema**: 所有租户共享数据库,通过 `tenant_id` 隔离
- **自动过滤**: MyBatis Plus 拦截器自动添加租户条件
#### 实现
```java
@TableName("system_users")
public class UserDO extends TenantBaseDO {
private Long id;
private String username;
// tenant_id 由 TenantBaseDO 提供
}
// 查询时自动过滤
List<UserDO> users = userMapper.selectList();
// SQL: SELECT * FROM system_users WHERE deleted = 0 AND tenant_id = ?
```
### 缓存设计
#### 缓存策略
1. **本地缓存**: Caffeine本地缓存
2. **分布式缓存**: Redis分布式缓存
#### 缓存使用
```java
// 使用 Spring Cache
@Cacheable(value = "user", key = "#id")
public UserDO getUser(Long id) {
return userMapper.selectById(id);
}
// 使用 RedisTemplate
@Service
public class UserServiceImpl {
@Autowired
private RedisTemplate<String, UserDO> redisTemplate;
public UserDO getUser(Long id) {
String key = "user:" + id;
UserDO user = redisTemplate.opsForValue().get(key);
if (user == null) {
user = userMapper.selectById(id);
redisTemplate.opsForValue().set(key, user, 1, TimeUnit.HOURS);
}
return user;
}
}
```
---
## 安全架构
### 认证授权
#### 认证流程
```
1. 用户登录
2. 后端验证用户名密码
3. 生成 JWT Token
4. 返回 Token 给前端
5. 前端存储 Token
6. 后续请求携带 Token
7. 后端验证 Token
8. 允许访问
```
#### 授权模型
```
用户 (User)
角色 (Role)
权限 (Permission)
资源 (Resource)
```
### 数据权限
#### 权限范围
| 权限范围 | 说明 |
|---------|------|
| 全部数据权限 | 查看所有数据 |
| 本部门数据权限 | 只能查看本部门数据 |
| 本部门及以下数据权限 | 查看本部门及子部门数据 |
| 仅本人数据权限 | 只能查看自己的数据 |
| 自定义数据权限 | 自定义数据权限规则 |
#### 实现
```java
@DataScope(deptAlias = "d", userAlias = "u")
public List<UserDO> getUserList() {
return userMapper.selectList();
}
// SQL 自动添加
// AND (d.id = ? OR d.id IN (?, ?) OR u.id = ?)
```
### API 安全
#### 接口加密
```java
// 请求加密
@PostMapping("/create")
public CommonResult<Long> createUser(@RequestBody String encryptedData) {
// 解密
String json = decrypt(encryptedData);
UserCreateReqVO reqVO = JSON.parseObject(json, UserCreateReqVO.class);
// 业务处理
Long id = userService.createUser(reqVO);
// 加密返回
return success(encrypt(id));
}
```
#### 接口签名
```java
// 请求签名
@PostMapping("/create")
public CommonResult<Long> createUser(
@RequestHeader("X-Signature") String signature,
@RequestBody UserCreateReqVO reqVO
) {
// 验证签名
if (!verifySignature(signature, reqVO)) {
return error(401, "签名验证失败");
}
// 业务处理
return success(userService.createUser(reqVO));
}
```
---
## 技术架构
### 技术选型
#### 后端技术栈
| 技术 | 版本 | 用途 |
|------|------|------|
| Spring Boot | 2.7.18 | 应用框架 |
| Spring Security | 5.8.16 | 安全框架 |
| MyBatis Plus | 3.5.15 | ORM 框架 |
| Flowable | 6.8.0 | 工作流引擎 |
| Quartz | 2.3.2 | 定时任务 |
| Redisson | 3.52.0 | 分布式锁 |
| Knife4j | 3.0.3 | API 文档 |
#### 前端技术栈
| 技术 | 版本 | 用途 |
|------|------|------|
| Vue | 3.2+ | 前端框架 |
| TypeScript | 4.x | 类型系统 |
| Vite | 4.x | 构建工具 |
| Element Plus | 2.x | UI 组件库 |
| Pinia | 2.x | 状态管理 |
### 框架封装
#### Web 封装
- 全局异常处理
- 统一响应格式
- 请求日志记录
- 参数校验
#### 安全封装
- JWT 认证
- 权限注解
- 数据权限
- API 加密
#### 数据库封装
- BaseMapperX
- LambdaQueryWrapperX
- 分页插件
- 租户插件
---
## 部署架构
### 单机部署
```
┌─────────────────────────────────────────────────────────────┐
│ 服务器 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Nginx │ │ JDK 8 │ │ MySQL │ │
│ │ (前端) │ │ (后端) │ │ (数据库) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Redis │ │ MinIO │ │
│ │ (缓存) │ │ (文件存储) │ │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
### 集群部署
```
┌─────────────────────────────────────────────────────────────┐
│ 负载均衡 │
│ (Nginx / F5) │
└─────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 应用服务器 1 │ │ 应用服务器 2 │ │ 应用服务器 3 │
│ (后端服务) │ │ (后端服务) │ │ (后端服务) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
└────────────────┼────────────────┘
┌─────────────────┐
│ MySQL 主从 │
│ Redis 集群 │
└─────────────────┘
```
### 容器化部署
```
┌─────────────────────────────────────────────────────────────┐
│ Kubernetes 集群 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Pod 1 │ │ Pod 2 │ │ Pod 3 │ │
│ │ (后端服务) │ │ (后端服务) │ │ (后端服务) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ MySQL │ │ Redis │ │ MinIO │ │
│ │ (StatefulSet)│ │ (StatefulSet)│ │ (Deployment)│ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
---
## 性能优化
### 数据库优化
1. **索引优化**: 合理创建索引
2. **SQL 优化**: 避免全表扫描
3. **分页查询**: 使用分页插件
4. **读写分离**: 主从数据库配置
5. **连接池**: Druid 连接池优化
### 缓存优化
1. **本地缓存**: Caffeine 本地缓存
2. **分布式缓存**: Redis 缓存
3. **缓存预热**: 系统启动时加载热点数据
4. **缓存更新**: 定时更新缓存
### 接口优化
1. **批量操作**: 批量插入、批量更新
2. **异步处理**: 消息队列异步处理
3. **接口合并**: 减少请求次数
4. **压缩传输**: Gzip 压缩
### 前端优化
1. **代码分割**: 路由懒加载
2. **资源压缩**: Gzip、Brotli 压缩
3. **CDN 加速**: 静态资源 CDN
4. **浏览器缓存**: 合理设置缓存策略
---
## 扩展性设计
### 水平扩展
1. **应用集群**: 多台应用服务器
2. **数据库集群**: 主从、分库分表
3. **缓存集群**: Redis 集群
4. **文件存储**: 分布式文件系统
### 垂直扩展
1. **升级硬件**: CPU、内存、磁盘
2. **优化配置**: JVM、数据库参数
### 微服务化
1. **模块拆分**: 按业务模块拆分
2. **服务注册**: Nacos、Eureka
3. **服务调用**: Dubbo、Feign
4. **网关路由**: Spring Cloud Gateway
---
**文档版本**: v1.0.0
**最后更新**: 2025-01-19
**维护团队**: Lyzsys 架构团队

805
doc/部署指南.md Normal file
View File

@@ -0,0 +1,805 @@
# Lyzsys 部署指南
## 📖 目录
- [部署概述](#部署概述)
- [环境准备](#环境准备)
- [后端部署](#后端部署)
- [前端部署](#前端部署)
- [数据库部署](#数据库部署)
- [缓存部署](#缓存部署)
- [文件存储部署](#文件存储部署)
- [生产环境部署](#生产环境部署)
- [容器化部署](#容器化部署)
- [监控部署](#监控部署)
---
## 部署概述
### 部署架构
```
┌─────────────────────────────────────────────────────────────┐
│ 用户端 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ PC 浏览器 │ │ 移动 App │ │ 小程序 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Nginx │
│ (反向代理 + 静态资源) │
└─────────────────────────────────────────────────────────────┘
┌─────────────┴─────────────┐
│ │
▼ ▼
┌──────────────────────────┐ ┌──────────────────────────┐
│ 前端静态资源 │ │ 后端 API 服务 │
│ (Vue3 SPA 应用) │ │ (Spring Boot 应用) │
└──────────────────────────┘ └──────────────────────────┘
┌─────────────────────────┼─────────────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ MySQL │ │ Redis │ │ MinIO │
│ (主数据库) │ │ (缓存/会话) │ │ (文件存储) │
└──────────────────┘ └──────────────────┘ └──────────────────┘
```
### 部署方式
1. **传统部署**: 直接在服务器上部署
2. **Docker 部署**: 使用 Docker 容器部署
3. **Kubernetes 部署**: 使用 K8s 编排部署
---
## 环境准备
### 服务器要求
#### 最低配置
| 组件 | CPU | 内存 | 硬盘 |
|------|-----|------|------|
| 后端服务 | 2核 | 4GB | 20GB |
| MySQL | 1核 | 2GB | 50GB |
| Redis | 1核 | 1GB | 10GB |
| 前端 | 1核 | 1GB | 10GB |
#### 推荐配置
| 组件 | CPU | 内存 | 硬盘 |
|------|-----|------|------|
| 后端服务 | 4核 | 8GB | 50GB |
| MySQL | 4核 | 16GB | 500GB |
| Redis | 2核 | 4GB | 50GB |
| 前端 | 2核 | 2GB | 20GB |
### 软件要求
| 软件 | 版本 | 用途 |
|------|------|------|
| JDK | 8+ | 后端运行环境 |
| MySQL | 5.7+ / 8.0+ | 数据库 |
| Redis | 5.0+ | 缓存 |
| Nginx | 1.18+ | Web 服务器 |
| Node.js | 16+ | 前端构建 |
| Docker | 20.10+ | 容器化(可选) |
---
## 后端部署
### 方式一: JAR 包部署
#### 1. 打包项目
```bash
cd lyzsys_backend
mvn clean package -DskipTests
```
生成的 JAR 包位于 `lyzsys-server/target/lyzsys-server.jar`
#### 2. 上传文件
将 JAR 包上传到服务器:
```bash
scp lyzsys-server/target/lyzsys-server.jar user@server:/opt/lyzsys/
```
#### 3. 配置文件
创建配置文件 `application-prod.yaml`:
```yaml
spring:
# 数据源配置
datasource:
url: jdbc:mysql://mysql-server:3306/lyzsys?useSSL=false&serverTimezone=Asia/Shanghai
username: lyzsys
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
# Redis 配置
redis:
host: redis-server
port: 6379
database: 1
password: your_redis_password
# 项目配置
lyzsys:
web:
api-prefix: /admin-api
security:
mock-enable: false
upload:
base-url: http://your-domain.com
```
#### 4. 启动服务
```bash
# 启动服务
java -jar lyzsys-server.jar --spring.profiles.active=prod
# 后台启动
nohup java -jar lyzsys-server.jar --spring.profiles.active=prod > lyzsys.log 2>&1 &
# 指定内存启动
java -Xms512m -Xmx1024m -jar lyzsys-server.jar --spring.profiles.active=prod
```
#### 5. 创建系统服务
创建 `/etc/systemd/system/lyzsys.service`:
```ini
[Unit]
Description=Lyzsys Server
After=syslog.target network.target
[Service]
Type=simple
ExecStart=/usr/bin/java -jar /opt/lyzsys/lyzsys-server.jar --spring.profiles.active=prod
ExecStop=/bin/kill -15 $MAINPID
User=lyzsys
Group=lyzsys
WorkingDirectory=/opt/lyzsys
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
```
启动服务:
```bash
# 重载配置
systemctl daemon-reload
# 启动服务
systemctl start lyzsys
# 开机启动
systemctl enable lyzsys
# 查看状态
systemctl status lyzsys
```
### 方式二: Docker 部署
#### 1. 创建 Dockerfile
创建 `Dockerfile`:
```dockerfile
FROM openjdk:8-jre-slim
LABEL maintainer="lyzsys"
# 设置工作目录
WORKDIR /opt/lyzsys
# 复制 JAR 包
COPY lyzsys-server/target/lyzsys-server.jar app.jar
# 暴露端口
EXPOSE 48080
# 启动应用
ENTRYPOINT ["java", "-jar", "app.jar"]
```
#### 2. 构建镜像
```bash
docker build -t lyzsys/lyzsys-server:latest .
```
#### 3. 运行容器
```bash
docker run -d \
--name lyzsys-server \
-p 48080:48080 \
-e SPRING_PROFILES_ACTIVE=prod \
-e SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/lyzsys \
-e SPRING_DATASOURCE_USERNAME=lyzsys \
-e SPRING_DATASOURCE_PASSWORD=your_password \
-e SPRING_DATA_REDIS_HOST=redis \
-e SPRING_DATA_REDIS_PASSWORD=your_redis_password \
lyzsys/lyzsys-server:latest
```
#### 4. 使用 Docker Compose
创建 `docker-compose.yml`:
```yaml
version: '3.8'
services:
lyzsys-server:
image: lyzsys/lyzsys-server:latest
container_name: lyzsys-server
ports:
- "48080:48080"
environment:
- SPRING_PROFILES_ACTIVE=prod
- SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/lyzsys
- SPRING_DATASOURCE_USERNAME=lyzsys
- SPRING_DATASOURCE_PASSWORD=your_password
- SPRING_DATA_REDIS_HOST=redis
- SPRING_DATA_REDIS_PASSWORD=your_redis_password
depends_on:
- mysql
- redis
restart: always
```
启动:
```bash
docker-compose up -d
```
---
## 前端部署
### 方式一: Nginx 部署
#### 1. 构建项目
```bash
cd lyzsys-ui-admin
# 安装依赖
pnpm install
# 构建生产版本
pnpm build:prod
```
生成的文件位于 `dist/` 目录
#### 2. 上传文件
`dist/` 目录上传到服务器:
```bash
scp -r dist/* user@server:/var/www/lyzsys/
```
#### 3. 配置 Nginx
创建 Nginx 配置 `/etc/nginx/conf.d/lyzsys.conf`:
```nginx
server {
listen 80;
server_name your-domain.com;
root /var/www/lyzsys;
index index.html;
# 前端路由
location / {
try_files $uri $uri/ /index.html;
}
# API 代理
location /admin-api/ {
proxy_pass http://localhost:48080/admin-api/;
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_read_timeout 60s;
proxy_send_timeout 60s;
}
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Gzip 压缩
gzip on;
gzip_types text/plain text/css application/json application/javascript;
gzip_min_length 1024;
}
```
#### 4. 重启 Nginx
```bash
nginx -t
nginx -s reload
```
### 方式二: Docker 部署
#### 1. 创建 Dockerfile
创建 `Dockerfile`:
```dockerfile
FROM nginx:alpine
# 复制构建文件
COPY dist/ /usr/share/nginx/html/
# 复制 Nginx 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 暴露端口
EXPOSE 80
# 启动 Nginx
CMD ["nginx", "-g", "daemon off;"]
```
#### 2. 构建镜像
```bash
docker build -t lyzsys/lyzsys-ui-admin:latest .
```
#### 3. 运行容器
```bash
docker run -d \
--name lyzsys-ui-admin \
-p 80:80 \
lyzsys/lyzsys-ui-admin:latest
```
---
## 数据库部署
### MySQL 部署
#### 1. 安装 MySQL
```bash
# CentOS/RHEL
yum install -y mysql-server
# Ubuntu/Debian
apt-get install -y mysql-server
```
#### 2. 配置 MySQL
编辑 `/etc/my.cnf`:
```ini
[mysqld]
# 基础配置
port = 3306
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# 连接配置
max_connections = 500
max_connect_errors = 100
# 缓存配置
innodb_buffer_pool_size = 1G
query_cache_size = 128M
# 日志配置
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
```
#### 3. 创建数据库
```bash
mysql -u root -p
CREATE DATABASE lyzsys CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'lyzsys'@'%' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON lyzsys.* TO 'lyzsys'@'%';
FLUSH PRIVILEGES;
```
#### 4. 导入数据
```bash
mysql -u lyzsys -p lyzsys < lyzsys.sql
```
### Docker 部署 MySQL
```bash
docker run -d \
--name mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=root_password \
-e MYSQL_DATABASE=lyzsys \
-e MYSQL_USER=lyzsys \
-e MYSQL_PASSWORD=your_password \
-v /data/mysql:/var/lib/mysql \
mysql:8.0
```
---
## 缓存部署
### Redis 部署
#### 1. 安装 Redis
```bash
# CentOS/RHEL
yum install -y redis
# Ubuntu/Debian
apt-get install -y redis-server
```
#### 2. 配置 Redis
编辑 `/etc/redis/redis.conf`:
```ini
# 绑定地址
bind 0.0.0.0
# 端口
port 6379
# 密码
requirepass your_redis_password
# 持久化
save 900 1
save 300 10
save 60 10000
# 最大内存
maxmemory 1gb
maxmemory-policy allkeys-lru
```
#### 3. 启动 Redis
```bash
# 启动 Redis
redis-server /etc/redis/redis.conf
# 或使用 systemd
systemctl start redis
systemctl enable redis
```
### Docker 部署 Redis
```bash
docker run -d \
--name redis \
-p 6379:6379 \
-v /data/redis:/data \
redis:7-alpine \
redis-server --appendonly yes --requirepass your_redis_password
```
---
## 文件存储部署
### MinIO 部署
#### 1. Docker 部署 MinIO
```bash
docker run -d \
--name minio \
-p 9000:9000 \
-p 9001:9001 \
-e MINIO_ROOT_USER=admin \
-e MINIO_ROOT_PASSWORD=admin123 \
-v /data/minio:/data \
minio/minio server /data --console-address ":9001"
```
#### 2. 配置 MinIO
1. 访问 http://localhost:9001
2. 登录admin / admin123
3. 创建 Bucket: `lyzsys`
4. 创建 Access Key 和 Secret Key
5. 配置后端 `application.yaml`:
```yaml
lyzsys:
storage:
minio:
endpoint: http://localhost:9000
access-key: your_access_key
secret-key: your_secret_key
bucket-name: lyzsys
```
---
## 生产环境部署
### 安全配置
#### 1. 配置防火墙
```bash
# 开放必要端口
firewall-cmd --permanent --add-port=80/tcp
firewall-cmd --permanent --add-port=443/tcp
firewall-cmd --permanent --add-port=48080/tcp
firewall-cmd --reload
```
#### 2. 配置 SSL 证书
使用 Let's Encrypt 免费证书:
```bash
# 安装 certbot
yum install -y certbot
# 获取证书
certbot certonly --standalone -d your-domain.com
# 证书位置
# /etc/letsencrypt/live/your-domain.com/fullchain.pem
# /etc/letsencrypt/live/your-domain.com/privkey.pem
```
配置 Nginx SSL
```nginx
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# ... 其他配置
}
# HTTP 跳转 HTTPS
server {
listen 80;
server_name your-domain.com;
return 301 https://$server_name$request_uri;
}
```
### 性能优化
#### 1. MySQL 优化
```ini
# my.cnf
[mysqld]
innodb_buffer_pool_size = 4G
innodb_log_file_size = 512M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
```
#### 2. Redis 优化
```ini
# redis.conf
maxmemory 2gb
maxmemory-policy allkeys-lru
save ""
```
#### 3. JVM 优化
```bash
java -Xms2g -Xmx2g \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/opt/lyzsys/logs/ \
-jar lyzsys-server.jar
```
---
## 容器化部署
### Docker Compose 完整部署
创建 `docker-compose.yml`:
```yaml
version: '3.8'
services:
# MySQL
mysql:
image: mysql:8.0
container_name: lyzsys-mysql
environment:
- MYSQL_ROOT_PASSWORD=root_password
- MYSQL_DATABASE=lyzsys
- MYSQL_USER=lyzsys
- MYSQL_PASSWORD=your_password
volumes:
- mysql-data:/var/lib/mysql
ports:
- "3306:3306"
restart: always
# Redis
redis:
image: redis:7-alpine
container_name: lyzsys-redis
command: redis-server --appendonly yes --requirepass your_redis_password
volumes:
- redis-data:/data
ports:
- "6379:6379"
restart: always
# MinIO
minio:
image: minio/minio
container_name: lyzsys-minio
environment:
- MINIO_ROOT_USER=admin
- MINIO_ROOT_PASSWORD=admin123
volumes:
- minio-data:/data
ports:
- "9000:9000"
- "9001:9001"
command: server /data --console-address ":9001"
restart: always
# 后端服务
backend:
image: lyzsys/lyzsys-server:latest
container_name: lyzsys-backend
environment:
- SPRING_PROFILES_ACTIVE=prod
- SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/lyzsys
- SPRING_DATASOURCE_USERNAME=lyzsys
- SPRING_DATASOURCE_PASSWORD=your_password
- SPRING_DATA_REDIS_HOST=redis
- SPRING_DATA_REDIS_PASSWORD=your_redis_password
ports:
- "48080:48080"
depends_on:
- mysql
- redis
restart: always
# 前端服务
frontend:
image: lyzsys/lyzsys-ui-admin:latest
container_name: lyzsys-frontend
ports:
- "80:80"
depends_on:
- backend
restart: always
volumes:
mysql-data:
redis-data:
minio-data:
```
启动:
```bash
docker-compose up -d
```
---
## 监控部署
### Spring Boot Admin
#### 1. 添加依赖
```xml
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>
```
#### 2. 配置应用
```yaml
spring:
application:
name: lyzsys-admin-server
server:
port: 48081
```
#### 3. 客户端配置
```yaml
spring:
boot:
admin:
client:
url: http://localhost:48081
```
### SkyWalking
#### 1. 安装 SkyWalking
```bash
docker run -d \
--name skywalking \
-p 11800:11800 \
-p 12800:12800 \
apache/skywalking-oap-server
```
#### 2. 配置 Agent
```bash
java -javaagent:/path/to/skywalking-agent.jar \
-Dskywalking.agent.service_name=lyzsys \
-Dskywalking.collector.backend_service=localhost:11800 \
-jar lyzsys-server.jar
```
---
**文档版本**: v1.0.0
**最后更新**: 2025-01-19
**维护团队**: Lyzsys 运维团队

Some files were not shown because too many files have changed in this diff Show More