Java Spring MVC中的JSON流输出

Java Spring MVC中的JSON流输出,java,rest,spring-mvc,jackson,java-stream,Java,Rest,Spring Mvc,Jackson,Java Stream,我的应用程序是使用SpringBoot(1.3.3.RELEASE)和SpringMVC、SpringData JPA Hibernate构建的。MySql是数据库,Jackson是JSON序列化程序。在Java8上 我想在我的控制器方法中返回一个巨大的数据集。我不想检索所有数据,然后将其传递到Jackson序列化程序,而是希望返回如下所示的对象流: @RequestMapping(value = "/candidates/all", method = RequestMeth

我的应用程序是使用SpringBoot(1.3.3.RELEASE)和SpringMVC、SpringData JPA Hibernate构建的。MySql是数据库,Jackson是JSON序列化程序。在Java8上

我想在我的控制器方法中返回一个巨大的数据集。我不想检索所有数据,然后将其传递到Jackson序列化程序,而是希望返回如下所示的对象流:

@RequestMapping(value = "/candidates/all", method = RequestMethod.GET)
public Stream<Candidate> getAllCandidates(){
    try { 
        return candidateDao.findAllByCustomQueryAndStream();
    } catch(Exception e){
        LOG.error("Exception in getCandidates",e);
    }
    return null;
}
@Query("select c from Candidate c")
public Stream<Candidate> findAllByCustomQueryAndStream();
如何指示Jackson序列化内容而不是流对象?

多亏了我能够解决这个问题

我提供了一个定制的httpMessageConverter,它了解如何处理流。像这样:

@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
    MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
    ObjectMapper objectMapper =jsonConverter.getObjectMapper();
    SimpleModule module = new SimpleModule("Stream");
    module.addSerializer(Stream.class, 
        new JsonSerializer<Stream>() {
            @Override
            public void serialize(Stream value, JsonGenerator gen, SerializerProvider serializers)
            throws IOException, JsonProcessingException {
                 serializers.findValueSerializer(Iterator.class, null)
                .serialize(value.iterator(), gen, serializers);
            }
    });
 
    objectMapper.registerModule(module);
    jsonConverter.setObjectMapper(objectMapper);
    return jsonConverter;
}
@Bean
公共映射Jackson2HttpMessageConverter映射Jackson2HttpMessageConverter(){
MappingJackson2HttpMessageConverter jsonConverter=新的MappingJackson2HttpMessageConverter();
ObjectMapper ObjectMapper=jsonConverter.getObjectMapper();
SimpleModule=新的SimpleModule(“流”);
module.addSerializer(Stream.class,
新的JsonSerializer(){
@凌驾
公共void序列化(流值、JsonGenerator gen、SerializerProvider序列化器)
抛出IOException、JsonProcessingException{
serializers.findValueSerializer(Iterator.class,null)
.serialize(value.iterator(),gen,serializers);
}
});
objectMapper.registerModule(模块);
setObjectMapper(objectMapper);
返回jsonConverter;
}

我发现,这种添加流支持的方式打破了LocalDate/LocalDateTime的良好输出,结果是这样做的:

@Bean
public Module customModule() {
    SimpleModule module = new SimpleModule("Stream");
    module.addSerializer(Stream.class, new JsonSerializer<Stream>() {

        @Override
        public void serialize(Stream value, JsonGenerator gen, SerializerProvider serializers)
                throws IOException, JsonProcessingException {
            serializers.findValueSerializer(Iterator.class, null)
                    .serialize(value.iterator(), gen, serializers);

        }
    });
    return module;
}
@Bean
公共模块customModule(){
SimpleModule=新的SimpleModule(“流”);
addSerializer(Stream.class,新的JsonSerializer()){
@凌驾
公共void序列化(流值、JsonGenerator gen、SerializerProvider序列化器)
抛出IOException、JsonProcessingException{
serializers.findValueSerializer(Iterator.class,null)
.serialize(value.iterator(),gen,serializers);
}
});
返回模块;
}

有一个建议的解决方案,可能是更好的方法

我不会将代码粘贴到这里,因为它可能会在该期中得到更新

到目前为止,我还没有发现我与其他模块(如可选as的Jdk8Module)一起添加的建议代码有任何问题

jacksonObjectMapper.registerModule(new StreamModule());
从控制器返回
Iterable
流通过
Iterable Iterable=Stream::iterator转换为迭代器

@RequestMapping(value = "/candidates/all", method = RequestMethod.GET)
public Iterable<Candidate> getAllCandidates(){
    ...

        return candidateDao.findAllByCustomQueryAndStream()::iterator;
@RequestMapping(value=“/candidates/all”,method=RequestMethod.GET)
公共Iterable getAllCandidates(){
...
返回候选dao.findAllByCustomQueryAndStream()::迭代器;

出于好奇:您如何使用
restemplate
阅读
Stream
?Stream.iterator是一种终端操作。这意味着它将所有内容缓存在ram中。这与使用Iterable作为getAllCandidates OutputOutput没有区别,目前正在研究如何减少大型数据集和spring mvc的内存占用你怎么说它会把所有东西都缓存在内存中?这是没有意义的吗?
@RequestMapping(value = "/candidates/all", method = RequestMethod.GET)
public Iterable<Candidate> getAllCandidates(){
    ...

        return candidateDao.findAllByCustomQueryAndStream()::iterator;