복붙노트

[SPRING] Spring RestTemplate을 사용하여 페이지 <Entity> 응답을 소비하는 방법

SPRING

Spring RestTemplate을 사용하여 페이지 응답을 소비하는 방법

나는 스프링 데이터 (mongoDb)를 사용하고 있으며 저장소를 가지고있다 :

public interface StoriesRepository extends PagingAndSortingRepository<Story, String> {}

그럼 나는 컨트롤러가 :

@RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Page<StoryResponse>> getStories(Pageable pageable) {
    Page<StoryResponse> stories = storiesRepository.findAll(pageable).map(StoryResponseMapper::toStoryResponse);
    return ResponseEntity.ok(stories);
}

모든 것은 정상적으로 작동하지만 RestTemplate getForEntity 메소드를 사용하여 엔드 포인트를 소비 할 수 없습니다.

def entity = restTemplate.getForEntity(getLocalhost("/story"), new TypeReference<Page<StoryResponse>>(){}.class)

내 페이지 엔티티를 성공적으로 deserialize하기 위해 어떤 클래스를 제공해야합니까?

해결법

  1. ==============================

    1.

    new TypeReference<Page<StoryResponse>>() {}
    

    이 문장의 문제점은 Jackson이 추상 형식을 인스턴스화 할 수 없다는 것입니다. Jackson에게 구체적인 유형으로 페이지를 인스턴스화하는 방법에 대한 정보를 제공해야합니다. 그러나 구체적인 유형 인 PageImpl에는 기본 생성자 또는 해당 @JsonCreators가 없으므로 다음 코드를 사용할 수 없습니다.

    new TypeReference<PageImpl<StoryResponse>>() {}
    

    필요한 정보를 Page 클래스에 추가 할 수 없기 때문에이 대답과 같이 기본 no-arg 생성자가있는 Page 인터페이스에 대한 사용자 정의 구현을 만드는 것이 좋습니다. 그런 다음 다음과 같이 유형 참조에서 해당 사용자 정의 구현을 사용하십시오.

    new TypeReference<CustomPageImpl<StoryResponse>>() {}
    

    다음은 링크 된 질문에서 복사 한 맞춤 구현입니다.

    public class CustomPageImpl<T> extends PageImpl<T> {
        private static final long serialVersionUID = 1L;
        private int number;
        private int size;
        private int totalPages;
        private int numberOfElements;
        private long totalElements;
        private boolean previousPage;
        private boolean firstPage;
        private boolean nextPage;
        private boolean lastPage;
        private List<T> content;
        private Sort sort;
    
        public CustomPageImpl() {
            super(new ArrayList<>());
        }
    
        @Override
        public int getNumber() {
            return number;
        }
    
        public void setNumber(int number) {
            this.number = number;
        }
    
        @Override
        public int getSize() {
            return size;
        }
    
        public void setSize(int size) {
            this.size = size;
        }
    
        @Override
        public int getTotalPages() {
            return totalPages;
        }
    
        public void setTotalPages(int totalPages) {
            this.totalPages = totalPages;
        }
    
        @Override
        public int getNumberOfElements() {
            return numberOfElements;
        }
    
        public void setNumberOfElements(int numberOfElements) {
            this.numberOfElements = numberOfElements;
        }
    
        @Override
        public long getTotalElements() {
            return totalElements;
        }
    
        public void setTotalElements(long totalElements) {
            this.totalElements = totalElements;
        }
    
        public boolean isPreviousPage() {
            return previousPage;
        }
    
        public void setPreviousPage(boolean previousPage) {
            this.previousPage = previousPage;
        }
    
        public boolean isFirstPage() {
            return firstPage;
        }
    
        public void setFirstPage(boolean firstPage) {
            this.firstPage = firstPage;
        }
    
        public boolean isNextPage() {
            return nextPage;
        }
    
        public void setNextPage(boolean nextPage) {
            this.nextPage = nextPage;
        }
    
        public boolean isLastPage() {
            return lastPage;
        }
    
        public void setLastPage(boolean lastPage) {
            this.lastPage = lastPage;
        }
    
        @Override
        public List<T> getContent() {
            return content;
        }
    
        public void setContent(List<T> content) {
            this.content = content;
        }
    
        @Override
        public Sort getSort() {
            return sort;
        }
    
        public void setSort(Sort sort) {
            this.sort = sort;
        }
    
        public Page<T> pageImpl() {
            return new PageImpl<>(getContent(), new PageRequest(getNumber(),
                    getSize(), getSort()), getTotalElements());
        }
    }
    
  2. ==============================

    2.나는이 쓰레드가 조금 오래되었음을 알고 있지만, 누군가는 이것으로부터 이익을 얻길 바랍니다.

    나는이 쓰레드가 조금 오래되었음을 알고 있지만, 누군가는 이것으로부터 이익을 얻길 바랍니다.

    @Ali Dehghani의 답변은 좋은데, PageImpl 이 이미 수행 한 것을 다시 구현한다는 점만 다릅니다. 나는 이것을 오히려 불필요하다고 생각했다. PageImpl 을 확장하고 @JsonCreator 생성자를 지정하는 클래스를 만들어보다 나은 해결책을 찾았습니다.

    import com.fasterxml.jackson.annotation.JsonCreator;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.company.model.HelperModel;
    import org.springframework.data.domain.PageImpl;
    import org.springframework.data.domain.PageRequest;
    
    import java.util.List;
    
    public class HelperPage extends PageImpl<HelperModel> {
    
        @JsonCreator
        // Note: I don't need a sort, so I'm not including one here.
        // It shouldn't be too hard to add it in tho.
        public HelperPage(@JsonProperty("content") List<HelperModel> content,
                          @JsonProperty("number") int number,
                          @JsonProperty("size") int size,
                          @JsonProperty("totalElements") Long totalElements) {
            super(content, new PageRequest(number, size), totalElements);
        }
    }
    

    그때:

    HelperPage page = restTemplate.getForObject(url, HelperPage.class);
    

    이는 CustomPageImpl 클래스를 만드는 것과 동일하지만 이미 PageImpl 에있는 모든 코드를 활용할 수 있습니다.

  3. ==============================

    3.언급 한 "경로 찾기"에서 RestTemplate의 교환 방법을 사용할 수 있습니다. 그러나 ParameterizedTypeReference > ()를 전달하는 대신 ParameterizedTypeReference > ()를 전달해야합니다. 응답을 받으면 콘텐츠 (Collection )를 검색 할 수 있습니다.

    언급 한 "경로 찾기"에서 RestTemplate의 교환 방법을 사용할 수 있습니다. 그러나 ParameterizedTypeReference > ()를 전달하는 대신 ParameterizedTypeReference > ()를 전달해야합니다. 응답을 받으면 콘텐츠 (Collection )를 검색 할 수 있습니다.

    코드는 다음과 같아야합니다.

    ResponseEntity<PagedResources<StoryResponse>> response = restTemplate.exchange(getLocalhost("/story"),
            HttpMethod.GET, null, new ParameterizedTypeReference<PagedResources<StoryResponse>>() {});
    PagedResources<StoryResponse> storiesResources = response.getBody();
    Collection<StoryResponse> stories = storiesResources.getContent();
    

    content storiesResources는 페이지 메타 데이터와 링크도 보유하고 있습니다.

    자세한 단계별 설명은 https://stackoverflow.com/a/46847429/8805916에서 확인할 수 있습니다.

  4. ==============================

    4.나는 스프링 라이브러리를 1. *로 다운 그레이드하고, 2를 사용하지 않도록 할 수있다. PageImpl을 확장하지 않는 Page에 대한 고유 한 코드를 만들어야했습니다.

    나는 스프링 라이브러리를 1. *로 다운 그레이드하고, 2를 사용하지 않도록 할 수있다. PageImpl을 확장하지 않는 Page에 대한 고유 한 코드를 만들어야했습니다.

  5. ==============================

    5.이 스레드를보고이 대답을 시도한다면 https://stackoverflow.com/a/44895867/8268335

    이 스레드를보고이 대답을 시도한다면 https://stackoverflow.com/a/44895867/8268335

    당신은 2 번째 문제를 만날 것입니다 :

    Can not construct instance of org.springframework.data.domain.Pageable
    

    그런 다음 여기에서 완벽한 솔루션을 찾습니다. https://stackoverflow.com/a/42002709/8268335

    위의 대답과 문제 해결에서 클래스 RestPageImpl을 만듭니다.

  6. ==============================

    6.당신은 아마 restTemplate의 exchange 메소드를 사용하고 그것으로부터 몸체를 얻을 수 있습니다 ..

    당신은 아마 restTemplate의 exchange 메소드를 사용하고 그것으로부터 몸체를 얻을 수 있습니다 ..

    다음 답변 (https://stackoverflow.com/a/31947188/3800576)을 확인하십시오. 이것은 당신을 도울지도 모른다.

  7. ==============================

    7.@ResponseBody 주석을 추가 할 수 있습니다.

    @ResponseBody 주석을 추가 할 수 있습니다.

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<Page<StoryResponse>> getStories(@RequestBody Pageable pageable) {
        Page<StoryResponse> stories = storiesRepository.findAll(pageable).map(StoryResponseMapper::toStoryResponse);
        return ResponseEntity.ok(stories);
    }
    
  8. from https://stackoverflow.com/questions/34099559/how-to-consume-pageentity-response-using-spring-resttemplate by cc-by-sa and MIT license