Как получить идентификатор арендатора, хранящийся в таблице схемы по умолчанию?

Я работаю над включением мультиарендности в моем приложении на основе Spring с использованием спящего режима. Я создал индивидуальную реализацию CurrentTenantIdentifierResolver и переопределил метод resolveCurrentTenantIdentifier() для определения идентификатора клиента. Приложение отлично работает, когда я указываю жестко запрограммированный идентификатор клиента.

Но затем возникла потребность получить идентификатор клиента из таблицы в схеме базы данных по умолчанию на основе значения в заголовке запроса. Я искал об этом во многих местах и ​​провел несколько попыток, но без особого успеха.

Любая помощь по этому поводу будет принята с благодарностью. Пожалуйста, дайте мне знать, какую всю информацию мне нужно предоставить для лучшего понимания сценария проблемы.

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

person Niharika G.    schedule 08.07.2015    source источник


Ответы (1)


Вот как я бы решил проблему:

  1. Используйте собственный ServletFilter для извлечения значения из запроса. заголовки.
  2. В вашем настраиваемом ServletFilter: выполните запрос по схеме по умолчанию, чтобы получить идентификатор клиента и поместить его в ThreadLocal
  3. В _1 _ просто верните значение из ThreadLocal.
person ben75    schedule 08.07.2015
comment
Спасибо @ ben75. На самом деле я не мог раньше объяснить вам настоящую проблему. Я добавил соответствующий код сейчас. Мне удалось получить идентификатор клиента из базы данных, но затем функция save () для всех моих реальных сущностей перестала работать. После отладки я обнаружил, что метод getConnection(String tenantIdentifier) в MultiTenantConnectionProviderImpl не вызывается. Таким образом, он пытается найти таблицу в схеме по умолчанию и терпит неудачу, поскольку не может найти ее там. Мы используем jpa spring-data на уровне доступа к данным - person Niharika G.; 09.07.2015