这似乎是Vaadin文档中缺少的部分。。。
我调用API来获取UI中的数据,如下所示:
@Override
public URI getUri(String url, PageRequest page) {
return UriComponentsBuilder.fromUriString(url)
.queryParam("page", page.getPageNumber())
.queryParam("size", page.getPageSize())
.queryParam("sort", (page.getSort().isSorted() ? page.getSort() : ""))
.build()
.toUri();
}
@Override
public Mono<Page<SomeDto>> getDataByPage(PageRequest pageRequest) {
return webClient.get()
.uri(getUri(URL_API + "/page", pageRequest))
.retrieve()
.bodyToMono(new ParameterizedTypeReference<>() {
});
}
在Vaadin文档中(https://vaadin.com/docs/v10/flow/binding-data/tutorial-flow-data-provider),我找到了一个DataProvider.fromCallbacks
的例子,但这需要流,这感觉不是正确的方法,因为我需要阻止请求以获得流。。。
DataProvider<SomeDto, Void> lazyProvider = DataProvider.fromCallbacks(
q -> service.getData(PageRequest.of(q.getOffset(), q.getLimit())).block().stream(),
q -> service.getDataCount().block().intValue()
);
当尝试这个实现时,我得到以下错误:
org.springframework.core.codec.CodecException: Type definition error: [simple type, class org.springframework.data.domain.Page]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `org.springframework.data.domain.Page` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: (io.netty.buffer.ByteBufInputStream); line: 1, column: 1]
grid.setItems(lazyProvider);
我没有使用vaadin的经验,所以我将讨论反序列化问题。
Jackson在反序列化时需要Creator
。要么:
- 默认的无arg构造函数
- 另一个用
@JsonCreator
注释的构造函数 - 用
@JsonCreator
注释的静态工厂方法
如果我们看看spring对Page
-PageImpl
和GeoPage
的实现,它们都没有。所以你有两个选择:
- 编写自定义反序列化程序并将其注册到
ObjectMapper
实例
反序列化程序:
public class PageDeserializer<T> extends StdDeserializer<Page<T>> {
public PageDeserializer() {
super(Page.class);
}
@Override
public Page<T> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
//TODO implement for your case
return null;
}
}
和注册:
SimpleModule module = new SimpleModule();
module.addDeserializer(Page.class, new PageDeserializer<>());
objectMapper.registerModule(module);
- 制作自己的类来扩展
PageImpl
、PageRequest
等,并用@JsonCreator
注释它们的构造函数,用@JsonProperty
注释参数
您的页面:
public class MyPage<T> extends PageImpl<T> {
@JsonCreator
public MyPage(@JsonProperty("content_prop_from_json") List<T> content, @JsonProperty("pageable_obj_from_json") MyPageable pageable, @JsonProperty("total_from_json") long total) {
super(content, pageable, total);
}
}
您的页面:
public class MyPageable extends PageRequest {
@JsonCreator
public MyPageable(@JsonProperty("page_from_json") int page, @JsonProperty("size_from_json") int size, @JsonProperty("sort_object_from_json") Sort sort) {
super(page, size, sort);
}
}
根据您对Sort
对象的需求,您可能还需要创建MySort
,或者您可以将其从构造函数中删除,并向超级构造函数提供未排序的排序。如果您手动从输入进行反序列化,则需要提供以下类型参数:
JavaType javaType = TypeFactory.defaultInstance().constructParametricType(MyPage.class, MyModel.class);
Page<MyModel> deserialized = objectMapper.readValue(pageString, javaType);
例如,如果输入来自请求体,那么仅在变量中声明泛型类型就足以让对象映射器获取它。
@PostMapping("/deserialize")
public ResponseEntity<String> deserialize(@RequestBody MyPage<MyModel> page) {
return ResponseEntity.ok("OK");
}
就我个人而言,我会选择第二种选择,即使您必须创建更多的类,它也避免了在编写反序列化程序时手动提取属性和创建实例的繁琐。
这个问题有两部分。
第一个是关于在Vaadin中异步加载DataProvider
的数据。这是不受支持的,因为Vaadin已经优先考虑了直接通过JDBC获取数据的典型情况。这意味着您最终会在加载数据时阻塞线程。Vaadin23将增加对在单独线程上进行阻塞的支持,而不是保持UI线程被阻塞,但它仍然会被阻塞。
你问题的另一半似乎与瓦丁没有直接关系。异常消息表示REST客户端使用的Jackson实例未配置为支持创建org.springframework.data.domain.Page
实例。我对这部分问题没有直接的经验,所以我不能给出任何关于如何解决它的建议