如何获取存储在默认模式表中的租户标识符? [英] How to fetch tenant identifier stored in a table of default schema?

查看:158
本文介绍了如何获取存储在默认模式表中的租户标识符?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用hibernate在基于Spring的应用程序中启用多租户。我创建了一个 CurrentTenantIdentifierResolver 的自定义实现,并提供了 resolveCurrentTenantIdentifier()方法来确定租户标识符。当我提供硬编码的租户标识符时,该应用程序正常工作。

但是接下来需要根据请求头中的值从数据库的缺省模式中的表中获取租户标识符。我曾在很多地方搜索过这方面的内容,并做了一些尝试,但收效甚微。



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


$ b CustomTenantIdentifierResolver.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);
返回tenantSchema;
}
} catch(Exception ex){
return DEFAULT_TENANT_SCHEMA;
}
//返回myschema;
}

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

}

TenantRequestContextImpl.java

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

@Autowired
private TenantReadService tenantReadService;
$ b @Override
public String getTenantIdValue(){
String tenantId =((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes())
.getRequest()。getHeader(tenantId );
返回tenantId;

$ b @Override
public String getTenantSchema(String tenantId){
Tenant tenant = tenantReadService.findById(Integer.parseInt(tenantId));
返回tenant.getTenantSchemaName();


TenantReadServiceImpl.java

  @Repository 
public class TenantReadServiceImpl implements TenantReadService {

@Autowired
private SessionFactory的defaultSessionFactory;

public TenantReadServiceImpl(){


$ b $ 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);
租户租户=(租户)query.uniqueResult();
defaultSessionFactory.getCurrentSession()。clear();
归还租户;


$ / code $ / pre
$ b

MultitenancyPlatformConfig.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);
返回dataSource;

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


私有属性hibProperties(){
属性properties = new Properties();
properties.put(hibernate.format_sql,
true);
properties.put(hibernate.dialect,
org.hibernate.dialect.PostgreSQLDialect);
properties.put(hibernate.default_schema,public);
返回属性;

$ b @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);
返回dataSource;


$Be $ b $ 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());
退货工厂;


私有属性hibProperties(){
属性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);
返回属性;


$Be
public JpaTransactionManager transactionManager(){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory()。getObject());
返回transactionManager;



$ div $解析方案

我是如何解决这个问题的:


  1. 使用自定义 ServletFilter 从请求头中提取值。
  2. 在您的自定义ServletFilter中:执行查询默认模式以获取租户标识符并将其放入 ThreadLocal

  3. resolveCurrentTenantIdentifier 仅返回ThreadLocal的值。


    1. I am working to enable multitenancy in my spring based application using hibernate. I created a custom implementation of CurrentTenantIdentifierResolver and overidden the resolveCurrentTenantIdentifier() method to determine the tenant identifier. The application works fine when I provide a hard-coded tenant identifier.

      But then a requirement came up to fetch the tenant identifier from a table in default schema of database based on a value in request header. I searched regarding this at many places and did some hit and trials but with little success.

      Any help regarding this would be greatly appreciated. Please let me know what all information I need to provide for better understanding of the problem scenario.

      CustomTenantIdentifierResolver.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;
          }
      
      }
      

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

      TenantReadServiceImpl.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;
          }
      }
      

      MultitenancyPlatformConfig.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;
          }
      }
      

      解决方案

      Here is how I would solve the problem :

      1. Use a custom ServletFilter to extract the value from the request headers.
      2. In your custom ServletFilter : perform a query on the default schema to get the tenant identifier and put it in a ThreadLocal
      3. In resolveCurrentTenantIdentifier just return the value from the ThreadLocal.

      这篇关于如何获取存储在默认模式表中的租户标识符?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆