我们为 SDN 提供 Spring Boot 启动器。
请通过依赖项管理包含启动器模块,并配置要使用的 bolt URL,例如 。
启动器假定服务器已禁用身份验证。
由于 SDN 启动器依赖于 Java 驱动程序的启动器,因此那里所说的所有有关配置的内容也适用于此处。
有关可用属性的引用,请在命名空间中使用 IDE 自动完成。spring.neo4j.uri=bolt://localhost:7687
spring.neo4j
SDN 支持
这些都包含在同一个二进制文件中。 响应式编程模型在数据库端需要 4+ Neo4j 服务器,而在另一方面需要响应式 Spring。
准备数据库
在这个例子中,我们停留在电影图中,因为它对每个 Neo4j 实例都是免费的。
如果您没有正在运行的数据库,但安装了 Docker,请运行:
docker run --publish=7474:7474 --publish=7687:7687 -e 'NEO4J_AUTH=neo4j/secret' neo4j:5
您现在可以访问 http://localhost:7474。
上面的命令将服务器的密码设置为 。
请注意准备在提示符 () 中运行的命令。
执行它以使用一些测试数据填充数据库。secret
:play movies
创建新的 Spring Boot 项目
设置Spring Boot项目的最简单方法是 start.spring.io(如果您不想使用该网站,它也集成在主要IDE中)。
选择“Spring Web Starter”以获取创建基于 Spring 的 Web 应用程序所需的所有依赖项。 Spring Initializr 将负责为您创建一个有效的项目结构,并为所选构建工具提供所有文件和设置。
使用 Maven
您可以针对 Spring Initializer 发出 curl 请求,以创建基本的 Maven 项目:
curl https://start.spring.io/starter.tgz \
-d dependencies=webflux,data-neo4j \
-d bootVersion=3.2.0 \
-d baseDir=Neo4jSpringBootExample \
-d name=Neo4j%20SpringBoot%20Example | tar -xzvf -
这将创建一个新文件夹。
由于此启动器尚未在初始值设定项上,因此必须手动将以下依赖项添加到您的:Neo4jSpringBootExample
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
对于现有项目,您还可以手动添加依赖项。
使用 Gradle
思路是一样的,只需生成一个 Gradle 项目:
curl https://start.spring.io/starter.tgz \
-d dependencies=webflux,data-neo4j \
-d type=gradle-project \
-d bootVersion=3.2.0 \
-d baseDir=Neo4jSpringBootExampleGradle \
-d name=Neo4j%20SpringBoot%20Example | tar -xzvf -
Gradle 的依赖项如下所示,必须添加到:build.gradle
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-neo4j'
}
对于现有项目,您还可以手动添加依赖项。
配置项目
现在,在您喜欢的 IDE 中打开这些项目中的任何一个。
查找并配置您的 Neo4j 凭据:application.properties
spring.neo4j.uri=bolt://localhost:7687
spring.neo4j.authentication.username=neo4j
spring.neo4j.authentication.password=verysecret
这是连接到 Neo4j 实例所需的最低限度。
使用此启动器时,无需添加驱动程序的任何编程配置。 此启动器将自动启用 SDN 存储库。 |
配置 Neo4j Cypher-DSL
根据运行应用程序时使用的 Neo4j 版本,
建议配置运行Neo4j Cypher-DSL时使用的方言。
使用的默认方言面向 Neo4j 4.4。作为 Neo4j 的 LTS 版本。
这可以通过定义 Cypher-DSL bean 来更改。Configuration
@Bean
Configuration cypherDslConfiguration() {
return Configuration.newConfig()
.withDialect(Dialect.NEO4J_5).build();
}
尽管 Spring Data Neo4j 尽量兼容 Neo4j 5 和默认方言的组合,
始终建议明确定义方言。
例如,它将导致更优化的查询,并用于更新的 Neo4j 版本。elementId() |
使用此启动器时,无需添加驱动程序的任何编程配置。 此启动器将自动启用 SDN 存储库。 |
尽管 Spring Data Neo4j 尽量兼容 Neo4j 5 和默认方言的组合,
始终建议明确定义方言。
例如,它将导致更优化的查询,并用于更新的 Neo4j 版本。elementId() |
在模块路径上运行
Spring Data Neo4j 可以在模块路径上运行。它的自动模块名称是 。
由于当前 Spring Data 构建设置中的限制,它本身不提供模块。
因此,它使用自动但稳定的模块名称。但是,它确实取决于
模块化库(Cypher-DSL)。没有由于
上述限制,我们无法代表您表达对该库的要求。spring.data.neo4j
module-info.java
因此,在模块路径上运行 Spring Data Neo4j 6.1+ 的项目所需的最低要求
如下:module-info.java
module-info.java
module your.module {
requires org.neo4j.cypherdsl.core;
requires spring.data.commons;
requires spring.data.neo4j;
opens your.domain to spring.core; (1)
exports your.domain; (2)
}
1 | Spring Data Neo4j 使用 Spring Data Commons 及其反射功能,因此
您至少需要打开您的域包。spring.core |
2 | 我们假设这里还包含存储库:必须导出这些存储库才能被 和 访问。如果你不想把它们出口到世界各地,
您可以将它们限制在这些模块中。your.domain spring.beans spring.context spring.data.commons |
1 | Spring Data Neo4j 使用 Spring Data Commons 及其反射功能,因此
您至少需要打开您的域包。spring.core |
2 | 我们假设这里还包含存储库:必须导出这些存储库才能被 和 访问。如果你不想把它们出口到世界各地,
您可以将它们限制在这些模块中。your.domain spring.beans spring.context spring.data.commons |
创建您的域名
我们的域层应该完成两件事:
-
将图形映射到对象
-
提供对这些内容的访问
示例 node-entity
SDN 完全支持 Java 和 Kotlin 中的类的不可修改实体。
因此,我们在这里将重点介绍不可变的实体,MovieEntity.java显示了这样一个实体。data
SDN 支持 Neo4j Java 驱动程序支持的所有数据类型,请参阅“Cypher 类型系统”一章中的将 Neo4j 类型映射到本地语言类型。 未来的版本将支持其他转换器。 |
import java.util.ArrayList;
import java.util.List;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.Property;
import org.springframework.data.neo4j.core.schema.Relationship;
import org.springframework.data.neo4j.core.schema.Relationship.Direction;
@Node("Movie") (1)
public class MovieEntity {
@Id (2)
private final String title;
@Property("tagline") (3)
private final String description;
@Relationship(type = "ACTED_IN", direction = Direction.INCOMING) (4)
private List<Roles> actorsAndRoles = new ArrayList<>();
@Relationship(type = "DIRECTED", direction = Direction.INCOMING)
private List<PersonEntity> directors = new ArrayList<>();
public MovieEntity(String title, String description) { (5)
this.title = title;
this.description = description;
}
// Getters omitted for brevity
}
1 | @Node 用于将此类标记为托管实体。
它还用于配置 Neo4j 标签。
标签默认为类的名称,如果您只使用 plain .@Node |
2 | 每个实体都必须有一个 ID。
此处显示的 movie 类使用该属性作为唯一的业务键。
如果你没有这样的唯一密钥,你可以使用 和 的组合来配置 SDN 以使用 Neo4j 的内部 ID。
我们还为 UUID 提供生成器。title @Id @GeneratedValue |
3 | 这显示为一种为字段使用与图形属性不同的名称的方法。@Property |
4 | 这定义了与类型类和关系类型的关系PersonEntity ACTED_IN |
5 | 这是应用程序代码要使用的构造函数。 |
一般而言:使用内部生成的 ID 的不可变实体有点矛盾,因为 SDN 需要一种方法来使用数据库生成的值来设置字段。
如果你没有找到一个好的业务密钥,或者不想对 ID 使用生成器,下面是同一个实体,它使用内部生成的 id 以及一个常规构造函数和一个所谓的 wither-Method,这是 SDN 使用的:
import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.Property;
import org.springframework.data.annotation.PersistenceConstructor;
@Node("Movie")
public class MovieEntity {
@Id @GeneratedValue
private Long id;
private final String title;
@Property("tagline")
private final String description;
public MovieEntity(String title, String description) { (1)
this.id = null;
this.title = title;
this.description = description;
}
public MovieEntity withId(Long id) { (2)
if (this.id.equals(id)) {
return this;
} else {
MovieEntity newObject = new MovieEntity(this.title, this.description);
newObject.id = id;
return newObject;
}
}
}
1 | 这是应用程序代码要使用的构造函数。 它将 id 设置为 null,因为包含内部 ID 的字段不应作。 |
2 | 这就是 -attribute 的所谓凋零。
它创建一个新实体并相应地设置字段,而不修改原始实体,从而使其不可变。id |
声明 Spring Data 存储库
您在这里基本上有两个选择: 您可以使用 SDN 以与商店无关的方式工作,并使您的域特定扩展之一
-
org.springframework.data.repository.Repository
-
org.springframework.data.repository.CrudRepository
-
org.springframework.data.repository.reactive.ReactiveCrudRepository
-
org.springframework.data.repository.reactive.ReactiveSortingRepository
相应地选择命令式和反应式。
虽然从技术上讲没有被禁止,但不建议在同一应用程序中混合使用命令式数据库访问和反应式数据库访问。 我们不会支持你处理此类情况。 |
另一种选择是确定特定于商店的实现,并获得我们支持的所有开箱即用的方法。 这种方法的优点也是它最大的缺点:一旦推出,所有这些方法都将成为 API 的一部分。 大多数时候,拿走一些东西比事后添加东西更难。 此外,使用商店详细信息会将您的商店泄漏到您的域中。 从性能的角度来看,没有惩罚。
适合上述任何电影实体的响应式存储库如下所示:
import reactor.core.publisher.Mono;
import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;
public interface MovieRepository extends ReactiveNeo4jRepository<MovieEntity, String> {
Mono<MovieEntity> findOneByTitle(String title);
}
测试响应式代码是使用 .
查看 Project Reactor 的相应文档或查看我们的示例代码。reactor.test.StepVerifier |
SDN 支持 Neo4j Java 驱动程序支持的所有数据类型,请参阅“Cypher 类型系统”一章中的将 Neo4j 类型映射到本地语言类型。 未来的版本将支持其他转换器。 |
1 | @Node 用于将此类标记为托管实体。
它还用于配置 Neo4j 标签。
标签默认为类的名称,如果您只使用 plain .@Node |
2 | 每个实体都必须有一个 ID。
此处显示的 movie 类使用该属性作为唯一的业务键。
如果你没有这样的唯一密钥,你可以使用 和 的组合来配置 SDN 以使用 Neo4j 的内部 ID。
我们还为 UUID 提供生成器。title @Id @GeneratedValue |
3 | 这显示为一种为字段使用与图形属性不同的名称的方法。@Property |
4 | 这定义了与类型类和关系类型的关系PersonEntity ACTED_IN |
5 | 这是应用程序代码要使用的构造函数。 |
1 | 这是应用程序代码要使用的构造函数。 它将 id 设置为 null,因为包含内部 ID 的字段不应作。 |
2 | 这就是 -attribute 的所谓凋零。
它创建一个新实体并相应地设置字段,而不修改原始实体,从而使其不可变。id |
虽然从技术上讲没有被禁止,但不建议在同一应用程序中混合使用命令式数据库访问和反应式数据库访问。 我们不会支持你处理此类情况。 |
测试响应式代码是使用 .
查看 Project Reactor 的相应文档或查看我们的示例代码。reactor.test.StepVerifier |