first commit
This commit is contained in:
@ -35,7 +35,12 @@ public enum DatasourceErrorCode {
|
|||||||
/**
|
/**
|
||||||
* 创建模式/库错误
|
* 创建模式/库错误
|
||||||
*/
|
*/
|
||||||
CREATE_SCHEMA_ERROR(50105, "创建模式/库错误");
|
CREATE_SCHEMA_ERROR(50105, "创建模式/库错误"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化数据错误
|
||||||
|
*/
|
||||||
|
INIT_DATA_ERROR(50106, "初始化数据错误");
|
||||||
|
|
||||||
private final Integer code;
|
private final Integer code;
|
||||||
private final String msg;
|
private final String msg;
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
package com.qiaoba.module.tenant.handler;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数据处理器
|
|
||||||
*
|
|
||||||
* @author ailanyin
|
|
||||||
* @version 1.0
|
|
||||||
* @since 2023/6/8 15:27
|
|
||||||
*/
|
|
||||||
public interface DataHandler {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理
|
|
||||||
*
|
|
||||||
* @param conn conn
|
|
||||||
* @param needCreateTables 是否需要建表
|
|
||||||
* @param tenantId tenantId
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
boolean handle(Connection conn, String tenantId, Boolean needCreateTables);
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
package com.qiaoba.module.tenant.handler;
|
|
||||||
|
|
||||||
import com.qiaoba.common.base.enums.DataBaseEnum;
|
|
||||||
import com.qiaoba.common.base.exceptions.ServiceException;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理器工厂-根据不同类型的数据库-选择不同的处理器
|
|
||||||
*
|
|
||||||
* @author ailanyin
|
|
||||||
* @version 1.0
|
|
||||||
* @since 2023/6/8 15:34
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class DataHandlerFactory {
|
|
||||||
|
|
||||||
private static Map<String, DataHandler> handlerMap = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private final MysqlDataHandler mysqlDataHandler;
|
|
||||||
private final OracleDataHandler oracleDataHandler;
|
|
||||||
private final PostgreSqlHandler postgreSqlHandler;
|
|
||||||
private final SqlServerHandler sqlServerHandler;
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void register() {
|
|
||||||
handlerMap.put(DataBaseEnum.MY_SQL.getType(), mysqlDataHandler);
|
|
||||||
handlerMap.put(DataBaseEnum.ORACLE.getType(), oracleDataHandler);
|
|
||||||
handlerMap.put(DataBaseEnum.POSTGRE_SQL.getType(), postgreSqlHandler);
|
|
||||||
handlerMap.put(DataBaseEnum.SQL_SERVER.getType(), sqlServerHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DataHandler getHandler(String name) {
|
|
||||||
DataHandler dataHandler = handlerMap.get(name);
|
|
||||||
if (Objects.isNull(dataHandler)) {
|
|
||||||
throw new ServiceException("数据库处理器工厂异常, 类型:[" + name + "]找不到相对应的解析器");
|
|
||||||
}
|
|
||||||
return dataHandler;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,175 +0,0 @@
|
|||||||
package com.qiaoba.module.tenant.handler;
|
|
||||||
|
|
||||||
import cn.hutool.core.io.FileUtil;
|
|
||||||
import cn.hutool.core.lang.Snowflake;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.db.DbUtil;
|
|
||||||
import cn.hutool.db.sql.SqlExecutor;
|
|
||||||
import com.qiaoba.module.tenant.utils.MenuUtil;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.ibatis.jdbc.ScriptRunner;
|
|
||||||
import org.springframework.core.io.ClassPathResource;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MysqlHandler
|
|
||||||
*
|
|
||||||
* @author ailanyin
|
|
||||||
* @version 1.0
|
|
||||||
* @since 2023/6/5 16:28
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@Slf4j
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class MysqlDataHandler implements DataHandler {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 角色-超管ID
|
|
||||||
*/
|
|
||||||
private static final ThreadLocal<Long> ROLE_SUPER_ADMIN_ID = new ThreadLocal<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户-超管ID
|
|
||||||
*/
|
|
||||||
private static final ThreadLocal<Long> USER_SUPER_ADMIN_ID = new ThreadLocal<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean handle(Connection conn, String tenantId, Boolean needCreateTables) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 手动提交
|
|
||||||
conn.setAutoCommit(false);
|
|
||||||
// 创建表
|
|
||||||
if (needCreateTables) {
|
|
||||||
initTables(conn);
|
|
||||||
}
|
|
||||||
// 处理 sys_config
|
|
||||||
handleSysConfig(conn, tenantId);
|
|
||||||
// 处理 sys_post
|
|
||||||
handleSysPost(conn, tenantId);
|
|
||||||
// 处理 sys_role
|
|
||||||
handleSysRole(conn, tenantId);
|
|
||||||
// 处理 sys_user
|
|
||||||
handleSysUser(conn, tenantId);
|
|
||||||
// 处理 sys_user_role
|
|
||||||
bindUserAndRole(conn, tenantId);
|
|
||||||
// 处理 sys_menu
|
|
||||||
MenuUtil.handleMenu(conn, tenantId);
|
|
||||||
// 处理 sys_role_menu
|
|
||||||
bindRoleAndMenu(conn, tenantId);
|
|
||||||
conn.commit();
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
try {
|
|
||||||
conn.rollback();
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
DbUtil.close(conn);
|
|
||||||
ROLE_SUPER_ADMIN_ID.remove();
|
|
||||||
USER_SUPER_ADMIN_ID.remove();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initTables(Connection conn) throws Exception {
|
|
||||||
ClassPathResource resource = new ClassPathResource("MySQL/table/base_tables");
|
|
||||||
File file = resource.getFile();
|
|
||||||
FileReader reader = new FileReader(file);
|
|
||||||
ScriptRunner scriptRunner = new ScriptRunner(conn);
|
|
||||||
scriptRunner.setSendFullScript(true);
|
|
||||||
scriptRunner.runScript(reader);
|
|
||||||
reader.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleSysConfig(Connection conn, String tenantId) throws Exception {
|
|
||||||
handleSql(conn, tenantId, "MySQL/data/sys_config_data");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleSql(Connection conn, String tenantId, String fileName) throws Exception {
|
|
||||||
ClassPathResource resource = new ClassPathResource(fileName);
|
|
||||||
List<String> lines = FileUtil.readLines(resource.getFile(), Charset.defaultCharset());
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (String line : lines) {
|
|
||||||
if (StrUtil.isNotBlank(line)) {
|
|
||||||
Snowflake snowflake = new Snowflake();
|
|
||||||
line = StrUtil.format(line, snowflake.nextId(), tenantId);
|
|
||||||
sb.append(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (StrUtil.isNotBlank(sb.toString())) {
|
|
||||||
SqlExecutor.execute(conn, sb.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleSysPost(Connection conn, String tenantId) throws Exception {
|
|
||||||
handleSql(conn, tenantId, "MySQL/data/sys_post_data");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleSysRole(Connection conn, String tenantId) throws Exception {
|
|
||||||
handleUserOrRole(conn, tenantId, "MySQL/data/sys_role_data", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleUserOrRole(Connection conn, String tenantId, String fileName, Boolean isRole) throws Exception {
|
|
||||||
ClassPathResource resource = new ClassPathResource(fileName);
|
|
||||||
List<String> lines = FileUtil.readLines(resource.getFile(), Charset.defaultCharset());
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
long superAdminId = new Snowflake().nextId();
|
|
||||||
if (isRole) {
|
|
||||||
ROLE_SUPER_ADMIN_ID.set(superAdminId);
|
|
||||||
} else {
|
|
||||||
USER_SUPER_ADMIN_ID.set(superAdminId);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < lines.size(); i++) {
|
|
||||||
String line = lines.get(i);
|
|
||||||
if (StrUtil.isBlank(line)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (i == 0) {
|
|
||||||
// 第1行是超管
|
|
||||||
line = StrUtil.format(line, superAdminId, tenantId);
|
|
||||||
} else {
|
|
||||||
Snowflake snowflake = new Snowflake();
|
|
||||||
line = StrUtil.format(line, snowflake.nextId(), tenantId);
|
|
||||||
}
|
|
||||||
sb.append(line);
|
|
||||||
}
|
|
||||||
if (StrUtil.isNotBlank(sb.toString())) {
|
|
||||||
SqlExecutor.execute(conn, sb.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleSysUser(Connection conn, String tenantId) throws Exception {
|
|
||||||
handleUserOrRole(conn, tenantId, "MySQL/data/sys_user_data", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void bindUserAndRole(Connection conn, String tenantId) throws Exception {
|
|
||||||
// user_id role_id tenant_id
|
|
||||||
String sql = StrUtil.format("INSERT INTO `sys_user_role` VALUES ({}, {}, {});",
|
|
||||||
USER_SUPER_ADMIN_ID.get(),
|
|
||||||
ROLE_SUPER_ADMIN_ID.get(), tenantId);
|
|
||||||
SqlExecutor.execute(conn, sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void bindRoleAndMenu(Connection conn, String tenantId) throws Exception {
|
|
||||||
String sql = "INSERT INTO `sys_role_menu` VALUES ({}, {}, {});";
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
List<String> menuIds = MenuUtil.getAllMenuIdsByTenantId(conn, tenantId);
|
|
||||||
for (String menuId : menuIds) {
|
|
||||||
sb.append(StrUtil.format(sql, ROLE_SUPER_ADMIN_ID.get(), menuId, tenantId));
|
|
||||||
}
|
|
||||||
if (StrUtil.isNotBlank(sb.toString())) {
|
|
||||||
SqlExecutor.execute(conn, sb.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
package com.qiaoba.module.tenant.handler;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OracleDataHandler
|
|
||||||
*
|
|
||||||
* @author ailanyin
|
|
||||||
* @version 1.0
|
|
||||||
* @since 2023/6/5 16:28
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@Slf4j
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class OracleDataHandler implements DataHandler {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean handle(Connection conn, String tenantId, Boolean needCreateTables) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
package com.qiaoba.module.tenant.handler;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PostgreSqlHandler
|
|
||||||
*
|
|
||||||
* @author ailanyin
|
|
||||||
* @version 1.0
|
|
||||||
* @since 2023/6/5 16:28
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@Slf4j
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class PostgreSqlHandler implements DataHandler {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean handle(Connection conn, String tenantId, Boolean needCreateTables) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
package com.qiaoba.module.tenant.handler;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SqlServerHandler
|
|
||||||
*
|
|
||||||
* @author ailanyin
|
|
||||||
* @version 1.0
|
|
||||||
* @since 2023/6/5 16:28
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@Slf4j
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class SqlServerHandler implements DataHandler {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean handle(Connection conn, String tenantId, Boolean needCreateTables) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,9 @@
|
|||||||
package com.qiaoba.module.tenant.init;
|
package com.qiaoba.module.tenant.init;
|
||||||
|
|
||||||
|
import com.qiaoba.module.tenant.entity.vo.TenantInitVo;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化数据策略
|
* 初始化数据策略
|
||||||
*
|
*
|
||||||
@ -8,4 +12,13 @@ package com.qiaoba.module.tenant.init;
|
|||||||
* @since 2023/6/27 13:05
|
* @since 2023/6/27 13:05
|
||||||
*/
|
*/
|
||||||
public interface InitDataStrategy {
|
public interface InitDataStrategy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化数据
|
||||||
|
*
|
||||||
|
* @param conn 连接对象
|
||||||
|
* @param tenantId 租户ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
TenantInitVo init(Connection conn, String tenantId);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
package com.qiaoba.module.tenant.init;
|
||||||
|
|
||||||
|
import com.qiaoba.common.base.enums.DataBaseEnum;
|
||||||
|
import com.qiaoba.common.base.exceptions.ServiceException;
|
||||||
|
import com.qiaoba.module.tenant.init.impl.MysqlInitDataStrategy;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 策略工厂-租户初始化-导入数据
|
||||||
|
*
|
||||||
|
* @author ailanyin
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2023/6/27 16:41
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class InitDataStrategyFactory {
|
||||||
|
|
||||||
|
private static Map<String, InitDataStrategy> FACTORY = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private final MysqlInitDataStrategy mysqlInitDataStrategy;
|
||||||
|
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void register() {
|
||||||
|
FACTORY.put(DataBaseEnum.MY_SQL.getType(), mysqlInitDataStrategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InitDataStrategy getStrategy(String name) {
|
||||||
|
InitDataStrategy strategy = FACTORY.get(name);
|
||||||
|
if (Objects.isNull(strategy)) {
|
||||||
|
throw new ServiceException("[ InitDataStrategy ]策略工厂异常, 类型:[" + name + "]找不到相对应的策略");
|
||||||
|
}
|
||||||
|
return strategy;
|
||||||
|
}
|
||||||
|
}
|
@ -21,4 +21,12 @@ public interface InitTablesStrategy {
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
TenantInitVo create(Connection conn, String schema);
|
TenantInitVo create(Connection conn, String schema);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建表
|
||||||
|
*
|
||||||
|
* @param conn 连接对象
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
TenantInitVo create(Connection conn);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
package com.qiaoba.module.tenant.init.impl;
|
||||||
|
|
||||||
|
import cn.hutool.db.DbUtil;
|
||||||
|
import cn.hutool.http.HttpStatus;
|
||||||
|
import com.qiaoba.common.base.code.DatasourceErrorCode;
|
||||||
|
import com.qiaoba.module.tenant.entity.vo.TenantInitVo;
|
||||||
|
import com.qiaoba.module.tenant.init.InitDataStrategy;
|
||||||
|
import com.qiaoba.module.tenant.utils.InitDataUtil;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化数据策略
|
||||||
|
*
|
||||||
|
* @author ailanyin
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2023/6/27 13:05
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class MysqlInitDataStrategy implements InitDataStrategy {
|
||||||
|
@Override
|
||||||
|
public TenantInitVo init(Connection conn, String tenantId) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 手动提交
|
||||||
|
conn.setAutoCommit(false);
|
||||||
|
// 处理 sys_config
|
||||||
|
InitDataUtil.handleSysConfig(conn, tenantId, "MySQL/data/sys_config_data");
|
||||||
|
// 处理 sys_post
|
||||||
|
InitDataUtil.handleSysPost(conn, tenantId, "MySQL/data/sys_post_data");
|
||||||
|
// 处理 sys_role
|
||||||
|
InitDataUtil.handleSysRole(conn, tenantId, "MySQL/data/sys_role_data");
|
||||||
|
// 处理 sys_user
|
||||||
|
InitDataUtil.handleSysUser(conn, tenantId, "MySQL/data/sys_user_data");
|
||||||
|
// 处理 sys_user_role
|
||||||
|
InitDataUtil.bindUserAndRole(conn, tenantId);
|
||||||
|
// 处理 sys_menu todo
|
||||||
|
//MenuUtil.handleMenu(conn, tenantId);
|
||||||
|
// 处理 sys_role_menu
|
||||||
|
InitDataUtil.bindRoleAndMenu(conn, tenantId);
|
||||||
|
conn.commit();
|
||||||
|
return new TenantInitVo(HttpStatus.HTTP_OK, null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
conn.rollback();
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
return new TenantInitVo(DatasourceErrorCode.INIT_DATA_ERROR.getCode(), e.getMessage());
|
||||||
|
} finally {
|
||||||
|
DbUtil.close(conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -52,4 +52,16 @@ public class MysqlInitTablesStrategy implements InitTablesStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TenantInitVo create(Connection conn) {
|
||||||
|
try {
|
||||||
|
DbUtil.runScript(conn, "MySQL/table/base_tables");
|
||||||
|
return new TenantInitVo(HttpStatus.HTTP_OK, null);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return new TenantInitVo(DatasourceErrorCode.CREATE_TABLE_ERROR.getCode(), e.getMessage());
|
||||||
|
} finally {
|
||||||
|
IoUtil.close(conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,15 @@ public interface SysTenantDatasourceService {
|
|||||||
*/
|
*/
|
||||||
SysTenantDatasource selectPrimary(String tenantId);
|
SysTenantDatasource selectPrimary(String tenantId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询租户的主要数据源
|
||||||
|
*
|
||||||
|
* @param tenantId 租户ID
|
||||||
|
* @param allowNull 允许空
|
||||||
|
* @return 数据源
|
||||||
|
*/
|
||||||
|
SysTenantDatasource selectPrimary(String tenantId, boolean allowNull);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过IP查询
|
* 通过IP查询
|
||||||
*
|
*
|
||||||
|
@ -2,8 +2,10 @@ package com.qiaoba.module.tenant.service.impl;
|
|||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.qiaoba.common.base.code.DatasourceErrorCode;
|
||||||
import com.qiaoba.common.base.constants.BaseConstant;
|
import com.qiaoba.common.base.constants.BaseConstant;
|
||||||
import com.qiaoba.common.base.enums.BaseEnum;
|
import com.qiaoba.common.base.enums.BaseEnum;
|
||||||
|
import com.qiaoba.common.base.exceptions.ServiceException;
|
||||||
import com.qiaoba.module.tenant.entity.SysTenantDatasource;
|
import com.qiaoba.module.tenant.entity.SysTenantDatasource;
|
||||||
import com.qiaoba.module.tenant.entity.param.SysTenantDatasourceParam;
|
import com.qiaoba.module.tenant.entity.param.SysTenantDatasourceParam;
|
||||||
import com.qiaoba.module.tenant.mapper.SysTenantDatasourceMapper;
|
import com.qiaoba.module.tenant.mapper.SysTenantDatasourceMapper;
|
||||||
@ -13,6 +15,7 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 租户数据源 服务层实现
|
* 租户数据源 服务层实现
|
||||||
@ -32,6 +35,15 @@ public class SysTenantDatasourceServiceImpl implements SysTenantDatasourceServic
|
|||||||
return sysTenantDatasourceMapper.selectOne(paramToWrapper(new SysTenantDatasourceParam(tenantId, BaseEnum.YES.getCode())));
|
return sysTenantDatasourceMapper.selectOne(paramToWrapper(new SysTenantDatasourceParam(tenantId, BaseEnum.YES.getCode())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SysTenantDatasource selectPrimary(String tenantId, boolean allowNull) {
|
||||||
|
SysTenantDatasource primary = selectPrimary(tenantId);
|
||||||
|
if (!allowNull && Objects.isNull(primary)) {
|
||||||
|
throw new ServiceException(DatasourceErrorCode.NOT_FIND.getCode(), DatasourceErrorCode.NOT_FIND.getMsg());
|
||||||
|
}
|
||||||
|
return primary;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SysTenantDatasource selectByIp(String tenantId, String ip) {
|
public SysTenantDatasource selectByIp(String tenantId, String ip) {
|
||||||
SysTenantDatasourceParam param = new SysTenantDatasourceParam(tenantId);
|
SysTenantDatasourceParam param = new SysTenantDatasourceParam(tenantId);
|
||||||
|
@ -94,7 +94,11 @@ public class SysTenantInitServiceImpl implements SysTenantInitService {
|
|||||||
}
|
}
|
||||||
// 数据源模式
|
// 数据源模式
|
||||||
if (SysTenant.DATASOURCE_MODE.equals(sysTenant.getMode())) {
|
if (SysTenant.DATASOURCE_MODE.equals(sysTenant.getMode())) {
|
||||||
|
SysTenantDatasource primary = sysTenantDatasourceService.selectPrimary(tenantId, false);
|
||||||
|
Connection connection = JdbcUtil.getConnection(DataBaseEnum.getDriver(primary.getType()),
|
||||||
|
DataBaseEnum.getUrl(primary.getType(), primary.getIp(), primary.getPort(), primary.getDbName(), primary.getSchemaName()),
|
||||||
|
primary.getUsername(), primary.getPassword());
|
||||||
|
return InitTablesStrategyFactory.getStrategy(primary.getType()).create(connection);
|
||||||
}
|
}
|
||||||
return new TenantInitVo(500, "未知异常");
|
return new TenantInitVo(500, "未知异常");
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,116 @@
|
|||||||
|
package com.qiaoba.module.tenant.utils;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import cn.hutool.core.lang.Snowflake;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.db.sql.SqlExecutor;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据初始化工具类
|
||||||
|
*
|
||||||
|
* @author ailanyin
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2023/6/5 16:28
|
||||||
|
*/
|
||||||
|
public class InitDataUtil {
|
||||||
|
|
||||||
|
private InitDataUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色-超管ID
|
||||||
|
*/
|
||||||
|
private static final ThreadLocal<Long> ROLE_SUPER_ADMIN_ID = new ThreadLocal<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户-超管ID
|
||||||
|
*/
|
||||||
|
private static final ThreadLocal<Long> USER_SUPER_ADMIN_ID = new ThreadLocal<>();
|
||||||
|
|
||||||
|
|
||||||
|
public static void handleSysConfig(Connection conn, String tenantId, String filePath) throws Exception {
|
||||||
|
handleSql(conn, tenantId, filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void handleSysPost(Connection conn, String tenantId, String filePath) throws Exception {
|
||||||
|
handleSql(conn, tenantId, filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void handleSysRole(Connection conn, String tenantId, String filePath) throws Exception {
|
||||||
|
handleUserOrRole(conn, tenantId, filePath, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void handleUserOrRole(Connection conn, String tenantId, String filePath, Boolean isRole) throws Exception {
|
||||||
|
ClassPathResource resource = new ClassPathResource(filePath);
|
||||||
|
List<String> lines = FileUtil.readLines(resource.getFile(), Charset.defaultCharset());
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
long superAdminId = new Snowflake().nextId();
|
||||||
|
if (isRole) {
|
||||||
|
ROLE_SUPER_ADMIN_ID.set(superAdminId);
|
||||||
|
} else {
|
||||||
|
USER_SUPER_ADMIN_ID.set(superAdminId);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < lines.size(); i++) {
|
||||||
|
String line = lines.get(i);
|
||||||
|
if (StrUtil.isBlank(line)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (i == 0) {
|
||||||
|
// 第1行是超管
|
||||||
|
line = StrUtil.format(line, superAdminId, tenantId);
|
||||||
|
} else {
|
||||||
|
Snowflake snowflake = new Snowflake();
|
||||||
|
line = StrUtil.format(line, snowflake.nextId(), tenantId);
|
||||||
|
}
|
||||||
|
sb.append(line);
|
||||||
|
}
|
||||||
|
if (StrUtil.isNotBlank(sb.toString())) {
|
||||||
|
SqlExecutor.execute(conn, sb.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void handleSysUser(Connection conn, String tenantId, String filePath) throws Exception {
|
||||||
|
handleUserOrRole(conn, tenantId, filePath, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bindUserAndRole(Connection conn, String tenantId) throws Exception {
|
||||||
|
// user_id role_id tenant_id
|
||||||
|
String sql = StrUtil.format("INSERT INTO sys_user_role VALUES ('{}', '{}', '{}');",
|
||||||
|
USER_SUPER_ADMIN_ID.get(),
|
||||||
|
ROLE_SUPER_ADMIN_ID.get(), tenantId);
|
||||||
|
SqlExecutor.execute(conn, sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bindRoleAndMenu(Connection conn, String tenantId) throws Exception {
|
||||||
|
String sql = "INSERT INTO sys_role_menu VALUES ('{}', '{}', '{}');";
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
List<String> menuIds = MenuUtil.getAllMenuIdsByTenantId(conn, tenantId);
|
||||||
|
for (String menuId : menuIds) {
|
||||||
|
sb.append(StrUtil.format(sql, ROLE_SUPER_ADMIN_ID.get(), menuId, tenantId));
|
||||||
|
}
|
||||||
|
if (StrUtil.isNotBlank(sb.toString())) {
|
||||||
|
SqlExecutor.execute(conn, sb.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void handleSql(Connection conn, String tenantId, String filePath) throws Exception {
|
||||||
|
ClassPathResource resource = new ClassPathResource(filePath);
|
||||||
|
List<String> lines = FileUtil.readLines(resource.getFile(), Charset.defaultCharset());
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (String line : lines) {
|
||||||
|
if (StrUtil.isNotBlank(line)) {
|
||||||
|
Snowflake snowflake = new Snowflake();
|
||||||
|
line = StrUtil.format(line, snowflake.nextId(), tenantId);
|
||||||
|
sb.append(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (StrUtil.isNotBlank(sb.toString())) {
|
||||||
|
SqlExecutor.execute(conn, sb.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user