IBM Cloud数据库

IBM Cloud MongoDB 连接 Tips

在IBM Cloud中,我们可以创建 MongoDB服务,我们可以点击OverView看到连接的一些信息。

在Endpoint中,可以看到连接的信息,还有TSL连接需要的CA证书。

MongoDB Compass中的连接方法


填好URI:

mongodb://username:passwrd@xxxx:31236/ibmclouddb?authSource=admin&replicaSet=replset&tls=true

选择

NodeJs TLS的例子


const MongoClient = require("mongodb").MongoClient;

let connectionString = "mongodb://<username>:<password>@<host>:<port>,<host>:<port>/<database>?authSource=admin&replicaSet=replset";

let options = {
    tls: true,
    tlsCAFile: `/path/to/cert`,
    useUnifiedTopology: true 
};

// connects to a MongoDB database
MongoClient.connect(connectionString, options, function (err, db) {
    if (err) {
        console.log(err);
    } else {
       // lists the databases that exist in the deployment
        db.db('example').admin().listDatabases(function(err, dbs) {
            console.log(dbs.databases);
            db.close();
        });
    }
});

Java连接的例子1


http://mongodb.github.io/mongo-java-driver/3.0/driver/reference/connecting/ssl/

通过下面的命令,把IBM cloud download下来的 CA文件转换一下。

    keytool -importcert -trustcacerts -file <path to certificate authority file> 
        -keystore <path to trust store> -storepass <password>
keytool -importcert -trustcacerts -file /Users/Documents/ca/631b75c3-4296-4ce9-b0f2-426423c5b0e6 -keystore /Users/Documents/ca/sslkey -storepass test
import java.io.FileNotFoundException;
import java.net.UnknownHostException;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
import org.springframework.util.ResourceUtils;


import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;

@Configuration
public class MongoConfig {

	@Value("${ssl.key.path}")
	private String sslkeypath;

	private String sslkeypass = "test";

	private String mongouri= "mongodb://userid:passwod@ip:31236/ibmclouddb?authSource=admin&replicaSet=replset&ssl=true";

	private String dbname = "testdb";

	@Bean
	public MongoDatabaseFactory mongoDbFactory() throws FileNotFoundException {

		MongoClient mongoClient;

                // ------打成jar会报错,下面这种写法待验证!----------
		// InputStream stream = getClass().getClassLoader().getResourceAsStream(cafile);
		// File caFile = new File("cafile");
                // FileUtils.copyInputStreamToFile(stream, caFile);
                // -------------------------------------------
          
                // sslkey是上面用keytool,生成的文件
		System.setProperty("javax.net.ssl.trustStore",
				StringUtil.joinStr(ResourceUtils.getURL("classpath:").getPath(), "sslkey"));
                // sslkeypass是keytool生成文件时指定的密码
		System.setProperty("javax.net.ssl.trustStorePassword", sslkeypass);

		final String mongoURI = mongouri;


		mongoClient = MongoClients.create(mongoURI);

		return new SimpleMongoClientDatabaseFactory(mongoClient, dbdbname);
	}

	@Bean
	@Primary
	public MongoTemplate mongoTemplate(MongoDatabaseFactory mongoDbFactory) throws UnknownHostException {
		return new MongoTemplate(mongoDbFactory);
	}

}

但是上面的方法本地测试好用,在IBM Cloud Engine上会出错。

Java连接的例子2


import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;

import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;

@Configuration
public class MongoConfig {


	private String mongouri= "mongodb://userid:passwod@ip:31236/ibmclouddb?authSource=admin&replicaSet=replset&ssl=true";

	@Value("${mongodb.db}")
	private String dbname;

	private String certificateDecoded = "-----BEGIN CERTIFICATE-----\n"
			+ "xxxxxxIYKLSZthAzzXtJpTW1\n" + "-----END CERTIFICATE-----\n" + "";

	@Bean
	public MongoDatabaseFactory mongoDbFactory() throws CertificateException, KeyStoreException,
			NoSuchAlgorithmException, IOException, KeyManagementException {

		final String mongoURI = mongouri;

		InputStream inputStream = new ByteArrayInputStream(certificateDecoded.getBytes(StandardCharsets.UTF_8));
		CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
		X509Certificate caCert = (X509Certificate) certificateFactory.generateCertificate(inputStream);

		TrustManagerFactory trustManagerFactory = TrustManagerFactory
				.getInstance(TrustManagerFactory.getDefaultAlgorithm());
		KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
		keyStore.load(null); 
		keyStore.setCertificateEntry("caCert", caCert);

		trustManagerFactory.init(keyStore);

		SSLContext sslContext = SSLContext.getInstance("TLS");
		sslContext.init(null, trustManagerFactory.getTrustManagers(), null);

		ConnectionString cs = new ConnectionString(mongoURI);
		MongoClientSettings settings = MongoClientSettings.builder().applyConnectionString(cs)
				.applyToSslSettings(builder -> {
					builder.enabled(true);
					builder.context(sslContext);
				}).build();

		MongoClient client = MongoClients.create(settings);

		return new SimpleMongoClientDatabaseFactory(client, dbname);
	}

	@Bean
	@Primary
	public MongoTemplate mongoTemplate(MongoDatabaseFactory mongoDbFactory) throws UnknownHostException {
		return new MongoTemplate(mongoDbFactory);
	}

}

也可以用下面的写法,把certificateDecoded作成一个文件。然后读取这个文件,成字符串。

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;

import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;

@Configuration
public class MongoConfig {

	@Value("${mongodb.uri}")
	private String mongouri;

	@Value("${mongodb.db}")
	private String dbName;
	
	@Value("${mongodb.cafile}")
	private String cafile;

	@Bean
	public MongoDatabaseFactory mongoDbFactory() throws CertificateException, KeyStoreException,
			NoSuchAlgorithmException, IOException, KeyManagementException {
        
                // 注意这里面读取了本地的一个文件,文件里面有certificateDecoded信息
		InputStream stream = getClass().getClassLoader().getResourceAsStream(cafile);
		File caFile = new File("cafile");
                FileUtils.copyInputStreamToFile(stream, caFile);

                String certificateDecoded = "";

		FileInputStream fileInputStream = null;
		try {
			fileInputStream = new FileInputStream(caFile);
			byte[] bytes = new byte[2048];
			int readCount = fileInputStream.read(bytes);
			certificateDecoded = new String(bytes, 0, readCount);

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} finally {
			if (fileInputStream != null) {
				fileInputStream.close();
			}
		}

		InputStream inputStream = new ByteArrayInputStream(certificateDecoded.getBytes(StandardCharsets.UTF_8));
		CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
		X509Certificate caCert = (X509Certificate) certificateFactory.generateCertificate(inputStream);

		TrustManagerFactory trustManagerFactory = TrustManagerFactory
				.getInstance(TrustManagerFactory.getDefaultAlgorithm());
		KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
		keyStore.load(null);
		keyStore.setCertificateEntry("caCert", caCert);

		trustManagerFactory.init(keyStore);

		SSLContext sslContext = SSLContext.getInstance("TLS");
		sslContext.init(null, trustManagerFactory.getTrustManagers(), null);

		ConnectionString cs = new ConnectionString(mongouri);
                // 注意这里面用到了数据库连接池 
		MongoClientSettings settings = MongoClientSettings.builder().applyToConnectionPoolSettings(
						builder -> builder.maxWaitTime(10, TimeUnit.SECONDS).minSize(2).maxConnectionIdleTime(30, TimeUnit.SECONDS)).applyConnectionString(cs)
				.applyToSslSettings(builder -> {
					builder.enabled(true);
					builder.context(sslContext);
				}).build();

		MongoClient client = MongoClients.create(settings);

		return new SimpleMongoClientDatabaseFactory(client, dbName);
	}

	@Bean
	@Primary
	public MongoTemplate mongoTemplate(MongoDatabaseFactory mongoDbFactory) {
		return new MongoTemplate(mongoDbFactory);
	}

}
数据库连接池参数说明
数据库连接池参数说明
@RestController
@RequestMapping("/sample/v1")
public class SampleController {

	@Autowired
	private MongoTemplate mongoTemplate;

	@GetMapping("/hello")
	public String hello() {
		Set<String> set = mongoTemplate.getCollectionNames();
		for (String t : set) {
			System.out.println(t);
		}
		return "hello!!!";
	}
}