Nacos配置中心 MybatisPlus 多环境数据库配置

3,063 阅读6分钟

配置中心的一大作用就是配置数据库信息,避免数据库用户名,密码暴露。

Nacos配置中心,0.2.1 和 0.2.2 版本不一样,使用方法差别好大。

看到以下方法区分 线上,灰度和日常环境:

  • 还有的使用Data ID与profiles实现
  • 使用Group实现
  • 使用Namespace实现

具体可以自己看一下,可能是我的版本不对,好像不行...

Spring Cloud Alibaba基础教程:Nacos配置的多环境管理

下面的我的用法,版本是 0.2.2

首先建三个配置文件

三个配置文件


对应日常,灰度,和线上
环境

接下来,敲代码

  • 数据库 sql
CREATE TABLE `user_account` (
  `user_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户id',
  `user_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '用户名',
  `mobile` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '手机号',
  `password` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '密码',
  `creator` bigint(20) DEFAULT NULL COMMENT '创建人',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `modifier` bigint(20) DEFAULT NULL COMMENT '修改人',
  `gmt_modify` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
  `is_deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '逻辑删除',
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
  • 依赖 用到了 Mybatis-Plus
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ler</groupId>
    <artifactId>nacosdbconfig</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>nacosdbconfig</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <nacos-config-spring-boot.version>0.2.2</nacos-config-spring-boot.version>
    </properties>

    <dependencies>

        <!--db-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <!--<version>5.1.35</version>-->
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.4</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>


        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.56</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8.1</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
            <version>1.18.8</version>
        </dependency>

        <!--swagger-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>


        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>nacos-config-spring-boot-starter</artifactId>
            <version>${nacos-config-spring-boot.version}</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>nacos-config-spring-boot-actuator</artifactId>
            <version>${nacos-config-spring-boot.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

    <profiles>
        <!--日常环境-->
        <profile>
            <id>dev</id>
            <properties>
                <activatedProperties>dev</activatedProperties>
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
        </profile>
        <!--灰度环境-->
        <profile>
            <id>gray</id>
            <properties>
                <activatedProperties>gray</activatedProperties>
            </properties>
        </profile>
        <!--生产环境-->
        <profile>
            <id>online</id>
            <properties>
                <activatedProperties>online</activatedProperties>
            </properties>
        </profile>
    </profiles>

    <build>
        <!-- 指定使用的 filter 从指定的文件中取数据 -->
        <filters>
            <filter>src/main/resources/application-${activatedProperties}.properties</filter>
        </filters>
        <resources>
            <!-- 配置需要被替换的资源文件路径, properties 应该在 src/main/resource 目录下 -->
            <resource>
                <directory>src/main/resources</directory>
                <!-- 是否使用过滤器 -->
                <filtering>true</filtering>
                <!--排除后,不会打包到Jar包内-->
                <excludes>
                    <exclude>application-dev.properties</exclude>
                    <exclude>application-gray.properties</exclude>
                    <exclude>application-online.properties</exclude>
                </excludes>
            </resource>
        </resources>

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

</project>
  • application.properties
server.port=8001

# 主配置服务器地址
nacos.config.server-addr=127.0.0.1:8848

#开启配置预加载功能
nacos.config.bootstrap.enable=true

# 主配置 data-id  修改为mysql_db_config_dev 可直接启动
nacos.config.data-id=@data-id@
# 主配置 group-id
nacos.config.group=DEFAULT_GROUP
# 主配置 配置文件类型
nacos.config.type=properties
# 主配置 最大重试次数
nacos.config.max-retry=10
# 主配置 开启自动刷新
nacos.config.auto-refresh=true
# 主配置 重试时间
nacos.config.config-retry-time=2333
# 主配置 配置监听长轮询超时时间
nacos.config.config-long-poll-timeout=46000
# 主配置 开启注册监听器预加载配置服务(除非特殊业务需求,否则不推荐打开该参数)
#nacos.config.enable-remote-sync-config=true

#nacos.config.ext-config[0].data-id=test
#nacos.config.ext-config[0].group=DEFAULT_GROUP
#nacos.config.ext-config[0].max-retry=10
#nacos.config.ext-config[0].type=yaml
#nacos.config.ext-config[0].auto-refresh=true
#nacos.config.ext-config[0].config-retry-time=2333
#nacos.config.ext-config[0].config-long-poll-timeout=46000
#nacos.config.ext-config[0].enable-remote-sync-config=true

主要是 nacos.config.data-id=@data-id@ 这一句

  • application-dev.properties
# 主配置 data-id
data-id=mysql_db_config_dev
  • application-gray.properties
# 主配置 data-id
data-id=mysql_db_config_gray
  • application-online.properties
# 主配置 data-id
data-id=mysql_db_config_online
  • MybatisPlusConfig
package com.ler.nacosdbconfig.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.MybatisXMLLanguageDriver;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;

/**
 * @author lww
 * @date 2019-08-25 01:04
 */
@Configuration
@MapperScan(basePackages = "com.ler.nacosdbconfig.dao", sqlSessionTemplateRef = "sqlSessionTemplate")
public class MybatisPlusConfig {

	@NacosValue(value = "${spring.datasource.url}", autoRefreshed = true)
	private String dataUrl;

	@NacosValue(value = "${spring.datasource.username}", autoRefreshed = true)
	private String userName;

	@NacosValue(value = "${spring.datasource.password}", autoRefreshed = true)
	private String password;

	@NacosValue(value = "${spring.datasource.initial-size}", autoRefreshed = true)
	private Integer initSize;

	@NacosValue(value = "${spring.datasource.max-active}", autoRefreshed = true)
	private Integer maxActive;

	private static final Logger log = LoggerFactory.getLogger(MybatisPlusConfig.class);

	@Bean("dataSource")
	public DataSource dataSourceDemo1() {
		try {
			DruidDataSource dataSource = new DruidDataSource();
			dataSource.setDriverClassName("com.mysql.jdbc.Driver");
			dataSource.setUrl(dataUrl);
			dataSource.setUsername(userName);
			dataSource.setPassword(password);

			dataSource.setInitialSize(initSize);
			dataSource.setMaxActive(maxActive);
			dataSource.setMinIdle(1);
			dataSource.setMaxWait(60_000);
			dataSource.setPoolPreparedStatements(true);
			dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
			dataSource.setTimeBetweenEvictionRunsMillis(60_000);
			dataSource.setMinEvictableIdleTimeMillis(300_000);
			dataSource.setValidationQuery("SELECT 1");
			return dataSource;
		} catch (Throwable throwable) {
			log.error("ex caught", throwable);
			throw new RuntimeException();
		}
	}

	@Bean(name = "sqlSessionFactory")
	public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {
		MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
		factoryBean.setDataSource(dataSource);
		factoryBean.setVfs(SpringBootVFS.class);
		factoryBean.setTypeAliasesPackage("com.ler.nacosdbconfig.domain");

		Resource[] mapperResources = new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*Dao.xml");
		factoryBean.setMapperLocations(mapperResources);

		MybatisConfiguration configuration = new MybatisConfiguration();
		configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
		configuration.setJdbcTypeForNull(JdbcType.NULL);
		configuration.setMapUnderscoreToCamelCase(true);
		configuration.addInterceptor(new PaginationInterceptor());
		configuration.setUseGeneratedKeys(true);
		factoryBean.setConfiguration(configuration);
		return factoryBean.getObject();
	}

	@Bean(name = "sqlSessionTemplate")
	public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
		return new SqlSessionTemplate(sqlSessionFactory);
	}

	@Bean(name = "transactionManager")
	public PlatformTransactionManager platformTransactionManager(@Qualifier("dataSource") DataSource dataSource) {
		return new DataSourceTransactionManager(dataSource);
	}

	@Bean(name = "transactionTemplate")
	public TransactionTemplate transactionTemplate(@Qualifier("transactionManager") PlatformTransactionManager transactionManager) {
		return new TransactionTemplate(transactionManager);
	}

}
  • MybatisGenerator
package com.ler.nacosdbconfig.mybatis.generator;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.ArrayList;
import java.util.List;
import lombok.Data;

/**
 * @author lww
 * @date 2019-04-12 6:53 PM
 */
public class MybatisGenerator {

	/**
	 * 需要生成的表
	 */
	private static String[] tableNames = {"user_account"};

	/**
	 * 生成配置,哪一个不需要生成就设置为false
	 */
	@Data
	private static class Cfg {
		private boolean needToGenDomain = true;
		private boolean needToGenDao = true;
		private boolean needToGenMapperXml = true;
		private boolean needToGenService = true;
		private boolean needToGenController = true;
	}


	/**
	 * 作者
	 */
	private static final String AUTHOR = "lww";
	/**
	 * 顶级包名
	 */
	private static final String ROOT_PACKAGE_NAME = "com.ler.nacosdbconfig";


	/**
	 * 数据库相关配置
	 */
	private static final String DB_URL = "jdbc:mysql://127.0.0.1:3306/blog?useUnicode=true&useSSL=false&characterEncoding=utf8";
	private static final String USER_NAME = "root";
	private static final String PASSWORD = "adminadmin";


	public static void main(String[] args) {
		String path = Thread.currentThread().getContextClassLoader().getResource("").getPath();
		//获取当前项目目录
		String substring = ROOT_PACKAGE_NAME.substring(ROOT_PACKAGE_NAME.lastIndexOf(".") + 1);
		String[] split = path.split(substring);
		if (split.length <= 0) {
			System.err.println("顶级包名配置错误,顶级包名的最后一个文件夹应该是项目名称!");
		}

		String projectRoot = split[0] + substring;
		// 代码生成器
		ExtendedAutoGenerator mpg = new ExtendedAutoGenerator();
		// 全局配置
		final GlobalConfig gc = new GlobalConfig();
		gc.setOutputDir(projectRoot + "/src/main/java");
		gc.setFileOverride(true);
		// 不需要ActiveRecord特性的请改为false AR特性
		gc.setActiveRecord(false);
		// 开启 swagger2 模式
		gc.setSwagger2(true);
		// XML 二级缓存
		gc.setEnableCache(false);
		// XML ResultMap
		gc.setBaseResultMap(false);
		// XML columList
		gc.setBaseColumnList(false);
		gc.setAuthor(AUTHOR);
		gc.setOpen(false);
		gc.setDateType(DateType.ONLY_DATE);
		// 自定义文件命名,注意 %s 会自动填充表实体属性!
		gc.setMapperName("%sDao");
		gc.setXmlName("%sDao");
		gc.setServiceName("%sService");
		gc.setServiceImplName("%sServiceImpl");
		gc.setControllerName("%sController");

		mpg.setGlobalConfig(gc);

		// 数据源配置
		DataSourceConfig dsc = new DataSourceConfig();
		dsc.setDbType(DbType.MYSQL);
		// dsc.setSchemaName("public");
		dsc.setUrl(DB_URL);
		dsc.setUsername(USER_NAME);
		dsc.setPassword(PASSWORD);
		dsc.setDriverName("com.mysql.jdbc.Driver");

		dsc.setTypeConvert(new MySqlTypeConvert() {
			// 自定义数据库表字段类型转换【可选】
			@Override
			public IColumnType processTypeConvert(GlobalConfig globalConfig, String fieldType) {
				System.out.println("转换类型:" + fieldType);
				// 注意!!processTypeConvert 存在默认类型转换,如果不是你要的效果请自定义返回、非如下直接返回。
				if ((fieldType.toLowerCase()).contains("tinyint(1)")) {
					return DbColumnType.INTEGER;
				}
				return super.processTypeConvert(gc, fieldType);
			}
		});
		mpg.setDataSource(dsc);

		// 包配置
		PackageConfig pc = new PackageConfig();
		pc.setModuleName("");
		pc.setParent(ROOT_PACKAGE_NAME);
		pc.setMapper("dao");
		pc.setEntity("domain");
		pc.setService("service");
		pc.setServiceImpl("service.impl");
		pc.setXml("mapper");
		pc.setController("controller");
		mpg.setPackageInfo(pc);

		// 自定义配置
		InjectionConfig injectionConfig = new InjectionConfig() {
			@Override
			public void initMap() {
				// to do nothing
			}
		};
		List<FileOutConfig> focList = new ArrayList<>();
		focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
			@Override
			public String outputFile(TableInfo tableInfo) {
				// 自定义输入文件名称
				return projectRoot + "/src/main/resources/mapper/" + tableInfo.getEntityName() + "Dao" + StringPool.DOT_XML;
			}
		});
		injectionConfig.setFileOutConfigList(focList);
		mpg.setCfg(injectionConfig);
		TemplateConfig templateConfig = new TemplateConfig().setXml(null);
		mpg.setTemplate(templateConfig);

		// 策略配置
		StrategyConfig strategy = new StrategyConfig();
		strategy.setNaming(NamingStrategy.underline_to_camel);
		strategy.setColumnNaming(NamingStrategy.underline_to_camel);
		// 自定义 mapper 父类
		strategy.setSuperMapperClass("com.baomidou.mybatisplus.core.mapper.BaseMapper");
		//是否为lombok模型
		strategy.setEntityLombokModel(true);
		strategy.setRestControllerStyle(true);
		strategy.setInclude(tableNames);
		//是否生成实体时,生成字段注解
		strategy.entityTableFieldAnnotationEnable(true);
		mpg.setStrategy(strategy);

		AbstractTemplateEngine templateEngine = new FreemarkerTemplateEngine();
		mpg.setTemplateEngine(templateEngine);
		// 忽略service跟controller生成,把mpg.execute()方法拆解开自行定制
		//mpg.execute();
		System.out.println("==========================准备生成文件...==========================");
		ConfigBuilder configBuilder = new ConfigBuilder(pc, dsc, strategy, templateConfig, gc);
		configBuilder.setInjectionConfig(injectionConfig);
		List<TableInfo> tableInfoList = configBuilder.getTableInfoList();

		Cfg cfg = new Cfg();
		for (TableInfo tableInfo : tableInfoList) {
			if (!cfg.isNeedToGenDomain()) {
				tableInfo.setEntityName(null);
			}
			if (!cfg.isNeedToGenMapperXml()) {
				tableInfo.setXmlName(null);
			}
			if (!cfg.isNeedToGenDao()) {
				tableInfo.setMapperName(null);
			}
			if (!cfg.isNeedToGenService()) {
				tableInfo.setServiceName(null);
				tableInfo.setServiceImplName(null);
			}
			if (!cfg.isNeedToGenController()) {
				tableInfo.setControllerName(null);
			}
		}
		// 模板引擎初始化执行文件输出
		templateEngine.init(mpg.pretreatmentConfigBuilder(configBuilder)).mkdirs().batchOutput().open();
		System.out.println("==========================文件生成完成!!!==========================");
	}

	private static class ExtendedAutoGenerator extends AutoGenerator {
		@Override
		public ConfigBuilder pretreatmentConfigBuilder(ConfigBuilder config) {
			return super.pretreatmentConfigBuilder(config);
		}
	}
}
  • Controller
package com.ler.nacosdbconfig.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ler.nacosdbconfig.domain.UserAccount;
import com.ler.nacosdbconfig.service.UserAccountService;
import io.swagger.annotations.ApiOperation;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author lww
 * @since 2019-08-25
 */
@RestController
public class UserAccountController {

	@Resource
	private UserAccountService userAccountService;

	@GetMapping("/user")
	public List<UserAccount> getUser() {
		List<UserAccount> list = userAccountService.list(new QueryWrapper<UserAccount>());
		return list;
	}
}
  • 启动类
package com.ler.nacosdbconfig;

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

@SpringBootApplication
public class NacosDbconfigApplication {

	public static void main(String[] args) {
		SpringApplication.run(NacosDbconfigApplication.class, args);
	}
}

运行一下代码生成器,代码就生成好了

最后结构

最后结构

#打包命令,先使用第一个

mvn clean compile package -Dmaven.test.skip=true -Pdev
mvn clean compile package -Dmaven.test.skip=true -Pgray
mvn clean compile package -Dmaven.test.skip=true -Ponline

打包命令运行


首先只有一个 properties文件,data-id根据环境变成了 mysql_db_config_dev

打包结果

启动看一下

启动

访问

访问

源码下载

项目代码

这些是我自己博客的文章,在这里分享一下