# 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 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 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 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 { default UserDO selectByUsername(String username) { return selectOne("username", username); } default List selectListByDeptIds(Collection deptIds) { return selectList(new LambdaQueryWrapperX() .in(UserDO::getDeptId, deptIds)); } default PageResult selectPage(UserPageReqVO pageReqVO) { return selectPage(pageReqVO, new LambdaQueryWrapperX() .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 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 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 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 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 importUsers(@RequestParam("file") MultipartFile file) { List list = ExcelUtils.read(file, UserImportExcelVO.class); return success(userService.importUsers(list)); } ``` #### 导出 ```java @GetMapping("/export") public void exportUsers(HttpServletResponse response, UserPageReqVO pageReqVO) { List 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 开发团队