Как отправить список Spring Data Rest
Я последовал за этот пример, который позволяет публиковать уникальный объект Person
. Я хочу службу REST, где я могу опубликовать коллекцию Person
сразу, например. список/любую коллекцию с именем Team
с многочисленными объектами Person
всего за один вызов.
Я имею в виду, что мое сомнение связано не только с отношениями oneToMany, где вы отправляете каждого человека в каждом веб-REST-вызове. Эта тема ответила правильно.
Я хочу отправить коллекцию объектов Person
, используя @RepositoryRestResource
или другую функцию из Spring Data Rest. Возможно ли это с Spring Data Rest или я должен обходным путем создать контроллер, получить список и проанализировать список Team
, чтобы вставить каждый Person
?
Я нашел этот запрос функции, который, кажется, отвечает, что в день недели Spring Rest Data отсутствует то, что я ищу, но я не уверен.
В моем бизнес-требовании приложение A опубликует список заказов для приложения B, и я должен сохранить его в базе данных для будущего процесса, поэтому, прочитав о Spring Data Rest и сделав несколько образцов, я нашел удивительный чистая архитектура и очень подходит для моего требования, за исключением того факта, что я не понял, как отправить сообщение о списке.
Ответы
Ответ 1
Ну, AFAIK, вы не можете сделать это с остатком данных spring, просто прочитайте документы, и вы увидите, что нет упоминания о публикации списка в ресурсе коллекции.
Причина этого мне непонятна, но, с одной стороны, сам REST не указывает, как вы должны выполнять пакетные операции.
Так что непонятно, как следует подходить к этой функции, например, если вы ПОСТАЛИ список для ресурса сбора? Или вы должны экспортировать ресурс, например, /someentity/batch
, который сможет исправлять, удалять и добавлять объекты в одну партию? Если вы добавите список, как вы должны вернуть идентификаторы? Для одиночного POST для коллекции spring -data-rest return id в заголовке Location. Для пакетного добавления это не может быть сделано.
Это не оправдывает того, что spring -data-rest отсутствует пакетные операции. Они должны реализовать это ИМХО, но, по крайней мере, это может помочь понять, почему они, возможно, отсутствуют.
Я могу сказать, что вы всегда можете добавить свой собственный контроллер в проект, который будет обрабатывать /someentity/batch правильно, и вы даже можете сделать из него библиотеку, чтобы вы могли использовать ее в других проектах. Или даже fork spring -data-rest и добавьте эту функцию. Хотя я пытался понять, как это работает и до сих пор не удалось.
Но вы, наверное, все это знаете, верно?
Для этого есть запрос функции.
Ответ 2
На основе user1685095 answer вы можете создать пользовательский контроллер PersonRestController
и опубликовать сообщение collection of Person
, поскольку оно пока еще не отображается Spring-date-rest
@RepositoryRestController
@RequestMapping(value = "/persons")
public class PersonRestController {
private final PersonRepository repo;
@Autowired
public AppointmentRestController(PersonRepository repo) {
this.repo = repo;
}
@RequestMapping(method = RequestMethod.POST, value = "/batch", consumes = "application/json", produces = "application/json")
public @ResponseBody ResponseEntity<?> savePersonList(@RequestBody Resource<PersonWrapper<Person>> personWrapper,
PersistentEntityResourceAssembler assembler) {
Resources<Person> resources = new Resources<Person>(repo.save(personWrapper.getContent()));
//TODO add extra links `assembler`
return ResponseEntity.ok(resources);
}
}
PersonWrapper:
Невозможно десериализовать экземпляр org.springframework.hateoas.Resources из токена START_ARRAY\n в [Источник: [email protected]; строка: 1, столбец: 1]
Обновление
public class PersonWrapper{
private List<Person> content;
public List<Person> getContent(){
return content;
}
public void setContent(List<Person> content){
this.content = content;
}
}
public class Person{
private String name;
private String email;
// Other fields
// GETTER & SETTER
}
Ответ 3
Я попытался использовать @RequestBody List<Resource<MyPojo>>
.
Когда тело запроса не содержит ссылок, оно работает хорошо, но
если элемент имеет ссылку, сервер не может десериализовать тело запроса.
Затем я попытался использовать @RequestBody Resources<MyPojo>
, но не смог определить имя списка по умолчанию.
Наконец, я попробовал обертку, содержащую List<Resource<MyPojo>>
, и она работает.
Вот мое решение:
Сначала создайте класс-оболочку для List<Resource<MyPojo>>
:
public class Bulk<T> {
private List<Resource<T>> bulk;
// getter and setter
}
Затем используйте @RequestBody Resource<Bulk<MyPojo>>
для параметров.
Наконец, пример json со ссылками для создания объемных данных по одному запросу:
{
"bulk": [
{
"title": "Spring in Action",
"author": "http://localhost:8080/authors/1"
},
{
"title": "Spring Quick Start",
"author": "http://localhost:8080/authors/2"
}
]
}
Ответ 4
Я думаю, что пример кода Халед Лела верен. Но я хотел бы прояснить это. Я предлагаю вариант с HAL и без обертки. Я думаю, что код ниже недостаточно.
Я знаю, что это не идеально. Это может быть короче и правильнее.
Вариант 1 (HAL)
@RepositoryRestController
@RequestMapping(value = "/article")
public class ArticleController {
private final ArticleRepository repository;
@Autowired
ArticleController(ArticleRepository repository) {
this.repository = repository;
}
@Transactional
@PostMapping(
value = "/batch",
consumes = MediaTypes.HAL_JSON_VALUE,
produces = MediaTypes.HAL_JSON_VALUE
)
public @ResponseBody
ResponseEntity<?> createBatch(@RequestBody Article entities[], PersistentEntityResourceAssembler assembler) {
List<Resource<?>> resourceList = repository
.save(Arrays.asList(entities))
.stream()
.map(entity -> assembler.toFullResource(entity)) // add HAL links
.collect(Collectors.toList());
Resources<Resource<?>> resources = new Resources<>(resourceList);
return new ResponseEntity<>(resources, HttpStatus.CREATED);
}
}
Вы должны заметить, что вам нужно использовать application/hal+json
вместо application/json
в запросах REST.
Или вы можете изменить значение consumes
и produces
, как показано ниже
@PostMapping(
value = "/batch",
consumes = {MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE},
produces = {MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE}
)
Вариант 2 (HAL + pagination)
@RepositoryRestController
@RequestMapping(value = "/article")
public class ArticleController {
private final ArticleRepository repository;
private PagedResourcesAssembler pagedResourcesAssembler;
@Autowired
ArticleController(ArticleRepository repository, PagedResourcesAssembler pagedResourcesAssembler) {
this.repository = repository;
this.pagedResourcesAssembler = pagedResourcesAssembler;
}
@Transactional
@PostMapping(
value = "/batch",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaTypes.HAL_JSON_VALUE
)
public @ResponseBody
ResponseEntity<?> createBatch(
@RequestBody Article entities[],
Pageable pageable,
PersistentEntityResourceAssembler assembler
) {
if (entities.length == 0) {
return new ResponseEntity<>(new Resources<>(Collections.emptyList()), HttpStatus.NO_CONTENT);
}
Page<?> page = new PageImpl<>(
repository.save(Arrays.asList(entities)),
pageable,
pageable.getPageSize()
);
PagedResources<?> resources = pagedResourcesAssembler.toResource(page, assembler);
return new ResponseEntity<>(resources, HttpStatus.CREATED);
}
}