这篇文章将会引导你创建restful风格的后端服务来访问数据。
接下来将会创建一个Spring应用程序, 来从数据库中以rest风格的方式存取一个Person
对象。Spring Data REST
同时具有 Spring HATEOAS 和 Spring Data JPA 的 特性。
Spring Data REST also supports Spring Data Neo4j, Spring Data Gemfire and Spring Data MongoDB as backend data stores, but those are not part of this guide.
创建下述目录结构:
└── src
└── main
└── java
└── hello
pom.xml
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>org.springframeworkgroupId>
<artifactId>gs-accessing-data-restartifactId>
<version>0.1.0version>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>1.5.7.RELEASEversion>
parent>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-restartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
<dependency>
<groupId>com.h2databasegroupId>
<artifactId>h2artifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
<repositories>
<repository>
<id>spring-releasesid>
<url>https://repo.spring.io/libs-releaseurl>
repository>
repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releasesid>
<url>https://repo.spring.io/libs-releaseurl>
pluginRepository>
pluginRepositories>
project>
Spring Boot Maven plugin
提供了很多便利的特性。
classPath
下 所有的jar, 然后构建成一个jar, 方便了运行spring-boot
程序和做服务迁移public static void main()
代码段, 作为 程序的入口。它提供对内置依赖的解析, 为依赖设置版本号。你可以在Spring-boot
可选的依赖版本集中覆写指定版本号。
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
已经配置为自动生成 , 没必要去关注它。
创建一个简单的 仓库:
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 {
List findByLastName(@Param("name") String name);
}
这个仓库是一个接口, 能够让你执行有关Person
的各种各样的操作,且必须继承 Spring Data Commons
下的
PagingAndSortingRepository
类, 在运行时 Spring
会自动创建接口的实现, 使用@RepositoryRestResource
注解来创建Spring-mvc
路由映射。
@RepositoryRestResource 作为一个仓库被暴露, 并不是必须加的 注解, 他仅仅用来指定导出到 一些细节(如果不想采取默认的导出方式【/persons】)
至此我们定义了一个客户端的查询来获取一系列Person
, 接下来我们看看如何运行。
使用Spring-boot
内嵌的tomcat
运行。 首先创建一个Application.java
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);
}
}
@SpringBootApplication
是一个很方便的注解, 包含了以下注解特性:
application context
提供bean
定义classPath
的设置, 载入所需的bean
和属性配置。@EnableWebMvc
@ComponentScan 扫描hello
包下的其它components
, configurations
, and services
and controllers
SpringApplication.run()
方法来启动应用, 做到了0 xml配置。纯java 构建web应用。Spring-boot
会创建PersonRepository
具体的实现。Spring Data REST
构建与Sping-Mvc
之上, 它创建了一系列SpringMvc 的 controllers
集合、JSON converters
还有其他的提供RESTful
后端服务的 所需的 bean
, 这些组件和Spring Data JPA
联系在一块(使用Spring Boot
全自动配置), 如果你想关注是如何工作的, 请查看RepositoryRestMvcConfiguration
的实现。
./mvnw clean package
java -jar target/gs-accessing-data-rest-0.1.0.jar
用强大的curl
命令来mock
我们的restful
服务。
$ curl http://localhost:8080
{
"_links" : {
"people" : {
"href" : "http://localhost:8080/people{?page,size,sort}",
"templated" : true
}
}
}
从href
中我们看到, 我们可以通过http://localhost:8080/people
去定位一些Person
还可以传递一些查询条件: 如: page
、 size
、sort
。
Spring-Data-Rest 使用 HAL format 作为Json输出。 links结点下会链接一些相邻的数据(有推荐、引导访问某些数据的含义)
$ 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
确保你能够看到包含响应头的响应消息-X POST
标志这是一个POST
请求 -H "Content-Type:application/json"
设置content -type
-d "{ \"firstName\" : \"Frodo\", \"lastName\" : \"Baggins\" }"
body体的要post的 内容Notice how the previous POST operation includes a Location header. This contains the URI of the newly created resource. Spring Data REST also has two methods on RepositoryRestConfiguration.setReturnBodyOnCreate(…) and setReturnBodyOnUpdate(…) which you can use to configure the framework to immediately return the representation of the resource just created. RepositoryRestConfiguration.setReturnBodyForPutAndPost(…) is a short cut method to enable representation responses for creates and updates.
至此, 我们能够查询所有的人。
$ 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
}
}
你也可以直接可以访问单条记录:
$ curl http://localhost:8080/people/1
{
"firstName" : "Frodo",
"lastName" : "Baggins",
"_links" : {
"self" : {
"href" : "http://localhost:8080/people/1"
}
}
}
在这个向导中只包含一个实体, 在一个更大的系统中, 实体之间有着复杂的联系。Spring Data REST
将会展示一些额外的连接, 导航到其它数据。
查看所有可能的客户端查询方式:
$ curl http://localhost:8080/people/search
{
"_links" : {
"findByLastName" : {
"href" : "http://localhost:8080/people/search/findByLastName{?name}",
"templated" : true
}
}
}
使用findByLastName
$ curl http://localhost:8080/people/search/findByLastName?name=Baggins
{
"_embedded" : {
"persons" : [ {
"firstName" : "Frodo",
"lastName" : "Baggins",
"_links" : {
"self" : {
"href" : "http://localhost:8080/people/1"
}
}
} ]
}
}
PUT
、PATCH
、DELETE
样例:
$ 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 replaces an entire record. Fields not supplied will be replaced with null. PATCH can be used to update a subset of items.
$ 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
}
}