Рубрики
Без рубрики

Прогнозы и выдержки из весенних данных ОТДЫХАЮТ

Создавайте пользовательские представления сущностей в Spring Data REST с помощью проекций и выдержек.

Автор оригинала: baeldung.

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 List 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 books;
}

Эти две сущности также имеют отношение “многие ко многим”.

Далее давайте определим стандартные репозитории 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();
    
    List getAuthors();
    
    @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 .