[SPRING] 페이지가 매겨진 API가있는 Spring RestTemplate
SPRING페이지가 매겨진 API가있는 Spring RestTemplate
Google의 REST API는 페이지에서 결과를 반환합니다. 하나의 컨트롤러 예제
@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();
예외를 throw합니다.
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
미리 감사드립니다.
해결법
-
==============================
1.스프링 부트 1.x에서 2.0으로 마이그레이션 할 때, 나머지 API 응답을 읽는 코드가 다음과 같이 변경되었습니다.
스프링 부트 1.x에서 2.0으로 마이그레이션 할 때, 나머지 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<>()); } }
-
==============================
2.Rest API 응답을 읽는 코드를 다음과 같이 변경했습니다.
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>()); } }
-
==============================
3.위에서 확장하면 모든 속성을 구현할 필요가 없습니다.
위에서 확장하면 모든 속성을 구현할 필요가 없습니다.
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()); } }
-
==============================
4.페이지를 구현할 필요가 없습니다. ParameterizedTypeReference의 형식으로 PagedResources
를 사용해야합니다. 페이지를 구현할 필요가 없습니다. ParameterizedTypeReference의 형식으로 PagedResources
를 사용해야합니다. 따라서 서비스가 다음과 비슷한 응답을 반환하는 경우 (간결성을 위해 객체가 제거됨) :
{ "_embedded": { "events": [ {...}, {...}, {...}, {...}, {...} ] }, "_links": { "first": {...}, "self": {...}, "next": {...}, "last": {...} }, "page": { "size": 5, "totalElements": 30, "totalPages": 6, "number": 0 } }
그리고 당신이 관심을 갖는 객체는 다음과 같이 요청을 실행해야합니다.
ResponseEntity<PagedResources<Event>> eventsResponse = restTemplate.exchange(uriBuilder.build(true).toUri(), HttpMethod.GET, null, new ParameterizedTypeReference<PagedResources<Event>>() {});
다음과 같은 리소스를 확보 한 경우 :
PagedResources<Event> eventsResources = eventsResponse.getBody();
페이지 메타 데이터 ( '페이지'섹션에서 얻은 정보), 링크 ( '_ 링크'섹션) 및 콘텐츠에 액세스 할 수 있습니다.
Collection<Event> eventsCollection = eventsResources.getContent();
-
==============================
5.전체 요소가 올바르게 설정되지 않았기 때문에 게시 된 솔루션이 저에게 효과적이지 않았습니다. 나는 위임 패턴을 사용하여 페이지를 구현했다. 다음은 작동 코드입니다.
전체 요소가 올바르게 설정되지 않았기 때문에 게시 된 솔루션이 저에게 효과적이지 않았습니다. 나는 위임 패턴을 사용하여 페이지를 구현했다. 다음은 작동 코드입니다.
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(); } }
from https://stackoverflow.com/questions/34647303/spring-resttemplate-with-paginated-api by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] 다중 소스에서 읽은 일괄 작업 일괄 처리 (0) | 2018.12.12 |
---|---|
[SPRING] ClassFormatError : 클래스 파일의 네이티브 또는 추상 메소드가 아닌 메소드의 Code 속성이 존재하지 않는 javax / mail / MessagingException (0) | 2018.12.12 |
[SPRING] Spring MVC에서 리다이렉트 (0) | 2018.12.12 |
[SPRING] Spring의 JSF 뷰 범위 (0) | 2018.12.12 |
[SPRING] 스프링 데이터 : "삭제 기준"이 지원됩니까? (0) | 2018.12.12 |