springboot动态数据源【非伪数据源】

说明:本文章的数据源不是在配置文件中配置两个或多个数据源,在业务方面对这些数据源来回切换,本文章中的数据源是可以动态添加,修改,切换的,废话不多说。

先看工程图:

1.pom.xml文件

java 复制代码
<?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">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example</groupId>
  <artifactId>demo</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>DemoOne</name>
  <description>Demo project for Spring Boot</description>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.2.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <mybatis-spring-boot.version>1.2.0</mybatis-spring-boot.version>
    <mysql-connector.version>5.1.39</mysql-connector.version>
    <java.version>1.8</java.version>
  </properties>

  <dependencies>

    <!--springboot相关包-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-freemarker</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>

    <!-- MySQL依赖导入 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <scope>runtime</scope>
    </dependency>

    <!-- Oracle依赖导入 -->
    <dependency>
      <groupId>com.oracle</groupId>
      <artifactId>ojdbc6</artifactId>
      <version>11.2.0.3</version>
    </dependency>

    <!-- postgresql依赖导入 -->
    <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>42.2.2</version>
    </dependency>

    <!--mybatis-plus相关依赖导入-->
    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
      <version>3.5.1</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid-spring-boot-starter</artifactId>
      <version>1.2.9</version>
    </dependency>
    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-boot-starter</artifactId>
      <version>3.5.1</version>
    </dependency>
    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-generator</artifactId>
      <version>3.5.2</version>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-dbcp2</artifactId>
      <version>2.8.0</version>
    </dependency>

    <!-- pagehelper分页 依赖导入-->
    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper-spring-boot-starter</artifactId>
      <exclusions>
        <exclusion>
          <artifactId>mybatis</artifactId>
          <groupId>org.mybatis</groupId>
        </exclusion>
        <exclusion>
          <artifactId>mybatis-spring</artifactId>
          <groupId>org.mybatis</groupId>
        </exclusion>
      </exclusions>
      <version>1.2.10</version>
    </dependency>


    <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
    </dependency>
    <!--get set 依赖导入-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.14.8</version>
    </dependency>

    <!-- knife4j 增强swagger依赖导入 -->
    <dependency>
      <groupId>com.github.xiaoymin</groupId>
      <artifactId>knife4j-spring-boot-starter</artifactId>
      <version>2.0.9</version>
    </dependency>

    <!-- hutool 工具包依赖导入 -->
    <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>5.8.0.M3</version>
    </dependency>

    <!--StringUtils工具包依赖导入-->
    <dependency>
      <groupId>commons-lang</groupId>
      <artifactId>commons-lang</artifactId>
      <version>2.6</version>
    </dependency>

    <!--字符串转驼峰依赖导入-->
    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>21.0</version>
    </dependency>

    <!--josn依赖导入-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.28</version>
    </dependency>



  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>

2.application.yml

java 复制代码
server:
  port: 9000
spring:
  datasource:
    dynamic:
      primary: master
      datasource:
        #默认数据库
        master:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://127.0.0.1:3306/my_demo_01?characterEncoding=utf8&useSSL=false&autoReconnect=true&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
          username: root
          password: root
        #my_demo_02:
        #  driver-class-name: com.mysql.cj.jdbc.Driver
        #  url: jdbc:mysql://127.0.0.1:3306/my_demo_02?characterEncoding=utf8&useSSL=false&autoReconnect=true&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
        #  username: root
        #  password: root

  jackson:
    date-format: dd/MM/yyyy
    time-zone: GMT+8
  mvc:
    date-format: dd/MM/yyyy HH:mm:ss
    pathmatch:
      matching-strategy: ant_path_matcher
logging:
  level:
    com.baomidou: debug
mybatis-plus:
  mapper-locations: classpath:mappers/*.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3.fs_order.sql和sys_user.sql

sql 复制代码
/*
 Navicat Premium Data Transfer

 Source Server         : 本机数据库mysql
 Source Server Type    : MySQL
 Source Server Version : 80011 (8.0.11)
 Source Host           : localhost:3306
 Source Schema         : my_demo_01

 Target Server Type    : MySQL
 Target Server Version : 80011 (8.0.11)
 File Encoding         : 65001

 Date: 30/10/2023 11:24:09
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`  (
  `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键',
  `user_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',
  `nick_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '昵称',
  `age` int(4) NULL DEFAULT NULL COMMENT '年龄',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES ('a', 'zhanglong', '张龙', 30);
INSERT INTO `sys_user` VALUES ('b', 'zhaohu', '赵虎', 31);
INSERT INTO `sys_user` VALUES ('c', 'wangchao', '王朝', 32);
INSERT INTO `sys_user` VALUES ('d', 'mahan', '马汉', 33);

SET FOREIGN_KEY_CHECKS = 1;
sql 复制代码
/*
 Navicat Premium Data Transfer

 Source Server         : 本机数据库mysql
 Source Server Type    : MySQL
 Source Server Version : 80011 (8.0.11)
 Source Host           : localhost:3306
 Source Schema         : my_demo_02

 Target Server Type    : MySQL
 Target Server Version : 80011 (8.0.11)
 File Encoding         : 65001

 Date: 30/10/2023 11:24:22
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for fs_order
-- ----------------------------
DROP TABLE IF EXISTS `fs_order`;
CREATE TABLE `fs_order`  (
  `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `order_num` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '订单号',
  `address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '订单地址',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '订单表' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of fs_order
-- ----------------------------
INSERT INTO `fs_order` VALUES ('111', '0456afa8-3c7b-40a6-a82c-544ea16ee082', '梁山八百里水泊');
INSERT INTO `fs_order` VALUES ('222', '625b2fa6-a3c5-49f9-bfc9-f8c84b5af6a0', '大运河桥');

SET FOREIGN_KEY_CHECKS = 1;

4.MySpringBootApplication.java

java 复制代码
package com.example;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

//@MapperScan("com.example.mapper")  //在数据层配置@Mapper一个功能
@SpringBootApplication
public class MySpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class, args);
    }
}

5.SwaggerConfig.java

java 复制代码
package com.example.config;

import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

import java.util.ArrayList;
import java.util.List;


/**
 * @author 李庆伟
 * @date 2022/5/20 10:22
 */
@ConditionalOnWebApplication
@Configuration
@EnableSwagger2WebMvc
@EnableKnife4j
public class SwaggerConfig {

    /**
     * Swagger2的配置文件,这里可以配置Swagger2的一些基本的内容,比如扫描的包等等
     * []
     * @return {@link Docket}
     * @throws
     * @author 李庆伟
     * @date 2021/12/13 16:28
     */
    @Bean
    public Docket createRestApi() {
        //设置请求在父类方法中,如果在本类方法中设置请求头,则覆盖父类方法
        List<Parameter> pars = makeHeader();
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage(makeScan()))
                //.apis(RequestHandlerSelectors.basePackage(App8300.class.getPackage().getName()))
                .build()
                .globalOperationParameters(pars)
                .apiInfo(apiInfo());
    }

    /**
     * swagger封装请求头
     * [pars]
     * @return {@link List< Parameter>}
     * @throws
     * @author 李庆伟
     * @date 2022/5/20 11:26
     */
    public List<Parameter> makeHeader(){
        List<Parameter> pars = new ArrayList<>();
        ParameterBuilder token = new ParameterBuilder();
        token.name("Authorization").description("Authorization")
                .modelRef(new ModelRef("string"))
                .parameterType("header")
                .required(false).build();
        pars.add(token.build());

        ParameterBuilder languageCode = new ParameterBuilder();
        languageCode.name("languageCode").description("languageCode")
                .modelRef(new ModelRef("string"))
                .parameterType("header")
                .required(false).build();
        pars.add(languageCode.build());

        return pars;
    }

    public String makeScan(){
        return "com.example.controller";
    }


    /**
     * 构建API文档的详细信息函数
     * @return
     */
    public ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title(makeApiName())
                .version("1.0")
                .build();
    }

    public String makeApiName(){
        return "项目接口 API";
    }



}

6.Result.java

java 复制代码
package com.example.results;

import com.alibaba.fastjson.JSON;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.servlet.ServletResponse;
import java.io.PrintWriter;
import java.util.List;

/**
 * @author 李庆伟
 * @date 2020/4/16 9:52
 */
@Data
public class Result {

    @ApiModelProperty(value = "返回码")
    private int code;

    @ApiModelProperty(value = "返回数据")
    private Object data;

    @ApiModelProperty(value = "返回描述")
    private String msg;

    @ApiModelProperty(value = "返回长度")
    private long count;

    @ApiModelProperty(value = "详细信息")
    private String detailMessage;

    /**返回成功 */
    public static Result success(List<Object> data, long count){
        Result result = new Result();
        result.setCode(0);//成功
        result.setMsg("成功!");//提示语
        result.setData(data);
        result.setCount(count);
        return result;
    }

    /**返回成功 */
    public static Result success(List data){
        Result result = new Result();
        result.setCode(0);//成功
        result.setMsg("成功!");//提示语
        result.setData(data);
        result.setCount(data == null || data.size() == 0 ? 0 : data.size());
        return result;
    }

    /**返回成功 */
    public static Result successForPage(List data,Integer count){
        Result result = new Result();
        result.setCode(0);//成功
        result.setMsg("失败!");//提示语
        result.setData(data);
        result.setCount(count == null ? 0 : count);
        return result;
    }

    /**返回成功 */
    public static Result success(){
        Result result = new Result();
        result.setCode(0);//成功
        result.setMsg("成功!");//提示语
        return result;
    }

    /**返回成功 */
    public static Result success(Object object){
        Result result = new Result();
        result.setCode(0);//成功
        result.setMsg("成功!");//提示语
        result.setData(object);//返回内容
        return result;
    }

    /**返回失败 */
    public static Result error(){
        Result result = new Result();
        result.setCode(1);//失败
        result.setMsg("失败!");//提示语
        return result;
    }

    /**返回失败 */
    public static Result error(int code, String msg){
        Result result = new Result();
        result.setCode(code);//失败
        result.setMsg("失败!");//提示语
        return result;
    }

    /**返回失败 */
    public static Result error(int code, String msg, String detailMessage){
        Result result = new Result();
        result.setCode(code);//失败
        result.setMsg("失败!");//提示语
        result.setDetailMessage(detailMessage);
        return result;
    }

    /**Response输出Json格式 */
    public static void responseJson(ServletResponse response, Object data) {
        PrintWriter out = null;
        try {
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json");
            out = response.getWriter();
            out.println(JSON.toJSONString(data));
            out.flush();
        } catch (Exception e) {
            System.out.println("Response输出Json异常:" + e);
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }
	/**返回信息*/
	public static Result response(int code, String msg, Object data) {
		Result result = new Result();
		result.setCode(code);
		result.setMsg(msg);
		result.setData(data);
		return result;
	}
}

7.DbDataSourceConstant.java

java 复制代码
package com.example.constant;

/**
 * @Description: TODO
 * @param:
 * @return: {@link }
 * @throws:
 * @author:李庆伟
 * @date: 2023/10/27 14:09
 */
public class DbDataSourceConstant {

    //oracle 驱动名称
    public static final String ORACLE_DRIVER_CLASS_NAME = "oracle.jdbc.driver.OracleDriver";

    //mysql 低版本驱动名称(6.0以下)
    public static final String MYSQL_LOW_DRIVER_CLASS_NAME = "com.mysql.jdbc.Driver";

    //mysql 高版本驱动名称(6.0以上)
    public static final String MYSQL_HIGH_DRIVER_CLASS_NAME = "com.mysql.cj.jdbc.Driver";

    //psotgresql 驱动名称
    public static final String PSOTGRESQL_HIGH_DRIVER_CLASS_NAME = "org.postgresql.Driver";
}

8.DbOprUtil.java

java 复制代码
package com.example.utils;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.example.constant.DbDataSourceConstant;
import com.example.dto.DbDataSourceDTO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Set;

/**
 * @Description: 操作数据源工具类
 * @param:
 * @return: {@link }
 * @throws:
 * @author:李庆伟
 * @date: 2023/6/30 17:14
 */
@Component
public class DbOprUtil {

    @Autowired
    private DataSource dataSource;
    @Resource
    private DefaultDataSourceCreator dataSourceCreator;


    /**
     * @Description: 添加数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/6/30 17:21
     */
    public Set<String> addDataSource(DbDataSourceDTO sourceDTO) {
        // 根据数据库类型设置驱动名称
        switch (sourceDTO.getType().toLowerCase()) {
            case "mysql":
                sourceDTO.setDriverClassName(DbDataSourceConstant.MYSQL_HIGH_DRIVER_CLASS_NAME);
                break;
            case "oracle":
                sourceDTO.setDriverClassName(DbDataSourceConstant.ORACLE_DRIVER_CLASS_NAME);
                break;
            case "postgresql":
                sourceDTO.setDriverClassName(DbDataSourceConstant.PSOTGRESQL_HIGH_DRIVER_CLASS_NAME);
                break;
            default:
                return null;
        }
        boolean status = DbLinkUtil.verifyUrlConnStatus(sourceDTO.getUrl(), sourceDTO.getDriverClassName(), sourceDTO.getUsername(), sourceDTO.getPassword());
        if (!status) {
            throw new RuntimeException("数据源链接失败!");
        }
        DataSourceProperty dataSourceProperty = new DataSourceProperty();
        BeanUtils.copyProperties(sourceDTO, dataSourceProperty);
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty);
        try {
            Connection connection = dataSource.getConnection();
            //String schema = connection.getSchema();
            ///System.err.println(schema);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        // 添加数据源
        ds.addDataSource(sourceDTO.getPoolName(), dataSource);
        return ds.getDataSources().keySet();
    }

    /**
     * @Description: 获取所以数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/6/30 17:22
     */
    public Set<String> getAllDataSource() {
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        return ds.getDataSources().keySet();
    }
    public DynamicRoutingDataSource getDataSource() {
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        return ds;
    }

    /**
     * @Description: 根据数据源名称删除数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/6/30 17:22
     */
    public void removeByDataSourceByName(String dataSourceName) {
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        ds.removeDataSource(dataSourceName);
    }

    /**
     * @Description: 手动切换到该数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/6/30 17:22
     */
    public void changeByDataSourceByName(String dataSourceName) {
        Set<String> set = getAllDataSource();
        if(set != null && set.size() > 0 && set.contains(dataSourceName)){
            DynamicDataSourceContextHolder.push(dataSourceName);
        } else {
            throw new RuntimeException("数据源链接切换失败!");
        }
    }




}

9.DbLinkUtil.java

java 复制代码
package com.example.utils;


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * @Description: 校验数据源连接是否成功
 * @param:
 * @return: {@link }
 * @throws:
 * @author:李庆伟
 * @date: 2023/6/30 17:14
 */
public class DbLinkUtil {

    /**
     * @Description: 校验数据源连接是否成功,不成功抛异常
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/27 14:37
     */
    public static boolean verifyUrlConnStatus(String url,String driverClassName, String username, String password) {

        boolean flag;
        Connection connection = null;
        // 加载驱动类
        try {
            Class.forName(driverClassName);
            connection = DriverManager.getConnection(url, username, password);
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("数据源链接不存在!");
        }finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return flag;
    }

    /**
     * @Description: 校验数据源连接是否成功,不成功返回false
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/27 14:37
     */
    public static boolean verifyUrlConnStatusForB(String url,String driverClassName, String username, String password) {

        boolean flag;
        Connection connection = null;
        // 加载驱动类
        try {
            Class.forName(driverClassName);
            connection = DriverManager.getConnection(url, username, password);
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
        }finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return flag;
    }
}

10.DataSourceController.java

java 复制代码
package com.example.controller;

import com.example.dto.DbDataSourceDTO;
import com.example.results.Result;
import com.example.service.DataSourceService;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

/**
 * 类名称:
 *
 * @author 李庆伟
 * @date 2023年10月27日 15:32
 */
@RestController
@RequestMapping("/operDb")
@Api(tags = "数据源操作")
public class DataSourceController {

    @Autowired
    private DataSourceService dataSourceService;

    /**
     * @Description: 数据源分页查询
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/7/7 14:36
     */
    @PostMapping(value = "find")
    @ApiOperation(value = "查询所有数据源",notes = "查询所有数据源")
    @ApiResponses({
            @ApiResponse(code = 0, message = "ok", response= DbDataSourceDTO.class),
    })
    public Result find() {
        List<DbDataSourceDTO> result = dataSourceService.find();
        return Result.success(result);
    }

    /**
     * @Description: 添加数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/7/7 15:31
     * 以下面数据为例:
     * poolName:my_demo_02
     * type:mysql
     * driverClassName:com.mysql.cj.jdbc.Driver
     * url:jdbc:mysql://127.0.0.1:3306/my_demo_02?characterEncoding=utf8&useSSL=false&autoReconnect=true&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
     * username:root
     * password:root
     */
    @PostMapping(value = "/add")
    @ApiOperation(value = "添加数据源", notes = "添加数据源", produces = "application/json")
    @ApiResponses({
            @ApiResponse(code = 0, message = "ok", response= DbDataSourceDTO.class),
    })
    public Result add(@Valid DbDataSourceDTO form) {
        dataSourceService.add(form);
        return Result.success();
    }

    /**
     * @Description: 测试数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/7/7 15:31
     */
    @PostMapping(value = "/checked")
    @ApiOperation(value = "测试数据源", notes = "测试数据源", produces = "application/json")
    @ApiResponses({
            @ApiResponse(code = 0, message = "ok", response= DbDataSourceDTO.class),
    })
    public Result checked(@Valid DbDataSourceDTO form) {
        dataSourceService.checked(form);
        return Result.success();
    }

    /**
     * @Description: 修改数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/7/10 15:44
     */
    @PostMapping(value = "/edit")
    @ApiOperation(value = "修改数据源", notes = "修改数据源", produces = "application/json")
    @ApiResponses({
            @ApiResponse(code = 0, message = "ok", response= DbDataSourceDTO.class),
    })
    public Result edit(@Valid DbDataSourceDTO form) {
        dataSourceService.update(form);
        return Result.success();
    }

    /**
     * @Description: 删除数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/7/10 15:54
     */
    @PostMapping(value = "/delete")
    @ApiOperation(value = "删除数据源", notes = "删除数据源", produces = "application/json")
    public Result delete(DbDataSourceDTO form) {
        dataSourceService.delete(form);
        return Result.success();
    }



}

11.DataSourceService.java

java 复制代码
package com.example.service;

import com.example.dto.DbDataSourceDTO;

import java.util.List;

/**
 * 类名称:
 *
 * @author 李庆伟
 * @date 2023年10月27日 15:41
 */
public interface DataSourceService {

    //查询所有数据源
    List<DbDataSourceDTO> find();

    //添加数据源
    void add(DbDataSourceDTO form);

    //测试数据源是否能连接上
    void checked(DbDataSourceDTO form);

    //修改数据源
    void update(DbDataSourceDTO form);

    //删除数据源
    void delete(DbDataSourceDTO form);

}

12.DataSourceServiceImpl.java

java 复制代码
package com.example.service.impl;

import com.example.constant.DbDataSourceConstant;
import com.example.dto.DbDataSourceDTO;
import com.example.service.DataSourceService;
import com.example.utils.DbLinkUtil;
import com.example.utils.DbOprUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 类名称:
 *
 * @author 李庆伟
 * @date 2023年10月27日 15:41
 */
@Service
public class DataSourceServiceImpl implements DataSourceService {


    @Autowired
    private DbOprUtil dbOprUtil;

    /**
     * @Description: 获取所有数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/30 9:52
     */
    @Override
    public List<DbDataSourceDTO> find() {
        Set<String> st = dbOprUtil.getAllDataSource();
        List<DbDataSourceDTO> list = new ArrayList<>();
        if(st != null && st.size() > 0){
            for (String str : st) {
                DbDataSourceDTO dbDataSourceDTO = new DbDataSourceDTO();
                dbDataSourceDTO.setPoolName(str);
                //数据源连接等信息在这里就不获取了,自己debug去找,里面都有
                list.add(dbDataSourceDTO);
            }
        }
        return list;
    }

    /**
     * @Description: 添加数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/30 9:52
     */
    @Override
    public void add(DbDataSourceDTO form) {
        //验证数据源是否可用
        checked(form);

        //添加到源中成功后 在添加到数据源库中

        //如果成功 Add到数据源中
        dbOprUtil.addDataSource(form);
    }

    /**
     * @Description: 验证数据源是否可用
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/30 9:53
     */
    @Override
    public void checked(DbDataSourceDTO form) {
        //master为系统初始化数据源名称,不能被其他数据源替代和删除
        if(form != null && StringUtils.isNotEmpty(form.getPoolName()) && "master".equals(form.getPoolName().toLowerCase())){
            throw new RuntimeException("该关键字不能作为名称使用");
        }
        switch (form.getType().toLowerCase()) {
            case "mysql":
                form.setDriverClassName(DbDataSourceConstant.MYSQL_HIGH_DRIVER_CLASS_NAME);
                break;
            case "oracle":
                form.setDriverClassName(DbDataSourceConstant.ORACLE_DRIVER_CLASS_NAME);
                break;
            case "postgresql":
                form.setDriverClassName(DbDataSourceConstant.PSOTGRESQL_HIGH_DRIVER_CLASS_NAME);
                break;
            default:
                form.setDriverClassName("");
        }
        //判断数据源连接是否能够连接成功
        DbLinkUtil.verifyUrlConnStatus(form.getUrl(),form.getDriverClassName(),form.getUsername(),form.getPassword());

    }

    /**
     * @Description: 修改数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/30 9:53
     */
    @Override
    public void update(DbDataSourceDTO form) {
        //验证数据源是否可用
        checked(form);
        //修改数据源库中存储数据源

        //删除已有数据源
        delete(form);

        //如果成功 Add到数据源中
        dbOprUtil.addDataSource(form);
    }

    /**
     * @Description: 删除数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/30 9:53
     */
    @Override
    public void delete(DbDataSourceDTO form) {
        if(!form.getPoolName().equals("master")){
            dbOprUtil.removeByDataSourceByName(form.getPoolName());
        }
    }

}

13.FsOrder.java

java 复制代码
package com.example.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * 类名称:订单
 *
 * @author 李庆伟
 * @date 2023年10月27日 15:26
 */
@Data
@TableName
public class FsOrder {

    @TableId
    private String id;

    private String orderNum;//订单号

    private String address;//订单地址
}

14.SysUser.java

java 复制代码
package com.example.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * 类名称:用户
 *
 * @author 李庆伟
 * @date 2023年10月27日 15:26
 */
@Data
@TableName
public class SysUser {

    @TableId
    private String id;

    private String userName;//用户名

    private String nickName;//昵称

    private Integer age;//年龄
}

15.TestController.java

java 复制代码
package com.example.controller;

import com.example.entity.FsOrder;
import com.example.entity.SysUser;
import com.example.results.Result;
import com.example.service.TestService;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * 类名称:
 *
 * @author 李庆伟
 * @date 2023年10月27日 15:32
 */
@RestController
@RequestMapping("/test")
@Api(tags = "测试通过动态数据源查询数据")
public class TestController {

    @Autowired
    private TestService testService;

    /**
     * @Description: 查询所有用户【在master数据库中】
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/30 10:58
     *
     */
    @PostMapping(value = "findAllSysUser")
    @ApiOperation(value = "查询所有用户【在master数据库中】",notes = "查询所有用户【在master数据库中】")
    @ApiResponses({
            @ApiResponse(code = 0, message = "ok", response= Result.class),
    })
    public Result findAllSysUser() {
        List<SysUser> result = testService.findAllSysUser();
        return Result.success(result);
    }

    /**
     * @Description: 查询所有的订单【在my_demo_02数据库中】
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/30 10:58
     *
     * 以下面数据为例:先添加下面为例子的数据源(调用DataSourceController中的add方法,可以在swagger中做,这里就不多说了)
     * poolName:my_demo_02
     * type:mysql
     * driverClassName:com.mysql.cj.jdbc.Driver
     * url:jdbc:mysql://127.0.0.1:3306/my_demo_02?characterEncoding=utf8&useSSL=false&autoReconnect=true&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
     * username:root
     * password:root
     */
    @PostMapping(value = "findAllFsOrder")
    @ApiOperation(value = "查询所有订单【在my_demo_02数据库中】",notes = "查询所有订单【在my_demo_02数据库中】")
    @ApiResponses({
            @ApiResponse(code = 0, message = "ok", response= Result.class),
    })
    public Result findAllFsOrder() {
        List<FsOrder> result = testService.findAllFsOrder();
        return Result.success(result);
    }

}

16.TestService.java

java 复制代码
package com.example.service;

import com.example.entity.FsOrder;
import com.example.entity.SysUser;

import java.util.List;

/**
 * 类名称:
 *
 * @author 李庆伟
 * @date 2023年10月30日 11:02
 */
public interface TestService {

    //查询所有的用户 【在master数据库中】
    List<SysUser> findAllSysUser();

    //查询所有的订单【在my_demo_02数据库中】
    List<FsOrder> findAllFsOrder();
}

17.TestServiceImpl.java

java 复制代码
package com.example.service.impl;

import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.entity.FsOrder;
import com.example.entity.SysUser;
import com.example.mapper.FsOrderMapper;
import com.example.mapper.SysUserMapper;
import com.example.service.TestService;
import com.example.utils.DbOprUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
 * 类名称:
 *
 * @author 李庆伟
 * @date 2023年10月30日 11:02
 */
@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private DbOprUtil dbOprUtil;

    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private FsOrderMapper fsOrderMapper;

    /**
     * @Description: 查询所有的用户 【在master数据库中】
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/30 11:04
     */
    @Override
    public List<SysUser> findAllSysUser() {
        //切换为master数据源,master为DbDataSourceDTO中的poolName(连接池名称:自定义不能重)
        dbOprUtil.changeByDataSourceByName("master");
        return sysUserMapper.selectList(new QueryWrapper<SysUser>());
    }

    /**
     * @Description: 查询所有的订单【在my_demo_02数据库中】
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/30 11:04
     */
    @Override
    public List<FsOrder> findAllFsOrder() {
        //切换为my_demo_02数据源,my_demo_02为DbDataSourceDTO中的poolName(连接池名称:自定义不能重)
        dbOprUtil.changeByDataSourceByName("my_demo_02");
        return fsOrderMapper.selectList(new QueryWrapper<FsOrder>());
    }


    //@DSTransactional//多数据源事务注解
    //public void save() {
    //    dbOprUtil.changeByDataSourceByName("master");
    //    //insert master对应库数据
    //    //业务就省略了
    //    dbOprUtil.changeByDataSourceByName("my_demo_02");
    //    //insert my_demo_02对应库数据
    //    //业务就省略了
    //}
}

18.FsOrderMapper.java

java 复制代码
package com.example.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * 类名称:订单
 *
 * @author 李庆伟
 * @date 2023年10月27日 15:26
 */
@Data
@TableName
public class FsOrder {

    @TableId
    private String id;

    private String orderNum;//订单号

    private String address;//订单地址
}

19.SysUser.java

java 复制代码
package com.example.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * 类名称:用户
 *
 * @author 李庆伟
 * @date 2023年10月27日 15:26
 */
@Data
@TableName
public class SysUser {

    @TableId
    private String id;

    private String userName;//用户名

    private String nickName;//昵称

    private Integer age;//年龄
}

20.测试看效果:http://localhost:9000/doc.html

动态数据源添加

数据源查询

不同数据源下的表数据查询

记录一点点。。。。。。。。。。。。。。。

相关推荐
lizi8888833 分钟前
单组件的编写
java
java_heartLake35 分钟前
设计模式之代理模式
java·设计模式·代理模式
魏 无羡1 小时前
pgsql 分组查询方法
java·服务器·数据库
兩尛2 小时前
java--面向对象编程(中级部分)
java·开发语言
Xxxx. .Xxxx2 小时前
C语言程序设计实验与习题指导 (第4版 )课后题-第二章+第三章
java·c语言·开发语言
姜西西_2 小时前
[Spring]Spring MVC 请求和响应及用到的注解
java·spring·mvc
逸狼2 小时前
【JavaEE初阶】多线程6(线程池\定时器)
java·开发语言·算法
qq_35323353892 小时前
【原创】java+springboot+mysql科研成果管理系统设计与实现
java·spring boot·mysql·mvc·web
dawn1912282 小时前
SpringMVC 入门案例详解
java·spring·html·mvc
极客先躯2 小时前
高级java每日一道面试题-2024年9月16日-框架篇-Spring MVC和Struts的区别是什么?
java·spring·面试·mvc·struts2·框架篇·高级java