此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Data Neo4j 7.4.4!spring-doc.cadn.net.cn

开始

我们为 SDN 提供了一个 Spring Boot Starters。 请通过您的依赖项管理包含 starter 模块,并配置要使用的 bolt URL,例如spring.neo4j.uri=bolt://localhost:7687. Starters假定服务器已禁用身份验证。 由于 SDN Starters依赖于 Java 驱动程序的Starters,因此此处提到的有关配置的所有内容也适用于此处。 有关可用属性的参考,请在spring.neo4jNamespace。spring-doc.cadn.net.cn

这些都包含在同一个二进制文件中。 反应式编程模型在数据库端需要一个 4+ Neo4j 服务器,另一方面需要一个反应式 Spring。spring-doc.cadn.net.cn

准备数据库

在这个例子中,我们停留在电影图中,因为它在每个 Neo4j 实例中都是免费的。spring-doc.cadn.net.cn

如果您没有正在运行的数据库但安装了 Docker,请运行:spring-doc.cadn.net.cn

在 Docker 中启动本地 Neo4j 实例。
docker run --publish=7474:7474 --publish=7687:7687 -e 'NEO4J_AUTH=neo4j/secret' neo4j:5

您现在可以访问 http://localhost:7474。 上述命令将服务器的密码设置为secret. 请注意,命令已准备好在提示符 (:play movies). 执行它以使用一些测试数据填充您的数据库。spring-doc.cadn.net.cn

创建新的 Spring Boot 项目

设置 Spring Boot 项目的最简单方法是 start.spring.io(如果您不想使用该网站,它也集成在主要的 IDE 中)。spring-doc.cadn.net.cn

选择 “Spring Web Starter” 以获取创建基于 Spring 的 Web 应用程序所需的所有依赖项。 Spring Initializr 将负责为您创建一个有效的项目结构,并为所选的构建工具准备好所有文件和设置。spring-doc.cadn.net.cn

使用 Maven

你可以向 Spring Initializer 发出 curl 请求,以创建一个基本的 Maven 项目:spring-doc.cadn.net.cn

使用 Spring Initializr 创建一个基本的 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. 由于此 starter 尚未在初始化器上,因此您必须手动将以下依赖项添加到您的pom.xml:spring-doc.cadn.net.cn

在 Maven 项目中包含 spring-data-neo4j-spring-boot-starter
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>

如果是现有项目,您还可以手动添加依赖项。spring-doc.cadn.net.cn

使用 Gradle

思路是一样的,只需生成一个 Gradle 项目即可:spring-doc.cadn.net.cn

使用 Spring Initializr 创建基本的 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:spring-doc.cadn.net.cn

在 Gradle 项目中包含 spring-data-neo4j-spring-boot-starter
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-neo4j'
}

如果是现有项目,您还可以手动添加依赖项。spring-doc.cadn.net.cn

配置项目

现在,在您最喜欢的 IDE 中打开这些项目中的任何一个。 找到application.properties并配置您的 Neo4j 凭证:spring-doc.cadn.net.cn

spring.neo4j.uri=bolt://localhost:7687
spring.neo4j.authentication.username=neo4j
spring.neo4j.authentication.password=verysecret

这是连接到 Neo4j 实例所需的最低要求。spring-doc.cadn.net.cn

使用此Starters时,无需添加驱动程序的任何编程配置。 此Starters将自动启用 SDN 存储库。

配置 Neo4j Cypher-DSL

根据您运行应用程序的 Neo4j 版本, 建议配置 Neo4j Cypher-DSL 运行时使用的方言。 使用的默认方言面向 Neo4j 4.4。作为 Neo4j 的 LTS 版本。 这可以通过定义 Cypher-DSL 来更改Configuration豆。spring-doc.cadn.net.cn

让 Cypher-DSL 使用 Neo4j 5 方言
@Bean
Configuration cypherDslConfiguration() {
	return Configuration.newConfig()
                .withDialect(Dialect.NEO4J_5).build();
}
尽管 Spring Data Neo4j 尽最大努力与 Neo4j 5 和默认方言的组合兼容, 始终建议显式定义 dialect。 例如,它将导致更优化的查询,并利用elementId()对于较新的 Neo4j 版本。

在 module-path 上运行

Spring Data Neo4j 可以在 module 路径上运行。它的自动模块名称是spring.data.neo4j. 由于当前 Spring Data 构建设置中的限制,它本身不提供模块。 因此,它使用自动但稳定的模块名称。但是,它确实取决于 一个模块化库 (Cypher-DSL)。如果没有module-info.java由于 上述限制,我们无法代表您表达对该库的要求。spring-doc.cadn.net.cn

因此,最低要求module-info.java在你的项目中,在模块路径上运行 Spring Data Neo4j 6.1+ 如下所示:spring-doc.cadn.net.cn

一个module-info.java在应该在模块路径上使用 Spring Data Neo4j 的项目中
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.contextspring.data.commons.如果您不想将它们导出到全世界, 您可以将它们限制为这些模块。

创建您的域

我们的域层应该完成两件事:spring-doc.cadn.net.cn

示例 Node-Entity

SDN 完全支持 Java 和data类。 因此,我们在这里将重点介绍不可变实体,MovieEntity.java显示了这样一个实体。spring-doc.cadn.net.cn

SDN 支持 Neo4j Java 驱动程序支持的所有数据类型,请参阅“密码类型系统”一章中的将 Neo4j 类型映射到本地语言类型。 未来版本将支持其他转换器。
MovieEntity.java
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 is used to mark this class as a managed entity. It also is used to configure the Neo4j label. The label defaults to the name of the class, if you’re just using plain @Node.
2 Each entity has to have an id. The movie class shown here uses the attribute title as a unique business key. If you don’t have such a unique key, you can use the combination of @Id and @GeneratedValue to configure SDN to use Neo4j’s internal id. We also provide generators for UUIDs.
3 This shows @Property as a way to use a different name for the field than for the graph property.
4 This defines a relationship to a class of type PersonEntity and the relationship type ACTED_IN
5 This is the constructor to be used by your application code.

As a general remark: immutable entities using internally generated ids are a bit contradictory, as SDN needs a way to set the field with the value generated by the database.spring-doc.cadn.net.cn

If you don’t find a good business key or don’t want to use a generator for IDs, here’s the same entity using the internally generated id together with a regular constructor and a so called wither-Method, that is used by SDN:spring-doc.cadn.net.cn

MovieEntity.java
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 This is the constructor to be used by your application code. It sets the id to null, as the field containing the internal id should never be manipulated.
2 This is a so-called wither for the id-attribute. It creates a new entity and sets the field accordingly, without modifying the original entity, thus making it immutable.

You can of course use SDN with Kotlin and model your domain with Kotlin’s data classes. Project Lombok is an alternative if you want or need to stay purely within Java.spring-doc.cadn.net.cn

Declaring Spring Data repositories

You basically have two options here: you can work in a store-agnostic fashion with SDN and make your domain specific extend one ofspring-doc.cadn.net.cn

Choose imperative and reactive accordingly.spring-doc.cadn.net.cn

While technically not prohibited, it is not recommended mixing imperative and reactive database access in the same application. We won’t support you with scenarios like this.

The other option is to settle on a store specific implementation and gain all the methods we support out of the box. The advantage of this approach is also its biggest disadvantage: once out, all those methods will be part of your API. Most of the time it’s harder to take something away, than to add stuff afterwards. Furthermore, using store specifics leaks your store into your domain. From a performance point of view, there is no penalty.spring-doc.cadn.net.cn

A reactive repository fitting to any of the movie entities above looks like this:spring-doc.cadn.net.cn

MovieRepository.java
import reactor.core.publisher.Mono;

import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;

public interface MovieRepository extends ReactiveNeo4jRepository<MovieEntity, String> {

	Mono<MovieEntity> findOneByTitle(String title);
}
Testing reactive code is done with a reactor.test.StepVerifier. Have a look at the corresponding documentation of Project Reactor or see our example code.