Spring Data REST 投影與片段

REST,Spring Data
Remote
0
11:27 AM · Dec 01 ,2025

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 投影來創建我們模型的自定義視圖。我們還學習瞭如何使用摘錄作為默認視圖,用於資源集合。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.