Выборочное расширение ассоциаций в ответе Spring Data Rest

У меня есть стандартная настройка Spring data JPA и Spring data Rest, которая правильно возвращает ассоциации как ссылки на правильные ресурсы.

{
    "id": 1,
    "version": 2,
    "date": "2011-11-22",
    "description": "XPTO",
    "_links": {
        "self": {
            "href": "http://localhost:8000/api/domain/1"
        },
        "otherDomain": {
            "href": "http://localhost:8000/api/domain/1/otherDomain"
        }
    }
}   

Однако в некоторых запросах я хотел бы иметь расширенную ассоциацию с «otherDomain» (чтобы клиенту не нужно было выполнять запросы N+1, чтобы получить полные данные).

Можно ли настроить Spring Data Rest для обработки ответа таким образом?


person Luis Santos    schedule 14.04.2014    source источник


Ответы (2)


Ответы по умолчанию должны оставаться прежними, чтобы убедиться, что полезная нагрузка для PUT запросов симметрична тем, которые возвращаются GET. Однако Spring Data REST представляет функцию, называемую прогнозами (подробности см. в тикете JIRA) который работает следующим образом:

Вы создаете выделенный интерфейс и добавляете все свойства, которые хотите включить в ответ:

public interface MyProjection {

  String getMyProperty();

  MyRelatedObject getOtherDomain();
}

Вы также можете

  • аннотируйте интерфейс с помощью @Projection и поместите его в тот же пакет, что и тип домена, или его подпакет
  • или вы вручную регистрируете проекцию, используя RepositoryRestConfiguration, и вызываете projectionConfiguration().addProjection(…) вручную (путем расширения RepositoryRestMvcConfiguration и переопределения configureRepositoryRestConfiguration(…)).

Это приведет к тому, что ресурсы, предоставляемые для типа домена, будут принимать параметр projection (имя также настраиваемое ProjectionConfiguration) с именем проекции. Если задано, мы пропустим рендеринг по умолчанию (который включает в себя рендеринг ссылок на связанные объекты вместо их встраивания) и позволим Джексону рендерить прокси, поддерживающий данный интерфейс.

Пример этого также можно найти в проекте Spring RESTBucks. См. OrderProjection для определения интерфейса.

person Oliver Drotbohm    schedule 14.04.2014
comment
Можно ли расширяться дальше по иерархии с помощью проекций? Например, если объект, стоящий за otherDomain, связан с oneMoreDomain, можно ли добавить его к исходному ответу? - person muenchdo; 10.09.2014
comment
Я думаю, что если ваш метод getOtherDomain() для MyProjection возвращает проекцию на oneMoreDomain, то это возможно. - person Ruslan Stelmachenko; 09.11.2014
comment
@Oliver Gierke, ТЫ СПАС МЕНЯ НЕКОТОРЫЙ БЕКОН! Это действительно должно быть в официальных документах, интересно, почему этого нет :( docs.spring.io/spring-data/rest/docs/2.2.1.RELEASE/reference/ На самом деле я хочу расширить некоторые EAGER ассоциации для проекции по умолчанию, но я могу похоже, этого не происходит :( Вы знаете, как? Итак, пока что @Projection работает... Подано jira.spring.io/browse/DATAREST-419 - person Hendy Irawan; 29.11.2014
comment
Оливер, я не думаю, что в справочных документах упоминается требование о том же пакете или подпакете. - person ; 08.04.2015
comment
@WillieWheeler - Хороший улов, я создал для этого DATAREST-508. - person Oliver Drotbohm; 08.04.2015
comment
Если мне нужен встроенный объект с идентификатором, как включить идентификатор во встроенный объект? - person SST; 17.10.2016

Мое решение применимо ко всем запросам, но некоторым оно может показаться уместным.

У меня есть симуляционная ситуация, когда у меня есть ассоциация userPersons, вложенная в мой ответ json User, например:

{
"_embedded":{
  "users":[
     {
        "userName":"Albert"
        "userPersons":[
           {
              "personId":2356,
              "activeBoolean":1
           },
           {
              "personId":123617783,
              "activeBoolean":1
           }
        ],
        "_links":{
           "self":{
              "href":"http://localhost:8080/api/users/1"
           }
        }
     }
  ]

} }

Моя базовая сущность выглядит так:

@Entity
public class User {


...

@Getter @Setter
private String userName;

@Getter @Setter
@OneToMany(mappedBy = "user")
private Set<Userperson> userPersons;

}

И один репозиторий:

@RepositoryRestResource
public interface UserRepo extends JpaRepository<User, Integer> {
}

Мое решение таково:

Просто НЕ раскрывая Userperson @RepositoryRestResource, Spring Data Rest встроит вашу ассоциацию.

Если вы определите @RepositoryRestResource для вложенного типа, Spring Data Rest отобразит ссылку на ресурс, а не встроит его.

Если вам нужен репозиторий вложенных типов для внутренней бизнес-логики, установите для него значение @RepositoryRestResource(exported = false), чтобы иметь такое же поведение.

Чтобы избежать проблемы 1+N, вы можете настроить ассоциацию для быстрой загрузки, возможно, используя @EntityGraph, например этого парня - хотя я еще не нашел лучшего способа реализовать это в Spring Data Rest.

person radrocket81    schedule 08.06.2017