我解释一下我的情况:SpringBoot + Hibernate + Multitenant (DB master + DB for tenant) + Postgressql。我有两种数据源配置,一种用于主数据库,一种用于每个客户端的数据库。
当我需要进行本机查询时,我的问题就开始了。我需要重新启动数据库序列。但我不太清楚如何恢复会话工厂。在我的身份验证中,我识别用户并设置租户持有人
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
private IUsuario userService;
private IUsuarioSucursalRol usrService;
private IEquipoMaster equipoService;
public JWTAuthorizationFilter(AuthenticationManager authManager, IUsuario userService,
IUsuarioSucursalRol usrService, IEquipoMaster equipoService) {
super(authManager);
this.userService = userService;
this.usrService = usrService;
this.equipoService = equipoService;
}
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
throws IOException, ServletException {
String header = req.getHeader(HEADER_AUTHORIZACION_KEY);
if (header == null || !header.startsWith(TOKEN_BEARER_PREFIX)) {
chain.doFilter(req, res);
return;
}
UsernamePasswordAuthenticationToken authentication = getAuthentication(header);
SecurityContextHolder.getContext().setAuthentication(authentication); // Asigna
// UsernamePasswordAuthenticationToken
chain.doFilter(req, res);
}
private UsernamePasswordAuthenticationToken isUser(String token, String user) {
//// Valida que el token del USUARIO y generara el
//// UsernamePasswordAuthenticationToken
try {
Integer tenantint = obtainTenant(token); // Obtiene el tenant del token
if (tenantint != null || tenantint != 0) { /// Valida que no venga un token erroneo sin tenant
String tenant = String.valueOf(tenantint);
TenantContextHolder.setTenantId(tenant); /// Coloca la base de datos
Usuario finduser = userService.findUsuario(user, tenantint); // Busca el usuario
if (finduser != null) {
if (finduser.getFechaBaja() == null) { /// Valida que no este dado de baja el usuario
boolean respuesta = usrService.isAdmin(finduser.getIdUsuario());
Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
if (respuesta) { // Es un admin
grantedAuthorities.add(new SimpleGrantedAuthority("ADMINISTRADOR"));
System.out.println("IS ADMINISTRADOR");
} else if (usrService.isUser((int) finduser.getIdUsuario())) { /// Es un usuario
grantedAuthorities.add(new SimpleGrantedAuthority("USUARIO"));
System.out.println("IS USUARIO");
} else { // Entonces es un vendedor por defecto
grantedAuthorities.add(new SimpleGrantedAuthority("VENDEDOR"));
System.out.println("IS VENDEDOR");
}
return new UsernamePasswordAuthenticationToken(user, null, grantedAuthorities);
}
}
}
} catch (Exception e) {
// TODO: handle exception
}
return null;
}}
然后,JpaRepository 负责在正确的数据库中执行查询。但是,我怎么能通过执行本机查询来做同样的事情呢?还有另一种方法可以做到这一点吗?
更新
更多代码:
public class CurrentTenantIdentifierResolverImpl implements CurrentTenantIdentifierResolver {
private static final String DEFAULT_TENANT_ID = "tenant_standar";
@Override
public String resolveCurrentTenantIdentifier() {
String tenant = TenantContextHolder.getTenant();
return StringUtils.isNotBlank(tenant) ? tenant : DEFAULT_TENANT_ID;
}
@Override
public boolean validateExistingCurrentSessions() {
return true;
}}
@Configuration
public class DataSourceBasedMultiTenantConnectionProviderImpl
extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl {
private static final long serialVersionUID = 1L;
/**
* Injected MasterTenantRepository to access the tenant information from the
* master_tenant table
*/
@Autowired
private ITenant masterTenantRepo;
@Autowired
private IBaseDatos masterdberepo;
/**
* Map to store the tenant ids as key and the data source as the value
*/
private Map<String, DataSource> dataSourcesMtApp = new TreeMap<>();
@Override
protected DataSource selectAnyDataSource() {
// This method is called more than once. So check if the data source map
// is empty. If it is then rescan master_tenant table for all tenant
// entries.
if (dataSourcesMtApp.isEmpty()) {
List<Tenant> masterTenants = masterTenantRepo.findAll();
for (Tenant masterTenant : masterTenants) {
BaseDatos base = masterdberepo.findDatosBaseTenant(masterTenant);
dataSourcesMtApp.put(String.valueOf(base.getIdTenant().getIdTenant()),
DataSourceUtil.createAndConfigureDataSource(base));
}
}
return this.dataSourcesMtApp.values().iterator().next();
}
protected String selectTenantDataSource(DataSource datasource) {
// This method is called more than once. So check if the data source map
// is empty. If it is then rescan master_tenant table for all tenant
// entries.
String tenant = "";
while (dataSourcesMtApp.keySet().iterator().hasNext()) {
tenant = dataSourcesMtApp.keySet().iterator().next();
if (dataSourcesMtApp.get(tenant).equals(datasource)) {
break;
}
}
return tenant;
}
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
// TODO Auto-generated method stub
return super.getConnection(tenantIdentifier);
}
@Override
protected DataSource selectDataSource(String tenantIdentifier) {
// If the requested tenant id is not present check for it in the master
// database 'master_tenant' table
tenantIdentifier = initializeTenantIfLost(tenantIdentifier);
if (!this.dataSourcesMtApp.containsKey(tenantIdentifier)) {
List<Tenant> masterTenants = masterTenantRepo.findAll();
for (Tenant masterTenant : masterTenants) {
BaseDatos base = masterdberepo.findDatosBaseTenant(masterTenant);
dataSourcesMtApp.put(String.valueOf(base.getIdTenant().getIdTenant()),
DataSourceUtil.createAndConfigureDataSource(base));
}
}
return this.dataSourcesMtApp.get(tenantIdentifier);
}
/**
* Initialize tenantId based on the logged in user if the tenant Id got lost in
* after form submission in a user session.
*
* @param tenantIdentifier
* @return tenantIdentifier
*/
private String initializeTenantIfLost(String tenantIdentifier) {
if (TenantContextHolder.getTenant() == null) {
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
CustomUserDetails customUserDetails = null;
if (authentication != null) {
Object principal = authentication.getPrincipal();
customUserDetails = principal instanceof CustomUserDetails ? (CustomUserDetails) principal : null;
}
TenantContextHolder.setTenantId(customUserDetails.getTenant().getNombre());
}
if (tenantIdentifier != TenantContextHolder.getTenant()) {
tenantIdentifier = TenantContextHolder.getTenant();
}
return tenantIdentifier;
}
}
@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = { "com.kretz.gestion.equipos.tenant.repository",
"com.kretz.gestion.equipos.tenant.model" })
@EnableJpaRepositories(basePackages = {
"com.kretz.gestion.equipos.tenant.repository" }, entityManagerFactoryRef = "tenantEntityManagerFactory", transactionManagerRef = "tenantTransactionManager")
public class TenantDatabaseConfig implements ApplicationListener<ApplicationReadyEvent> {
@Bean(name = "tenantJpaVendorAdapter")
public JpaVendorAdapter jpaVendorAdapter() {
return new HibernateJpaVendorAdapter();
}
@Bean(name = "tenantTransactionManager")
public JpaTransactionManager transactionManager(
@Qualifier("tenantEntityManagerFactory") EntityManagerFactory tenantEntityManager) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(tenantEntityManager);
return transactionManager;
}
/**
* The multi tenant connection provider
*
* @return
*/
@Bean(name = "datasourceBasedMultitenantConnectionProvider")
@ConditionalOnBean(name = "masterEntityManagerFactory")
public MultiTenantConnectionProvider multiTenantConnectionProvider() {
// Autowires the multi connection provider
return crearDataSource();
}
@Bean(name = "datasource")
public DataSourceBasedMultiTenantConnectionProviderImpl crearDataSource() {
return new DataSourceBasedMultiTenantConnectionProviderImpl();
}
/**
* The current tenant identifier resolver
*
* @return
*/
@Bean(name = "currentTenantIdentifierResolver")
public CurrentTenantIdentifierResolver currentTenantIdentifierResolver() {
return new CurrentTenantIdentifierResolverImpl();
}
/**
* Creates the entity manager factory bean which is required to access the JPA
* functionalities provided by the JPA persistence provider, i.e. Hibernate in
* this case.
*
* @param connectionProvider
* @param tenantResolver
* @return
*/
@Bean(name = "tenantEntityManagerFactory")
@ConditionalOnBean(name = "datasourceBasedMultitenantConnectionProvider")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
@Qualifier("datasourceBasedMultitenantConnectionProvider") MultiTenantConnectionProvider connectionProvider,
@Qualifier("currentTenantIdentifierResolver") CurrentTenantIdentifierResolver tenantResolver) {
System.out.println(" LocalContainerEntityManagerFactoryBean PASO");
LocalContainerEntityManagerFactoryBean emfBean = new LocalContainerEntityManagerFactoryBean();
// All tenant related entities, repositories and service classes must be scanned
emfBean.setPackagesToScan(
new String[] { Empresa.class.getPackage().getName(), IEmpresa.class.getPackage().getName() });
emfBean.setJpaVendorAdapter(jpaVendorAdapter());
emfBean.setPersistenceUnitName("tenantdb-persistence-unit");
Map<String, Object> properties = new HashMap<>();
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT, MultiTenancyStrategy.DATABASE);
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_CONNECTION_PROVIDER, connectionProvider);
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, tenantResolver);
// ImprovedNamingStrategy is deprecated and unsupported in Hibernate 5
// properties.put("hibernate.ejb.naming_strategy",
// "org.hibernate.cfg.ImprovedNamingStrategy");
properties.put(org.hibernate.cfg.Environment.DIALECT, "org.hibernate.dialect.PostgreSQL95Dialect"); // LUISINA
properties.put(org.hibernate.cfg.Environment.SHOW_SQL, true);
properties.put(org.hibernate.cfg.Environment.FORMAT_SQL, true);
properties.put(org.hibernate.cfg.Environment.ENABLE_LAZY_LOAD_NO_TRANS, true);
// properties.put(org.hibernate.cfg.Environment.USE_TRANSIENT_ANNOTATION, true);
properties.put(org.hibernate.cfg.Environment.HBM2DDL_AUTO, "validate");
properties.put(org.hibernate.cfg.Environment.NON_CONTEXTUAL_LOB_CREATION, true);
properties.put(org.hibernate.cfg.Environment.C3P0_MAX_SIZE, 20);
properties.put(org.hibernate.cfg.Environment.C3P0_MIN_SIZE, 5);
properties.put(org.hibernate.cfg.Environment.C3P0_MAX_STATEMENTS, 50);
properties.put(org.hibernate.cfg.Environment.C3P0_ACQUIRE_INCREMENT, 5);
properties.put(org.hibernate.cfg.Environment.C3P0_TIMEOUT, 1800);
emfBean.setJpaPropertyMap(properties);
return emfBean;
}
@Autowired
@Qualifier("datasourceBasedMultitenantConnectionProvider")
MultiTenantConnectionProvider connectionProvider;
@Override
@ConditionalOnBean(name = "datasourceBasedMultitenantConnectionProvider")
public void onApplicationEvent(ApplicationReadyEvent event) {
}
}
谢谢。