亚马逊AWS官方博客

将 Spring Boot 应用程序与 Amazon DocumentDB 集成

Amazon DocumentDB(与 MongoDB 兼容)是一种可扩展、高度持久和完全托管的数据库服务,用于操作任务关键型 MongoDB 工作负载。在 Amazon DocumentDB 上,您可以使用相同的 MongoDB 应用程序代码、驱动程序和工具来运行、管理和扩展工作负载,无需关心管理底层基础设施。

Spring Boot 提供了简单快速的方法,可基于 Spring 框架来构建生产级的应用程序。为了做到这一点,Spring Boot 预先打包自动配置模块,用于通常与 Spring Framework 一起使用的大多数库。简而言之,开源 Spring Boot 遵循有关配置的惯例,在 Spring 框架之上添加了自动配置功能。

在这篇文章中,您将探索使用 Spring Data MongoDB API,将 Spring Boot 应用程序集成到 Amazon DocumentDB 的基础知识。您还可以创建示例数据模型和存储库类用于执行数据库操作。

解决方案概览

Spring Boot 和 Amazon DocumentDB 的配置相对简单,只涉及几个配置步骤。

Spring Boot 允许应用程序使用 MongoTemplate 类和 MongoRepository 接口,与 Amazon DocumentDB 交互。MongoTemplate 遵循 Spring 中的标准模板模式,为底层持久性引擎提供了现成的基本 API。MongoTemplate 为聚合、流式处理、更新和自定义查询等操作提供了直接可用的 API。MongoRepository 遵循以 Spring Data 为中心的方法,基于所有 Spring Data 项目中广为人知的创建、读取、更新和删除(CRUD,Create, Read, Update, and Delete)访问模式,提供了更灵活、更简单的 API 操作。

对于这两个选项,您首先要在 pom.xml 中为 Maven 项目定义依赖项。

这篇文章重点介绍如何使用 MongoRepository 与 Amazon DocumentDB 交互。

先决条件

您需要满足以下先决条件:

  • Amazon DocumentDB 集群 – 这篇文章首先介绍现有的 Amazon DocumentDB 集群,您要将其与 Spring Boot 应用程序集成。如果您还没有 Amazon DocumentDB 集群,请参阅 Get Started with Amazon DocumentDB(Amazon DocumentDB 入门)以创建新集群。
  • 集成式开发环境(IDE) – 例如,EclipseAWS Cloud9。本文在演示中使用了 AWS Cloud9,这是一款基于云的 IDE,让您只需使用浏览器即可编写、运行和调试代码。其包括代码编辑器、调试程序和终端。启用增强了对 Java 开发的支持,改善您在使用 Java 时的开发体验。
  • Java 17 – 有关在 AWS Cloud9 中安装或升级 Java 的信息,请参阅 Amazon Corretto 17 Installation Instructions(Amazon Corretto 17 安装说明)。
  • Maven – 请参阅设置 Maven 以在 AWS Cloud9 中安装 Maven
  • Spring Initializr

您的账户中可能会产生与 Amazon DocumentDB 和 AWS Cloud9 资源相关的费用。您可以使用 AWS 定价计算器来估计此费用。

使用 Spring Initializr 创建 Spring Boot 应用程序

使用以下步骤,创建一个支持 Spring Data MongoDB 的新 Spring Boot 应用程序项目。作为替代方法,您可以使用 GitHub 存储库中的 spring-boot-docdb-sample 应用程序。

  1. 浏览到 https://start.spring.io/
  2. 指定以下选项:
    1. 选择 Maven project(Maven 项目),且 Language(语言)为 Java
    2. 选择 Spring Boot 的版本 3.0.0。
    3. 为应用程序指定组和构件名称。
    4. 指定 Java 版本 17。
    5. 选择 ADD DEPENDENCIES(添加依赖项),然后搜索并选择 Spring Data MongoDB。您可以使用 Spring Data MongoDB 依赖项,从此应用程序与 Amazon DocumentDB 集群进行交互。
  3. 选择 GENERATE(生成)以生成一个 Spring Boot 项目,其中包含引导所需的全部文件。
  4. 将 ZIP 文件下载到本地计算机上的路径并解压缩文件。

Spring initializr

如果您使用的是 AWS Cloud9 IDE,请将 ZIP 文件上传到 AWS Cloud9 环境并解压缩文件。

验证 Maven 依赖项

在应用程序的目录中找到 pom.xml 文件,然后验证是否已按如下方式添加 Spring Data MongoDB 依赖项:

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

定义数据模型

要在 Amazon DocumentDB 数据库中存储和检索数据,我们先创建一个 POJO 模型或实体类。该实体代表 Amazon DocumentDB 中的集合,并使用注释来定义集合名称、属性、键和其他方面。

在此示例中,您创建一个产品集合和对应的模型对象,该对象将产品的详细信息存储在目录数据库中。您创建具有六个属性的产品模型:idnameskudescriptioninventorycategory

Amazon DocumentDB 在集合中存储数据。默认情况下,Spring Data 将产品的类或模型映射到名为 product 的集合。如果要更改集合的名称,您可以在类上使用 Spring Data MongoDB 的 @Document 注释。在以下示例中,我们使用 @Document(collection = "products") 来将集合名称指定为 products

您可以使用 @Id 注释指定文档的主键 _id。如果您未指定任何内容,Amazon DocumentDB 将在创建文档时生成 _id 字段。其他属性不添加注释。这会假设它们映射到与属性本身具有相同名称的字段。在项目的目录中,创建一个 Product.java 文件,其中具有以下内容:

@Document(collection = "products")
public class Product {

    @Id
    private String id;    
    
    /** 
     * 设置对应于 products 集合中字段的数据成员
     */
     
    private String name;
    private String sku;
    private String description;
    private int inventory;
    private String category;
    

    /**
     * @param id
     * @param name
     * @param sku
     * @param description
     * @param inventory
     * @param category
     */
    public Product(String name, String sku, String description, int inventory, String category) {
        
        this.name = name;
        this.sku = sku;
        this.description = description;
        this.inventory = inventory;
        this.category = category;
    }
}

为每个属性添加 getter 和 setter 方法。您可以使用特定于 IDE 的快捷方式生成 getter 和 setter 方法。例如,右键单击代码编辑器窗格,选择 Refactoring(重构),然后选择 Generate Getter and Setter in Cloud9(在 Cloud9 中生成 Getter 和 Setter)。

此外,建议覆盖 toString 方法来输出对象,例如,右键单击代码编辑器窗格,选择 Refactoring(重构),然后选择 Generate toString() in Cloud9(在 Cloud9 中生成 toString())

Cloud9

在启用 TLS 的情况下进行连接

要从基于 Java 的 Spring Boot 应用程序连接到启用了 TLS 的 Amazon DocumentDB 集群,您的程序必须使用 AWS 提供的证书颁发机构(CA,Certificate Authority)文件来验证连接。要使用 Amazon RDS CA 证书,请执行以下操作:

  1. tmp 文件夹下创建一个临时 certs 文件夹。您可以根据组织的安全策略来创建用于存储证书的文件夹。本文中,在 tmp 下创建 certs 文件夹:
    mkdir /tmp/certs/
  2. 运行以下命令,使用包含在文件中的 CA 证书创建信任存储。请确保更新 <truststorePassword>。以下 shell 脚本示例将证书捆绑包导入 Linux 操作系统上的信任存储。有关其他选项,请参阅启用了 TLS 的情况下的连接
    mydir=/tmp/certs
    truststore=${mydir}/rds-truststore.jks
    storepassword=<truststorePassword>
    
    curl -sS "https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem" > ${mydir}/rds-combined-ca-bundle.pem
    awk 'split_after == 1 {n++;split_after=0} /-----END CERTIFICATE-----/ {split_after=1}{print > "rds-ca-" n ".pem"}' < ${mydir}/rds-combined-ca-bundle.pem
    
    for CERT in rds-ca-*; do
      alias=$(openssl x509 -noout -text -in $CERT | perl -ne 'next unless /Subject:/; s/.*(CN=|CN = )//; print')
      echo "Importing $alias"
      keytool -import -file ${CERT} -alias "${alias}" -storepass ${storepassword} -keystore ${truststore} -noprompt
      rm $CERT
    done
    
    rm ${mydir}/rds-combined-ca-bundle.pem
    
    echo "Trust store content is: "
    
    keytool -list -v -keystore "$truststore" -storepass ${storepassword} | grep Alias | cut -d " " -f3- | while read alias 
    do
       expiry=`keytool -list -v -keystore "$truststore" -storepass ${storepassword} -alias "${alias}" | grep Valid | perl -ne 'if(/until: (.*?)\n/) { print "$1\n"; }'`
       echo " Certificate ${alias} expires in '$expiry'" 
    done
    

数据库和连接配置

设置连接详细信息和 SSL 信任存储需要两个配置文件。首先,在 application.properties 中定义您的 Amazon DocumentDB 连接参数,例如数据库、URI 或主机、端口、用户名和密码。然后在配置类中设置密钥库。

配置 Spring Boot 应用程序属性文件

要将 Spring Boot 应用程序连接到 Amazon DocumentDB,我们需要在 application.properties 文件中定义数据库配置。您需要配置数据库 URI、数据库名称或主机名、用户名、密码等属性,以及其他与连接相关的属性。要连接到 Amazon DocumentDB 集群,您需要在位于 src/main/resources 文件夹的 application.properties 文件中指定连接 URI 字符串。

要检索您的 Amazon DocumentDB 集群端点并配置 application.properties,请完成以下步骤:

  1. 在 Amazon DocumentDB 控制台的导航窗格中,选择 Clusters(集群)。
  2. 找到您的集群并选择区域集群标识符。
  3. Connectivity & security(连接和安全性)选项卡上,复制用于通过 application.DocumentDB connection string 连接到集群的命令。
  4. 从复制的连接字符串中删除 &ssl_ca_certs=rds-combined-ca-bundle.pem,因为您已经将 AWS 提供的 CA 文件导入了信任存储。
  5. 将连接 URI 添加到位于您的项目 src/main/resources 文件夹的 application.properties 文件中。连接 URI 的键为 spring.data.mongodb.uri。确保复制的连接字符串格式如下:
    spring.data.mongodb.uri=mongodb://<用户名>:<密码>@<集群端点>: 27017/?ssl=true&replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false

    或者,您可以单独提供连接详细信息,包括主机名、端口、用户名和密码以及对应的属性键,例如 spring.data.mongodb.hostspring.data.mongodb.port。有关可用的 Spring Boot 参数配置选项的完整列表,请参阅 Common Application Properties(常用应用程序属性)下的 Data Properties(数据属性)

  6. 您也可以选择在 application.properties 文件中指定数据库名称:
    spring.data.mongodb.database=catalog

创建配置类并设置密钥库

现在属性配置已经完成,您需要定义配置类来设置密钥库属性,以便建立安全连接。

要在应用程序中使用密钥库,请在配置类中设置以下系统属性,:

javax.net.ssl.trustStore: <truststore>
javax.net.ssl.trustStorePassword: <truststorePassword> 

请参阅以下示例配置类。使用 @Configuration 注释将该类标记为配置类。具有 @Configuration 注释的类由 Spring 容器用作 bean 定义的来源。

@Configuration
public class DocumentDBConf {
	
	private MongoProperties properties;
	
	public static final String KEY_STORE_TYPE = "/tmp/certs/rds-truststore.jks";
    	public static final String DEFAULT_KEY_STORE_PASSWORD = "changeit";

        public DocumentDBConf(final MongoProperties properties) {
            super();
            this.properties = properties;
        }

        @Bean
        public MongoClientSettings mongoClientSettings() { 
             setSslProperties();
	     return MongoClientSettings.builder()
                    .applyToSslSettings(builder -> builder.enabled(true))
                    .build();
	}

        private static void setSslProperties() { 
    	      System.setProperty("javax.net.ssl.trustStore", KEY_STORE_TYPE);
    	      System.setProperty("javax.net.ssl.trustStorePassword",          
                    DEFAULT_KEY_STORE_PASSWORD);
        }
	@Bean
        public MongoPropertiesClientSettingsBuilderCustomizer mongoPropertiesCustomizer(final MongoProperties properties) {
			return new MongoPropertiesClientSettingsBuilderCustomizer(properties);
	}
}

以上是 Spring Boot 中 Amazon DocumentDB 配置的全部内容现在,您可以通过扩展 MongoRepository 开始定义基于接口的存储库类。

配置存储库接口

现在,您可以使用 MongoRepository 访问数据库中的数据。MongoRepository 提供常用功能,例如创建、读取、更新和删除(CRUD,Create, Read, Update, and Delete)操作。它充当模型与数据库之间的链接。它获取域类(Product)进行管理,并获取域类的 ID 类型作为类型参数。您可以编写几种方法,由存储库为您生成查询。

创建查询 Product 文档的存储库接口,如下所示:

public interface ProductRepository extends MongoRepository<Product, String> {

}

ProductRepository 扩展 MongoRepository 接口。此接口包含许多操作,包括标准的 CRUD 操作。您将在下一节中定义其他自定义操作。

定义服务类

服务类利用了 Spring Data 存储库接口。我们通过引用您在上一步中创建的存储库来定义它:

@Service
public class ProductService {
    
    @Autowired
    private ProductRepository productRepo;
}

在下一节中,您将在此类上通过添加其他方法进行构建,该节还介绍了 CRUD 示例。

使用 CrudRepository

使用扩展了 CrudRepositoryMongoRepository 时,您的存储库可以从 CrudRepository 接口的实施类访问基本功能,包括 savecountfindAlldelete 方法。您的 ProductRepository 接口扩展了 MongoRepository,并可以访问所有基本 CRUD 操作。

我们来逐个探索和测试这些操作。

保存或创建

首先,您使用 save 方法向集合中添加一些文档。save 方法获取 Product 对象作为输入,并将产品文档保存到 Amazon DocumentDB 集合中。将以下代码片段添加到您的服务类中:

public void saveProducts() {
 
	productRepo.save(new Product("RayBan Sunglass Pro", "1590234","RayBan Sunglasses for professional sports people", 100, "fashion"));
	productRepo.save(new Product("GUCCI Handbag", "3451290", "Fashion Hand bags for all ages", 75, "fashion"));
	productRepo.save(new Product("Round hat", "8976045", "", 200, "fashion"));
	productRepo.save(new Product("Polo shirt", "6497023", "Cool shirts for hot summer", 25, "cloth"));
	productRepo.save(new Product("Swim shorts", "8245352", "Designer swim shorts for athletes", 200, "cloth"));
	productRepo.save(new Product("Running shoes", "3243662", "Shoes for work out and trekking", 20, "footware"));
	
	System.out.println(" Save complete ");
        
}

计数

在下一个示例中,如果存储库中没有任何方法,则调用服务类中的 count() 方法,对集合中的文档进行计数。

public long getCount() {
    long count = productRepo.count();
    System.out.println(" Total number of products : "+count);
    return count;
}

读取

在此示例中,您执行三种不同的读取操作。您可以按名称或 SKU 提取产品,然后根据类别查找产品列表。

您在存储库(ProductRepository)中添加了三种简单方法。第一种方法 findProductByName 根据 name 属性查询集合。查询筛选条件使用注释 @Query 定义,在本例中,注释为 @Query("{name:'?0'}")。第二种方法 findProductBySKU 根据 sku 属性查询集合,并在查询响应中仅输出 nameinventory 属性。第三种方法 findAll 检索特定类别的所有文档。请参阅以下代码:

public interface ProductRepository extends MongoRepository<Product, String> {
    
    @Query("{name:'?0'}")
    Product findProductByName(String name);
    
    @Query(value="{sku:'?0'}", fields="{'name' : 1, 'inventory' : 1}")
    Product findProductBySKU (String sku);   

    @Query("{category:'?0'}")
    List<Product> findAllByCategory(String category);
                                                        
}

您可以从存储库在服务类中调用这三种方法,按名称、SKU 和类别查找文档。

public Product getProductByName(String name) {
	System.out.println(" Getting product by name : " + name);
	Product product = productRepo.findProductByName(name);
	System.out.println(product);
	return product; 
}

public Product getProductBySKU(String sku) {
	System.out.println(" Getting product by SKU : " + sku);
	Product product = productRepo.findProductBySKU(sku);
	System.out.println(product);
 	return product; 
}

public List<Product> findAllProductsByCategory(String category) {
	List<Product> productList = productRepo.findAllByCategory(category);
	productList.forEach(product -> System.out.println(product));
	return productList;
}

更新

您可以通过传递更新后的实体对象,使用 save 方法来更新现有文档。在此示例中,您按 SKU 查询现有产品并将库存增加 10。将以下方法添加到您的服务中:

public void updateInventory(String sku) {
	Product product =  getProductBySKU(sku);
	System.out.println(" Updating Inventory for product by sku: " + sku);	
	product.setInventory(product.getInventory()+10);
	Product updatedProd = productRepo.save(product);
}

删除

在本示例中,您将创建两个删除操作。首先,您按照 ID 删除一个产品;在第二种方法中,您将删除集合中的所有文档(products)。将以下方法添加到您的服务类中:

public void deleteProduct(String id) {
 	productRepo.deleteById(id);
	System.out.println("Product with id " + id + " deleted");
}

public void deleteAll() {
	productRepo.deleteAll();
	System.out.println("All Products deleted.");
}

构建 Spring Boot 应用程序

默认的 Spring Boot 应用程序已经由 Spring Initializr 在根程序包(例如 com.example.documentdb)中创建。在 IDE 中打开默认应用程序:

@SpringBootApplication
public class DocumentdbApplication {

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

CommandLineRunner 接口表明,当 bean 包含在 SpringApplication 中时应该运行,以便在控制台上查看输出。实施 CommandLineRunner 接口并为 run 方法提供植入方法。我们使用 @Autowired 注释定义对您服务的引用。Spring 使用 @SpringBootApplication 注释来初始化应用程序上下文:

@SpringBootApplication
public class DocumentdbApplication implements CommandLineRunner{

    @Autowired
    private ProductService prodService;

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

	@Override
	public void run(String... args) throws Exception {
		
		System.out.printf("%n Insert few products : %n");
		prodService.saveProducts();
		
		System.out.printf("%n Count all products : %n");
		prodService.getCount();
		
		
		System.out.printf("%n Get product by name : %n");
		prodService.getProductByName("GUCCI Handbag");
		
		System.out.printf("%n Get product by sku : %n");
		prodService.getProductBySKU("8976045");
		
		System.out.printf("%n Get all products by category : %n");
		prodService.findAllProductsByCategory("fashion");
		
		System.out.printf("%n Update Inventory for Product by sku :  %n");
		prodService.updateInventory("3451290");
		
		System.out.printf("%n Delete product id  %n");
		prodService.deleteProduct("639a0046efe46b7343dd5004"); 
		
		System.out.printf("%n Deleting all products/documents  %n");
		prodService.deleteAll(); 
	}
}

运行并测试您的应用程序

使用以下 Maven 命令运行 Spring Boot 应用程序:

mvn spring-boot:run

以下屏幕截图是 Spring Boot 应用程序的示例输出。

输出

您做到了! 您已成功从 Spring Boot 应用程序连接到 Amazon DocumentDB。

总结

在这篇文章中,您了解了如何通过简单的应用程序将 Amazon DocumentDB 与 Spring Boot 应用程序集成,该应用程序使用 Spring Data MongoDB 将对象保存到数据库以及从数据库中提取对象,所有这些过程都无需编写具体的存储库实施,而且配置简单。

这篇文章中使用的示例在 GitHub 上作为示例项目提供。


Original URL: https://aws.amazon.com/cn/blogs/database/integrate-your-spring-boot-application-with-amazon-documentdb/

关于作者

Gururaj S BayariGururaj S Bayari 是 AWS 的资深 DocumentDB 专家解决方案架构师。他非常乐于帮助客户采用 Amazon 的专用数据库。他针对采用 NoSQL 和/或关系数据库的互联网规模的高性能工作负载,帮助客户进行设计、评估和优化。