feat: Implement database initialization using init.sql and update DataInitializer.
This commit is contained in:
@@ -3,61 +3,90 @@ package com.magistr.app.config;
|
||||
import com.magistr.app.config.tenant.TenantConfig;
|
||||
import com.magistr.app.config.tenant.TenantContext;
|
||||
import com.magistr.app.config.tenant.TenantRoutingDataSource;
|
||||
import com.magistr.app.model.Role;
|
||||
import com.magistr.app.model.User;
|
||||
import com.magistr.app.repository.UserRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
import javax.sql.DataSource;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.Statement;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* При запуске приложения проверяет каждый тенант:
|
||||
* - Если таблицы не существуют — выполняет init.sql
|
||||
* - init.sql создаёт все таблицы + admin (admin/admin) + тестовые данные
|
||||
*/
|
||||
@Component
|
||||
public class DataInitializer implements CommandLineRunner {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DataInitializer.class);
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final BCryptPasswordEncoder passwordEncoder;
|
||||
private final TenantRoutingDataSource routingDataSource;
|
||||
private final DataSource dataSource;
|
||||
|
||||
public DataInitializer(UserRepository userRepository,
|
||||
BCryptPasswordEncoder passwordEncoder,
|
||||
TenantRoutingDataSource routingDataSource) {
|
||||
this.userRepository = userRepository;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
public DataInitializer(TenantRoutingDataSource routingDataSource, DataSource dataSource) {
|
||||
this.routingDataSource = routingDataSource;
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
// Создаём admin в каждом тенанте
|
||||
for (TenantConfig tenant : routingDataSource.getTenantConfigs().values()) {
|
||||
String domain = tenant.getDomain();
|
||||
try {
|
||||
TenantContext.setCurrentTenant(tenant.getDomain());
|
||||
initAdmin(tenant.getDomain());
|
||||
TenantContext.setCurrentTenant(domain);
|
||||
|
||||
if (needsInit()) {
|
||||
log.info("[{}] Tables not found — executing init.sql...", domain);
|
||||
executeInitSql();
|
||||
log.info("[{}] init.sql executed successfully", domain);
|
||||
} else {
|
||||
log.info("[{}] Tables already exist, skipping init", domain);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to init admin for tenant '{}': {}", tenant.getDomain(), e.getMessage());
|
||||
log.error("[{}] Initialization failed: {}", domain, e.getMessage());
|
||||
} finally {
|
||||
TenantContext.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initAdmin(String tenantDomain) {
|
||||
Optional<User> existing = userRepository.findByUsername("admin");
|
||||
/**
|
||||
* Проверяет, существует ли таблица 'users' в текущей БД тенанта.
|
||||
*/
|
||||
private boolean needsInit() {
|
||||
try (Connection conn = dataSource.getConnection();
|
||||
ResultSet rs = conn.getMetaData().getTables(null, null, "users", new String[]{"TABLE"})) {
|
||||
return !rs.next();
|
||||
} catch (Exception e) {
|
||||
log.warn("Could not check tables: {}", e.getMessage());
|
||||
return true; // Если не смогли проверить — пробуем init
|
||||
}
|
||||
}
|
||||
|
||||
if (existing.isEmpty()) {
|
||||
User admin = new User();
|
||||
admin.setUsername("admin");
|
||||
admin.setPassword(passwordEncoder.encode("admin"));
|
||||
admin.setRole(Role.ADMIN);
|
||||
userRepository.save(admin);
|
||||
log.info("[{}] Created default admin user (admin/admin)", tenantDomain);
|
||||
} else {
|
||||
log.info("[{}] Admin user already exists", tenantDomain);
|
||||
/**
|
||||
* Читает init.sql из classpath и выполняет его через JDBC.
|
||||
*/
|
||||
private void executeInitSql() throws Exception {
|
||||
// Читаем SQL файл из ресурсов
|
||||
String sql;
|
||||
try (InputStream is = new ClassPathResource("init.sql").getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
|
||||
sql = reader.lines().collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
// Выполняем SQL
|
||||
try (Connection conn = dataSource.getConnection();
|
||||
Statement stmt = conn.createStatement()) {
|
||||
stmt.execute(sql);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user