springboot动态配置多数据源+自定义拦截器

1.简介

当微服务需要连接多个数据源到时候,我们需要手动去创建相应的SqlSessionFactory、DataSourceTransactionManager、SqlSessionTemplate 对象并交给spring托管,以及创建相应的mapper,若想添加自定义的拦截器,我们可以在相应的SqlSessionFactory对象对拦截器进行赋值,下面给大家将一下如何配置多数据源以及添加自定义拦截器

2.代码

2.1 配置文件

spring: 
    datasource:
        primary: 
            url: jdbc:mysql://localhost:3306/test_service?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=true&autoReconnect=true
            username: ***
            password: ****
            type: com.zaxxer.hikari.HikariDataSource
            driver-class-name: com.mysql.cj.jdbc.Driver
            hikari:
                keepalive-time: 30000
                max-lifetime: 14400000
            mapper: **** //这个为自定义的mapper文件包路径
            xml: mybatis/mapper/*.xml /*注意:xml文件一定是要在resources目录下*/
            interceptor: aaaa,bbbb //这个为自定义的拦截器的名称(若拦截器在第三方jar里,此时名称需要写拦截器的完整包路径+类名,若拦截器在此项目中,只需要写ioc容器中的类名即可)
        slave: 
            url: jdbc:mysql://localhost:3306/test_service?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=true&autoReconnect=true
            username: ***
            password: ****
            type: com.zaxxer.hikari.HikariDataSource
            driver-class-name: com.mysql.cj.jdbc.Driver
            hikari:
                keepalive-time: 30000
                max-lifetime: 14400000
            mapper: **** //这个为自定义的mapper文件包路径
            xml: mybatis/mapper/*.xml /*注意:xml文件一定是要在resources目录下*/
            interceptor: aaaa,bbbb //这个为自定义的拦截器的名称(若拦截器在第三方jar里,此时名称需要写拦截器的完整包路径+类名,若拦截器在此项目中,只需要写ioc容器中的类名即可)

2.2 自定义mapper

需要创建两个不同的mapper对象,例如:

注意:配置文件中的mapper字段只能填到TeacherMapper/StudentMapper文件的包路径,即com.*.*.mapper.one/com.*.*.mapper.two ,因为后续的@MapperScan注解扫描的是包路径

2.3 配置类

primary配置文件

package com.example.aopservice.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author zhl
 * @date 2023/12/7 16:28
 */
@MapperScan(basePackages = "${spring.datasource.primary.mapper}",sqlSessionTemplateRef = "db1SqlSessionTemplate")
public class DataSourcePrimaryConfig {


    @Value("${spring.datasource.primary.interceptor:}")
    private String interceptorName;//当这个字段不为空时,会给SqlSessionFactory添加自定义的拦截器
    @Value("${spring.datasource.primary.xml}")
    private String xmlPath; //xml路径


    @Resource
    private Map<String,Interceptor> map;//将所有Interceptor对象都注入,为后续根据类名取出相应拦截器并赋值到SqlSessionFactory


    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    @Primary
    public DataSource db1DataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public SqlSessionFactory db1SqlSessionFactory(@Qualifier("db1DataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:"+xmlPath));
        if(interceptorName!=null && !"".equals(interceptorName)){
           List<String> collect = Stream.of(interceptorName.split(",")).collect(Collectors.toList());
            Interceptor[] interceptors = collect.stream().map(name -> map.get(name)).toArray(Interceptor[]::new);
            bean.setPlugins(interceptors);
        }
        return bean.getObject();
    }

    @Bean
    @Primary
    public DataSourceTransactionManager db1TransactionManager(@Qualifier("db1DataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    @Primary
    public SqlSessionTemplate db1SqlSessionTemplate(@Qualifier("db1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }


}

slave配置文件

package com.example.aopservice.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author zhl
 * @date 2023/12/7 16:32
 */
@MapperScan(basePackages = "${spring.datasource.slave.mapper}",sqlSessionTemplateRef = "db2SqlSessionTemplate")
public class DataSourceSlaveConfig {

    @Value("${spring.datasource.slave.interceptor:}")
    private String interceptorName;//当这个字段不为空时,会给SqlSessionFactory添加自定义的拦截器
    @Value("${spring.datasource.slave.xml}")
    private String xmlPath;

    @Resource
    private Map<String,Interceptor> map;//将所有Interceptor对象都注入,为后续根据类名取出相应拦截器并赋值到SqlSessionFactory


    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    public DataSource db2DataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public SqlSessionFactory db2SqlSessionFactory(@Qualifier("db2DataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:"+xmlPath));
        if(interceptorName!=null && !"".equals(interceptorName)){
           List<String> collect = Stream.of(interceptorName.split(",")).collect(Collectors.toList());
            Interceptor[] interceptors = collect.stream().map(name -> map.get(name)).toArray(Interceptor[]::new);
            bean.setPlugins(interceptors);
        }
        return bean.getObject();
    }

    @Bean
    public DataSourceTransactionManager db2TransactionManager(@Qualifier("db2DataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    public SqlSessionTemplate db2SqlSessionTemplate(@Qualifier("db2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }




}

注意:mapper对应的xml文件在一定要resources文件下的mybatis/mapper文件夹下面(后续也可以让使用者动态添加xml文件的路径,暂时没实现,后续有时间会补充一下) 已补充

2.4 动态添加自定义拦截器

上述代码大家可以看到,我们把所有的Interceptor对象都注入进每个config文件中了,每个config文件根据配置文件里面的interceptorName,可以动态添加我们想要的拦截器。

3.总结

上述为配置多数据源以及如何动态添加自定义拦截器,其实我是将这两个配置文件分装成了一个自定义jar,后续多数据源情况可以直接在pom文件引入jar就可以。

为什么称之为动态呢,是因为我在封装jar的时候在每个配置类没有添加@Component注解,而是通过在springboot启动类上添加了@Import注解创建的config对象,因为大多数情况都是单一数据源,而且我之前写过一篇文章springboot+mybatis拦截器+自定义注解实现数据脱敏-CSDN博客我在封装自定义jar的时候也把那两个拦截器封装进去了,那两个拦截器同样没有加@Component注解,即没有交给spring托管,都是通过@Import注解手动去引入的。

以上就是如何配置多数据源及动态添加自定义拦截器,有问题的小伙伴请留言

  • 25
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
配置MyBatis Plus的拦截器以实现字段自动填充,你可以按照以下步骤进行操作: 1. 创建一个类实现`MetaObjectHandler`接口,该接口包含了字段自动填充的方法。在这个类中,你可以实现`insertFill`和`updateFill`方法,在插入和更新操作时自动填充指定字段。 ```java @Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, "createUser", String.class, "defaultUser"); this.strictInsertFill(metaObject, "createTime", Date.class, new Date()); } @Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, "updateUser", String.class, "defaultUser"); this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date()); } } ``` 在这个示例中,我们在插入和更新操作时分别填充了`createUser`、`createTime`、`updateUser`和`updateTime`字段。 2. 在你的配置类中添加拦截器配置。例如: ```java @Configuration public class MyBatisPlusConfig { @Autowired private MyMetaObjectHandler myMetaObjectHandler; @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new MybatisPlusInnerInterceptor()); // 添加自动填充拦截器 interceptor.addInnerInterceptor(new IAutoFillInnerInterceptor(myMetaObjectHandler)); return interceptor; } } ``` 在这个示例中,我们创建了一个`MybatisPlusInterceptor`对象,并通过`addInnerInterceptor`方法添加自定义的内部拦截器`IAutoFillInnerInterceptor`,并将`MyMetaObjectHandler`作为参数传递给拦截器。 3. 创建一个自定义的内部拦截器`IAutoFillInnerInterceptor`,继承自`AbstractSqlParserHandler`,并实现其中的方法。 ```java public class IAutoFillInnerInterceptor extends AbstractSqlParserHandler { private final MetaObjectHandler metaObjectHandler; public IAutoFillInnerInterceptor(MetaObjectHandler metaObjectHandler) { this.metaObjectHandler = metaObjectHandler; } @Override public SqlNode handler(MetaObject metaObject, SqlNode sqlNode) { // 在这里执行字段自动填充逻辑 metaObjectHandler.insertFill(metaObject); metaObjectHandler.updateFill(metaObject); return super.handler(metaObject, sqlNode); } } ``` 在这个示例中,我们在`handler`方法中调用了`MetaObjectHandler`的插入和更新填充方法。 通过以上步骤,你就可以成功配置MyBatis Plus的拦截器,并实现字段自动填充了。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值