使用 REST 訪問 Neo4j 資料

本指南將引導您完成建立一個應用程式的過程,該應用程式透過基於超媒體的 RESTful 前端訪問基於圖的資料。

您將構建什麼

您將構建一個 Spring 應用程式,它允許您使用 Spring Data REST 建立和檢索儲存在 Neo4j NoSQL 資料庫中的 Person 物件。Spring Data REST 結合了 Spring HATEOASSpring Data Neo4j 的功能,並自動將它們組合在一起。

Spring Data REST 還支援 Spring Data JPASpring Data GemfireSpring Data MongoDB 作為後端資料儲存,但本指南只涉及 Neo4j。

你需要什麼

如何完成本指南

與大多數 Spring 入門指南一樣,您可以從頭開始並完成每個步驟,也可以跳過您已熟悉的基本設定步驟。無論哪種方式,您最終都會得到可工作的程式碼。

從頭開始,請轉到[從頭開始]

跳過基礎知識,請執行以下操作

完成後,您可以將結果與 {project_id}/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 https://: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 的使用者名稱和密碼均為 neo4j。但是,它要求更改新賬戶密碼。為此,請執行以下命令

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

這將密碼從 neo4j 更改為 secret(在生產環境中不要這樣做!)。完成後,您應該已準備好執行本指南。

從 Spring Initializr 開始

您可以使用此預初始化專案,然後單擊“生成”下載 ZIP 檔案。此專案已配置為符合本教程中的示例。

手動初始化專案

  1. 導航到 https://start.spring.io。此服務會為您拉取應用程式所需的所有依賴項,併為您完成大部分設定。

  2. 選擇 Gradle 或 Maven 以及您想要使用的語言。本指南假設您選擇了 Java。

  3. 點選 Dependencies 並選擇 Rest RepositoriesSpring Data Neo4j

  4. 單擊生成

  5. 下載生成的 ZIP 檔案,這是一個已根據您的選擇配置好的 Web 應用程式存檔。

如果您的 IDE 集成了 Spring Initializr,您可以從 IDE 中完成此過程。
您還可以從 Github fork 該專案並在您的 IDE 或其他編輯器中開啟它。

訪問 Neo4j 的許可權

Neo4j 社群版需要憑據才能訪問。您可以透過在 src/main/resources/application.properties 中設定屬性來配置憑據,如下所示

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

這包括您之前設定的預設使用者名稱(neo4j)和新設定的密碼(secret)。

請勿將實際憑據儲存在您的原始碼倉庫中。相反,請使用Spring Boot 的屬性覆蓋在執行時配置它們。

建立領域物件

您需要建立一個新的領域物件來表示一個人,如下面的示例(在 src/main/java/com/example/accessingneo4jdatarest/Person.java 中)所示

package com.example.accessingneo4jdatarest;

import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.GeneratedValue;

@Node
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.CrudRepository;
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>, CrudRepository<Person, Long> {

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

}

此儲存庫是一個介面,允許您執行涉及 Person 物件的各種操作。它透過擴充套件 Spring Data Commons 中定義的 PagingAndSortingRepositry 介面來獲取這些操作。

在執行時,Spring Data REST 自動建立此介面的實現。然後它使用 @RepositoryRestResource 註解指示 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。例如,如果 spring-webmvc 在類路徑中,此註解會將應用程式標記為 Web 應用程式並激活關鍵行為,例如設定 DispatcherServlet

  • @ComponentScan:告訴 Spring 在 com/example 包中查詢其他元件、配置和服務,使其能夠找到控制器。

main() 方法使用 Spring Boot 的 SpringApplication.run() 方法啟動應用程式。您是否注意到沒有一行 XML?也沒有 web.xml 檔案。這個 Web 應用程式是 100% 純 Java,您不必處理任何管道或基礎設施的配置。

@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/{project_id}-0.1.0.jar

如果您使用 Maven,您可以透過使用 ./mvnw spring-boot:run 執行應用程式。或者,您可以使用 ./mvnw clean package 構建 JAR 檔案,然後按如下方式執行 JAR 檔案

java -jar target/{project_id}-0.1.0.jar
這裡描述的步驟建立了一個可執行的 JAR。您還可以構建一個經典的 WAR 檔案

日誌輸出已顯示。服務應在幾秒鐘內啟動並執行。

測試應用程式

現在應用程式已執行,您可以對其進行測試。您可以使用任何您喜歡的 REST 客戶端。以下示例使用名為 curl 的 *nix 工具。

首先,您想檢視頂層服務。以下示例(帶輸出)展示瞭如何操作

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

這裡您第一次瞭解了這個伺服器可以提供什麼。在 https://:8080/people 有一個 people 連結。它有一些選項,例如 ?page?size?sort

Spring Data REST 使用 HAL 格式進行 JSON 輸出。它靈活方便,提供了一種在所服務資料旁邊提供連結的方法。
$ curl https://:8080/people
{
  "_links" : {
    "self" : {
      "href" : "https://:8080/people{?page,size,sort}",
      "templated" : true
    },
    "search" : {
      "href" : "https://: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" }' https://:8080/people
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Location: https://: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" : "Baggins" }' 是正在傳送的資料

注意前面的 POST 操作如何包含一個 Location 頭部。這包含新建立資源的 URI。Spring Data REST 還有兩種方法(RepositoryRestConfiguration.setReturnBodyOnCreate(…)setReturnBodyOnCreate(…)),您可以使用它們來配置框架,使其在建立資源後立即返回資源的表示。

由此,您可以透過執行以下命令(顯示其輸出)查詢所有人員

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

people 物件包含一個帶有 Frodo 的列表。注意它如何包含一個 self 連結。Spring Data REST 還使用 Evo Inflector 庫將實體名稱複數化以進行分組。

您可以透過執行以下命令(顯示其輸出)直接查詢單個記錄

$ curl https://:8080/people/0
{
  "firstName" : "Frodo",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "https://:8080/people/0"
    }
  }
}
這可能看起來純粹基於網路,但幕後有一個嵌入式的 Neo4j 圖資料庫。在生產環境中,您可能會連線到獨立的 Neo4j 伺服器。

在本指南中,只有一個領域物件。在一個更復雜的系統中,如果領域物件之間存在關聯,Spring Data REST 會渲染額外的連結以幫助導航到連線的記錄。

您可以透過執行以下命令(顯示其輸出)找到所有自定義查詢

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

您可以看到查詢的 URL,包括 HTTP 查詢引數:name。請注意,這與介面中嵌入的 @Param("name") 註解相匹配。

要使用 findByLastName 查詢,請執行以下命令(顯示其輸出)

$ curl https://:8080/people/search/findByLastName?name=Baggins
{
  "_embedded" : {
    "people" : [ {
      "firstName" : "Frodo",
      "lastName" : "Baggins",
      "_links" : {
        "self" : {
          "href" : "https://:8080/people/0"
        },
        "person" : {
          "href" : "https://:8080/people/0"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "https://: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" }' https://:8080/people/0
$ curl https://:8080/people/0
{
  "firstName" : "Bilbo",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "https://:8080/people/0"
    }
  }
}

以下示例(顯示其輸出)展示了一個 PATCH 呼叫

$ curl -X PATCH -H "Content-Type:application/json" -d '{ "firstName": "Bilbo Jr." }' https://:8080/people/0
$ curl https://:8080/people/0
{
  "firstName" : "Bilbo Jr.",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "https://:8080/people/0"
    }
  }
}
PUT 替換整個記錄。未提供的欄位將替換為 nullPATCH 可用於更新專案子集。

您還可以刪除記錄,如下面的示例(顯示其輸出)所示

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

這種超媒體驅動的介面的一個方便之處在於,您可以使用 curl(或您喜歡的任何 REST 客戶端)發現所有 RESTful 端點。您無需與客戶交換正式的合同或介面文件。

總結

恭喜!您剛剛開發了一個具有基於超媒體的 RESTful 前端和基於 Neo4j 的後端的應用程式。

獲取程式碼