JAVA大数据场景使用StreamingOutput

JAX-RS StreamingOutput 详细讲解

一、StreamingOutput 是什么

StreamingOutput 不是"返回数据对象",而是"你亲手往 HTTP
响应流里写字节"。

它的接口定义:

java 复制代码
@FunctionalInterface
public interface StreamingOutput {
    void write(OutputStream output) throws IOException;
}

核心含义: - JAX-RS 不帮你序列化对象 - 不缓存完整结果 - 直接把 HTTP

Response 的 OutputStream 交给你


二、与普通返回方式的根本区别

普通返回

java 复制代码
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<User> getUsers() {
    return userService.findAll();
}

流程:

  • Java 对象
    → MessageBodyWriter
    → JSON
    → 一次性返回

特点: - 数据必须先完整生成 - 占用内存 - 适合小数据


StreamingOutput 返回

java 复制代码
@GET
@Produces("text/csv")
public StreamingOutput streamCsv() {
    return output -> {
        output.write("id,name\n".getBytes());
        output.write("1,Alice\n".getBytes());
    };
}

流程:

  • 客户端建立连接
    → 容器打开 OutputStream
    → 调用 write()
    → 边写边发送

特点: - 流式输出 - 几乎不占内存 - 适合大数据、下载


三、为什么说是在"写 HTTP 管道"

OutputStream 就是 TCP 连接上的 HTTP Response Body。

  • write():客户端立刻收到
  • flush():强制推送缓冲区
  • 异常:连接直接中断

你已经进入网络 IO 层。


四、典型使用场景

1. 大数据 CSV 导出

java 复制代码
@GET
@Produces("text/csv")
public StreamingOutput export() {
    return out -> {
        BufferedWriter writer = new BufferedWriter(
            new OutputStreamWriter(out, StandardCharsets.UTF_8)
        );
        writer.write("id,name\n");
        for (User u : userService.streamAll()) {
            writer.write(u.getId() + "," + u.getName() + "\n");
            writer.flush();
        }
    };
}

2. 长任务实时输出

java 复制代码
@GET
@Produces(MediaType.TEXT_PLAIN)
public StreamingOutput task() {
    return out -> {
        for (int i = 1; i <= 5; i++) {
            out.write(("step " + i + "\n").getBytes());
            out.flush();
            Thread.sleep(1000);
        }
    };
}

五、Response + StreamingOutput(推荐)

java 复制代码
@GET
public Response download() {
    StreamingOutput stream = out -> {
        out.write("hello".getBytes());
    };
    return Response.ok(stream)
            .header("Content-Disposition", "attachment; filename=test.txt")
            .build();
}

六、常见致命坑

1. 没有返回值概念

java 复制代码
return out -> {
    out.write(data);
};

2. 不要关闭 OutputStream

java 复制代码
out.close(); // ❌

3. write 后抛异常会导致下载损坏

4. 不会自动 JSON 序列化

java 复制代码
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(out, obj);

七、什么时候必须用 StreamingOutput

场景 是否使用
小 JSON ❌
大文件下载 ✅
实时输出 ✅
普通 REST 查询 ❌

八、核心总结

StreamingOutput = 你控制 HTTP 响应流本身

不是返回数据,而是写网络字节。

相关推荐
badhope9 分钟前
Spring AI Alibaba停更:Java程序员的信任,还能被辜负几次?
java·spring
星创易联9 分钟前
PLC数据采集与远程运维平台:从边缘计算到集中监控
大数据·运维·边缘计算
亲笔签12 分钟前
“场景重庆”典型案例 | 数字笔迹技术赋能政务服务 打造可信电子签署创新场景
大数据·人工智能
const_qiu16 分钟前
第一章 1.1-1.2:基础模型调用与 TypeScript 入门 —— Java 开发者的视角
java·javascript·typescript
Wang's Blog21 分钟前
Java 项目实战: 交友项目 - Dubbo 负载均衡策略与实战验证
java·dubbo·交友
SL_staff25 分钟前
销售知识库7天落地实践:面向业务侧的零代码嵌入方案
java·开源·产品
kimnoic27 分钟前
PHP 8.2的DNF类型怎么用才规范
开发语言·php
GreatSQL社区35 分钟前
主从复制SQL线程中断——字符集砸出的坑
java·数据库·算法
198******1263436 分钟前
2026 企业 AI 办公工具选型指南:搭建适配业务的智能工作体系
大数据·人工智能·数据挖掘
_Evan_Yao1 小时前
前后端联调怎么排查问题?从 Network 到后端日志,一步步定位错误
开发语言·后端·团队开发·需求分析