2016-01-07 61 views
12

我们的REST API正在返回Pages中的结果。这里是一个控制器的例子带分页API的Spring RestTemplate

@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: [email protected]; 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 

预先感谢您

回答

6

改变了代码读取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>()); 
    } 

} 
+0

为什么传入null httpEntity? null/* httpEntity */ –

+0

这不会返回正确的页数或结果总数。 – ACOMIT001

0

发布对我来说没有工作的解决方案创建的类,因为总要素设定不正确。我使用委托模式实现了页面,该模式对我很有用。这里是工作代码:

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

这只能处理1-arg构造函数的情况。如果你有一个3参数的构造函数,那么这是没用的。 – cst1992

+1

其他字段未填充除totalElements和content之外的上述代码。 – MasterCode

6

在上面展开,但不需要实现每个属性。

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()); 
    } 
} 
2

没有必要实施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();