Отключить язык приложений гипертекста (HAL) в JSON?
Использование Spring Data REST с JPA в версии 2.0.2.RELEASE.
Как отключить язык гипертекстовых приложений (HAL) в JSON? http://stateless.co/hal_specification.html
Я уже много пробовал, но безрезультатно. Например, я установил заголовки Accept и Content-type в "application/json" вместо "application/hal + json", но я все еще получаю содержимое JSON с гиперссылками.
Например, я хотел бы получить что-то вроде:
{
"name" : "Foo",
"street" : "street Bar",
"streetNumber" : 2,
"streetLetter" : "b",
"postCode" : "D-1253",
"town" : "Munchen",
"country" : "Germany",
"phone" : "+34 4410122000",
"vat" : "000000001",
"employees" : 225,
"sector" : {
"description" : "Marketing",
"average profit": 545656665,
"average employees": 75,
"average profit per employee": 4556
}
}
Вместо:
{
"name" : "Foo",
"street" : "street Bar",
"streetNumber" : 2,
"streetLetter" : "b",
"postCode" : "D-1253",
"town" : "Munchen",
"country" : "Germany",
"phone" : "+34 4410122000",
"vat" : "000000001",
"employees" : 225,
"_links" : {
"self" : {
"href" : "http://localhost:8080/app/companies/1"
},
"sector" : {
"href" : "http://localhost:8080/app/companies/1/sector"
}
}
}
Спасибо за вашу помощь.
Ответы
Ответ 1
(Hyper) типы носителей
Настройки по умолчанию для Spring Data REST используют HAL в качестве формата представления гипермедиа по умолчанию, поэтому сервер будет возвращать следующие данные для указанных заголовков Accept
:
- Нет заголовка →
application/hal+json
→ HAL
-
application/hal+json
→ application/hal+json
→ HAL
-
application/json
→ application/json
→ HAL (это то, что настраивается по умолчанию)
-
application/x-spring-data-verbose+json
→ application/x-spring-data-verbose+json
→ a Spring Формат данных (с помощью links
для контейнера ссылок и content
в качестве обертки для элементов коллекции.
Если вы настроите RepositoryRestConfiguration.setDefaultMediaType(…)
на не-HAL-формат, сервер вернет формат JSON, специфичный для данных Spring, если вы явно не запросите application/hal+json
. Разумеется, вариант конфигурации, вероятно, немного вводит в заблуждение, поэтому я добавил DATAREST-294, чтобы улучшить это. Проблема была решена в 2.1 RC1 (Dijkstra) 2014.
Обратите внимание, что нам действительно нужен формат гипермедиа, чтобы иметь возможность выражать отношения между управляемыми ресурсами и обеспечивать возможность обнаружения сервера. Таким образом, вы не сможете полностью избавиться от него. Это связано в основном с тем, что вы можете легко свернуть сервер, если вы обнаружите объекты, которые имеют двунаправленные отношения или составляют огромный граф объектов.
Встраивание связанных объектов
Если вы никогда не хотите иметь секторы, связанные с ними и всегда встраивать их, один параметр состоит в том, чтобы просто исключить SectorRepository
из экспорта в качестве ресурса REST в первую очередь. Вы можете достичь этого, аннотируя интерфейс репозитория с помощью @RepositoryRestResource(exported = false)
.
Чтобы получить представление, возвращенное, как вы разместили в своем нижнем примере, посмотрите на проекции, введенные в Spring Data REST 2.1 M1, Это в основном позволяет создавать дополнительные представления на ресурсе, который может отличаться от стандартного с помощью простого интерфейса.
В основном вы определяете интерфейс:
@Projection(name = "foo", types = YourDomainClass.class)
interface Inlined {
// list all other properties
Sector getSector();
}
Если вы поместите этот интерфейс в (дополнительный) пакет вашего класса домена или вручную зарегистрируйте его через RepositoryRestConfiguration.projectionConfiguration()
, ресурсы, отображающие YourDomainClass
, будут принимать параметр запроса projection
, так что передача в foo
в этом пример предоставил бы встроенное представление так, как вы хотите.
Этот коммит содержит больше информации об этой функции в целом, this commit имеет пример проекции.
Ответ 2
Итак, вы хотите 2 вещи:
1) избавиться от поля _links
2) включить поле соответствующего sector
Возможное решение (у меня работает: D)
1) избавиться от _links
Для этого создайте класс ниже:
[... package declaration, imports ...]
public class MyRepositoryRestMvcConfiguration extends RepositoryRestMvcConfiguration {
public MyRepositoryRestMvcConfiguration(ApplicationContext context, ObjectFactory<ConversionService> conversionService) {
super(context, conversionService);
}
@Bean
protected LinkCollector linkCollector() {
return new LinkCollector(persistentEntities(), selfLinkProvider(), associationLinks()) {
public Links getLinksFor(Object object, List<Link> existingLinks) {
return new Links();
}
};
}
}
и использовать его, например:
[... package declaration, imports ...]
@SpringBootApplication
@Import({MyRepositoryRestMvcConfiguration.class})
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
Я почти уверен (99%, но не протестирован), что вам не понадобится этот класс для удаления _links
для связанных сущностей/сущностей, включенных в способ, который показывает следующая точка (2).
2) включить поле соответствующего sector
Для этого вы можете использовать выдержки (специально созданные для этого сценария). Поскольку пример Spring настолько красноречив, и просто глупо просто копировать его здесь, я просто укажу на него: https://docs.spring.io/spring-data/rest/docs/3.1.x/reference/html/#projection -excerpts.excerpting-общедоступные данные.
Но для удобства и удобства я вставлю основные части весеннего примера:
@Projection(name = "inlineAddress", types = { Person.class })
interface InlineAddress {
String getFirstName();
String getLastName();
Address getAddress();
}
увидеть на Javadoc проекционного, что types
означают тип типа проекции, связанный с.
Выдержка может быть использована следующим образом:
@RepositoryRestResource(excerptProjection = InlineAddress.class)
interface PersonRepository extends CrudRepository<Person, Long> {}
чтобы получить это (когда также используется MyRepositoryRestMvcConfiguration):
{
"firstName" : "Frodo",
"lastName" : "Baggins",
"address" : {
"street": "Bag End",
"state": "The Shire",
"country": "Middle Earth"
}
}
Для вас sector
является эквивалентом address
.
Финальные заметки
При возврате массивов поле _links
не будет удалено (это слишком навязчиво для этого); в итоге у вас будет что-то вроде этого:
{
"_embedded" : {
"persons" : [ {person1}, {person2}, ..., {personN} ]
},
"_links" : {
e.g. first, next, last, self, profile
},
"page" : {
"size" : 1,
"totalElements" : 10,
"totalPages" : 10,
"number" : 0
}
}
Как вы можете видеть, даже если бы _links
удалили _links
этого все равно будет недостаточно; _embedded
было бы также хотеть, чтобы _embedded
заменялось persons
что приводило бы к менее поддерживаемому коду (слишком много весенних навязчивых переопределений). Но если кто-то действительно хочет этого, он должен начать проверять RepositoryRestMvcConfiguration
и RepositoryEntityController.getCollectionResource
.
Spring развивается, поэтому я чувствую необходимость указать, что это работает по крайней мере:
spring-data-rest-webmvc 3.1.3.RELEASE
или, если вы предпочитаете весеннюю загрузку:
spring-boot-starter-parent 2.1.1.RELEASE