当前位置: 首页 > 知识库问答 >
问题:

如何获取存储在默认模式表中的租户标识符?

高弘光
2023-03-14

我正在努力使用Hibernate在我的基于Spring的应用程序中启用多租户。我创建了一个自定义实现的MONtTenantIdfierResolver和重写的解析器MONtTenant标识符()方法来确定租户标识符。当我提供硬编码的租户标识符时,应用程序工作正常。

但是随后出现了一个要求,即根据请求头中的值从数据库默认模式中的表中获取租户标识符。我在许多地方搜索了这个问题,并做了一些打击和试验,但收效甚微。

任何有关这方面的帮助都将不胜感激。请让我知道我需要提供哪些信息来更好地理解问题场景。

CustomTenantIdentifier解析程序。JAVA

public class CustomTenantIdentifierResolver implements CurrentTenantIdentifierResolver {

     public static final String DEFAULT_TENANT_SCHEMA = "public";

    @Override
    public String resolveCurrentTenantIdentifier() {
        try {
            Provider<TenantRequestContext> tenantProvider = SpringContext
                .getBean(Provider.class);
            if (tenantProvider == null) {
                return DEFAULT_TENANT_SCHEMA;
            } else {
                TenantRequestContext tenantRequestContext = tenantProvider
                    .get();
                String tenantId = tenantRequestContext.getTenantIdValue();
                String tenantSchema = tenantRequestContext.getTenantSchema(tenantId);
                return tenantSchema;
            }
        } catch (Exception ex) {
            return DEFAULT_TENANT_SCHEMA;
        }
        // return "myschema";
    }

    @Override
    public boolean validateExistingCurrentSessions() {
        return true;
    }

}

租户请求ContextImpl。JAVA

@Component  
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)  
public class TenantRequestContextImpl  implements TenantRequestContext{

    @Autowired
    private TenantReadService tenantReadService;

    @Override
    public String getTenantIdValue() {
        String tenantId =((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes())
            .getRequest().getHeader("tenantId");
        return tenantId;
    }

    @Override
    public String getTenantSchema(String tenantId) {
        Tenant tenant = tenantReadService.findById(Integer.parseInt(tenantId));
        return tenant.getTenantSchemaName();
    }
}

租户服务impl。JAVA

@Repository
public class TenantReadServiceImpl implements TenantReadService {

    @Autowired
    private SessionFactory defaultSessionFactory;

    public TenantReadServiceImpl() {

    }

    public TenantReadServiceImpl(SessionFactory defaultSessionFactory) {
        this.defaultSessionFactory = defaultSessionFactory;
    }

    @Override
    @Transactional
    public Tenant findById(Integer tenantId) {
        String hql = "from Tenant where id=" + tenantId;
        Query query = defaultSessionFactory.getCurrentSession().createQuery(hql);
        Tenant tenant = (Tenant) query.uniqueResult();
        defaultSessionFactory.getCurrentSession().clear();
        return tenant;
    }
}

MultiTenancPlatformConfig。JAVA

@Configuration
@EnableTransactionManagement
@ComponentScan("com.mypackage")
public class MultitenancyPlatformConfig {

    @Bean(name="defaultDataSource")
    public DataSource dataSource() {
        final JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
        DataSource dataSource = dsLookup.getDataSource(java:comp/env/jdbc/myDataSource);
        return dataSource;
    }

    @Autowired
    @Bean(name = "defaultSessionFactory")
    public SessionFactory getSessionFactory(DataSource defaultDataSource) {
        LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(
            defaultDataSource);
        sessionBuilder.addAnnotatedClasses(Tenant.class);
        sessionBuilder.addProperties(hibProperties());
        return sessionBuilder.buildSessionFactory();
    }

    private Properties hibProperties() {
       Properties properties = new Properties();
       properties.put("hibernate.format_sql",
            "true");
       properties.put("hibernate.dialect",
            "org.hibernate.dialect.PostgreSQLDialect");
       properties.put("hibernate.default_schema", "public");
       return properties;
    }

    @Autowired
    @Bean(name = "tenantReadService")
    public TenantReadService getTenantReadService(SessionFactory defaultSessionFactory) {
        return new TenantReadServiceImpl(defaultSessionFactory);
    }
}

MyPlatformConfig.java

@Configuration
@EnableTransactionManagement
@ComponentScan("com.mypackage")
@EnableJpaRepositories("com.mypackage.repository")
    public class MyPlatformConfig {

    @Bean
    public DataSource dataSource() {
        final JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
        DataSource dataSource = dsLookup.getDataSource("java:comp/env/jdbc/ihubDataSource");
        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(false);
        vendorAdapter.setDatabase(Database.POSTGRESQL);
        vendorAdapter.setDatabasePlatform("org.postgresql.Driver");

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan("com.mypackage.entity");
        factory.setJpaProperties(hibProperties());
        return factory;
    }

    private Properties hibProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect","org.hibernate.dialect.PostgreSQLDialect");
        properties.put("hibernate.format_sql","true");
        properties.put("hibernate.tenant_identifier_resolver"," com.mypackage.tenantresolvers.CustomTenantIdentifierResolver");
        properties.put("hibernate.multi_tenant_connection_provider", "com.mypackage.connectionproviders.MultiTenantConnectionProviderImpl");
        properties.put("hibernate.multiTenancy", "SCHEMA");
        return properties;
    }

    @Bean
    public JpaTransactionManager transactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return transactionManager;
    }
}

共有1个答案

郎献
2023-03-14

以下是我解决这个问题的方法:

  1. 使用自定义ServletFilter从请求头中提取值
  2. 在自定义ServletFilter中:对默认模式执行查询,以获取租户标识符并将其放入ThreadLocal中
  3. resolveCurrentTenantIdentifier中,只需从ThreadLocal返回值
 类似资料:
  • 我们正面临着解决这个问题的艰难时刻!我们正在尝试在不使用默认租户的情况下为Spring Boot服务使用MTA。这意味着当当前上下文中没有租户时,我们希望从我们的CurrentTenantIdentifierResolver实现返回null。这在我们用JavaEE+Hibernate+Deltaspike数据构建的其他服务中运行良好,但在Spring服务启动时失败。 异常消息如下:“由:org.h

  • 编辑:这个问题已经过时了 在我问这个问题的时候,身份框架是一个移动的目标。作者改变了相当多的东西,他们已经脱钩了其他几个,使一切变得更容易。 看一下GitHub上的ASP.NET标识示例项目。 我得到一个异常。ApplicationDbContext的定义由新建应用程序向导自动生成: 因此,我的猜测是,列用于区分和。但是,它不存在于我的数据库中(该数据库是由应用程序自动创建的)

  • 问题内容: 我的对象是: 函数的类别是: 当我尝试使用此功能时: 它不和我一起工作,有帮助吗?!!! 问题答案: 我用这个类来解决这个问题: 然后我用这个功能来使用它

  • 我正在使用Drools 6.3.0决赛。假设我有这样的规则 让我们进一步假设我用这个规则构建了KieSession,添加了一些事实,现在我想知道所有规则/所有与我的事实匹配的规则中使用的标识符。 所以我想在这里得到的是$人和$孩子。 我知道我可以获取使用AgendaEventListener触发的规则,从事件中我可以获取规则的名称,以及$person和$child的对象。但我没有找到从匹配中获取标

  • 本文向大家介绍如何在Android中获取默认手机IMEI?,包括了如何在Android中获取默认手机IMEI?的使用技巧和注意事项,需要的朋友参考一下 此示例演示了如何在android中获取默认手机IMEI。 步骤1-在Android Studio中创建一个新项目,转到File⇒New Project并填写所有必需的详细信息以创建一个新项目。 步骤2-将以下代码添加到res / layout /

  • 我有两个存储桶,一个来自谷歌云存储,一个由firebase创建,firebase创建的存储桶是默认的,我想更改默认的存储桶并删除firebase创建的存储桶。