2015-07-13 8 views
10

Poszłam za this example, co pozwala wysłać unikalny obiekt Person. Chcę usługi REST, gdzie mogę opublikować kolekcję Person na raz, np. listę/kolekcję o nazwie Team z wieloma obiektami Person w jednym wywołaniu.jak wysłać listę do Spring Data Reszta

Mam na myśli, że moje wątpliwości nie dotyczą dokładnie jednego związku, w którym wysyła się każdą osobę w każdym wywołaniu REST w sieci. Ten temat to well answered.

Chcę wysłać kolekcję obiektów Person, korzystając z @RepositoryRestResource lub innej funkcji z usługi Spring Data Rest. Czy jest to możliwe dzięki Spring Data Rest lub czy powinienem obejść ten problem, tworząc kontroler, otrzymuję listę i analizuję listę Team, aby wstawić każdy Person?

Znalazłem this feature request, który wydaje się odpowiadać, że brakujące dane w czasie odpoczynku wiosennego nie są zgodne z oczekiwaniami, ale nie jestem pewien.

Zgodnie z moim wymaganiem biznesowym, aplikacja A opublikuje listę zamówień do aplikacji B i będę musiał zapisać ją w bazie danych dla przyszłego procesu, więc po przeczytaniu o Spring Data Rest i zrobieniu kilku próbek odkryłem, że jest on niesamowicie czysty. architektura i bardzo nadaje się do moich wymagań, z wyjątkiem faktu, że nie wymyśliłem, jak wysłać, aby opublikować listę.

Odpowiedz

8

Cóż, AFAIK, nie możesz tego zrobić z wiosennym odpoczynkiem danych, po prostu przeczytaj dokumenty i zobaczysz, że nie ma żadnej wzmianki o umieszczeniu listy w zasobach kolekcji.

Przyczyna tego jest dla mnie niejasna, ale z jednej strony - sam REST nie określa dokładnie, jak należy wykonywać operacje wsadowe. Więc nie jest jasne, w jaki sposób należy podejść do tej funkcji, na przykład, czy powinieneś POST wyświetlić listę do zasobu kolekcji? A może wyeksportować zasoby takie jak /someentity/batch, które będą mogły poprawiać, usuwać i dodawać elementy w jednej partii? Jeśli dodasz listę, jak powinieneś zwrócić identyfikatory? Dla pojedynczego POST do zbierania danych źródłowych spoczynkowych w nagłówku Location. W przypadku dodawania wsadowego nie można tego zrobić.

Nie usprawiedliwia to braku operacji wsadowych w trybie wiosennych danych. Powinny wdrożyć tę IMHO, ale przynajmniej mogą pomóc zrozumieć, dlaczego ich brakuje.

Mogę jednak powiedzieć, że zawsze możesz dodać własny kontroler do projektu, który będzie poprawnie obsługiwał/dobrać/wsadowo, a nawet będziesz mógł z niego zrobić bibliotekę, dzięki czemu będziesz mógł z niego korzystać w innych projektach. . Lub nawet dane sprężystych wideł i dodaj tę funkcję. Chociaż starałem się zrozumieć, jak to działa i zawiodło do tej pory. Ale prawdopodobnie wiesz wszystko, prawda?

There is a feature request for this.

+0

Rozważę swoją odpowiedź jako ostatecznej odpowiedzi: „Wiosna Dane reszta nie może użyj, aby otrzymać listę ". Oczywiście, szanuję to, ale dla mnie Spring Data Rest byłaby o wiele bardziej użyteczna, gdyby otrzymała listę i wstawiła do bazy danych. Oczywiście mogę to zrobić bez Spring Data Rest. Wystarczy utworzyć kontroler z @RequestBody List , a następnie dodać wszystkie dane w bazie danych. Niemniej jednak często korzystałbym z Spring Data Rest, jeśli mógłbym opublikować listę w mojej usłudze. –

+0

@JimC Tak, ja też. Jest problem dotyczący operacji wsadowych w ich JIRA, jak sądzę. Próbowałem utworzyć inny problem - SDR nie obsługuje adnotacji OrderColumn - ale nie otrzymałem żadnej odpowiedzi. – user1685095

0

Próbowałem użyć @RequestBody List<Resource<MyPojo>>. Gdy treść żądania nie zawiera żadnych linków, działa dobrze, ale jeśli element przenosi łącze, serwer nie może przekształcić hierarchii treści żądania.

Potem próbowałem użyć @RequestBody Resources<MyPojo>, ale nie mogłem znaleźć domyślnej nazwy listy.

W końcu próbowałem opakowanie, które zawierało List<Resource<MyPojo>> i działało.

Oto moje rozwiązanie:

Najpierw utworzyć klasy otoki dla List<Resource<MyPojo>>:

public class Bulk<T> { 
    private List<Resource<T>> bulk; 
    // getter and setter 
} 

Następnie użyj @RequestBody Resource<Bulk<MyPojo>> parametrów.

Wreszcie przykład json z linkami do tworzenia danych zbiorczych w jedno żądanie:

{ 
    "bulk": [ 
     { 
      "title": "Spring in Action", 
      "author": "http://localhost:8080/authors/1" 
     }, 
     { 
      "title": "Spring Quick Start", 
      "author": "http://localhost:8080/authors/2" 
     } 
    ] 
} 
2

podstawie user1685095answer, można dokonać zwyczaj Controller PersonRestController i wystawiać po collection of Person, gdyż nie wydają jeszcze wystawiony przez 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 naprawić:

Nie można deserializować instancję org.springframework.hateoas.Resources z START_ARRAY żeton \ n na [Źródło: [email protected]; Linia: 1, kolumna 1]

Aktualizacja

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 
} 
+0

Czy możesz wyjaśnić, czym jest klasa Wrapper? Dzięki – drenda

+1

@drenda Sprawdź aktualizację mojej odpowiedzi, –

+0

Dziękuję. Teraz jest jasne! – drenda

0

myślę Khaled Lela kod przykładem jest prawidłowe. Ale chciałbym to wyjaśnić. Proponuję wariant z HAL i bez opakowania. Myślę, że poniższy kod nie jest wystarczająco wypełniony. Wiem, że to nie jest idealne. Może być krótszy i bardziej poprawny.

Wariant 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); 
    } 
} 

Należy zauważyć, że trzeba użyć application/hal+json zamiast application/json w swoich żądań REST. Albo można zmienić wartość consumes i produces jak poniżej

@PostMapping(
     value = "/batch", 
     consumes = {MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE}, 
     produces = {MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE} 
) 

Wariant 2 (HAL + paginacja)

@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); 
    } 
}