feat: initial iShare project code

This commit is contained in:
purovps
2026-02-16 23:20:59 +08:00
parent 8c83a6fd46
commit 6f270a972e
1910 changed files with 218015 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>pigx-common</artifactId>
<groupId>com.pig4cloud</groupId>
<version>5.2.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-datasource</artifactId>
<packaging>jar</packaging>
<description>pigx 动态切换数据源</description>
<dependencies>
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-core</artifactId>
</dependency>
<!--mybatis-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
</dependency>
<!-- druid 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<scope>provided</scope>
</dependency>
<!--拦截器依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,109 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.common.datasource;
import com.baomidou.dynamic.datasource.creator.DataSourceCreator;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.creator.druid.DruidDataSourceCreator;
import com.baomidou.dynamic.datasource.processor.DsHeaderProcessor;
import com.baomidou.dynamic.datasource.processor.DsProcessor;
import com.baomidou.dynamic.datasource.processor.DsSessionProcessor;
import com.baomidou.dynamic.datasource.processor.DsSpelExpressionProcessor;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.pig4cloud.pigx.common.datasource.config.*;
import lombok.RequiredArgsConstructor;
import org.jasypt.encryption.StringEncryptor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.expression.BeanFactoryResolver;
import java.util.ArrayList;
import java.util.List;
/**
* @author lengleng
* @date 2020-02-06
* <p>
* 动态数据源切换配置
*/
@Configuration
@RequiredArgsConstructor
@Import(DynamicLogConfiguration.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(DruidDataSourceProperties.class)
public class DynamicDataSourceAutoConfiguration {
/**
* 获取动态数据源提供者
* @param defaultDataSourceCreator 默认数据源创建器
* @param stringEncryptor 字符串加密器
* @param properties 数据源属性
* @return 动态数据源提供者
*/
@Bean
public DynamicDataSourceProvider dynamicDataSourceProvider(DefaultDataSourceCreator defaultDataSourceCreator,
StringEncryptor stringEncryptor, DruidDataSourceProperties properties) {
return new JdbcDynamicDataSourceProvider(defaultDataSourceCreator, stringEncryptor, properties);
}
/**
* 获取默认数据源创建器
* @param druidDataSourceCreator Druid数据源创建器
* @return 默认数据源创建器
*/
@Bean
public DefaultDataSourceCreator defaultDataSourceCreator(DruidDataSourceCreator druidDataSourceCreator) {
DefaultDataSourceCreator defaultDataSourceCreator = new DefaultDataSourceCreator();
List<DataSourceCreator> creators = new ArrayList<>();
creators.add(druidDataSourceCreator);
defaultDataSourceCreator.setCreators(creators);
return defaultDataSourceCreator;
}
/**
* 获取数据源处理器
* @return 数据源处理器
*/
@Bean
public DsProcessor dsProcessor(BeanFactory beanFactory) {
DsProcessor lastParamDsProcessor = new LastParamDsProcessor();
DsProcessor headerProcessor = new DsHeaderProcessor();
DsProcessor sessionProcessor = new DsSessionProcessor();
DsSpelExpressionProcessor spelExpressionProcessor = new DsSpelExpressionProcessor();
spelExpressionProcessor.setBeanResolver(new BeanFactoryResolver(beanFactory));
lastParamDsProcessor.setNextProcessor(headerProcessor);
headerProcessor.setNextProcessor(sessionProcessor);
sessionProcessor.setNextProcessor(spelExpressionProcessor);
return lastParamDsProcessor;
}
/**
* 获取清除TTL数据源过滤器
* @return 清除TTL数据源过滤器
*/
@Bean
public ClearTtlDataSourceFilter clearTtlDsFilter() {
return new ClearTtlDataSourceFilter();
}
}

View File

@@ -0,0 +1,24 @@
package com.pig4cloud.pigx.common.datasource.annotation;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import com.pig4cloud.pigx.common.datasource.DynamicDataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**
* @author Lucky
* @date 2019-05-18
* <p>
* 开启动态数据源
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@EnableAutoConfiguration(exclude = { DruidDataSourceAutoConfigure.class })
@Import(DynamicDataSourceAutoConfiguration.class)
public @interface EnableDynamicDataSource {
}

View File

@@ -0,0 +1,34 @@
package com.pig4cloud.pigx.common.datasource.config;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import org.springframework.core.Ordered;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
/**
* @author lengleng
* @date 2020/12/11
* <p>
* 清空上文的DS 设置避免污染当前线程
*/
public class ClearTtlDataSourceFilter extends GenericFilterBean implements Ordered {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
DynamicDataSourceContextHolder.clear();
filterChain.doFilter(servletRequest, servletResponse);
DynamicDataSourceContextHolder.clear();
}
@Override
public int getOrder() {
return Integer.MIN_VALUE;
}
}

View File

@@ -0,0 +1,41 @@
package com.pig4cloud.pigx.common.datasource.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author lengleng
* @date 2019-05-14
* <p>
* 参考DruidDataSourceWrapper
*/
@Data
@ConfigurationProperties("spring.datasource.druid")
public class DruidDataSourceProperties {
/**
* 数据源用户名
*/
private String username;
/**
* 数据源密码
*/
private String password;
/**
* jdbcurl
*/
private String url;
/**
* 数据源驱动
*/
private String driverClassName;
/**
* 查询数据源的SQL
*/
private String queryDsSql = "select * from gen_datasource_conf where del_flag = '0'";
}

View File

@@ -0,0 +1,17 @@
package com.pig4cloud.pigx.common.datasource.config;
import com.pig4cloud.pigx.common.core.factory.YamlPropertySourceFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.PropertySource;
/**
* @author lengleng
* @date 2022/8/8
*
* 注入SQL 格式化的插件
*/
@ConditionalOnClass(name = "com.pig4cloud.pigx.common.data.mybatis.DruidSqlLogFilter")
@PropertySource(value = "classpath:dynamic-ds-log.yaml", factory = YamlPropertySourceFactory.class)
public class DynamicLogConfiguration {
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.common.datasource.config;
import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.creator.druid.DruidConfig;
import com.baomidou.dynamic.datasource.provider.AbstractJdbcDataSourceProvider;
import com.pig4cloud.pigx.common.datasource.support.DataSourceConstants;
import com.pig4cloud.pigx.common.datasource.util.DsConfTypeEnum;
import com.pig4cloud.pigx.common.datasource.util.DsJdbcUrlEnum;
import org.jasypt.encryption.StringEncryptor;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
/**
* @author lengleng
* @date 2020/2/6
* <p>
* 从数据源中获取 配置信息
*/
public class JdbcDynamicDataSourceProvider extends AbstractJdbcDataSourceProvider {
private final DruidDataSourceProperties properties;
private final StringEncryptor stringEncryptor;
public JdbcDynamicDataSourceProvider(DefaultDataSourceCreator defaultDataSourceCreator,
StringEncryptor stringEncryptor, DruidDataSourceProperties properties) {
super(defaultDataSourceCreator, properties.getDriverClassName(), properties.getUrl(), properties.getUsername(),
properties.getPassword());
this.stringEncryptor = stringEncryptor;
this.properties = properties;
}
/**
* 执行语句获得数据源参数
* @param statement 语句
* @return 数据源参数
* @throws SQLException sql异常
*/
@Override
protected Map<String, DataSourceProperty> executeStmt(Statement statement) throws SQLException {
ResultSet rs = statement.executeQuery(properties.getQueryDsSql());
Map<String, DataSourceProperty> map = new HashMap<>(8);
while (rs.next()) {
String name = rs.getString(DataSourceConstants.NAME);
String username = rs.getString(DataSourceConstants.DS_USER_NAME);
String password = rs.getString(DataSourceConstants.DS_USER_PWD);
Integer confType = rs.getInt(DataSourceConstants.DS_CONFIG_TYPE);
String dsType = rs.getString(DataSourceConstants.DS_TYPE);
DataSourceProperty property = new DataSourceProperty();
property.setUsername(username);
property.setPassword(stringEncryptor.decrypt(password));
String url;
// JDBC 配置形式
DsJdbcUrlEnum urlEnum = DsJdbcUrlEnum.get(dsType);
if (DsConfTypeEnum.JDBC.getType().equals(confType)) {
url = rs.getString(DataSourceConstants.DS_JDBC_URL);
}
else {
String host = rs.getString(DataSourceConstants.DS_HOST);
String port = rs.getString(DataSourceConstants.DS_PORT);
String dsName = rs.getString(DataSourceConstants.DS_NAME);
url = String.format(urlEnum.getUrl(), host, port, dsName);
}
// Druid Config
DruidConfig druidConfig = new DruidConfig();
druidConfig.setValidationQuery(urlEnum.getValidationQuery());
property.setDruid(druidConfig);
property.setUrl(url);
map.put(name, property);
}
// 添加默认主数据源
DataSourceProperty property = new DataSourceProperty();
property.setUsername(properties.getUsername());
property.setPassword(properties.getPassword());
property.setUrl(properties.getUrl());
map.put(DataSourceConstants.DS_MASTER, property);
return map;
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.common.datasource.config;
import com.baomidou.dynamic.datasource.processor.DsProcessor;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import org.aopalliance.intercept.MethodInvocation;
/**
* @author lengleng
* @date 2020/2/6
* <p>
* 参数数据源解析 @DS("#last)
*/
public class LastParamDsProcessor extends DsProcessor {
private static final String LAST_PREFIX = "#last";
/**
* 抽象匹配条件 匹配才会走当前执行器否则走下一级执行器
* @param key DS注解里的内容
* @return 是否匹配
*/
@Override
public boolean matches(String key) {
if (key.startsWith(LAST_PREFIX)) {
// https://github.com/baomidou/dynamic-datasource-spring-boot-starter/issues/213
DynamicDataSourceContextHolder.clear();
return true;
}
return false;
}
/**
* 抽象最终决定数据源
* @param invocation 方法执行信息
* @param key DS注解里的内容
* @return 数据源名称
*/
@Override
public String doDetermineDatasource(MethodInvocation invocation, String key) {
Object[] arguments = invocation.getArguments();
return String.valueOf(arguments[arguments.length - 1]);
}
}

View File

@@ -0,0 +1,66 @@
package com.pig4cloud.pigx.common.datasource.support;
/**
* @author lengleng
* @date 2019-04-01
* <p>
* 数据源相关常量
*/
public interface DataSourceConstants {
/**
* 数据源名称
*/
String NAME = "name";
/**
* 默认数据源master
*/
String DS_MASTER = "master";
/**
* jdbcurl
*/
String DS_JDBC_URL = "url";
/**
* 配置类型
*/
String DS_CONFIG_TYPE = "conf_type";
/**
* 用户名
*/
String DS_USER_NAME = "username";
/**
* 密码
*/
String DS_USER_PWD = "password";
/**
* 数据库类型
*/
String DS_TYPE = "ds_type";
/**
* 数据库名称
*/
String DS_NAME = "ds_name";
/**
* 主机类型
*/
String DS_HOST = "host";
/**
* 端口
*/
String DS_PORT = "port";
/**
* 实例名称
*/
String DS_INSTANCE = "instance";
}

View File

@@ -0,0 +1,30 @@
package com.pig4cloud.pigx.common.datasource.util;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author lengleng
* @date 2020/12/11
* <p>
* 数据源配置类型
*/
@Getter
@AllArgsConstructor
public enum DsConfTypeEnum {
/**
* 主机链接
*/
HOST(0, "主机链接"),
/**
* JDBC链接
*/
JDBC(1, "JDBC链接");
private final Integer type;
private final String description;
}

View File

@@ -0,0 +1,70 @@
package com.pig4cloud.pigx.common.datasource.util;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* @author lengleng
* @date 2020/12/11
* <p>
* jdbc-url
*/
@Getter
@AllArgsConstructor
public enum DsJdbcUrlEnum {
/**
* mysql 数据库
*/
MYSQL("mysql",
"jdbc:mysql://%s:%s/%s?characterEncoding=utf8"
+ "&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true"
+ "&useLegacyDatetimeCode=false&allowMultiQueries=true&allowPublicKeyRetrieval=true",
"select 1", "mysql8 链接"),
/**
* pg 数据库
*/
PG("pg", "jdbc:postgresql://%s:%s/%s", "select 1", "postgresql 链接"),
/**
* SQL SERVER
*/
MSSQL("mssql", "jdbc:sqlserver://%s:%s;database=%s;characterEncoding=UTF-8", "select 1", "sqlserver 链接"),
/**
* oracle
*/
ORACLE("oracle", "jdbc:oracle:thin:@%s:%s:%s", "select 1 from dual", "oracle 链接"),
/**
* db2
*/
DB2("db2", "jdbc:db2://%s:%s/%s", "select 1 from sysibm.sysdummy1", "DB2 TYPE4 连接"),
/**
* 达梦
*/
DM("dm", "jdbc:dm://%s:%s/%s", "select 1 from dual", "达梦连接"),
/**
* pg 数据库
*/
HIGHGO("highgo", "jdbc:highgo://%s:%s/%s", "select 1", "highgo 链接");
private final String dbName;
private final String url;
private final String validationQuery;
private final String description;
public static DsJdbcUrlEnum get(String dsType) {
return Arrays.stream(DsJdbcUrlEnum.values()).filter(dsJdbcUrlEnum -> dsType.equals(dsJdbcUrlEnum.getDbName()))
.findFirst().get();
}
}

View File

@@ -0,0 +1,7 @@
# 动态数据源增加 sqlLogFilter 格式化输出
spring:
datasource:
dynamic:
druid:
proxyFilters:
- sqlLogFilter