65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 AuraDB Free 构建 Java 微服务

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2022 年 7 月 7 日

CPOL

9分钟阅读

viewsIcon

5470

在本文中,我们将构建一个 Java 微服务,该服务连接到 Neo4j AuraDB Free 数据库并与之交互,处理其中的图数据。

照片来自 Umer SayyamUnsplash

今天的冒险之旅,我们要构建一个 Java 微服务,它将连接到 Neo4j AuraDB Free 数据库并与之交互,处理其中的图数据。我们的数据将是 Goodreads 数据集 的精简版本,其中包含书籍、作者和评论信息。虽然书籍和作者 非常适合 MongoDB 这样的文档数据库,但一旦您将评论加入其中,关系中的细微差别就使得这个项目更适合 AuraDB。这样,我们就可以利用不同实体之间的关系,根据连接的结构来改进分析。虽然我们在这里所做的一切都可以使用其他数据存储来实现,但图数据库极大地简化了对实体如何连接的查询。

如果您是图数据库新手,这里有一些资源

Neo4j 提供了多种部署选项。我们可以启动一个 Docker 容器(就像 我们在早期使用 MongoDB 的项目中那样),或者利用 AuraDB 数据库即服务选项的免费套餐。Neo4j 将负责管理数据库,这应该包含我们所需的一切。

对于这个任务,我们将创建我们的 Neo4j 数据库,加载数据,然后构建一个与数据库交互的微服务,并为客户端服务提供 API。

数据库即服务:AuraDB

注册并创建 Neo4j AuraDB Free 实例需要几个步骤,例如验证您的电子邮件地址,并等待实例启动(这需要几分钟)。您可以在我的同事 Michael Hunger 的许多“发现 AuraDB Free”博客文章中找到有关该过程的详细信息以及截图,例如 这篇

图数据加载

实例运行后,我们就可以开始加载数据了。包含书籍的入门文件在今天的 代码库 中提供,文件夹的 readme 文件中以及加载脚本中都包含说明。readme 文件中的几个查询可以帮助我们验证数据。

注意更大版本的数据集 也适合 AuraDB Free 套餐实例,但为了方便和加速本文的加载速度,我们选择保持数据集较小。

应用服务

是时候开始构建我们的应用程序来提取评论数据了。对于我们的微服务,我们将构建一个 Spring Boot 应用程序,其中包含几个 REST 端点,用于从连接的 Neo4j 数据库访问数据。

我们可以使用 Spring Initializr (位于 start.spring.io) 来构建项目的框架。

在表单上,我们可以将“项目”、“语言”和“Spring Boot”字段保留默认值。在“项目元数据”部分,我选择了更新我个人项目的组名,但您也可以保留默认值。我将工件命名为 `neo4j-java-microservice`,但命名并不一定重要。此部分中的所有其他字段均可保持不变。在“依赖项”部分,我们需要 `Spring Reactive Web`、`Lombok` 和 `Spring Data Neo4j`。 Spring Data Neo4j 是连接各种数据存储的众多 Spring Data 项目之一,它帮助我们映射和访问加载到数据库中的数据。最后,项目模板就完成了,我们可以点击底部的“生成”按钮下载项目。

注意:Spring Initializr 通过页面右侧列中的月亮或太阳图标显示为暗模式或亮模式。

生成操作会将项目作为 ZIP 文件下载,因此我们可以将其解压缩并在您喜欢的 IDE 中打开。

`pom.xml` 文件包含我们在 Spring Initializr 上设置的依赖项和软件版本,因此我们可以继续处理 `src/main/resources` 文件夹中的 `application.properties` 文件。在这里,我们要使用 URI 和数据库凭据连接到我们的 Neo4j 实例。我们通常不希望将数据库凭据嵌入应用程序中,尤其是因为这是一个基于云的实例。硬编码这些值可能会意外地让其他人登录或篡改我们的数据库。

通常,像数据库凭据这样的配置值会在运行时通过像 Spring Cloud Config 这样的项目进行外部化并由项目读取。然而,配置值超出了本文的范围。现在,我们可以在属性文件中嵌入数据库 URI、用户名、密码和数据库名。

#database connection
spring.neo4j.uri=<insert Neo4j URI here>
spring.neo4j.authentication.username=<insert Neo4j username here>
spring.neo4j.authentication.password=<insert Neo4j password here>
spring.data.neo4j.database=<insert Neo4j database here>

注意:数据库应为 `neo4j`,除非您已专门使用命令更改了默认值。

项目代码

让我们从领域类开始,逐步了解 Java 文件。

数据领域类

@Data
@Node
class Review {
	@Id
	@GeneratedValue
	private Long neoId;
	@NonNull
	private String review_id;

	private String book_id, review_text, date_added, date_updated, started_at, read_at;
	private Integer rating, n_comments, n_votes;
}

`@Data` 是一个 Lombok 注解,它为领域类生成我们的 getter、setter、equals、hashCodetoString 方法。它减少了样板代码,这很好。接下来是 `@Node` 注解。这是一个 Spring Data Neo4j 注解,它将该类标记为 Neo4j 实体类(Neo4j 实体称为节点)。

在类声明中,我们为类定义了几个字段(属性)。`@Id` 注解将字段标记为唯一标识符,`@GeneratedValue` 表示该值由 Neo4j 内部生成。在我们的下一个字段 `review_id` 上,有一个 Lombok `@NonNull` 注解,指定此字段不能为空。我们还有其他一些我们想要检索的字段,用于评论文本、日期和评分信息。

接下来,我们需要一个存储库接口,我们可以在其中定义与数据库中的数据交互的方法。

interface ReviewRepository extends ReactiveCrudRepository<Review, Long> {
	Flux<Review> findFirst1000By();

	@Query("MATCH (r:Review)-[rel:WRITTEN_FOR]->(b:Book {book_id: $book_id}) RETURN r;")
	Flux<Review> findReviewsByBook(String book_id);
}

我们希望此存储库扩展 `ReactiveCrudRepository`,这将使我们能够使用响应式方法和类型来处理数据。然后,我们定义几个方法。虽然我们可以使用 Spring Data 的一些默认方法的开箱即用实现(在 文档代码示例 中列出),但我们想稍微自定义一下,所以我们将定义自己的方法。我们不使用默认的 `.findAll()` 方法,而是只想提取 1,000 条结果,因为提取全部 35,342 条评论可能会使客户端的结果渲染过程过载。

请注意,我们没有为 `findFirst1000By()` 方法提供任何实现代码(没有查询或逻辑)。相反,我们正在使用 Spring Data 的另一项功能:派生方法。这是 Spring 根据方法名称构造(即“派生”)查询应该是什么样子的。在我们的例子中,我们的存储库处理的是评论(`ReactiveCrudRepository<Review, Long>`),因此 `findFirst1000` 正在查找前 1,000 条评论。通常,此语法会继续通过查找特定标准(评分、评论者、日期等)的结果。但是,由于我们想提取任何随机评论集,我们可以通过简单地省略方法名称中的标准来欺骗 Spring。这就是我们得到 `findFirst1000By` 的地方。

注意:这是一个隐藏的变通方法,一旦您知道了它就非常方便,但如果 Spring 能为这些情况提供开箱即用的解决方案那就更好了。

我们的 下一个方法(`findReviewsByBook()`)更直接。我们想查找特定书籍的评论,所以我们需要按 `book_id` 查找评论。为此,我们使用 `@Query` 注解,其中包含数据库相关查询语言的查询,对于 Neo4j 来说是 Cypher。此查询查找为具有指定书籍 ID 的书籍编写的评论。

存储库完成后,我们可以编写我们的 控制器类,它设置一些 REST 端点供其他服务访问数据。

@RestController
@RequestMapping("/neo")
@AllArgsConstructor
class ReviewController {
	private final ReviewRepository reviewRepo;

	@GetMapping
	String liveCheck() { return "Neo4j Java Microservice is up"; }

	@GetMapping("/reviews")
	Flux<Review> getReviews() { return reviewRepo.findFirst1000By(); }

	@GetMapping("/reviews/{book_id}")
	Flux<Review> getBookReviews(@PathVariable String book_id) { return reviewRepo.findReviewsByBook(book_id); }
}

`@RestController` Spring 注解将此块指定为 REST 控制器类,`@RequestMapping` 为所有类方法定义了一个高级端点。在类声明中,我们 注入 `ReviewRepository`,以便我们可以使用我们编写的方法。

接下来,我们为每个方法映射端点。`liveCheck()` 方法使用高级 `/neo` 端点返回一个字符串,确保我们的服务已启动且可访问。我们可以通过添加一个嵌套端点(`/reviews`)来执行 `getReviews()` 方法。此方法使用我们在存储库中编写的 `findFirst1000By()` 方法,并返回一个响应式 `Flux<>` 类型,我们期望结果中有 0 条或多条评论。

我们的 最后一个方法 具有嵌套端点 `/reviews/{book_id}`,其中 book_id 是一个路径变量,根据我们要搜索的书籍而变化。`getBookReviews()` 方法将指定的 book_id 作为路径变量传入,然后调用存储库中的 `findReviewsByBook()` 方法,并返回一个 `Flux<>` 评论。

付诸实践

是时候测试我们新服务了!我喜欢从下往上开始项目,所以首先确保 Neo4j AuraDB 实例仍在运行。

注意:AuraDB 免费套餐会在三天后自动暂停。您可以通过实例上的“播放”图标恢复。

接下来,我们需要启动我们的 `neo4j-java-microservice` 应用程序,无论是通过 IDE 还是命令行。一旦它运行起来,我们就可以使用以下命令来测试应用程序。

  1. 测试应用程序是否已启动:在浏览器中打开 `localhost:8080/neo` 或在命令行中使用 `curl localhost:8080/neo`。
  2. 测试后端评论 API 查找评论:在浏览器中打开 `localhost:8080/neo/reviews` 或在命令行中使用 `curl localhost:8080/neo/reviews`。
  3. 测试 API 查找特定书籍的评论:在浏览器中打开 `localhost:8080/neo/reviews/178186` 或在命令行中使用 `curl localhost:8080/neo/178186`。

这是我们服务生成的评论 API 结果输出!

查找 1000 条评论

按书籍查找评论

总结!

我们回顾了使用 Neo4j AuraDB 免费套餐创建图数据库实例,并加载了书籍、作者和评论数据。然后,我们构建了一个微服务应用程序来连接到云数据库并检索评论。最后,我们通过启动应用程序并访问每个端点来测试我们所有的代码,以确保我们可以访问数据。

我们还有很多可以做的来扩展我们已经构建的内容。为了保护敏感数据,使其私有但可供多个服务访问,我们可以使用 Spring Cloud Config 等工具来外部化数据库凭据。我们还可以将此服务添加到像 Docker Compose 这样的编排工具中,以一起管理多个服务。另一个探索领域是更充分地利用图数据的好处,从数据库中提取更多相关实体。编码愉快!

资源

© . All rights reserved.