Java 从Spring REST控制器返回流

Java 从Spring REST控制器返回流,java,spring,Java,Spring,如果可以从SpringRestController返回流,我会很好奇 @RestController public class X { @RequestMapping(...) public Stream<?> getAll() { ... } } @RestController 公共X类{ @请求映射(…) 公共流getAll(){…} } 这样做可以吗?我试过了,Spring返回的不是流的值 我是否继续返回列表?您可以在Spring 5.0/WebFlux中对实体进行

如果可以从Spring
RestController
返回
流,我会很好奇

@RestController
public class X {
  @RequestMapping(...)
  public Stream<?> getAll() { ... }
}
@RestController
公共X类{
@请求映射(…)
公共流getAll(){…}
}
这样做可以吗?我试过了,Spring返回的不是流的值


我是否继续返回
列表?

您可以在Spring 5.0/WebFlux中对实体进行流式处理

请看这个示例被动Rest控制器
spring.main.web-application-type:“被动”
):

@RestController
公共类XService{
XDto类{
最终整数x;
公共XDto(int x){this.x=x;}
}
溪流生产商(){
返回IntStream.range(1,10).mapToObj(i->{
系统输出打印项次(“生产”+i);
尝试{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}
返回新的XDto(i);
});
}
//服务器发送事件流(SSE)
@GetMapping(value=“/api/x/sse”,
products=MediaType.TEXT\u事件\u流\u值)
公共流量getXSse(){
返回通量.fromStream(produceX());
}
//JSON行流
@GetMapping(value=“/api/x/json流”,
products=MediaType.APPLICATION\u STREAM\u JSON\u VALUE)
公共流量getAllJsonStream(){
返回通量.fromStream(produceX());
}
//与列表相同-阻止JSON列表
@GetMapping(value=“/api/x/json list”,
products=MediaType.APPLICATION\u JSON\u值)
公共交通{
返回通量.fromStream(produceX());
}
}

Spring的反应式堆栈web框架是5.0中新增的,它是完全反应式和非阻塞的。它适用于具有少量线程的事件循环样式处理

Server sent events是一个标准,描述一旦建立了初始客户端连接,服务器如何向客户端发起数据传输


这也可以通过Spring MVC Controller实现,但有几个问题:Spring数据JPA存储库中的限制、数据库是否支持可保持游标(ResultSet Holdability)以及Jackson版本

我很难理解的关键概念是,Java8流返回一系列在终端操作中执行的函数,因此必须在执行终端操作的上下文中访问数据库

Spring数据JPA限制

我发现SpringDataJPA文档没有为Java8流提供足够的细节。看起来您可以简单地声明
Stream readAll()
,但我需要使用
@Query
对该方法进行注释以使其工作。我也不能使用JPA标准API
规范
。所以我不得不接受一个硬编码的查询,比如:

@Query("select mo from MyObject mo where mo.foo.id in :fooIds")
Stream<MyObject> readAllByFooIn(@Param("fooIds") Long[] fooIds);
但不是

@Transaction @RequestMapping
public Stream<MyObject> getAll() {
    return service.streamAll;
}
下一步

我接下来的步骤是尝试在
可调用
WebAsyncTask
中重构它,并将JSON序列化移动到服务中

参考资料

  • 一定要阅读Marko Topolnik的博客文章,没有它我就不知道从哪里开始
  • MySQL>5.0.2现在支持游标,因此您可以将
    useCursorFetch=true
    添加到连接字符串--
  • Java 8流的FasterXml序列化--

列表是更好的方法。如果返回流,我不知道返回值是什么样子。但是如果客户机对java7之类的流一无所知呢?!我不会在这个问题上下注,不管JSON或用于序列化的任何东西是否能够处理流。默认情况下,流不可序列化。可能是这样的,流链接到一个非序列化的底层数据结构,该数据结构不会返回。@Jens如果是REST控制器,则客户端不需要任何依赖项;如果是REST,则OP表示提供一些端点的通用API。@px06您是对的。但客户端必须能够反序列化流我尝试了您的代码,但遇到了以下问题:
未能发送…$XDto,原因是:java.lang.IllegalArgumentException:没有适合类的转换器…$XDto
我缺少什么?@platzhersh检查此项:添加getter,setter那么你很好这是一个极好的答案,解释了处理流和事务性JPA dbs的细微差别。很遗憾spring不能在本地处理这个问题。我知道这是一个很老的评论,但我真的想听听有丰富经验的人的意见:Heez的评论不符合stream,对吗?如果是流(非阻塞),我应该避免事务特性,对吗?
@Transaction @RequestMapping(...)
public List<MyObject> getAll() {
   try(Stream<MyObject> stream = service.streamAll) {
        return stream.collect(Collectors.toList())
    };
}
@Transaction @RequestMapping
public Stream<MyObject> getAll() {
    return service.streamAll;
}
@RequestMapping(...)
@Transactional
public void getAll(HttpServletResponse response) throws IOException {
    try(final Stream<MyObject> stream = service.streamAll()) {
        final Writer writer = new BufferedWriter(new OutputStreamWriter(response.getOutputStream()));
        new ObjectMapper().writerFor(Iterator.class).writeValue(writer, stream.iterator());
    }
}