SpringBoot2配置MongoDB多数据源,配置SSL,实现无实体类映射主从读写分离

博客有个好处,就是可以在涨人气的同时当个备忘录用。

最近有个需求,有一个远程的mongo数据库,里面有好几个集合,需要每天定时增量更新到本地数据库,同时要保证数据的安全性,防止中途被抓包暴露。

实现思路就是多数据源,设置定时器,主读从写,然后使用SSL加密。然而以前mongo用的很少,就是一个简单的CRUD功能,所以一开始就遇到很多坑。

一、SpringBoot配置多数据源

首先在pom中导入依赖


        
            org.springframework.boot
            spring-boot-starter-data-mongodb
        
        
            org.springframework.boot
            spring-boot-configuration-processor
            true
        

然后在application.properties中配置相关数据源

spring.data.mongodb.primary.host=远程数据库主机
spring.data.mongodb.primary.port=远程数据库端口
spring.data.mongodb.primary.database=远程数据库名称
spring.data.mongodb.primary.username=账号
spring.data.mongodb.primary.password=密码

spring.data.mongodb.secondary.host=127.0.0.1
spring.data.mongodb.secondary.port=27017
spring.data.mongodb.secondary.database=本地数据库名称
spring.data.mongodb.secondary.username=账号
spring.data.mongodb.secondary.password=密码

之后创建一个数据源抽象类

/*
    数据源抽象类
 */
@Data
public abstract class AbstractMongoConfig {
    private String host, database, username, password;
    private int port;

    public MongoDbFactory secMongoDbFactory() {
        String url = "mongodb://"+username+":"+password+"@"+host+":"+port+"/"+database;
        MongoClientURI uri = new MongoClientURI(url);
        return new SimpleMongoDbFactory(new MongoClient(uri),database);
    }

    public abstract MongoTemplate getMongoTemplate() throws Exception;

}

设置主从数据源,从application.properties中读取连接信息

/*
    配置远程数据库数据源
 */
@Configuration
@ConfigurationProperties(prefix = "spring.data.mongodb.primary")
public class PrimaryMongoConfig extends AbstractMongoConfig{

    @Primary
    @Override
    public @Bean(name = "primaryMongoTemplate") MongoTemplate getMongoTemplate(){
        return new MongoTemplate(priMongoDbFactory());
    }

}
/*
    配置本地数据库数据源
 */
@Configuration
@ConfigurationProperties(prefix = "spring.data.mongodb.secondary")
public class SecondaryMongoConfig extends  AbstractMongoConfig {

    @Override
    public @Bean(name = "secondaryMongoTemplate") MongoTemplate getMongoTemplate(){
        return new MongoTemplate(secMongoDbFactory());
    }

}

为了方式SpringBoot自动注入mongotemplate,还要在启动类上增加内容

@SpringBootApplication(exclude={MongoAutoConfiguration.class, MongoDataAutoConfiguration.class}) //排除自动注入mongoTemplate

二、使用多数据源

使用时,指明要使用哪个数据源就可以了,如要对远程数据库操作,就使用primaryMongoTemplate。

在对mongo进行操作的使用,也可以使用实体类映射,但是要加上@Document注解,如果属性名和字段名不同,那么要加上@Field注解,如

@Data
@Document("test") // 对应集合名
public class BackUpEntity {

    @Field("update_time") // 对应字段名
    private Long updateTime;

}

然而mongo中可能有很多的内嵌文档等,有些复杂的表很难建立实体类映射,但是mongo简单在,可以使用json类型数据进行操作,不需要考虑实体类构造,简化代码如下。

@Repository
public class CommonRepository {

    @Autowired
    @Qualifier(value = "primaryMongoTemplate")
    private MongoTemplate primaryMongoTemplate;

    @Autowired
    @Qualifier(value = "secondaryMongoTemplate")
    private MongoTemplate secondaryMongoTemplate;

    /*
        查询远程数据库数据
     */
    public JSONArray findSecondaryAll(String collectionName){
 
            JSONArray json = JSONArray.parseArray(JSON.toJSONString(primaryMongoTemplate.findAll(String.class,collectionName)));
            return json;
       
    }

     /*
        备份远程数据库数据到本地
     */
    public String backUpMongo(List list, String collectionName){
            
            secondaryMongoTemplate.insert(list,collectionName);
            return "备份集合"+collectionName+"成功";
   
    }
} 
  

在本地数据库写入数据的时候要先将查询到的JSONArray数据转成List再传入

List list = JSONObject.parseArray(findJson.toJSONString(), Object.class); 
  

再写入的时候遇到了一个坑,报错信息

Exception authenticating MongoCredential{mechanism=SCRAM-SHA-1, userName='root', source='ys_pbx_data_test', password=, mechanismProperties=};

这是因为本地安装mongo的时候,并没有生成对应的管理员用户,所以要对数据库先生成管理员,赋予权限,然后在配置文件中填入账号密码,没有的话就会报错。

 

 

之后编写service层和controller层,调用repository,传入collectionName就可以了。

三、配置MongoDB SSL

因为数据比较重要,所以要对其进行加密。mongo使用的是tcp传输,但是支持ssl加密。使用Wireshark进行抓包时,可以发现传输过程中的确都是明文。一开始理解错需求,使用了AES加密了接口返回数据,数据包还是明文的,不过也防止了查询接口直接暴露数据。

我的远程数据库是阿里云的,SSL配置可以参考:

官方文档:http://mongodb.github.io/mongo-java-driver/3.0/driver/reference/connecting/ssl/

阿里云:https://www.alibabacloud.com/help/zh/doc-detail/89245.htm?spm=a2c63.p38356.879954.6.5e4261d9OMoRgd#concept-v1g-vyv-y2b

https://www.alibabacloud.com/help/zh/doc-detail/89276.html

具体过程如下

第一步是改造远程数据库的数据源配置,新建一个配置类

@Configuration
public class MongoSSLConfig {

    @Bean
    public static MongoClient createNetworkMongoClient() {
        MongoCredential credentials = getCredentials();
        String host = "主机名";
        int port = "端口";
        List addrs = Collections.singletonList(new ServerAddress(host, port));
        System.setProperty("javax.net.ssl.trustStore","证书路径,注意使用jks文件");
        System.setProperty("javax.net.ssl.trustStorePassword","信任库密码");
        MongoClientOptions options = MongoClientOptions.builder()
                .sslEnabled(true) //开启SSL连接
                .sslInvalidHostNameAllowed(true) //不检查证书域名
                .build();
        return new MongoClient(addrs, credentials, options);
    }

    private static MongoCredential getCredentials() {
        String username = "用户名";
        String database = "数据库名";
        String pass = "密码";
        char[] password = pass.toCharArray();
        return MongoCredential.createCredential(username, database, password);
    }
}

修改 数据源抽象类 配置远程数据库新连接

public MongoDbFactory priMongoDbFactory() {
        MongoClient mongoClient = MongoSSLConfig.createNetworkMongoClient();
        return new SimpleMongoDbFactory(mongoClient,database);
    }

 在primaryMongoConfig中调用新方法

public @Bean(name = "primaryMongoTemplate") MongoTemplate getMongoTemplate(){
        return new MongoTemplate(priMongoDbFactory());
    }

第二步就是生成远程数据库的信任证书并下载到本地。

第三步将证书入本机信赖库,具体操作可以看官方文档,并将jks证书路径填入上面的代码中,如果使用pem等格式证书可能报错。

最后重启项目,可以正常运作,再次抓包,发现明文数据已经被加密。

 

你可能感兴趣的:(数据库,java,mongodb,spring,boot)