ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

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

2021-02-18 11:00:18  阅读:1439  来源: 互联网

标签:SpringBoot2.0 jpa 数据源 org druid springframework datasource spring import


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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有