1. 概要

この記事では、Spring DataRESTの投影と抜粋の概念について説明します。

プロジェクションを使用してモデルのカスタムビューを作成する方法と、リソースコレクションのデフォルトビューとして抜粋を使用する方法を学習します。

2. 私たちのドメインモデル

まず、ドメインモデルを定義することから始めましょう:BookAuthor。

Bookエンティティクラスを見てみましょう。

@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;
}

そして、 Author モデル:

@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;
}

2つのエンティティには、多対多の関係もあります。

次に、各モデルの標準Spring DataRESTリポジトリを定義しましょう。

public interface BookRepository extends CrudRepository<Book, Long> {}
public interface AuthorRepository extends CrudRepository<Author, Long> {}

これで、 Book エンドポイントにアクセスして、 http:// localhost:8080 / books / {id}:のIDを使用して特定のBookのの詳細を取得できます。

{
  "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"
    }
  }
}

Author モデルにはリポジトリがあるため、作成者の詳細は応答の一部ではないことに注意してください。 ただし、それらへのリンクは見つかります– http:// localhost:8080 / books / 1/authors。

3. プロジェクションの作成

エンティティの属性のサブセットまたはカスタムビューのみに関心がある場合があります。 そのような場合、予測を利用することができます。

Spring Data RESTプロジェクションを使用して、Bookのカスタムビューを作成しましょう。

まず、CustomBookという単純なProjectionを作成します。

@Projection(
  name = "customBook", 
  types = { Book.class }) 
public interface CustomBook { 
    String getTitle();
}

私たちのプロジェクションは、@Projectionアノテーションを持つインターフェースとして定義されていることに注意してください。 name 属性を使用してプロジェクションの名前をカスタマイズしたり、types属性を使用して適用するオブジェクトを定義したりできます。

この例では、 CustomBook プロジェクションには、本のtitleのみが含まれます。

Projection:を作成した後、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={projectionname}でプロジェクションの結果にアクセスできます。

また、モデルと同じパッケージで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 = {projectionname}での出力は次のようになります。

{
  "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"
    }
  }
}

次に、抜粋を見ていきます。

5. 抜粋

抜粋は、リソースコレクションのデフォルトビューとして適用する予測です。

BookRepository をカスタマイズして、コレクションの応答に customBook Projectionを自動的に使用してみましょう。

これを実現するために、@RepositoryRestResourceアノテーションのexcerptProjection属性を使用します。

@RepositoryRestResource(excerptProjection = CustomBook.class)
public interface BookRepository extends CrudRepository<Book, Long> {}

これで、 http:// localhost:8080 / books を呼び出すことで、customBookが書籍コレクションのデフォルトビューであることを確認できます。

{
  "_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"
    }
  }
}

同じことがhttp:// localhost:8080 / authors / 1 /booksで特定の著者による本を表示する場合にも当てはまります。

{
  "_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"
    }
  }
}

前述のように、抜粋はコレクションリソースにのみ自動的に適用されます。 単一のリソースの場合、前のセクションで示したように、Projectionパラメーターを使用する必要があります。

これは、単一のリソースのデフォルトビューとしてプロジェクションを適用すると、部分的なビューからリソースを更新する方法を知ることが難しくなるためです。

最後に、の投影と抜粋は読み取り専用を目的としていることを覚えておくことが重要です。

6. 結論

SpringDataRESTプロジェクションを使用してモデルのカスタムビューを作成する方法を学びました。 また、リソースコレクションのデフォルトビューとして抜粋を使用する方法も学びました。

例の完全なソースコードは、GitHubにあります。