1. Обзор
В этой статье мы рассмотрим концепции проекций и выдержек Spring Data REST.
Мы узнаем, как использовать проекции для создания пользовательских представлений наших моделей и как использовать выдержки в качестве представлений по умолчанию для коллекций ресурсов .
2. Наши Доменные модели
Во-первых, давайте начнем с определения наших моделей предметной области: Книга и Автор.
Давайте взглянем на класс сущностей 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 Listauthors; }
И Автор модель:
@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 Listbooks; }
Эти две сущности также имеют отношение “многие ко многим”.
Далее давайте определим стандартные репозитории Spring Data REST для каждой из моделей:
public interface BookRepository extends CrudRepository{}
public interface AuthorRepository extends CrudRepository{}
Теперь мы можем получить доступ к конечной точке Book , чтобы получить конкретную информацию Book , используя ее идентификатор в 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" } } }
Обратите внимание, что поскольку модель Author имеет свой репозиторий, сведения об авторах не являются частью ответа. Мы можем, однако, найти ссылку на них – http://localhost:8080/books/1/authors.
3. Создание проекции
Иногда нас интересует только подмножество или пользовательское представление атрибутов сущности . Для таких случаев мы можем использовать проекции.
Давайте создадим пользовательский вид для нашей Книги , используя весенние проекции отдыха данных.
Мы начнем с создания простой проекции под названием Custom Book :
@Projection( name = "customBook", types = { Book.class }) public interface CustomBook { String getTitle(); }
Обратите внимание, что наша проекция определяется как интерфейс с @Projection аннотацией . Мы можем использовать атрибут name для настройки имени проекции, а также атрибуты types для определения объектов, к которым она применяется.
В нашем примере проекция Custom Book будет включать только title книги.
Давайте еще раз взглянем на наше Электронное представление после создания нашей проекции:
{ "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={имя проекции}.
Кроме того, обратите внимание, что нам нужно определить нашу проекцию в том же пакете, что и наши модели. В качестве альтернативы мы можем использовать Repository Rest Configured Adapter для его явного добавления:
@Configuration public class RestConfig implements RepositoryRestConfigurer { @Override public void configureRepositoryRestConfiguration( RepositoryRestConfiguration repositoryRestConfiguration) { repositoryRestConfiguration.getProjectionConfiguration() .addProjection(CustomBook.class); } }
4. Добавление новых данных в прогнозы
Теперь давайте посмотрим, как добавить новые данные в нашу проекцию.
Как мы обсуждали в предыдущем разделе, мы можем использовать проекцию, чтобы выбрать, какие атрибуты включить в наше представление. Более того, мы также можем добавить данные, которые не включены в исходное представление.
4.1. Скрытые данные
По умолчанию идентификаторы не включаются в исходное представление ресурсов.
Чтобы увидеть детей в результате, мы можем включить поле id явно:
@Projection( name = "customBook", types = { Book.class }) public interface CustomBook { @Value("#{target.id}") long getId(); String getTitle(); }
Теперь выход на http://localhost:8080/books/1?projection={имя проекции} будет:
{ "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(); ListgetAuthors(); @Value("#{target.getAuthors().size()}") int getAuthorCount(); }
И окончательный Проекционный выход будет:
{ "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. Выдержки
Выдержки-это проекции, которые мы применяем в качестве представлений по умолчанию к коллекциям ресурсов.
Давайте настроим наш Книжный репозиторий для автоматического использования пользовательской книги | Проекции для ответа коллекции.
Для достижения этой цели мы будем использовать атрибут excerpt Projection аннотации @RepositoryRestResource :
@RepositoryRestResource(excerptProjection = CustomBook.class) public interface BookRepository extends CrudRepository{}
Теперь мы можем убедиться, что custom Book является представлением по умолчанию для коллекции книг, вызвав http://localhost:8080/books :
{ "_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. Заключение
Мы научились использовать проекции Spring Data REST для создания пользовательских представлений наших моделей. Мы также узнали, как использовать выдержки в качестве представлений по умолчанию для коллекций ресурсов.
Полный исходный код примеров можно найти на GitHub .