1. 概述
在本文中,我們將探討 Spring Data REST 的投影和摘錄概念。我們將學習如何 使用投影來創建我們模型自定義視圖,以及如何使用摘錄作為資源集合的默認視圖。
2. 我們的領域模型
首先,讓我們通過定義我們的領域模型開始:書和作者。
讓我們看一下書實體類:
@Entity
public class Book {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
@Column(nullable = false)
private String title;
private String isbn;
@ManyToMany(mappedBy = "books", fetch = FetchType.EAGER)
private List<Author> authors;
}
以及作者模型:
@Entity
public class Author {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
@Column(nullable = false)
private String name;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(
name = "book_author",
joinColumns = @JoinColumn(
name = "book_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(
name = "author_id", referencedColumnName = "id"))
private List<Book> books;
}
這兩個實體之間也存在多對多關係。
接下來,讓我們為每個模型定義標準 Spring Data REST 存儲庫:
public interface BookRepository extends CrudRepository<Book, Long> {}
public interface AuthorRepository extends CrudRepository<Author, Long> {}
現在,我們可以訪問書端點以使用其 ID 獲取特定書的詳細信息,網址為 http://localhost:8080/books/{id}:
{
"title" : "Animal Farm",
"isbn" : "978-1943138425",
"_links" : {
"self" : {
"href" : "http://localhost:8080/books/1"
},
"book" : {
"href" : "http://localhost:8080/books/1"
},
"authors" : {
"href" : "http://localhost:8080/books/1/authors"
}
}
}
請注意,由於作者模型具有其存儲庫,因此作者的詳細信息不包含在響應中。但是,我們可以找到指向它們的鏈接——http://localhost:8080/books/1/authors。
3. 創建投影
有時,我們只對實體屬性的子集或自定義視圖感興趣。
讓我們使用 Spring Data REST 投影創建一個自定義視圖,用於我們的 Book。
我們將首先創建一個簡單的 Projection,名為 CustomBook:
@Projection(
name = "customBook",
types = { Book.class })
public interface CustomBook {
String getTitle();
}
請注意,我們的投影定義為具有 @Projection 註解的接口。我們可以使用 name 屬性來自定義投影的名稱,以及 types 屬性來定義其應用的對象。
在我們的示例中,CustomBook 投影將僅包含書的 title,而忽略 isbn。
讓我們再次查看在創建投影后,我們的 Book 表示形式:
{
"title" : "Animal Farm",
"isbn" : "978-1943138425",
"_links" : {
"self" : {
"href" : "http://localhost:8080/books/1"
},
"book" : {
"href" : "http://localhost:8080/books/1{?projection}",
"templated" : true
},
"authors" : {
"href" : "http://localhost:8080/books/1/authors"
}
}
}
太好了,我們可以看到指向我們的投影的鏈接。讓我們檢查在 http://localhost:8080/books/1?projection=customBook 創建的視圖:
{
"title" : "Animal Farm",
"_links" : {
"self" : {
"href" : "http://localhost:8080/books/1"
},
"book" : {
"href" : "http://localhost:8080/books/1{?projection}",
"templated" : true
},
"authors" : {
"href" : "http://localhost:8080/books/1/authors"
}
}
}
在這裏,我們可以看到我們只獲取 title 字段,而 isbn 字段不再出現在自定義視圖中。
作為一般規則,我們可以通過 http://localhost:8080/books/1?projection={projection name} 訪問投影的結果。
此外,請注意,我們需要在模型包中定義我們的 Projection。 另一種方法是使用 RepositoryRestConfigurerAdapter 顯式添加它:
@Configuration
public class RestConfig implements RepositoryRestConfigurer {
@Override
public void configureRepositoryRestConfiguration(
RepositoryRestConfiguration repositoryRestConfiguration, CorsRegistry cors) {
repositoryRestConfiguration.getProjectionConfiguration()
.addProjection(CustomBook.class);
}
}
4. 添加新數據到投影
現在,讓我們看看如何向我們的投影添加新數據。
正如我們在上一部分討論的,我們可以使用投影來選擇包含在視圖中的屬性。 此外,我們還可以添加未包含在原始視圖中的數據。
4.1. 隱藏數據
默認情況下,id 不包含在原始資源視圖中。
要查看結果中的 id,我們可以顯式包含 id 字段:
@Projection(
name = "customBook",
types = { Book.class })
public interface CustomBook {
@Value("#{target.id}")
long getId();
String getTitle();
}
現在,在 http://localhost:8080/books/1?projection={projection name} 的輸出將是:
{
"id" : 1,
"title" : "Animal Farm",
"_links" : {
...
}
}
請注意,我們還可以使用 @JsonIgnore 隱藏的原始視圖中的數據。
4.2. 計算數據
我們還可以包含從資源屬性計算的新數據。
例如,我們可以包含作者數量在我們的投影中:
@Projection(name = "customBook", types = { Book.class })
public interface CustomBook {
@Value("#{target.id}")
long getId();
String getTitle();
@Value("#{target.getAuthors().size()}")
int getAuthorCount();
}
我們可以檢查它在 http://localhost:8080/books/1?projection=customBook:
{
"id" : 1,
"title" : "Animal Farm",
"authorCount" : 1,
"_links" : {
...
}
}
4.3. 輕鬆訪問相關資源
最後,如果我們需要訪問相關資源——比如在我們的例子中,一本書的作者,我們可以避免額外的請求,而是顯式包含它們:
@Projection(
name = "customBook",
types = { Book.class })
public interface CustomBook {
@Value("#{target.id}")
long getId();
String getTitle();
List<Author> getAuthors();
@Value("#{target.getAuthors().size()}")
int getAuthorCount();
}
最終 Projection 輸出將是:
{
"id" : 1,
"title" : "Animal Farm",
"authors" : [ {
"name" : "George Orwell"
} ],
"authorCount" : 1,
"_links" : {
"self" : {
"href" : "http://localhost:8080/books/1"
},
"book" : {
"href" : "http://localhost:8080/books/1{?projection}",
"templated" : true
},
"authors" : {
"href" : "http://localhost:8080/books/1/authors"
}
}
}
接下來,我們將查看摘錄。
Let’s customize our attribute of the @RepositoryRestResource(excerptProjection = CustomBook.class)
public interface BookRepository extends CrudRepository<Book, Long> {}
Now we can make sure that :
{
"_embedded" : {
"books" : [ {
"id" : 1,
"title" : "Animal Farm",
"authors" : [ {
"name" : "George Orwell"
} ],
"authorCount" : 1,
"_links" : {
"self" : {
"href" : "http://localhost:8080/books/1"
},
"book" : {
"href" : "http://localhost:8080/books/1{?projection}",
"templated" : true
},
"authors" : {
"href" : "http://localhost:8080/books/1/authors"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/books"
},
"profile" : {
"href" : "http://localhost:8080/profile/books"
}
}
}
The same applies to viewing books by a specific author at {
"_embedded" : {
"books" : [ {
"id" : 1,
"authors" : [ {
"name" : "George Orwell"
} ],
"authorCount" : 1,
"title" : "Animal Farm",
"_links" : {
"self" : {
"href" : "http://localhost:8080/books/1"
},
"book" : {
"href" : "http://localhost:8080/books/1{?projection}",
"templated" : true
},
"authors" : {
"href" : "http://localhost:8080/books/1/authors"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/authors/1/books"
}
}
}
As mentioned, excerpts apply automatically only to collection resources. For a single resource, we have to use the .
6. 結論
我們學習瞭如何使用 Spring Data REST 投影來創建我們模型的自定義視圖。我們還學習瞭如何使用摘錄作為默認視圖,用於資源集合。
Now we can make sure that :
{
"_embedded" : {
"books" : [ {
"id" : 1,
"title" : "Animal Farm",
"authors" : [ {
"name" : "George Orwell"
} ],
"authorCount" : 1,
"_links" : {
"self" : {
"href" : "http://localhost:8080/books/1"
},
"book" : {
"href" : "http://localhost:8080/books/1{?projection}",
"templated" : true
},
"authors" : {
"href" : "http://localhost:8080/books/1/authors"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/books"
},
"profile" : {
"href" : "http://localhost:8080/profile/books"
}
}
}
The same applies to viewing books by a specific author at {
"_embedded" : {
"books" : [ {
"id" : 1,
"authors" : [ {
"name" : "George Orwell"
} ],
"authorCount" : 1,
"title" : "Animal Farm",
"_links" : {
"self" : {
"href" : "http://localhost:8080/books/1"
},
"book" : {
"href" : "http://localhost:8080/books/1{?projection}",
"templated" : true
},
"authors" : {
"href" : "http://localhost:8080/books/1/authors"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/authors/1/books"
}
}
}
As mentioned, excerpts apply automatically only to collection resources. For a single resource, we have to use the . 我們學習瞭如何使用 Spring Data REST 投影來創建我們模型的自定義視圖。我們還學習瞭如何使用摘錄作為默認視圖,用於資源集合。6. 結論