本指南将引导您完成创建通过基于超媒体的RESTful前端访问关系JPA Data的应用程序的过程。

您将构建一个Spring应用程序,让您使用Spring Data Rest创建和检索存储在数据库中的Person对象。Spring Data Rest采用了Spring HATEOAS和Spring Data JPA的特性,并将它们自动组合在一起。
Spring Data Rest还支持将Spring Data Neo4j、Spring Data GemFire和Spring Data MongoDB作为后端数据存储,但这些不属于本指南的一部分。

程序结构

└── src
    └── main
        └── java
            └── hello

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>

    <groupId>org.springframework</groupId>
    <artifactId>gs-accessing-data-rest</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
    </parent>

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

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

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

</project>

Spring Boot将会你做如下的事:

  • 将 classpath 里面所有用到的jar包构建成一个可执行的 JAR 文件,方便执行你的程序
  • 搜索public static void main()方法并且将它当作可执行类
  • 根据springboot版本,去查找相应的依赖类版本,当然你可以定义其它版本。

创建域对象
创建一个新的域对象来代表一个人。

src/main/java/hello/Person.java

package hello;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    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类有 firstName和lastName。还有一个id对象被配置为自动生成,因此您不必处理它。
创建Person存储库
接下来,您需要创建一个简单的存储库:
src/main/java/hello/PersonRepository.java

package hello;

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将自动创建该接口的实现。然后它将使用@RepositoryRestResource 注释来指导spring mvc在/people处创建RESTful端点。

要导出存储库,不需要@RepositoryRestoreSource。@RepositoryRestoreSource仅用于更改导出详细信息,例如使用/people而不是/persons的默认值。

在这里,您还定义了一个自定义查询来检索基于lastName的Person对象列表。您将在本指南中进一步了解如何调用它。

创建Application
src/main/java/hello/Application.java

package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

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

SpringBoot自动使用Spring Data JPA来创建一个具体的PersonRepository实现,并将其配置为使用JPA与后端内存数据库通信。
Spring Data Rest构建在SpringMVC之上。它创建了一个SpringMVC控制器、JSON转换器和其他提供一个RESTful前端所需的bean的集合。这些组件链接到Spring Data JPA后端。使用SpringBoot,这一切都是自动配置的;如果您想调查这是如何工作的,可以从Spring Data Rest中的RepositoryRestmvcConfiguration开始。

运行及测试程序
运行Application.java,下面使用curl来测试(也可以在浏览器):
首先,您希望看到顶级服务:

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

这里,您可以第一眼看到这个服务器必须提供什么。在http://localhost:8080/people上有一个people链接。它有一些选择,比如?第几页,?获得多少个,还有?是否排序。
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/1
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操作如何包含位置头部。这包含新创建的资源的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" : {
    "persons" : [ {
      "firstName" : "Frodo",
      "lastName" : "Baggins",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/people/1"
        }
      }
    } ]
  },
  "page" : {
    "size" : 20,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}

Persons对象包含一个带有Frodo的列表。注意它如何包含一个自链接。Spring Data Rest还使用 Evo Inflector 将分组实体的名称复数化。
您可以直接查询单个记录:

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

这可能纯粹是基于Web的,但在内部,是有一个H2关系数据库。在生产中,您可能会使用真正的,如MYSQL。
在本指南中,只有一个域对象。在域对象相互关联的更复杂的系统中,Spring DataRest将呈现其他链接,以帮助导航到连接的记录。
查找所有自定义查询:

$ 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" : {
    "persons" : [ {
      "firstName" : "Frodo",
      "lastName" : "Baggins",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/people/1"
        }
      }
    } ]
  }
}

因为您在代码中将其定义为返回List<Person>,所以它将返回所有结果。如果您定义了它只返回Person,它将选择要返回的Person对象之一。因为这可能是不可预测的,所以对于可以返回多个条目的查询,您可能不希望这样做。
您还可以发出PUT、PATCH和 DELETE REST 调用来替换、更新或删除现有记录。

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

$ curl -X PATCH -H "Content-Type:application/json" -d '{"firstName": "Bilbo Jr."}' http://localhost:8080/people/1

$ curl http://localhost:8080/people/1
{
  "firstName" : "Bilbo Jr.",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people/1"
    }
  }
}

PUT替换整个记录。未提供的字段将替换为null。PATCH程序可用于更新项目.
您可以删除记录:

$ curl -X DELETE http://localhost:8080/people/1
$ 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端点,不需要提供正式接口文档。