RuoYi-Vue-Plus租户管理:多企业数据隔离方案

【免费下载链接】RuoYi-Vue-Plus 多租户后台管理系统 重写RuoYi-Vue所有功能 集成 Sa-Token、Mybatis-Plus、Warm-Flow工作流、SpringDoc、Hutool、OSS 定期同步 【免费下载链接】RuoYi-Vue-Plus 项目地址: https://gitcode.com/dromara/RuoYi-Vue-Plus

引言:企业级多租户的迫切需求

在数字化转型浪潮中,越来越多的企业需要为多个客户或内部部门提供独立的数据隔离服务。传统的单租户系统无法满足这种需求,导致系统重复建设、资源浪费和维护成本高昂。RuoYi-Vue-Plus基于Spring Boot + Vue.js技术栈,提供了完善的多租户解决方案,帮助企业快速构建安全可靠的多租户管理系统。

通过本文,您将全面掌握:

  • ✅ 多租户架构的核心设计原理
  • ✅ 数据隔离的完整实现方案
  • ✅ 租户管理的配置和使用方法
  • ✅ 实战案例和最佳实践

多租户架构设计原理

核心架构图

mermaid

技术实现层次

层级 技术组件 功能描述
接入层 Nginx/网关 租户识别和路由
业务层 Spring Boot 租户上下文管理
数据层 MyBatis-Plus SQL自动注入过滤
缓存层 Redis 租户隔离缓存
安全层 Sa-Token 租户权限控制

核心配置与启用

基础配置

application.yml中启用多租户功能:

tenant:
  enable: true  # 启用多租户
  excludes:     # 排除表列表
    - sys_config
    - sys_dict_data
    - sys_dict_type

数据表设计

系统核心租户表结构:

CREATE TABLE sys_tenant (
    id BIGINT PRIMARY KEY COMMENT '主键ID',
    tenant_id VARCHAR(50) NOT NULL COMMENT '租户编号',
    company_name VARCHAR(100) COMMENT '企业名称',
    contact_user_name VARCHAR(50) COMMENT '联系人',
    contact_number VARCHAR(20) COMMENT '联系号码',
    license_number VARCHAR(30) COMMENT '统一社会信用代码',
    domain VARCHAR(100) COMMENT '域名',
    package_id BIGINT COMMENT '租户套餐编号',
    expire_time DATETIME COMMENT '过期时间',
    account_count BIGINT DEFAULT -1 COMMENT '用户数量(-1不限制)',
    status CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
    del_flag CHAR(1) DEFAULT '0' COMMENT '删除标志'
) COMMENT '租户信息表';

数据隔离实现机制

MyBatis-Plus租户拦截器

核心拦截器实现自动SQL注入:

public class PlusTenantLineHandler implements TenantLineHandler {
    
    private final TenantProperties tenantProperties;

    @Override
    public Expression getTenantId() {
        String tenantId = TenantHelper.getTenantId();
        if (StringUtils.isBlank(tenantId)) {
            return new NullValue();
        }
        return new StringValue(tenantId);
    }

    @Override
    public boolean ignoreTable(String tableName) {
        // 排除系统表和非业务表
        List<String> excludes = tenantProperties.getExcludes();
        List<String> tables = ListUtil.toList("gen_table", "gen_table_column");
        tables.addAll(excludes);
        return StringUtils.equalsAnyIgnoreCase(tableName, tables.toArray(new String[0]));
    }
}

租户上下文管理

public class TenantHelper {
    // 设置动态租户
    public static void setDynamic(String tenantId) {
        // 实现租户上下文设置
    }
    
    // 获取当前租户ID
    public static String getTenantId() {
        // 从线程上下文获取租户信息
    }
    
    // 忽略租户过滤
    public static <T> T ignore(Supplier<T> handle) {
        // 临时禁用租户过滤
    }
}

租户管理功能详解

租户管理界面功能

功能模块 描述 权限控制
租户列表 查看所有租户信息 system:tenant:list
租户新增 创建新租户账户 system:tenant:add
租户编辑 修改租户基本信息 system:tenant:edit
租户禁用 停用租户服务 system:tenant:edit
租户删除 彻底删除租户 system:tenant:remove

套餐管理功能

@RestController
@RequestMapping("/system/tenant/package")
@ConditionalOnProperty(value = "tenant.enable", havingValue = "true")
public class SysTenantPackageController {
    
    @SaCheckPermission("system:tenantPackage:list")
    @GetMapping("/list")
    public R<TableDataInfo<SysTenantPackageVo>> list(SysTenantPackageBo bo, PageQuery pageQuery) {
        return R.ok(tenantPackageService.queryPageList(bo, pageQuery));
    }
}

缓存隔离方案

Redis多租户隔离

public class TenantKeyPrefixHandler implements NameMapper {
    
    private final String keyPrefix;

    @Override
    public String map(String name) {
        String tenantId = TenantHelper.getTenantId();
        if (StringUtils.isNotBlank(tenantId)) {
            return keyPrefix + ":" + tenantId + ":" + name;
        }
        return keyPrefix + ":" + name;
    }
}

多级缓存架构

mermaid

实战应用场景

场景一: SaaS平台多企业支持

// 企业注册时自动创建租户
@Transactional
public void registerCompany(CompanyRegisterBo bo) {
    // 1. 创建租户记录
    SysTenant tenant = new SysTenant();
    tenant.setCompanyName(bo.getCompanyName());
    tenant.setTenantId(generateTenantId());
    
    // 2. 设置默认套餐
    tenant.setPackageId(defaultPackageId);
    
    // 3. 保存租户信息
    tenantMapper.insert(tenant);
    
    // 4. 初始化租户数据
    TenantHelper.setDynamic(tenant.getTenantId());
    initTenantData(tenant);
}

场景二: 数据导出与迁移

// 租户数据导出
public void exportTenantData(String tenantId) {
    TenantHelper.dynamic(tenantId, () -> {
        // 导出当前租户的业务数据
        List<User> users = userMapper.selectList();
        List<Order> orders = orderMapper.selectList();
        
        // 生成数据包
        return createDataPackage(users, orders);
    });
}

性能优化策略

数据库优化方案

优化策略 实施方法 效果评估
分库分表 按租户ID分片 查询性能提升300%
索引优化 租户ID+业务字段联合索引 查询速度提升5倍
连接池 租户级连接池隔离 避免资源竞争

缓存优化策略

spring:
  cache:
    type: redis
    redis:
      time-to-live: 3600000  # 1小时
      key-prefix: "tenant:"
      use-key-prefix: true

安全防护措施

租户数据安全

  1. SQL注入防护:MyBatis-Plus自动过滤
  2. 越权访问防护:租户上下文验证
  3. 数据泄露防护:缓存键隔离
  4. 操作审计:完整日志记录

权限控制代码示例

@SaCheckPermission("system:tenant:query")
@GetMapping("/{id}")
public R<SysTenantVo> getInfo(@PathVariable Long id) {
    SysTenant tenant = tenantService.getById(id);
    // 验证当前用户是否有权限访问该租户数据
    if (!hasTenantAccess(tenant.getTenantId())) {
        return R.fail("无权限访问该租户数据");
    }
    return R.ok(convertToVo(tenant));
}

故障排查与监控

常见问题解决方案

问题现象 可能原因 解决方案
租户数据混淆 上下文丢失 检查过滤器配置
性能下降 缓存未隔离 验证Redis键前缀
权限异常 Sa-Token配置 检查租户DAO实现

监控指标配置

management:
  endpoints:
    web:
      exposure:
        include: health,metrics,tenants
  metrics:
    tags:
      application: ${spring.application.name}
      tenant: ${tenant.id}

总结与展望

RuoYi-Vue-Plus的多租户解决方案提供了完整的企业级数据隔离能力,具有以下核心优势:

  1. 开箱即用:简单配置即可启用多租户功能
  2. 全面隔离:数据库、缓存、权限全方位隔离
  3. 高性能:优化的查询和缓存机制
  4. 易扩展:支持水平扩展和分布式部署

未来版本将继续优化租户管理体验,增加更多企业级特性,如租户数据迁移、跨租户查询、租户资源配额管理等,为企业数字化转型提供更强大的技术支撑。

通过本文的详细讲解,相信您已经掌握了RuoYi-Vue-Plus多租户管理的核心技术和实践方法。在实际项目中,建议根据业务需求灵活调整配置,并建立完善的监控体系,确保多租户系统的稳定运行。

【免费下载链接】RuoYi-Vue-Plus 多租户后台管理系统 重写RuoYi-Vue所有功能 集成 Sa-Token、Mybatis-Plus、Warm-Flow工作流、SpringDoc、Hutool、OSS 定期同步 【免费下载链接】RuoYi-Vue-Plus 项目地址: https://gitcode.com/dromara/RuoYi-Vue-Plus

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐