SpringBoot 2 REST 訪問 Neo4j 數據

開篇詞

該指南將引導你創建通過基於超媒體的 RESTful 前端訪問圖數據。
 

你將創建的應用

我們將構建一個 Spring 應用,該應用允許我們使用 Spring Data REST 創建和檢索存儲在 Neo4j NoSQL 數據庫中的 Person 對象。Spring Data REST 具有 Spring HATEOASSpring Data Neo4j 的功能,並將它們自動結合在一起。
 

你將需要的工具

如何完成這個指南

像大多數的 Spring 入門指南一樣,你可以從頭開始並完成每個步驟,也可以繞過你已經熟悉的基本設置步驟。如論哪種方式,你最終都有可以工作的代碼。

  • 要從頭開始,移步至搭建並啓動一個 Neo4j 服務器
  • 要跳過基礎,執行以下操作:
    • 下載並解壓縮該指南將用到的源代碼,或藉助 Git 來對其進行克隆操作:git clone https://github.com/spring-guides/gs-accessing-neo4j-data-rest.git
    • 切換至 gs-accessing-neo4j-data-rest/initial 目錄;
    • 跳轉至該指南的訪問 Neo 4j 的權限

待一切就緒後,可以檢查一下 gs-accessing-neo4j-data-rest/complete 目錄中的代碼。
 

搭建並啓動一個 Neo4j 服務器

在構建該應用之前,我們需要搭建一個 Neo4j 服務器。

Neo4j 有一個開源服務器,我們可以免費安裝。

在安裝了 Homebrew 的Mac 上,可以在終端窗口中鍵入以下內容:

brew install neo4j

有關其他選項,請參見 https://neo4j.com/download/community-edition/

安裝 Neo4j 後,可以通過運行以下命令以默認配置啓動它:

neo4j start

我們應該看到類似於以下內容的消息:

Starting Neo4j. Started neo4j (pid 96416). By default, it is available at http://localhost:7474/ There may be a short delay until the server is ready. See /usr/local/Cellar/neo4j/3.0.6/libexec/logs/neo4j.log for current status.

默認情況下,Neo4j 的用戶名和密碼爲 neo4jneo4j。但是,它要求更改爲新的賬戶密碼。爲此,請運行以下命令:

curl -v -u neo4j:neo4j -X POST localhost:7474/user/neo4j/password -H "Content-type:application/json" -d "{\"password\":\"secret\"}"

這會將密碼從 neo4j 更改爲 secret(不要在生產環境中這麼做!)。完成後,我們就可以準備運行該指南。
 

從 Spring Initializr 開始

對於所有的 Spring 應用來說,你應該從 Spring Initializr 開始。Initializr 提供了一種快速的方法來提取應用程序所需的依賴,併爲你完成許多設置。該例子需要 Rest Repositories 和 Spring Data Neo4j 依賴。下圖顯示了此示例項目的 Initializr 設置:

上圖顯示了選擇 Maven 作爲構建工具的 Initializr。你也可以使用 Gradle。它還將 com.exampleaccessing-neo4j-data-rest 的值分別顯示爲 Group 和 Artifact。在本示例的其餘部分,將用到這些值。

以下清單顯示了選擇 Maven 時創建的 pom.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>accessing-neo4j-data-rest</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>accessing-neo4j-data-rest</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-neo4j</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-rest</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

以下清單顯示了在選擇 Gradle 時創建的 build.gradle 文件:

plugins {
	id 'org.springframework.boot' version '2.2.2.RELEASE'
	id 'io.spring.dependency-management' version '1.0.8.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-neo4j'
	implementation 'org.springframework.boot:spring-boot-starter-data-rest'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

test {
	useJUnitPlatform()
}

 

訪問 Neo 4j 的權限

Neo4j Community Edition 需要憑據才能訪問它。我們可以通過在 src/main/resources/application.properties 中設置屬性來配置憑據,如下所示:

spring.data.neo4j.username=neo4j
spring.data.neo4j.password=secret

這包括默認的用戶名(neo4j)和我們先前設置的新密碼(secret)。

不要在源存儲庫中存儲真實憑證。相反,請使用 Spring Boot 的屬性替代在運行中對它們進行配置。

 

創建域對象

我們需要創建一個新的域對象來展現一個人,如以下示例(在 src/main/java/com/example/accessingneo4jdatarest/Person.java 中)所示:

package com.example.accessingneo4jdatarest;


import org.neo4j.ogm.annotation.GeneratedValue;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.NodeEntity;

@NodeEntity
public class Person {

  @Id @GeneratedValue private Long id;

  private String firstName;
  private String lastName;

  public String getFirstName() {
    return firstName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
}

Person 對象有一個名字和一個姓氏。還有一個 ID 對象,該對象被配置爲自動生成,因此我們無需手動生成。
 

創建一個 Person 存儲庫

接下來,我們需要創建一個簡單的存儲庫,如以下示例所示(在 src/main/java/com/example/accessingneo4jdatarest/PersonRepository.java 中):

package com.example.accessingneo4jdatarest;

import java.util.List;

import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

@RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {

  List<Person> findByLastName(@Param("name") String name);

}

該存儲庫是一個接口,可讓我們執行涉及 Person 對象的各種操作。它通過擴展 Spring Data Commons 中定義的 PagingAndSortingRepository 接口來獲得這些操作。

在運行時,Spring Data REST 自動創建該接口的實現。然後,它使用 @RepositoryRestResources 註解指示 Spring MVC 在 /people 處創建 RESTful 端點。

導出存儲庫不需要 @RepositoryRestResource。它僅用於更改導出詳細信息,例如使用 /people 代替 /persons 的默認值。

這裏,我們還定義了一個自定義查詢,以基於 lastName 值檢索 Person 對象的列表。我們可以在該指南的後續部分中看到如何調用它。
 

查找應用類

當我們使用 Spring Initializr 創建項目時,它會創建一個應用類。我們可以在 src/main/java/com/example/accessingneo4jdatarest/Application.java 中找到它。請注意,Spring Initializr 連接(並適當地更改了其大小寫)包名並添加其至 Application 中以創建應用名稱。這種情況下,我們獲得 AccessingNeo4jDataRestApplication,如下清單所示:

package com.example.accessingneo4jdatarest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@EnableTransactionManagement
@EnableNeo4jRepositories
@SpringBootApplication
public class AccessingNeo4jDataRestApplication {

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

在該示例中,我們無需對該應用類做任何更改。
@SpringBootApplication 是一個便利的註解,它添加了以下所有內容:

  • @Configuration:將類標記爲應用上下文 Bean 定義的源;
  • @EnableAutoConfiguration:告訴 Spring Boot 根據類路徑配置、其他 bean 以及各種屬性的配置來添加 bean。
  • @ComponentScan:告知 Spring 在 com/example 包中尋找他組件、配置以及服務。

main() 方法使用 Spring Boot 的 SpringApplication.run() 方法啓動應用。

@EnableNeo4jRepositories 註解激活 Spring Data Neo4j。Spring Data Neo4j 創建了 PersonRepository 的具體實現,並將其配置爲使用 Cypher 查詢語言與嵌入式 Neo4j 數據庫對話。

構建可執行 JAR

我們可以結合 Gradle 或 Maven 來從命令行運行該應用。我們還可以構建一個包含所有必須依賴項、類以及資源的可執行 JAR 文件,然後運行該文件。在整個開發生命週期中,跨環境等等情況下,構建可執行 JAR 可以輕鬆地將服務作爲應用進行發佈、版本化以及部署。

如果使用 Gradle,則可以藉助 ./gradlew bootRun 來運行應用。或通過藉助 ./gradlew build 來構建 JAR 文件,然後運行 JAR 文件,如下所示:

java -jar build/libs/gs-accessing-neo4j-data-rest-0.1.0.jar

由官網提供的以上這條命令的執行結果與我本地的不一樣,我需要這樣才能運行:java -jar build/libs/accessing-neo4j-data-rest-0.0.1-SNAPSHOT.jar

如果使用 Maven,則可以藉助 ./mvnw spring-boot:run 來運行該用。或可以藉助 ./mvnw clean package 來構建 JAR 文件,然後運行 JAR 文件,如下所示:

java -jar target/gs-accessing-neo4j-data-rest-0.1.0.jar

由官網提供的以上這條命令的執行結果與我本地的不一樣,我需要這樣才能運行:java -jar target/accessing-neo4j-data-rest-0.0.1-SNAPSHOT.jar

我們還可以將 JAR 應用轉換成 WAR 應用

顯示日誌記錄輸出。該服務應在幾秒內啓動並運行。
 

測試應用

現在該應用正在運行,我們可以對其進行測試。我們可以使用任何喜歡的 REST 客戶端。以下示例使用 curl

首先,我們要查看頂級服務。以下示例(帶有輸出)顯示瞭如何執行該操作:

curl http://localhost:8080
{
  "_links" : {
    "people" : {
      "href" : "http://localhost:8080/people{?page,size,sort}",
      "templated" : true
    }
  }
}

這裏,我們可以初步瞭解該服務器所提供的功能。在 http://localhost:8080/people 上有一個 people 鏈接。它有一些選項,例如 ?page?size?sort

Spring Data REST 使用 HAL 格式進行 JSON 輸出。它非常靈活,並提供了一種便捷的方式來提供與所提供數據相鄰的鏈接。

curl http://localhost:8080/people
{
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people{?page,size,sort}",
      "templated" : true
    },
    "search" : {
      "href" : "http://localhost:8080/people/search"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 0,
    "totalPages" : 0,
    "number" : 0
  }
}

當前沒有任何元素,因此也沒有分頁內容,所以是時候創建一個新的 Person 了!爲此,請運行以下命令(及其輸出顯示):

curl -i -X POST -H "Content-Type:application/json" -d '{  "firstName" : "Frodo",  "lastName" : "Baggins" }' http://localhost:8080/people
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Location: http://localhost:8080/people/0
Content-Length: 0
Date: Wed, 26 Feb 2014 20:26:55 GMT
  • -i:確保我們可以看到包括標題的響應消息。顯示新創建的 Person 的 URI;
  • -X POST 表示這是用於創建新條目的 POST
  • -H "Content-Type:application/json":設置內容類型,以便應用知道有效負載包含 JSON 對象;
  • -d'{"firstName: "Frodo", "lastName": "Barggins""}':被髮送的數據;

請注意,對 POST 操作的響應如何包含 Location 標頭。它包含新創建資源的 URI。Spring Data REST 還具有兩個方法(RepositoryRestConfiguration.setReturnBodyOnCreate(…)setReturnBodyOnUpdate(…)),我們可以使用它們來配置框架以立即返回剛剛創建的資源的表示形式。
RepositoryRestConfiguration.setReturnBodyForPutAndPost(…) 是一種啓用創建和更新操作的表示形式響應的快捷方式。

我們可以查詢所有人,如以下示例所示:

curl http://localhost:8080/people
{
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people{?page,size,sort}",
      "templated" : true
    },
    "search" : {
      "href" : "http://localhost:8080/people/search"
    }
  },
  "_embedded" : {
    "people" : [ {
      "firstName" : "Frodo",
      "lastName" : "Baggins",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/people/0"
        }
      }
    } ]
  },
  "page" : {
    "size" : 20,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}

people 對象包含一個包含 Frodo 的列表。注意它是如何包含一個 self 鏈接的。Spring Data REST 還使用 Evo Inflector 來對實體名稱進行復數以進行分組。

我們可以直接查詢單個記錄,如下所示:

curl http://localhost:8080/people/1
{
  "firstName" : "Frodo",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people/0"
    }
  }
}

這似乎完全是基於 Web 的,但是後臺有一個嵌入式 Neo4j 圖形數據庫。在生產中,我們可能會連接到獨立的 Neo4j 服務器。

在該指南中,只有一個域對象。在域對象相互關聯的更復雜的系統中,Spring Data REST 展示了更多鏈接,以幫助導航至連接的記錄。

我們可以通過運行以下命令(及其輸出顯示)找到所有自定義查詢:

curl http://localhost:8080/people/search
{
  "_links" : {
    "findByLastName" : {
      "href" : "http://localhost:8080/people/search/findByLastName{?name}",
      "templated" : true
    }
  }
}

我們可以看到查詢的 URL,包括 HTTP 查詢參數,name。請注意,這與接口中嵌入的 @Param("name") 註解匹配。

以下示例顯示瞭如何使用 findByLastName 查詢:

curl http://localhost:8080/people/search/findByLastName?name=Baggins
{
  "_embedded" : {
    "people" : [ {
      "firstName" : "Frodo",
      "lastName" : "Baggins",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/people/0"
        },
        "person" : {
          "href" : "http://localhost:8080/people/0"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people/search/findByLastName?name=Baggins"
    }
  }
}

因爲我們已將其定義爲在代碼中返回 List<Person>,所以它將返回所有結果。如果已將其定義爲僅返回 Person,則它將選擇要返回的 Person 對象之一。由於這可能是不可預測的,因此對於可能返回多個條目的查詢,我們可能不想這樣做。

我還可以發出 PUTPATCHDELETE REST 調用來分別替換、更新或刪除現有記錄。以下示例使用 PUT 調用:

curl -X PUT -H "Content-Type:application/json" -d '{ "firstName": "Bilbo", "lastName": "Baggins" }' http://localhost:8080/people/0
curl http://localhost:8080/people/0
{
  "firstName" : "Bilbo",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people/0"
    }
  }
}

下面示例使用 PATCH 調用:

curl -X PATCH -H "Content-Type:application/json" -d '{ "firstName": "Bilbo Jr." }' http://localhost:8080/people/0
curl http://localhost:8080/people/0
{
  "firstName" : "Bilbo Jr.",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people/0"
    }
  }
}

PUT 替換整個記錄。未提供的字段將替換爲 null。我們可以使用 PATCH 更新項的子集。

我們還可以刪除記錄,如以下示例所示:

curl -X DELETE http://localhost:8080/people/0
curl http://localhost:8080/people
{
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people{?page,size,sort}",
      "templated" : true
    },
    "search" : {
      "href" : "http://localhost:8080/people/search"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 0,
    "totalPages" : 0,
    "number" : 0
  }
}

該超媒體驅動接口的一個方便方面是,我們可以使用 curl(或您喜歡的任何REST客戶端)來
發現所有 RESTful 端點。我們無需與客戶交換正式合同或接口文件。
 

概述

恭喜你!我們已經開發了具有基於超媒體的 RESTful 前端和基於 Neo4j 後端的應用。
 

參見

以下指南也可能會有所幫助:

想看指南的其他內容?請訪問該指南的所屬專欄:《Spring 官方指南

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章