如果可以返回 Stream
,我很感兴趣来自 Spring RestController
@RestController
public class X {
@RequestMapping(...)
public Stream<?> getAll() { ... }
}
可以做这样的事情吗?我试过了,Spring 返回的不是流的值。
我应该继续返回 List<?>
?
最佳答案
这也可以用 Spring MVC Controller 来完成,但是有几个问题:Spring Data JPA Repository 的限制,数据库是否支持Holdable Cursors(ResultSet Holdability)以及Jackson 的版本。
我难以理解的关键概念是,Java 8 Stream 返回一系列在终端操作中执行的函数,因此数据库必须在执行终端操作。
Spring Data JPA 限制
我发现 Spring Data JPA 文档没有为 Java 8 Streams 提供足够的详细信息。看来您可以简单地声明 Stream<MyObject> readAll()
,但我需要用 @Query
注释该方法让它工作。我也无法使用 JPA 标准 API Specification
.所以我不得不接受一个硬编码的查询,比如:
@Query("select mo from MyObject mo where mo.foo.id in :fooIds")
Stream<MyObject> readAllByFooIn(@Param("fooIds") Long[] fooIds);
可保持光标
如果您有一个支持可保持游标的数据库,则在提交事务后可以访问结果集。这很重要,因为我们通常注释我们的 @Service
@Transactional
的类方法, 所以如果你的数据库支持可保持游标 ResultSet
服务方法返回后可以访问,即在@Controller
方法。如果数据库不支持可保持游标,例如MySQL,您需要添加 @Transaction
Controller 的 @RequestMapping
注释方法。
所以现在可以在 @Service
之外访问 ResultSet方法对不对?这又取决于可持性。对于 MySQL,它只能在 @Transactional
中访问。方法,因此以下将起作用(尽管违背了使用 Java 8 Streams 的全部目的):
@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;
}
因为终端操作符在你的@Controller
中不是它发生在 Controller 方法返回后的 Spring 中。
在不支持可保持游标的情况下将流序列化为 JSON
要将流序列化为没有可保持游标的 JSON,请添加 HttpServletResponse response
到 Controller 方法,获取输出流并使用ObjectMapper
写流。使用 FasterXML 3.x,您可以调用 ObjectMapper().writeValue(writer, stream)
,但在 2.8.x 中,您必须使用流的迭代器:
@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());
}
}
后续步骤
我接下来的步骤是尝试在 Callable
中重构它。 WebAsyncTask
并将 JSON 序列化移动到服务中。
引用文献
- 请务必阅读 Marko Topolnik 的博文 https://www.airpair.com/java/posts/spring-streams-memory-efficiency ,没有它我不知道从哪里开始。
- MySQL >5.0.2 现在支持游标,所以你可以添加
useCursorFetch=true
到连接字符串 -- https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-configuration-properties.html - Java 8 Stream 的 FasterXml 序列化 -- https://stackoverflow.com/a/37979665/2562746
关于java - 从 Spring REST Controller 返回流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39972903/