使用 AuraDB Free 构建 Java 微服务





5.00/5 (2投票s)
在本文中,我们将构建一个 Java 微服务,该服务连接到 Neo4j AuraDB Free 数据库并与之交互,处理其中的图数据。
今天的冒险之旅,我们要构建一个 Java 微服务,它将连接到 Neo4j AuraDB Free 数据库并与之交互,处理其中的图数据。我们的数据将是 Goodreads 数据集 的精简版本,其中包含书籍、作者和评论信息。虽然书籍和作者 非常适合 MongoDB 这样的文档数据库,但一旦您将评论加入其中,关系中的细微差别就使得这个项目更适合 AuraDB。这样,我们就可以利用不同实体之间的关系,根据连接的结构来改进分析。虽然我们在这里所做的一切都可以使用其他数据存储来实现,但图数据库极大地简化了对实体如何连接的查询。
如果您是图数据库新手,这里有一些资源
- 博客文章: 如何知道图数据库是否能解决您的问题?
- Neo4j 指南: 什么是图数据库?
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、hashCode
和 toString
方法。它减少了样板代码,这很好。接下来是 `@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 还是命令行。一旦它运行起来,我们就可以使用以下命令来测试应用程序。
- 测试应用程序是否已启动:在浏览器中打开 `localhost:8080/neo` 或在命令行中使用 `curl localhost:8080/neo`。
- 测试后端评论 API 查找评论:在浏览器中打开 `localhost:8080/neo/reviews` 或在命令行中使用 `curl localhost:8080/neo/reviews`。
- 测试 API 查找特定书籍的评论:在浏览器中打开 `localhost:8080/neo/reviews/178186` 或在命令行中使用 `curl localhost:8080/neo/178186`。
这是我们服务生成的评论 API 结果输出!
总结!
我们回顾了使用 Neo4j AuraDB 免费套餐创建图数据库实例,并加载了书籍、作者和评论数据。然后,我们构建了一个微服务应用程序来连接到云数据库并检索评论。最后,我们通过启动应用程序并访问每个端点来测试我们所有的代码,以确保我们可以访问数据。
我们还有很多可以做的来扩展我们已经构建的内容。为了保护敏感数据,使其私有但可供多个服务访问,我们可以使用 Spring Cloud Config 等工具来外部化数据库凭据。我们还可以将此服务添加到像 Docker Compose 这样的编排工具中,以一起管理多个服务。另一个探索领域是更充分地利用图数据的好处,从数据库中提取更多相关实体。编码愉快!
资源
- GitHub: 代码库
- GitHub: 更多微服务代码
- 开发者指南: Neo4j 图数据库
- Neo4j AuraDB: 创建免费数据库
- 文档: Spring Data Neo4j