如果可以从SpringRestController
返回Stream
,我很好奇
@RestController
public class X {
@RequestMapping(...)
public Stream<?> getAll() { ... }
}
这样做可以吗?我试过了,Spring返回的不是流的值。
我应该继续返回列表吗
匿名用户
您可以在Spring 5.0 / WebFlux 中流式传输实体。
看一下这个示例反应式Rest控制器(< code > spring . main . web-application-type:" REACTIVE " ):
@RestController
public class XService {
class XDto{
final int x;
public XDto(int x) {this.x = x;}
}
Stream<XDto> produceX(){
return IntStream.range(1,10).mapToObj(i -> {
System.out.println("produce "+i);
try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
return new XDto(i);
});
}
// stream of Server-Sent Events (SSE)
@GetMapping(value = "/api/x/sse",
produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<XDto> getXSse() {
return Flux.fromStream(produceX());
}
// stream of JSON lines
@GetMapping(value = "/api/x/json-stream",
produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
public Flux<XDto> getAllJsonStream() {
return Flux.fromStream(produceX());
}
// same as List<XDto> - blocking JSON list
@GetMapping(value = "/api/x/json-list",
produces = MediaType.APPLICATION_JSON_VALUE)
public Flux<XDto> getAll() {
return Flux.fromStream(produceX());
}
}
Spring Framework 5.0-WebFlux:
Spring的反应式堆栈Web框架是5.0中新增的,是完全反应式和非阻塞的。它适用于具有少量线程的事件循环样式处理。
服务器发送的事件(SSE):
服务器发送事件是描述一旦建立了初始客户端连接,服务器如何向客户端发起数据传输的标准。
WebSocket与服务器发送事件/事件源
这也可以用Spring MVC控制器来完成,但是有一些问题:Spring数据JPA存储库的限制,数据库是否支持可保持游标(ResultSet Holdability)以及Jackson的版本。
我很难理解的关键概念是,Java 8 Stream返回一系列在终端操作中执行的函数,因此数据库必须在执行终端操作的上下文中可访问。
Spring数据 JPA 限制
我发现Spring数据JPA文档没有为Java 8流提供足够的细节。看起来你可以简单地声明流
@Query("select mo from MyObject mo where mo.foo.id in :fooIds")
Stream<MyObject> readAllByFooIn(@Param("fooIds") Long[] fooIds);
可保持光标
如果您有一个支持可持有游标的数据库,则在提交事务后可以访问结果集。这很重要,因为我们通常用< code>@Transactional
来注释我们的< code>@Service类方法,所以如果您的数据库支持可保持游标,则可以在服务方法返回后(即在< code>@Controller方法中)访问< code>ResultSet。如果数据库不支持可持有游标,例如MySQL,您需要将< code>@Transaction注释添加到控制器的< code>@RequestMapping方法中。
所以现在ResultSet可以在@Service
方法之外访问,对吗?这同样取决于可保留性。对于MySQL,它只能在@Transactional
方法中访问,因此以下方法将起作用(尽管违背了使用Java8 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
中,它在控制器方法返回后发生在Spring中。
在不支持可保留游标的情况下将流序列化为JSON
要将流序列化为JSON而不使用可保留游标,请将<code>HttpServletResponse,但在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());
}
}
下一步
我的下一步是尝试在可调用的
WebAsyncTask
中重构它,并将JSON序列化移到服务中。
引用
请务必阅读Marko Topolnik的博客文章https://www.airpair.com/java/posts/spring-streams-memory-efficiency没有它,我就不知道从哪里开始
MySQL
我得到这个错误消息: 无法写入JSON: 未找到用于java.io.FileDescriptor类的序列化程序,也未发现用于创建BeanSerializer的属性 (为了避免异常,禁用SerializationFeature.fail_on_empty_beans)) (通过引用链: org.springframework.core.io.filesystemResource[\“outputSt
我正在使用Spring形式。我只需要得到Staemap作为响应,但我得到的是整个jsp页面作为响应。
你好,我是拉威尔的新手,也许这对你们来说太傻了。在laravel 8中,路由web。php我创建了一条如下的路线: 我想问的是,我们也可以从回调视图返回控制器吗?所以在路由 /editprofile中,第二个参数不是'App\Http\Controller\SiteController@edit_profile',而是一个回调函数,如路由'/home'。 但是它返回错误哈哈。假设我不想用__con
我无法完成的任务是将参数从一个场景传递到另一个场景并返回。 或者换句话说:主控制器加载子控制器的fxml,将对象传递给子控制器,切换场景。不得有两扇开着的窗户。工作完成后,副控制器将场景切换回主控制器,并将一些对象传递回主控制器。这就是我失败的地方。 这个问题和这个问题很相似但仍然没有答案。传递参数JavaFX FXML在注释中也提到了: 有没有人知道如何在没有外部库的情况下实现这一点?
我试图为web api控制器中的GET方法返回一个状态代码304 not modified。 我成功的唯一方法是这样的: 这里的问题是,它并不是一个例外,它只是没有被修改,所以客户端缓存是可以的。我还希望返回类型为User(正如所有web api示例使用GET显示的那样),而不是返回HttpResponseMessage或类似的内容。
问题内容: 我试图创建一个服务来获取json并将其传递给我homeCtrl我可以获取数据,但是当将其传递给我的homeCtrl时,它总是返回undefined。我卡住了。 我的服务: 我的家庭控制器: 问题答案: 您应该从函数返回promise ,当它被解析后,它应该从该函数返回。 厂 同样在控制器内部,您应该调用factory函数,并在service函数解析该调用并将其分配给 码