java - 从 Spring REST Controller 返回流

标签 java spring

如果可以返回 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 序列化移动到服务中。

引用文献

关于java - 从 Spring REST Controller 返回流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39972903/

相关文章:

java - Java中用二进制数据手动构造SQL

java - 服务层和 Controller : who takes care of what?

java - Spring 中未调用 Rest Controller

java - 无法运行程序 "/Applications/Utilities/Terminal.app": error=13, 权限被拒绝

java - Hibernate saveOrUpdate() 似乎没有级联创建和保存

java - 当使用 jsp cewolf 标签库中的 @Injected 类时,Spring 返回 NullPointerException

java - 在 ActiveMQ 中启动时为 "Camel is shutting down"

java - Thymeleaf:更新表单提交表

java - Kotlin Guava Cache 未显示正确的 hitCount

java - 异常“NoClassDefFoundError for javax/mail/Authenticator