若依+mybatis-plus集成多租户问题记录

一、插件TenantLineInnerInterceptor实现多租户

参考:

多租户插件 | MyBatis-Plus

【精选】Mybatis Plus 多租户id使用-CSDN博客

二、保存报错

原先的功能接口都无法保存,出现如下错误:net.sf.jsqlparser.statement.select.SetOperationList cannot be cast to net.sf.jsqlparser.statement.select.PlainSelect

 解决方案:

进行依赖排除处理jsqlparser、mybatis、mybatis-spring,重新运行项目服务后正常

<!--mybatis-->
	<dependency>
	    <groupId>com.baomidou</groupId>
	    <artifactId>mybatis-plus-boot-starter</artifactId>
	    <version>3.5.3.1</version>
	</dependency>
	<!-- pagehelper 分页封装使用 -->
	<!-- pagehelper 依赖升级版本1.4.6并且排除jsqlparser依赖,使pagehelper分页与mybatis-plus分页兼容存在 -->
	<dependency>
		<groupId>com.github.pagehelper</groupId>
		<artifactId>pagehelper-spring-boot-starter</artifactId>
		<version>1.4.6</version>
		<exclusions>
			<exclusion>
				<groupId>org.mybatis</groupId>
				<artifactId>mybatis</artifactId>
			</exclusion>
			<exclusion>
				<groupId>org.mybatis</groupId>
				<artifactId>mybatis-spring</artifactId>
			</exclusion>
			<exclusion>
				<groupId>com.github.jsqlparser</groupId>
				<artifactId>jsqlparser</artifactId>
			</exclusion>
		</exclusions>
	</dependency>

参考:【java】使pagehelper分页与mybatis-plus分页兼容存在 - 掘金

三、sql中存在inner join报错TENANT_ID字段不存在

解决方案:   

对应mapper方法加了@InterceptorIgnore(tenantLine = "true")也无效,于是将inner join改为left join解决。

官网说明

四、oracle版本模糊查询用“||“拼接报错

Caused by: net.sf.jsqlparser.parser.ParseException: Encountered unexpected token: "||" <OP CONCAT>
at ine 4. column 47
Was expecting one of:
q
AA
0s
"COLLATE
"CONNECT"EMIT“
"ESCAPE"
"EXCEPT
"GROUP"
"HAVING""INTERSECT“MINUS"
"START""UNION"
net,sf,isalparser.parser,cciSalParserateParseException(CCJSqlParser.java:31234)

 解决方案:

用oracle的concat()函数代替"||"拼接。

五、解决自动任务和超级管理员不隔离数据问题

通过实现TenantLineHandler的ignoreTable方法解决。

1、TenantProperties.java用于系统读取配置文件

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import java.util.List;

/**
 * 白名单配置
 */
@Data
@Configuration
@ConfigurationProperties(prefix = "tenant")
public class TenantProperties {

    /**
     * 是否开启租户模式
     */
    private Boolean enable;

    /**
     * 多租户字段名称
     */
    private String column;

    /**
     * 需要排除的多租户的表
     */
    private List<String> exclusionTable;

    /**
     * 需要排除的租户
     */
    private List<String> exclusionTenant;

}

2、.yml文件配置

tenant:
  # 是否开启租户模式
  enable: true
  # 需要排除的租户  NO_LOGIN用于处理定时任务不隔离租户;给admin分配SUPER_ADMIN租户号,SUPER_ADMIN用于处理超级用户查询全部租户数据
  exclusionTenant:
    - "SUPER_ADMIN"
    - "NO_LOGIN"
  # 需要排除的多租户的表
  exclusionTable:
    - "sys_config"
    - "sys_dict_data"
    - "sys_dict_type"
    - "sys_job"
    - "sys_job_log"
    - "sys_user_role"
    - "sys_role_dept"
    - "sys_role"
    - "sys_logininfor"
    - "sys_menu"
    - "sys_role_menu"
    - "sys_oper_log"
  # 租户字段名称
  column: tenant_id

3、实现TenantLineHandler

需要将mybatisPlusInterceptor加入插件中

sessionFactory.setPlugins(mybatisPlusInterceptor());

    @Autowired
    private TenantProperties tenantProperties;

 @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() {
            @Override
            public Expression getTenantId() {
                String tenant = SecurityUtils.getUserTenantId();
                if (tenant != null) {
                    return new StringValue(tenant);
                }
                return new NullValue();
                //获得当前登录用户的租户id
//                return new LongValue(1111);
            }

            @Override
            public String getTenantIdColumn() {
                // 指定对应数据库表中存储租户ID的字段名
                return tenantProperties.getColumn();
            }

            /**
             * 过滤不需要根据租户隔离的表
             * 这是 default 方法,默认返回 false 表示所有表都需要拼多租户条件
             * @param tableName 表名
             */
            @Override
            public boolean ignoreTable(String tableName) {
                String tenant = SecurityUtils.getUserTenantId();

                // 不隔离的租户
                Map<String, String> collect = tenantProperties.getExclusionTenant().stream().collect(Collectors.toMap(a -> a, o -> o));
                if(collect.containsKey(tenant)){
                    return true;
                }
                //不隔离的表
                return tenantProperties.getExclusionTable().stream().anyMatch(
                        (t) -> t.equalsIgnoreCase(tableName)
                );
            }
        }));
        return interceptor;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
    {
        String typeAliasesPackage = env.getProperty("mybatis-plus.typeAliasesPackage");
        String mapperLocations = env.getProperty("mybatis-plus.mapperLocations");
        String configLocation = env.getProperty("mybatis-plus.configLocation");
        typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
        VFS.addImplClass(SpringBootVFS.class);

        //final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        MybatisSqlSessionFactoryBean sessionFactory=new MybatisSqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
        sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
        sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
        // 多租户开关
        if(tenantProperties.getEnable()){
            sessionFactory.setPlugins(mybatisPlusInterceptor());
        }
        return sessionFactory.getObject();
    }

4、在SecurityUtils中新增获取租户号方法

    /**
     * 获取租户ID
     **/
    public static String getUserTenantId()
    {
        try{
            LoginUser loginUser = getLoginUser();
            if(loginUser != null){
                String tenantId = getLoginUser().getUser().getTenantId();
                if(tenantId == null){
                    throw new ServiceException("获取租户ID异常", HttpStatus.UNAUTHORIZED);
                }else {
                    return tenantId;
                }
            }else{
                return "NO_LOGIN";
            }
        }catch (Exception e){

        }
        return "NO_LOGIN";
    }

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一些可能包括在大熊猫国家公园门户网站 Mybatis-plus 技术博客中的内容: 1. Mybatis-plus 简介:介绍 Mybatis-plus 的功能、优势等。 2. Mybatis-plus 基本使用:包括如何集成 Mybatis-plus、如何进行 CRUD 操作、如何使用条件构造器、如何使用自定义 SQL 等。 3. Mybatis-plus 高级查询:介绍 Mybatis-plus 的各种高级查询方式,如 Lambda 表达式、QueryWrapper、UpdateWrapper、EntityWrapper 等。 4. Mybatis-plus 分页:介绍 Mybatis-plus 的分页查询方式、分页插件的使用、自定义分页插件的实现等。 5. Mybatis-plus 乐观锁:介绍 Mybatis-plus 的乐观锁功能、如何使用乐观锁、乐观锁的实现原理等。 6. Mybatis-plus 多租户:介绍 Mybatis-plus多租户功能、如何使用多租户多租户的实现原理等。 7. Mybatis-plus 性能优化:介绍 Mybatis-plus 的性能优化技巧、如何使用分片表、如何使用缓存等。 8. Mybatis-plus 与 Spring Boot 集成:介绍如何将 Mybatis-plus 集成到 Spring Boot 项目中、如何配置 Mybatis-plus、如何使用 Mybatis-plus Starter 等。 9. Mybatis-plus 与其他技术集成:介绍如何将 Mybatis-plus 与其他技术集成,如 Redis、Elasticsearch、ShardingSphere 等。 此外,Mybatis-plus 技术博客也可以包括一些实践经验、案例分析、问题解决过程等内容,以帮助读者更好地理解和使用 Mybatis-plus。在大熊猫国家公园门户网站 Mybatis-plus 技术博客中,可以结合实际项目经验,讲解如何使用 Mybatis-plus 来构建高性能、可扩展的数据访问层。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值