数据库
首页 > 数据库> > SpringBoot2.0.5 + jpa + druid 多数据源 数据库密码加密

SpringBoot2.0.5 + jpa + druid 多数据源 数据库密码加密

作者:互联网

SpringBoot2.0.5 + jpa + druid 多数据源 数据库密码加密

 

文章目录

 

一、druid 多数据源

1. pom.xml

建议使用1.1.10以上版本

<!-- druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!-- 若项目本来用了logback 可以不引入,设置filters 为slf4j  -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
		<!--   sqlserver数据库连接  -->
        <dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>mssql-jdbc</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.21</version>
            <scope>runtime</scope>
        </dependency>
		<!--用于读取配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

2.配置文件 application.properties

#druid的一些基本配置
spring.datasource.druid.default.initialSize = 5
spring.datasource.druid.default.minIdle = 5
spring.datasource.druid.default.maxActive = 30
spring.datasource.druid.default.maxWait = 1200000
spring.datasource.druid.default.timeBetweenEvictionRunsMillis = 1200000
spring.datasource.druid.default.minEvictableIdleTimeMillis = 300000
spring.datasource.druid.default.primary-validationQuery = SELECT 'x'
spring.datasource.druid.default.secondary-validationQuery = SELECT 1
spring.datasource.druid.default.testWhileIdle = true
spring.datasource.druid.default.testOnBorrow = false
spring.datasource.druid.default.testOnReturn = false
spring.datasource.druid.default.poolPreparedStatements = true
spring.datasource.druid.default.maxPoolPreparedStatementPerConnectionSize = 30
spring.datasource.druid.primary.filters=stat,wall,slf4j
spring.datasource.druid.default.connectionProperties = druid.stat.mergeSql=false;druid.stat.slowSqlMillis=5000
spring.aop.proxy-target-class = true
# merge multi DruidDataSource Data
spring.datasource.druid.default.useGlobalDataSourceStat = true

# 主数据源
spring.datasource.druid.primary.url=jdbc:sqlserver://xxx:1433;DatabaseName=xxx
spring.datasource.druid.primary.username=xxx
spring.datasource.druid.primary.password=xxx
spring.datasource.druid.primary.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.druid.primary.primary-dialect=org.hibernate.dialect.SQLServer2012Dialect
# 部分sql由于wall查询存在错误
spring.datasource.druid.primary.filters=
# 第二数据源 mysql
spring.datasource.druid.secondary.url=jdbc:mysql://xxx:3306/xxx?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
spring.datasource.druid.secondary.username=xxx
spring.datasource.druid.secondary.password=xxx
spring.datasource.druid.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.secondary.primary-dialect=org.hibernate.dialect.MySQLDialect

3.DruidDefaultPropertiesConfig 用于接收通用的druid配置

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Data
@Component
@ConfigurationProperties(prefix = "spring.datasource.druid.default")
public class DruidDefaultPropertiesConfig {
    private int initialSize;
    private int minIdle;
    private int maxActive;
    private int maxWait;
    private int timeBetweenEvictionRunsMillis;
    private int minEvictableIdleTimeMillis;
    private String validationQuery;
    private boolean testWhileIdle;
    private boolean testOnBorrow;
    private boolean testOnReturn;
    private boolean poolPreparedStatements;
    private int maxPoolPreparedStatementPerConnectionSize;
    private String filters;
    private String connectionProperties;
    private boolean useGlobalDataSourceStat;
}

4.设置DataSource

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;
import javax.xml.crypto.Data;
import java.sql.SQLException;

@Configuration
public class DruidDataSourceConfig {

    @Autowired
    DruidDefaultPropertiesConfig druidDefaultPropertiesConfig;

    @Primary
    @Qualifier("primaryDataSource")
    @Bean(name = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.druid.primary")
    public DataSource primaryDataSource() {
        return getDruidDataSource();
    }

    @Qualifier("secondaryDataSource")
    @Bean(name = "secondaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.druid.secondary")
    public DataSource secondaryDataSource() {
        return getDruidDataSource();
    }

    private DruidDataSource getDruidDataSource() {
        DruidDataSource datasource = DruidDataSourceBuilder.create().build();
        datasource.setInitialSize(druidDefaultPropertiesConfig.getInitialSize());
        datasource.setMinIdle(druidDefaultPropertiesConfig.getMinIdle());
        datasource.setMaxActive(druidDefaultPropertiesConfig.getMaxActive());
        datasource.setMaxWait(druidDefaultPropertiesConfig.getMaxWait());
        datasource.setTimeBetweenEvictionRunsMillis(druidDefaultPropertiesConfig.getTimeBetweenEvictionRunsMillis());
        datasource.setMinEvictableIdleTimeMillis(druidDefaultPropertiesConfig.getMinEvictableIdleTimeMillis());
        datasource.setValidationQuery(druidDefaultPropertiesConfig.getValidationQuery());
        datasource.setTestWhileIdle(druidDefaultPropertiesConfig.isTestWhileIdle());
        datasource.setTestOnBorrow(druidDefaultPropertiesConfig.isTestOnBorrow());
        datasource.setTestOnReturn(druidDefaultPropertiesConfig.isTestOnReturn());
        datasource.setPoolPreparedStatements(druidDefaultPropertiesConfig.isPoolPreparedStatements());
        datasource.setMaxPoolPreparedStatementPerConnectionSize(druidDefaultPropertiesConfig.getMaxPoolPreparedStatementPerConnectionSize());
        datasource.setUseGlobalDataSourceStat(druidDefaultPropertiesConfig.isUseGlobalDataSourceStat());
        try {
            datasource.setFilters(druidDefaultPropertiesConfig.getFilters());
        } catch (SQLException e) {
            System.err.println("druid configuration initialization filter: "+ e);
        }
        datasource.setConnectionProperties(druidDefaultPropertiesConfig.getConnectionProperties());
        return datasource;
    }
}

5.数据源设置

第一数据源

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.persistence.EntityManager;
import javax.sql.DataSource;
import java.util.Map;

@Configuration
@EnableTransactionManagement
//设置Repository所在位置
@EnableJpaRepositories(
        entityManagerFactoryRef="entityManagerFactoryPrimary",
        transactionManagerRef="transactionManagerPrimary",
        basePackages= { "xx.repository",
                "xx.xx.repository",
                "xx.xx.repository" })
public class PrimaryConfig {

    @Autowired
    @Qualifier("primaryDataSource")
    private DataSource primaryDataSource;

    @Autowired
    private JpaProperties jpaProperties;

    @Primary
    @Bean(name = "entityManagerPrimary")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
        return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
    }

    @Primary
    @Bean(name = "entityManagerFactoryPrimary")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary (EntityManagerFactoryBuilder builder) {
        //设置实体类位置
        String[] packages = new String[]{
            "xxx.domain",
            "xxx.domain",
        };
        LocalContainerEntityManagerFactoryBean entityManagerFactory = builder
                .dataSource(primaryDataSource)
                .packages(packages)
                .properties(getVendorProperties())
                .persistenceUnit("primaryPersistenceUnit")
                .build();
        return entityManagerFactory;
    }

    @Value("${spring.datasource.druid.primary.primary-dialect}")
    private String primaryDialect;

    private Map<String, Object> getVendorProperties() {
        Map<String, Object> properties = jpaProperties.getHibernateProperties(new HibernateSettings());
        properties.put("hibernate.dialect",primaryDialect);
        return properties;
    }

    @Primary
    @Bean(name = "transactionManagerPrimary")
    public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
    }

}

第二数据源

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.persistence.EntityManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@Configuration
@EnableTransactionManagement
//设置Repository所在位置
@EnableJpaRepositories(
        entityManagerFactoryRef="entityManagerFactorySecondary",
        transactionManagerRef="transactionManagerSecondary",
        basePackages= { "xx.repository" })
public class SecondaryConfig {
    @Autowired
    @Qualifier("secondaryDataSource")
    private DataSource secondaryDataSource;

    @Autowired
    private JpaProperties jpaProperties;

    @Bean(name = "entityManagerSecondary")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
        return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
    }

    @Bean(name = "entityManagerFactorySecondary")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary(EntityManagerFactoryBuilder builder) {
        //设置实体类位置
        String[] packages = new String[]{"xxx.domain"};
        LocalContainerEntityManagerFactoryBean entityManagerFactory = builder
                .dataSource(secondaryDataSource)
                .packages(packages)
                .properties(getVendorProperties())
                .persistenceUnit("secondaryPersistenceUnit")
                .build();
        entityManagerFactory.setJpaPropertyMap(jpaProperties.getProperties());
        return entityManagerFactory;

    }

    @Value("${spring.datasource.druid.secondary.primary-dialect}")
    private String secondaryDialect;

    private Map<String, Object> getVendorProperties() {
        Map<String, Object> properties = jpaProperties.getHibernateProperties(new HibernateSettings());
        properties.put("hibernate.dialect",secondaryDialect);
        return properties;
    }


    @Bean(name = "transactionManagerSecondary")
    public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
    }
}


需要注意这里是springboot 2.0.X的写法
其他写法参考 文章 未验证
SpringBoot 1.5.x 需要修改getVendorPropertiest方法

private Map<String, String> getVendorProperties() {
 return jpaProperties.getHibernateProperties(userDataSource);
}

springBoot2.1的写法

private Map<String, Object> getVendorProperties() {
    return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
}

7.需要注意的坑

1.不同类型数据库需要设置hibernate.dialect ,需要根据数据库版本设置

2.spring.datasource.druid.primary.filters=stat,wall,slf4j 原来项目中有一些sql由于设置了wall ,查询报错,目前只能去掉wall的设置

二.数据库密码加密

1. 使用druid密码加密

druid 官方文档

使用druid jar加密,获取到publickey和password

java -cp druid-1.0.16.jar com.alibaba.druid.filter.config.ConfigTools you_password

解密类

import com.alibaba.druid.filter.config.ConfigTools;
import com.alibaba.druid.util.DruidPasswordCallback;


public class DesPassword extends DruidPasswordCallback {

    public static void main(String[] args) throws Exception{
        String publickey = "";
        String password = "";
        String pwd = ConfigTools.decrypt(publickey, password);
        System.out.println(pwd);
    }
}

修改配置文件

# 公钥
secondary.publickey=${spring.datasource.druid.secondary.publickey}
# 配置 connection-properties,启用加密,配置公钥。
spring.datasource.druid.secondary.connection-properties=config.decrypt=true;config.decrypt.key=${secondary.publickey};druid.stat.mergeSql=false;druid.stat.slowSqlMillis=5000
# 启动ConfigFilter
spring.datasource.druid.secondary.filters=stat,wall,slf4j,config

其中spring.datasource.druid.secondary.publickey 设置到jvm中,避免暴露

#idea中
-Dspring.datasource.druid.secondary.publickey=
#Java启动
java -jar xxx.jar --spring.datasource.druid.secondary.publickey=

2.使用Jasypt 加密

增加依赖

<!-- jasypt -->
<dependency>
 <groupId>com.github.ulisesbocchio</groupId>
 <artifactId>jasypt-spring-boot-starter</artifactId>
 <version>3.0.3</version>
</dependency>

配置

 # 加密盐值
jasypt.encryptor.password=abc
# 加密算法设置 3.0.0 以后
jasypt.encryptor.algorithm=PBEWithMD5AndDES
jasypt.encryptor.iv-generator-classname=org.jasypt.iv.NoIvGenerator

加密盐值不建议配置在配置文件

#设置jvm
 -Djasypt.encryptor.password=abc
#java 
java  -jar xx.jar --jasypt.encryptor.password=abc

工具类加密解密

import org.jasypt.util.text.BasicTextEncryptor;
import org.junit.Test;

public class JasyptUtil {
    @Test
    public void jasyptTest() {
        BasicTextEncryptor encryptor = new BasicTextEncryptor();
        // application.properties, jasypt.encryptor.password
        encryptor.setPassword("abc");
        // encrypt root
        System.out.println(encryptor.encrypt("1234"));
        System.out.println(encryptor.decrypt(""));
    }
}

配置密码

spring.datasource.druid.primary.password=ENC(加密后密码)

参考文章

Spring Boot Jpa多数据源配置
SpringBoot敏感配置加密:Druid
jasypt:
数据库密码配置项都不加密?心也太大了吧!
在Springboot中通过jasypt 进行加密解密
SpringBoot 集成 Jasypt 对数据库加密以及踩坑的记录分享

标签:SpringBoot2.0,jpa,数据源,org,druid,springframework,datasource,spring,import
来源: https://blog.csdn.net/jiea201611/article/details/113766834