web-dev-qa-db-ja.com

ページ分割されたAPIを使用したSpring RestTemplate

REST APIはページで結果を返します。これは1つのコントローラーの例です

@RequestMapping(value = "/search", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8")
@ResponseStatus(HttpStatus.OK)
public Page<MyObject> findAll(Pageable pageable) {
  ...
}

RestTemplateでそのAPIを使用する簡単な方法はありますか?

私たちがやれば

ParameterizedTypeReference<Page<MyObject>> responseType = new ParameterizedTypeReference<Page<MyObject>>() { };

ResponseEntity<Page<MyObject>> result = restTemplate.exchange(url, HttpMethod.GET, null/*httpEntity*/, responseType);

List<MyObject> searchResult = result.getBody().getContent();

例外をスローします

org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Can not construct instance of org.springframework.data.domain.Page, 
problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information at [Source: Java.io.PushbackInputStream@3be1e1f2; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of org.springframework.data.domain.Page, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information

前もって感謝します

32
turgos

Rest APIレスポンスを読み取るコードを次のように変更しました。

ParameterizedTypeReference<RestResponsePage<MyObject>> responseType = new ParameterizedTypeReference<RestResponsePage<MyObject>>() { };

ResponseEntity<RestResponsePage<MyObject>> result = restTemplate.exchange(url, HttpMethod.GET, null/*httpEntity*/, responseType);

List<MyObject> searchResult = result.getBody().getContent();

そして、これは私がRestResponsePageのために作成したクラスです

package com.basf.gb.cube.seq.vaadinui.util;

import Java.util.ArrayList;
import Java.util.List;

import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;

public class RestResponsePage<T> extends PageImpl<T>{

  private static final long serialVersionUID = 3248189030448292002L;

  public RestResponsePage(List<T> content, Pageable pageable, long total) {
    super(content, pageable, total);
    // TODO Auto-generated constructor stub
  }

  public RestResponsePage(List<T> content) {
    super(content);
    // TODO Auto-generated constructor stub
  }

  /* PageImpl does not have an empty constructor and this was causing an issue for RestTemplate to cast the Rest API response
   * back to Page.
   */
  public RestResponsePage() {
    super(new ArrayList<T>());
  }

} 
13
turgos

Spring Boot 1.xから2.0に移行するとき、Rest API応答を読み取るコードを次のように変更しました。

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;

import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

import Java.util.ArrayList;
import Java.util.List;

public class RestPageImpl<T> extends PageImpl<T>{

    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    public RestPageImpl(@JsonProperty("content") List<T> content,
                        @JsonProperty("number") int number,
                        @JsonProperty("size") int size,
                        @JsonProperty("totalElements") Long totalElements,
                        @JsonProperty("pageable") JsonNode pageable,
                        @JsonProperty("last") boolean last,
                        @JsonProperty("totalPages") int totalPages,
                        @JsonProperty("sort") JsonNode sort,
                        @JsonProperty("first") boolean first,
                        @JsonProperty("numberOfElements") int numberOfElements) {

        super(content, PageRequest.of(number, size), totalElements);
    }

    public RestPageImpl(List<T> content, Pageable pageable, long total) {
        super(content, pageable, total);
    }

    public RestPageImpl(List<T> content) {
        super(content);
    }

    public RestPageImpl() {
        super(new ArrayList<>());
    }
}
24
장재훈

上記を拡張しますが、すべてのプロパティを実装する必要はありません。

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

import Java.util.ArrayList;
import Java.util.List;

public class RestPageImpl<T> extends PageImpl<T>{

    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    public RestPageImpl(@JsonProperty("content") List<T> content,
                        @JsonProperty("number") int page,
                        @JsonProperty("size") int size,
                        @JsonProperty("totalElements") long total) {
        super(content, new PageRequest(page, size), total);
    }

    public RestPageImpl(List<T> content, Pageable pageable, long total) {
        super(content, pageable, total);
    }

    public RestPageImpl(List<T> content) {
        super(content);
    }

    public RestPageImpl() {
        super(new ArrayList());
    }
}
8
Stephen

Pageを実装する必要はありません。 ParameterizedTypeReferenceの型としてPagedResources<T>を使用する必要があります。

そのため、サービスが次のような応答を返した場合(簡潔にするためにオブジェクトは削除されます):

{
    "_embedded": {
        "events": [
            {...},
            {...},
            {...},
            {...},
            {...}
        ]
    },
    "_links": {
        "first": {...},
         "self": {...},
         "next": {...},
         "last": {...}
    },
    "page": {
        "size": 5,
        "totalElements": 30,
        "totalPages": 6,
        "number": 0
    }
}

そして、あなたが気にするオブジェクトはEvent型であり、次のようにリクエストを実行する必要があります:

ResponseEntity<PagedResources<Event>> eventsResponse = restTemplate.exchange(uriBuilder.build(true).toUri(),
                HttpMethod.GET, null, new ParameterizedTypeReference<PagedResources<Event>>() {});

次のようなリソースを入手した場合:

PagedResources<Event> eventsResources = eventsResponse.getBody();

ページのメタデータ("page"セクションで取得したもの)、リンク("_links"セクション)およびコンテンツにアクセスできます。

Collection<Event> eventsCollection = eventsResources.getContent();
3
Vladimir Mitev

最近導入されたと思われるemptyの未知のプロパティを無視するように、小さな変更を行う必要がありました。

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

import Java.util.ArrayList;
import Java.util.List;

@JsonIgnoreProperties(ignoreUnknown = true)
public class RestResponsePage<T> extends PageImpl<T> {
    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    public RestResponsePage(@JsonProperty("content") List<T> content,
                            @JsonProperty("number") int number,
                            @JsonProperty("size") int size,
                            @JsonProperty("totalElements") Long totalElements,
                            @JsonProperty("pageable") JsonNode pageable,
                            @JsonProperty("last") boolean last,
                            @JsonProperty("totalPages") int totalPages,
                            @JsonProperty("sort") JsonNode sort,
                            @JsonProperty("first") boolean first,
                            @JsonProperty("numberOfElements") int numberOfElements) {

        super(content, PageRequest.of(number, size), totalElements);
    }

    public RestResponsePage(List<T> content, Pageable pageable, long total) {
        super(content, pageable, total);
    }

    public RestResponsePage(List<T> content) {
        super(content);
    }

    public RestResponsePage() {
        super(new ArrayList<>());
    }
}
1
Loren

投稿されたソリューションは、合計要素が正しく設定されていなかったため、私にとってはうまくいきませんでした。デリゲートパターンを使用してページを実装しました。作業コードは次のとおりです。

import org.springframework.core.convert.converter.Converter;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

import Java.util.ArrayList;
import Java.util.Iterator;
import Java.util.List;

public class RestPage<T> implements Page<T> {
    private PageImpl<T> pageDelegate = new PageImpl<>(new ArrayList<>(0));

    public List<T> getContent() {
        return pageDelegate.getContent();
    }

    public int getNumber() {
        return pageDelegate.getNumber();
    }

    public int getNumberOfElements() {
        return pageDelegate.getNumberOfElements();
    }

    public int getSize() {
        return pageDelegate.getSize();
    }

    public Sort getSort() {
        return pageDelegate.getSort();
    }

    public long getTotalElements() {
        return pageDelegate.getTotalElements();
    }

    public int getTotalPages() {
        return pageDelegate.getTotalPages();
    }

    public boolean hasContent() {
        return pageDelegate.hasContent();
    }

    public boolean hasNext() {
        return pageDelegate.hasNext();
    }

    public boolean hasPrevious() {
        return pageDelegate.hasPrevious();
    }

    public boolean isFirst() {
        return pageDelegate.isFirst();
    }

    public boolean isLast() {
        return pageDelegate.isLast();
    }

    public Iterator<T> iterator() {
        return pageDelegate.iterator();
    }

    public <S> Page<S> map(Converter<? super T, ? extends S> converter) {
        return pageDelegate.map(converter);
    }

    public Pageable nextPageable() {
        return pageDelegate.nextPageable();
    }

    public Pageable previousPageable() {
        return pageDelegate.previousPageable();
    }

    public void setContent(List<T> content) {
        pageDelegate = new PageImpl<>(content, null, getTotalElements());
    }


    public void setTotalElements(int totalElements) {
        pageDelegate = new PageImpl<>(getContent(), null, totalElements);
    }

    public String toString() {
        return pageDelegate.toString();
    }
}
0

Kotlinのソリューション

import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.JsonNode
import org.springframework.data.domain.PageImpl
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Pageable

import Java.util.ArrayList

class RestResponsePage<T> : PageImpl<T> {
    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    constructor(@JsonProperty("content") content: List<T>,
                @JsonProperty("number") number: Int,
                @JsonProperty("size") size: Int,
                @JsonProperty("totalElements") totalElements: Long?,
                @JsonProperty("pageable") pageable: JsonNode,
                @JsonProperty("last") last: Boolean,
                @JsonProperty("totalPages") totalPages: Int,
                @JsonProperty("sort") sort: JsonNode,
                @JsonProperty("first") first: Boolean,
                @JsonProperty("numberOfElements") numberOfElements: Int) : super(content, PageRequest.of(number, size), totalElements!!) {
    }

    constructor(content: List<T>, pageable: Pageable, total: Long) : super(content, pageable, total) {}

    constructor(content: List<T>) : super(content) {}

    constructor() : super(ArrayList<T>()) {}
}

そしてリクエスト

var response: ResponseEntity<*> = restTemplate.getForEntity<RestResponsePage<SomeObject>>(url)

Javaでのソリューション

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

import Java.util.ArrayList;
import Java.util.List;

public class RestResponsePage<T> extends PageImpl<T> {
    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    public RestResponsePage(@JsonProperty("content") List<T> content,
                        @JsonProperty("number") int number,
                        @JsonProperty("size") int size,
                        @JsonProperty("totalElements") Long totalElements,
                        @JsonProperty("pageable") JsonNode pageable,
                        @JsonProperty("last") boolean last,
                        @JsonProperty("totalPages") int totalPages,
                        @JsonProperty("sort") JsonNode sort,
                        @JsonProperty("first") boolean first,
                        @JsonProperty("numberOfElements") int numberOfElements) {

        super(content, PageRequest.of(number, size), totalElements);
    }

    public RestResponsePage(List<T> content, Pageable pageable, long total) {
        super(content, pageable, total);
    }

    public RestResponsePage(List<T> content) {
        super(content);
    }

    public RestResponsePage() {
        super(new ArrayList<>());
    }
}
0
Danijel Sudar