Как отправить список 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);
    }
}