2026-01-19 18:34:10 +08:00
|
|
|
|
# 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
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-01-22 17:56:09 +08:00
|
|
|
|
## Demo 示例模块
|
|
|
|
|
|
|
|
|
|
|
|
### 模块简介
|
|
|
|
|
|
|
|
|
|
|
|
**lyzsys-module-demo** 是一个完整的业务模块示例,展示了如何在 Lyzsys 系统中快速创建一个新的业务模块。该模块实现了项目管理的完整 CRUD 功能,包括增删改查和 Excel 导出。
|
|
|
|
|
|
|
|
|
|
|
|
### 功能特性
|
|
|
|
|
|
|
|
|
|
|
|
- ✅ 完整的 CRUD 接口(增删改查)
|
|
|
|
|
|
- ✅ 分页查询支持
|
|
|
|
|
|
- ✅ 批量删除功能
|
|
|
|
|
|
- ✅ Excel 导出功能
|
|
|
|
|
|
- ✅ 业务字段唯一性校验
|
|
|
|
|
|
- ✅ 权限控制
|
|
|
|
|
|
- ✅ 前后端完整实现
|
|
|
|
|
|
|
|
|
|
|
|
### 模块结构
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
lyzsys-module-demo/
|
|
|
|
|
|
├── pom.xml # Maven 配置
|
|
|
|
|
|
└── src/main/java/cn/iocoder/lyzsys/module/demo/
|
|
|
|
|
|
├── controller/admin/project/ # 控制器层
|
|
|
|
|
|
│ ├── ProjectController.java # 项目控制器
|
|
|
|
|
|
│ └── vo/ # VO 对象
|
|
|
|
|
|
│ ├── ProjectPageReqVO.java # 分页查询请求
|
|
|
|
|
|
│ ├── ProjectRespVO.java # 响应 VO
|
|
|
|
|
|
│ └── ProjectSaveReqVO.java # 保存请求 VO
|
|
|
|
|
|
├── service/project/ # 服务层
|
|
|
|
|
|
│ ├── ProjectService.java # 服务接口
|
|
|
|
|
|
│ └── ProjectServiceImpl.java # 服务实现
|
|
|
|
|
|
├── dal/ # 数据访问层
|
|
|
|
|
|
│ ├── dataobject/project/ # 数据对象
|
|
|
|
|
|
│ │ └── ProjectDO.java # 项目实体类
|
|
|
|
|
|
│ └── mysql/project/ # Mapper 接口
|
|
|
|
|
|
│ └── ProjectMapper.java # 项目 Mapper
|
|
|
|
|
|
└── enums/ # 枚举类
|
|
|
|
|
|
└── ErrorCodeConstants.java # 错误码常量
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 核心代码示例
|
|
|
|
|
|
|
|
|
|
|
|
#### 实体类(ProjectDO)
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
@TableName("demo_project")
|
|
|
|
|
|
@Data
|
|
|
|
|
|
@EqualsAndHashCode(callSuper = true)
|
|
|
|
|
|
public class ProjectDO extends BaseDO {
|
|
|
|
|
|
@TableId
|
|
|
|
|
|
private Long id;
|
|
|
|
|
|
|
|
|
|
|
|
// 遵循命名规范:第一个单词不能只有一个字母
|
|
|
|
|
|
private String projectName; // ✅ 正确(而非 pName)
|
|
|
|
|
|
private String projectCode; // ✅ 正确(而非 pCode)
|
|
|
|
|
|
private LocalDateTime establishDate; // ✅ 正确(而非 eDate)
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### Controller 示例
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
@Tag(name = "管理后台 - 项目管理")
|
|
|
|
|
|
@RestController
|
|
|
|
|
|
@RequestMapping("/demo/project")
|
|
|
|
|
|
public class ProjectController {
|
|
|
|
|
|
|
|
|
|
|
|
@PostMapping("/create")
|
|
|
|
|
|
@Operation(summary = "创建项目")
|
|
|
|
|
|
@PreAuthorize("@ss.hasPermission('demo:project:create')")
|
|
|
|
|
|
public CommonResult<Long> createProject(@Valid @RequestBody ProjectSaveReqVO createReqVO) {
|
|
|
|
|
|
return success(projectService.createProject(createReqVO));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 其他 CRUD 方法...
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 数据库设计
|
|
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
|
CREATE TABLE `demo_project` (
|
|
|
|
|
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '项目ID',
|
|
|
|
|
|
`project_name` varchar(100) NOT NULL COMMENT '项目名称',
|
|
|
|
|
|
`project_code` varchar(50) NOT NULL COMMENT '项目编号',
|
|
|
|
|
|
`establish_date` datetime NULL COMMENT '立项时间',
|
|
|
|
|
|
-- 标准字段
|
|
|
|
|
|
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
|
|
|
|
|
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
|
|
|
|
|
`updater` varchar(64) DEFAULT '' COMMENT '更新者',
|
|
|
|
|
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
|
|
|
|
|
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
|
|
|
|
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
|
|
|
|
|
PRIMARY KEY (`id`)
|
|
|
|
|
|
) ENGINE=InnoDB COMMENT='项目管理表';
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 菜单配置
|
|
|
|
|
|
|
|
|
|
|
|
Demo 模块的菜单结构:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
项目管理(一级菜单,sort: 1)
|
|
|
|
|
|
└── 项目列表(二级菜单,sort: 1)
|
|
|
|
|
|
├── 项目查询(demo:project:query)
|
|
|
|
|
|
├── 项目新增(demo:project:create)
|
|
|
|
|
|
├── 项目修改(demo:project:update)
|
|
|
|
|
|
├── 项目删除(demo:project:delete)
|
|
|
|
|
|
└── 项目导出(demo:project:export)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 前端实现
|
|
|
|
|
|
|
|
|
|
|
|
前端代码位置:
|
|
|
|
|
|
- API 接口:`src/api/demo/project/index.ts`
|
|
|
|
|
|
- 列表页面:`src/views/demo/project/index.vue`
|
|
|
|
|
|
- 表单组件:`src/views/demo/project/ProjectForm.vue`
|
|
|
|
|
|
|
|
|
|
|
|
### 作为参考模板
|
|
|
|
|
|
|
|
|
|
|
|
Demo 模块可以作为新业务模块开发的参考模板,包含了:
|
|
|
|
|
|
|
|
|
|
|
|
1. **标准的代码结构** - 遵循项目分层架构
|
|
|
|
|
|
2. **完整的业务逻辑** - 包括校验、异常处理等
|
|
|
|
|
|
3. **规范的命名方式** - 遵循驼峰命名规范
|
|
|
|
|
|
4. **权限控制示例** - 展示如何配置权限
|
|
|
|
|
|
5. **前后端联调** - 完整的前后端交互流程
|
|
|
|
|
|
|
|
|
|
|
|
**详细开发指南请参考**:
|
|
|
|
|
|
- [新模块开发指南](./新模块开发指南.md) - 基于 demo 模块的完整开发教程
|
|
|
|
|
|
- [编码规范](./编码规范.md) - 命名规范、菜单结构规范等
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 开发规范
|
|
|
|
|
|
|
|
|
|
|
|
为确保代码质量和团队协作效率,Lyzsys 项目制定了一系列开发规范。
|
|
|
|
|
|
|
|
|
|
|
|
### 核心规范文档
|
|
|
|
|
|
|
|
|
|
|
|
1. **[编码规范](./编码规范.md)** - 必读 ⭐⭐⭐⭐⭐
|
|
|
|
|
|
- 驼峰命名规范(重要:第一个单词不能只有一个字母)
|
|
|
|
|
|
- 菜单结构规范
|
|
|
|
|
|
- 代码结构规范
|
|
|
|
|
|
- 数据库设计规范
|
|
|
|
|
|
- API 接口规范
|
|
|
|
|
|
- 前端开发规范
|
|
|
|
|
|
|
|
|
|
|
|
2. **[新模块开发指南](./新模块开发指南.md)** - 实战教程 ⭐⭐⭐⭐⭐
|
|
|
|
|
|
- 快速开始
|
|
|
|
|
|
- 创建后端模块(完整步骤)
|
|
|
|
|
|
- 创建前端页面
|
|
|
|
|
|
- 配置菜单权限
|
|
|
|
|
|
- 以 Demo 模块为参考示例
|
|
|
|
|
|
|
|
|
|
|
|
### 关键规范要点
|
|
|
|
|
|
|
|
|
|
|
|
#### 命名规范核心原则
|
|
|
|
|
|
|
|
|
|
|
|
⚠️ **重要**:所有字段名、类名的驼峰命名中,**第一个单词不能只有一个字母**
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
// ✅ 正确示例
|
|
|
|
|
|
private String projectId; // 而非 pId
|
|
|
|
|
|
private String projectName; // 而非 pName
|
|
|
|
|
|
private String establishDate; // 而非 eDate
|
|
|
|
|
|
|
|
|
|
|
|
// ❌ 错误示例
|
|
|
|
|
|
private String pId; // 单字母开头,可能导致 MyBatis Plus 映射问题
|
|
|
|
|
|
private String mType; // 单字母开头
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 菜单结构规范
|
|
|
|
|
|
|
|
|
|
|
|
业务功能菜单优先展示,系统管理功能放在最后:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
1-90. 业务菜单(项目管理、客户管理等)
|
|
|
|
|
|
98. 系统管理
|
|
|
|
|
|
99. 基础设施
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 权限标识格式
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
格式:{模块名}:{业务}:{操作}
|
|
|
|
|
|
|
|
|
|
|
|
示例:
|
|
|
|
|
|
demo:project:query # 查询
|
|
|
|
|
|
demo:project:create # 新增
|
|
|
|
|
|
demo:project:update # 修改
|
|
|
|
|
|
demo:project:delete # 删除
|
|
|
|
|
|
demo:project:export # 导出
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 开发流程建议
|
|
|
|
|
|
|
|
|
|
|
|
1. **阅读规范文档** → 了解编码规范和开发流程
|
|
|
|
|
|
2. **参考 Demo 模块** → 理解标准的实现方式
|
|
|
|
|
|
3. **按照开发指南** → 逐步创建新模块
|
|
|
|
|
|
4. **代码评审** → 确保符合规范要求
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-01-19 18:34:10 +08:00
|
|
|
|
## 附录
|
|
|
|
|
|
|
|
|
|
|
|
### 常见问题
|
|
|
|
|
|
|
|
|
|
|
|
#### Q1: 如何添加新的业务模块?
|
|
|
|
|
|
|
2026-01-22 17:56:09 +08:00
|
|
|
|
**推荐方式**:参考 [新模块开发指南](./新模块开发指南.md),以 Demo 模块为模板创建新模块。
|
|
|
|
|
|
|
|
|
|
|
|
**快速步骤**:
|
|
|
|
|
|
1. 创建 Maven 模块和目录结构
|
|
|
|
|
|
2. 编写数据库表(遵循命名规范)
|
|
|
|
|
|
3. 按照 Demo 模块的结构创建后端代码
|
|
|
|
|
|
4. 创建前端页面和 API 接口
|
|
|
|
|
|
5. 配置菜单和权限
|
2026-01-19 18:34:10 +08:00
|
|
|
|
|
|
|
|
|
|
#### 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 开发团队
|