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

news2024/11/17 10:04:03

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

先看工程图:

1.pom.xml文件

<?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

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

/*
 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;
/*
 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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 动态数据源添加

 数据源查询

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1150781.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第五章 I/O管理 三、I/O控制方式(程序直接控制、中断驱动方式、DMA方式、通道控制方式)

目录 一、程序直接控制方式 1、以读操作为例 2、CPU的干预 3、数据传送的单位 4、数据的流向 5、优点 6、缺点 二、中断驱动方式 1、定义&#xff1a; 2、CPU干预的频率 3、数据传送的单位 4、数据的流向 5、主要缺点和主要优点 优点: 缺点: 三、DMA方式&#x…

R语言使用surveyCV包对NHANES数据(复杂调查加权数据)进行10折交叉验证

美国国家健康与营养调查&#xff08; NHANES, National Health and Nutrition Examination Survey&#xff09;是一项基于人群的横断面调查&#xff0c;旨在收集有关美国家庭人口健康和营养的信息。 地址为&#xff1a;https://wwwn.cdc.gov/nchs/nhanes/Default.aspx 既往咱们…

世界前沿技术发展报告2023《世界航空技术发展报告》(六)航空动力技术

&#xff08;六&#xff09;航空动力技术 1.军用航空动力技术1.1 美国空军授出下一代自适应推进项目合同1.2 法国完成下一代战斗机发动机原型机地面测试1.3 美国通用电气公司为美国陆军测试首台T901涡轴发动机1.4 美国液体活塞公司研制高功重比重油发动机 2.民用航空动力技术2.…

这样刻《少年强则国强》也行……

孙溟㠭篆刻《少年强则国强 》 这是篆书&#xff0c;隶书&#xff0c;简化字刻法有点意思。 孙溟㠭篆刻《少年强则国强》

信息系统项目管理师教程 第四版【第7章-项目立项管理-思维导图】

信息系统项目管理师教程 第四版【第7章-项目立项管理-思维导图】 课本里章节里所有蓝色字体的思维导图

一文告诉你样机是什么,分享几个常用的样机模板

一个项目的诞生通常需要经历头脑构思、绘制设计和最终着陆。在这个过程中&#xff0c;样机制作往往是在着陆实践之前进行的。俗话说&#xff1a;“样机使用得好&#xff0c;草稿过早”。样机设计是产品或网站最终设计的生动、静态和视觉表现。它为用户提供了一种模拟现实的方式…

大语言模型有什么魅力?和生成式AI是一回事吗?亚马逊云科技可以告诉你

大语言模型和生成式AI有什么关系呢&#xff1f;大语言模型为什么这么火&#xff1f;一提到大语言模型&#xff0c;想必大家第一个想到的就是ChatGPT这样的自然语言处理工具&#xff0c;那么大语言模型是什么&#xff1f;大语言模型和生成式AI是什么关系&#xff1f;就让我以亚马…

HackerOne 已向白帽支付了超 3 亿美元漏洞赏金

知名网络安全公司HackerOne近日宣布&#xff0c;自2012年成立以来&#xff0c;其漏洞赏金计划已向白帽和漏洞研究人员发放了超 3 亿美元的奖励。 HackerOne提供了一个漏洞赏金平台&#xff0c;将企业与白帽的安全专业知识、资产发现、持续评估和流程增强相结合&#xff0c;以发…

OSEK-任务调度机制

如下图所示&#xff0c;在调度表中有很多 Expiry Points&#xff0c;下面是一个20ms的调度表。有每2.5ms触发一次2.5ms的TASK&#xff0c;以及等等其他按照时间的TASK触发&#xff1b;并且根据配置也可以看出&#xff0c;所有的任务都是基于全抢占模式触发的&#xff0c;也就是…

如何完全卸载HbuilderX(全网最详细)

前序 今天本来想发行打包安卓端,结果发现突然就不行了(前天还行)报错 排查 然后我找了各种原因,排查了很久才发现是HbuilderX编辑器的问题,机智如我所以我们需要重新去下载一个HbuilderX,但是问题来了,很多人不知道怎么卸载,我自己网上也百度了很久没有正确简单的方法,直…

c: two-dimensional array

/*** ****************************************************************************** file twoDimensional.h* brief 二维数组 Pointers and 2-D arrays* author geovindu,Geovin Du,涂聚文 (geovindu163.com)* ide: vscode c11,c17 windows 10* date…

2023年N1叉车司机证模拟考试题库及N1叉车司机理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年N1叉车司机证模拟考试题库及N1叉车司机理论考试试题是由安全生产模拟考试一点通提供&#xff0c;N1叉车司机证模拟考试题库是根据N1叉车司机最新版教材&#xff0c;N1叉车司机大纲整理而成&#xff08;含2023年…

生产级 React 框架介绍

文章目录 生产级 React 框架生产级 React 框架Next.jsRemixGatsbyExpo 如何选择生产级 React 框架 生产级 React 框架 React 是一个流行的 JavaScript 框架&#xff0c;用于构建用户界面。React 框架可以帮助你快速构建高质量的 React 应用&#xff0c;但并不是所有的 React 框…

Linux下GPIO和看门狗应用编程

文章目录 GPIO应用编程看门狗应用编程 GPIO应用编程 应用层操控硬件可以通过操作这些硬件的设备文件来进行&#xff0c;设备文件是各种硬件设备向应用层提供的一个接口&#xff0c;应用层通过对设备文件的I/O操作来操控硬件设备。设备文件通常在/dev/目录下&#xff0c;该目录…

react:生命周期

一、生命周期阶段 官方文档&#xff1a;https://zh-hans.legacy.reactjs.org/docs/react-component.html React组件生命周期可分为三个阶段&#xff1a;挂载、更新、卸载 挂载&#xff1a;当组件实例被创建并插入 DOM 中时。其生命周期调用顺序如下&#xff1a; constructor()s…

rfsoc FPGA 49DR 16收16发模块

前面简单介绍过RFSOC板卡 https://blog.csdn.net/jingjiankai5228/article/details/114734631 整体来说RFSOC降低了传统AD DA软硬件开发难度&#xff0c;但是同样存在整数点FS/N谐波大的问题 交织采样是通过多个AD拼接完成的&#xff0c;所以校准比较关键&#xff0c;和以前常…

【算法练习Day33】不同路径不同路径 II

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 不同路径不同路径 II总结&a…

腾讯云轻量服务器“镜像类型”以及“镜像”选择方法

腾讯云轻量应用服务器镜像类型分为应用镜像、系统镜像、Docker基础镜像、自定义镜像和共享镜像&#xff0c;腾讯云百科txybk.com来详细说下不同镜像类型说明和详细介绍&#xff1a; 轻量应用服务器镜像类型说明 腾讯云轻量应用服务器 应用镜像&#xff1a;独有的应用镜像除了包…

RHCE---作业4

一.批量创建账户 .编写脚本for1.sh,使用for循环创建20账户&#xff0c;账户名前缀由用户从键盘输入&#xff0c;账户初始密码由用广输入&#xff0c;例如: test1、test2、test3、.....、 test10 read -p "请输入账户前缀名&#xff1a;" user read -p "请输入…

低代码软件在酒店行业的应用:提升效率与创新!

疫情放开后&#xff0c;旅游业开始兴盛发展&#xff0c;酒店行业也恢复了疫情前的繁忙。但是由于管理架构上的不完善导致很多酒店并不能很好地承接巨大的客流量&#xff0c;而消费者在旅游过程对体验要求是最高的&#xff0c;所以酒店拥有一个能够高效运营的管理系统至关重要。…