Files
tjt_czjs_backend/doc/后端开发文档.md
2026-01-19 18:54:03 +08:00

22 KiB
Raw Blame History

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. 创建数据库:
CREATE DATABASE lyzsys CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  1. 导入 SQL 脚本(位置:sql/ 目录)

  2. 修改配置文件 lyzsys-server/src/main/resources/application.yaml

快速开始

1. 克隆项目

git clone https://github.com/your-org/lyzsys.git
cd lyzsys/lyzsys_backend

2. 导入 IDE

将项目导入 IntelliJ IDEA

File → Open → 选择 lyzsys_backend 目录

等待 Maven 依赖下载完成。

3. 启动 Redis

redis-server

4. 运行主类

找到 lyzsys-server/src/main/java/cn/iocoder/lyzsys/server/LyzsysServerApplication.java

右键 → Run 'LyzsysServerApplication'

5. 访问应用

开发规范

命名规范

包命名: 全小写,使用点分隔

cn.iocoder.lyzsys.module.system.controller.admin

类命名: 大驼峰

UserController, UserService, UserDO

方法命名: 小驼峰

getUserById(), createUser(), deleteUser()

变量命名: 小驼峰

userName, userAge, isAdmin

常量命名: 全大写,下划线分隔

MAX_SIZE, DEFAULT_PAGE_SIZE, ERROR_CODE

注释规范

类注释:

/**
 * 用户 Controller
 *
 * @author 芋道源码
 */
@RestController
@RequestMapping("/system/user")
public class UserController {
}

方法注释:

/**
 * 创建用户
 *
 * @param createReqVO 创建信息
 * @return 用户 ID
 */
@PostMapping("/create")
public CommonResult<Long> createUser(@Valid @RequestBody UserCreateReqVO createReqVO) {
    return success(userService.createUser(createReqVO));
}

代码规范

  1. 使用 Lombok 简化代码:
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserDO extends TenantBaseDO {
    private Long id;
    private String username;
}
  1. 使用 MapStruct 进行对象转换:
@Mapper
public interface UserConvert {
    UserConvert INSTANCE = Mappers.getMapper(UserConvert.class);

    UserDO convert(UserCreateReqVO bean);

    UserRespVO convert(UserDO bean);
}
  1. 异常处理:
// 使用全局异常处理器
throw new ServiceException(USER_USERNAME_EXISTS);

// 或使用工具方法
throw exception(USER_USERNAME_EXISTS);

接口开发

Controller 层

@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 层

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 层

@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
  1. Token 验证:
请求携带 Token → 后端解析 Token → 验证有效性 → 允许访问
  1. Token 刷新:
Token 即将过期 → 使用刷新令牌 → 获取新 Token

权限模型

RBAC (基于角色的访问控制):

用户 (User)
  ↓
角色 (Role)
  ↓
权限 (Permission)
  ↓
资源 (Resource)

数据权限:

  • 全部数据权限
  • 本部门数据权限
  • 本部门及以下数据权限
  • 仅本人数据权限
  • 自定义数据权限

多租户

租户隔离

  1. 数据库隔离: 通过 tenant_id 字段隔离
  2. 自动过滤: MyBatis Plus 拦截器自动添加租户条件
  3. 租户上下文: TenantContextHolder 管理当前租户

使用示例

// 继承租户基类
@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)

流程定义

@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();
    }
}

流程实例

@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 缓存

// 使用 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;
    }
}

缓存注解

@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 消息队列

@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 定时任务

@Component
public class DemoJob extends QuartzJobBean {

    @Autowired
    private UserService userService;

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        // 定时清理过期用户
        userService.cleanExpiredUsers();
    }
}

文件管理

文件上传

@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 操作

导入

@PostMapping("/import")
public CommonResult<Integer> importUsers(@RequestParam("file") MultipartFile file) {
    List<UserImportExcelVO> list = ExcelUtils.read(file, UserImportExcelVO.class);
    return success(userService.importUsers(list));
}

导出

@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. 打包项目

cd lyzsys_backend
mvn clean package -DskipTests

2. 上传文件

lyzsys-server/target/lyzsys-server.jar 上传到服务器

3. 启动应用

java -jar lyzsys-server.jar --spring.profiles.active=prod

Docker 部署

1. 构建镜像

docker build -t lyzsys/lyzsys-server:latest .

2. 运行容器

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

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. 框架会自动添加数据权限过滤条件

参考资源


文档版本: v1.0.0 最后更新: 2025-01-19 维护团队: Lyzsys 开发团队