变态需求之【角色不同访问数据库的用户不同】

需求说明

不同的用户角色在访问系统的时候,后台要根据角色切换不同的数据库用户名和密码。

你就说变不变态吧。。。。

环境说明

复制代码
数据库:mysql8.0
jdk17
SpringBoot 2.7.6
mybatis plus 3.5.5

以下为代码讲解,可跳过自行拉取代码测试

代码

1、数据源上下文 Holder,存储当前线程的数据源标识

java 复制代码
public class DataSourceContextHolder {

    private static final ThreadLocal<UserType> CONTEXT_HOLDER = new ThreadLocal<>();

    // 设置数据源标识
    public static void setDataSourceType(UserType type) {
        CONTEXT_HOLDER.set(type);
    }

    // 获取数据源标识
    public static UserType getDataSourceType() {
        return CONTEXT_HOLDER.get() == null ? UserType.USER : CONTEXT_HOLDER.get();
    }

    // 清除数据源标识(避免内存泄漏)
    public static void clearDataSourceType() {
        CONTEXT_HOLDER.remove();
    }
}

2、动态数据源,根据ThreadLocal中的标识切换数据源

java 复制代码
/**
 * 动态数据源,根据ThreadLocal中的标识切换数据源
 *
 * @author smallNorth_Lee
 * @since 2026/1/22
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        UserType dataSourceType = DataSourceContextHolder.getDataSourceType();
        return dataSourceType == null ? UserType.ADMIN : dataSourceType;
    }
}

3、数据源拦截器

这里说明一下,模拟的是从请求头获取用户的角色,实际场景中会出现,"用户没有登录我怎么知道他的角色??",这里登录的接口肯定要为公共接口,不然没得聊。

java 复制代码
/**
 * 数据源拦截器
 *
 * @author smallNorth_Lee
 * @since 2026/1/22
 */
@Component
public class DataSourceInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       // TODO 这里模拟用户角色,实际项目中可自行调整,登录的接口肯定为公共的数据源,其它查询的时候需要判断用户角色
        String role = request.getHeader("role");
        if (role == null){
            role = "ADMIN";
        }
        String resLogger = "\n\n==============  request Start  ==============";
        resLogger += "\n当前用户角色为 : " + role;
        if (UserType.ADMIN.name().equals(role.toUpperCase())) {
            resLogger += "\n使用的数据源为 : {ADMIN}";
            DataSourceContextHolder.setDataSourceType(UserType.ADMIN);
        } else if (UserType.USER.name().equals(role.toUpperCase())) {
            resLogger += "\n使用的数据源为 : {USER}";
            DataSourceContextHolder.setDataSourceType(UserType.USER);
        }
        resLogger += "\n==============  request End  ==============\n";
        System.out.println(resLogger);
        return true;
    }

    // 清理数据源
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        DataSourceContextHolder.clearDataSourceType();
    }
}

4、数据源配置

yaml 复制代码
server:
  port: 2026
spring:
  application:
    name: dynamic-datasource
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/auth-center?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
    user:
      username: root
      password: 123456
    admin:
      username: root
      password: 123456
java 复制代码
/**
 * 数据源配置
 *
 * @author smallNorth_Lee
 * @since 2026/1/22
 */
@Configuration
public class DataSourceConfig {

    @Value("${spring.datasource.url}")
    private String url;

    @Value("${spring.datasource.driver-class-name}")
    private String driverClassName;

    @Value("${spring.datasource.admin.username}")
    private String adminUsername;
    @Value("${spring.datasource.admin.password}")
    private String adminPassword;

    @Bean("adminDataSource")
    public DataSource adminDataSource() {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl(url);
        dataSource.setUsername(adminUsername);
        dataSource.setPassword(adminPassword);
        dataSource.setDriverClassName(driverClassName);
        dataSource.setMaximumPoolSize(10);
        dataSource.setMinimumIdle(2);
        return dataSource;
    }

    @Value("${spring.datasource.user.username}")
    private String userUsername;
    @Value("${spring.datasource.user.password}")
    private String userPassword;

    @Bean("userDataSource")
    public DataSource userDataSource() {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl(url);
        dataSource.setUsername(userUsername);
        dataSource.setPassword(userPassword);
        dataSource.setDriverClassName(driverClassName);
        dataSource.setMaximumPoolSize(10);
        dataSource.setMinimumIdle(2);
        return dataSource;
    }

    @Bean("dynamicDataSource")
    @Primary // 设置为默认数据源
    public DataSource dynamicDataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        // 初始化数据源映射
        Map<Object, Object> dataSourceMap = new HashMap<>();
        dataSourceMap.put(UserType.ADMIN, adminDataSource());
        dataSourceMap.put(UserType.USER, userDataSource());
        // 设置数据源映射
        dynamicDataSource.setTargetDataSources(dataSourceMap);
        // 设置默认数据源
        dynamicDataSource.setDefaultTargetDataSource(adminDataSource());
        return dynamicDataSource;
    }

    // 事务管理
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dynamicDataSource());
    }
}

5、MyBatisPlus 配置类

java 复制代码
/**
 * MyBatisPlus 配置类
 *
 * @author smallNorth_Lee
 * @since 2026/1/22
 */
@Configuration
public class MyBatisPlusConfig {

    @Resource
    private DataSource dynamicDataSource;

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

    @Bean
    public MybatisSqlSessionFactoryBean sqlSessionFactory() {
        MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
        sqlSessionFactory.setDataSource(dynamicDataSource);
        return sqlSessionFactory;
    }
}

6、web配置,注册拦截器

java 复制代码
/**
 * web配置,注册拦截器
 *
 * @author smallNorth_Lee
 * @since 2026/1/22
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new DataSourceInterceptor()).addPathPatterns("/**");
    }
}

其它都是CRUD基础操作,可拉取代码测试哦,代码地址:一给我里giaogiao

相关推荐
YOU OU6 小时前
Redis基础常识与命令
数据库·redis·缓存
Scott9999HH6 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔6 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社7 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海7 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖8 小时前
JDK 26 新特性详解
java·开发语言
Database_Cool_8 小时前
OLTP 和 OLAP 区别详解:分析型数据库和事务型数据库怎么选(附阿里云 AnalyticDB MySQL 选型指南)
数据库·mysql·阿里云
爱写代码的阿森9 小时前
鸿蒙三方库 | harmony-utils之KvUtil键值型数据库操作详解
数据库·华为·harmonyos·鸿蒙·huawei
马优晨9 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
Database_Cool_9 小时前
单机 MySQL 迁移到分布式数据库方便吗?阿里云 PolarDB-X 100% MySQL 协议兼容零改造平滑迁移
数据库·分布式·mysql