現在のプロジェクトの要件の 1 つは、データを動的にクエリできること、フロントエンド ページ構成にデータ ソースを追加できること、そしてデータ ソースをビジネスにバインドできることです。データをクエリするときの構成は、 yml 構成ファイルは固定されておらず、データベース構成は、ビジネスにバインドされたデータベース テーブルに格納されているデータ ソースに基づく接続に基づいています。
Ruoyi はデータ ソースの切り替えをカプセル化し、AOP を通じてデータ ソースを指定しましたが、Ruoyi の元の方法では構成ファイル内の既存のデータ ソースを切り替えることしかできません。つまり、新しいデータ ソースを追加したい場合は、構成にデータ ソースを追加する必要があります。ファイルの変更も同様で、明らかに非常に面倒です。私たちのニーズを満たしていません。
/**
* 自定义多数据源切换注解
*
* 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
*
* @author ruoyi
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DataSource
{
/**
* 切换数据源名称
*/
public DataSourceType value() default DataSourceType.MASTER;
}
次に、私のアイデアは、Ruoyi のオリジナルのものに基づいて処理のレイヤーを追加し、もともと Ruoyi が書いた周囲の通知をコメントアウトし、処理に @Before() 事前通知を使用することです。
新しい列挙 OTHER をデータ ソース列挙に追加して、切り替えデータ ソースを識別します。
/**
* 数据源
*
* @author ruoyi
*/
public enum DataSourceType
{
/**
* 主库
*/
MASTER,
/**
* 从库
*/
SLAVE,
/**
* 其他
*/
OTHER
}
指定されたタイプはアスペクト事前通知で判断され、マスターの場合はデフォルトのデータソースが使用され、スレーブの場合は設定ファイルに設定されたスレーブライブラリが使用され、その他の場合はデータベーステーブルに存在するデータソースが使用されます。リクエストに基づいてメソッドのパラメーターはビジネス ID を取得し、データベースに移動してそれにバインドされているデータ ソース情報をクエリし、それを現在のデータ ソースとして設定します。使用後、データ ソースはポストを通じてクリアされます。通知@後。
/**
* 多数据源处理
*
* @author ruoyi
*/
@Log4j2
@Aspect
@Order(1)
@Component
public class DataSourceAspect
{
protected Logger logger = LoggerFactory.getLogger(getClass());
@Resource
private ISysDataSourceService sysDataSourceService;
@Pointcut("@annotation(com.ruoyi.common.annotation.DataSource)"
+ "|| @within(com.ruoyi.common.annotation.DataSource)")
public void dsPointCut()
{
}
@Before("dsPointCut()")
public void doBefore(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
logger.info("方法名称: " + method.getName());
DataSource dataSource = method.getAnnotation(DataSource.class);
DruidConfig dynamicDataSourceConfig = SpringContextUtils.getBean(DruidConfig.class);
Map<Object, Object> map = dynamicDataSourceConfig.getTargetDataSources();
log.info("TargetDataSources==="+map.toString());
// 通过判断 DataSource 中的值来判断当前方法应用哪个数据源
String value = String.valueOf(dataSource.value());
boolean flag;
String name = "";
switch (value) {
case "MASTER":
flag = true;
name = DataSourceType.MASTER.name();
break;
case "SLAVE":
flag = true;
name = DataSourceType.SLAVE.name();
break;
case "OTHER":
flag = true;
name = "OTHER";
if (map.get(name) != null) {
break;
} else {
//获取传入参数
Object[] args = joinPoint.getArgs();
JSONObject json = (JSONObject) args[0];
Long dataSourceId = json.getLong("dataSourceId");
log.info("获取的数据源ID=="+dataSourceId);
//从传入参数获取业务ID查找数据源信息,设置数据源信息
SysDataSource source = sysDataSourceService.getById(dataSourceId);
String url = source.getDbUrl();
String username = source.getDbUsername();
//密码解密
String password = SecurityUtil.jiemi(source.getDbPwd());
log.info("解密后密码=="+password);
log.info("数据源切换:" + url);
DruidDataSource s = dynamicDataSourceConfig.createDataSource(name, url, username,
password, source.getDbDriver());
}
break;
default:
flag = false;
break;
}
if (!flag) {
logger.error("************注意************");
name = DataSourceType.MASTER.name();
logger.info("加载到未知数据源,系统自动设置数据源为默认数据源!");
}
DynamicDataSource.setDataSource(name);
//设置成数据源
DynamicDataSourceContextHolder.setDataSourceType(name);
logger.info("当前数据源: " + name);
logger.info("当前数据源: " + ((DruidDataSource) map.get(name)).getUrl());
logger.info("set datasource is " + name);
}
@After("dsPointCut()")
public void doAfter() {
logger.info("*********准备清除数据源*********");
DynamicDataSource.clearDataSource();
DynamicDataSourceContextHolder.clearDataSourceType();
logger.info("*********数据源清除成功*********");
}
新しく追加された列挙型が druidConfig 構成ファイルに追加されることに注意してください。
データソースを切り替える必要がある場合は、クラスまたはメソッドにアノテーションを追加するだけです
@DataSource(値 = DataSourceType.OTHER)