想在controller里面把实时调第三方模型的实时返回的流式数据,按每句话用String类型return给前端

作者 : admin 本文共3681个字,预计阅读时间需要10分钟 发布时间: 2024-06-16 共1人阅读
1、如果想在 Controller 中将实时调用第三方模型的流式数据逐行返回给前端,可以使用 Spring MVC 的 ResponseBodyEmitter。在这种情况下,需要确保 Controller 方法是异步的,并使用一个新线程或者异步任务来获取第三方模型的实时数据,并将数据逐行发送给客户端。
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

@RestController
@RequestMapping("/api")
public class YourController {

    @PostMapping("/streamData")
    public ResponseBodyEmitter streamData() {
        ResponseBodyEmitter emitter = new ResponseBodyEmitter();

        // 启动一个新的线程来处理数据流
        new Thread(() -> {
            String apiUrl = "your_api_url_here";

            try {
                URL url = new URL(apiUrl);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();

                // 设置请求方法为POST
                connection.setRequestMethod("POST");
                connection.setDoOutput(true);

                // 获取输入流,这里是获取返回的数据流
                InputStream inputStream = connection.getInputStream();

                // 处理输入流,这里可以根据需要进行流式处理
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                String line;
                while ((line = reader.readLine()) != null) {
                    // 发送每行数据给客户端
                    try {
                        emitter.send(line, MediaType.TEXT_PLAIN);
                    } catch (IOException e) {
                        e.printStackTrace();
                        // 处理发送异常,比如客户端断开连接
                        break;
                    }
                }

                // 关闭资源
                reader.close();

                // 获取响应码,根据需要处理
                int responseCode = connection.getResponseCode();
                System.out.println("Response Code: " + responseCode);

                // 断开连接
                connection.disconnect();

                // 发送完成信号
                try {
                    emitter.complete();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            } catch (IOException e) {
                e.printStackTrace();
                // 发送错误信号
                try {
                    emitter.completeWithError(e);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }).start();

        return emitter;
    }
}

        在这个例子中,streamData 方法返回了 ResponseBodyEmitter 对象,并在一个新的线程中启动了获取第三方模型实时数据的任务。每获取到一行数据,就使用 emitter.send(line, MediaType.TEXT_PLAIN) 将数据逐行发送给客户端。

2、执行逻辑

当使用 ResponseBodyEmitter 时,你实际上创建了一个可以异步写入响应体的对象。在这个具体的例子中,当请求到达 /api/streamData 接口时,streamData 方法会创建一个 ResponseBodyEmitter 对象,并返回给客户端。

在这个方法内,我们启动了一个新的线程,该线程负责调用第三方模型,并从模型那里获取流式数据。具体来说,我们使用 HttpURLConnection 打开一个连接到第三方 API(your_api_url_here),发送 POST 请求,并获取该 API 返回的输入流(InputStream)。

接下来,我们创建一个 BufferedReader 来逐行读取从第三方 API 返回的数据流。对于每一行数据,我们使用 emitter.send(line, MediaType.TEXT_PLAIN) 将数据发送到客户端。这实际上是将数据推送给客户端,而不是等待客户端拉取数据。

在发送数据的过程中,我们对异常进行了处理。如果客户端断开连接或者其他错误发生,我们捕获 IOException 并相应地处理。最终,在处理完数据流之后,我们发送 complete 信号,表示数据流传输完成。

这种方式允许你在异步的情况下,实时地将第三方模型返回的数据发送给客户端。客户端可以通过订阅这个接口来获取实时数据,而不需要等待整个流程执行完毕。

请注意,这里使用了一个简单的线程来执行异步任务,但在实际应用中,你可能会考虑使用 Spring 的异步特性,例如 @Async 注解结合 ThreadPoolTaskExecutor,以便更好地管理异步任务。

3、客户端如何订阅接收返回的ResponseBodyEmitter ?

在前端使用 WebSocket 订阅数据的步骤包括创建 WebSocket 连接、监听连接状态、发送和接收消息等。以下是一个简单的使用 WebSocket 的示例,假设你的后端已经支持 WebSocket:




    
    
    WebSocket Example







这个示例中,我们创建了一个 WebSocket 连接到 ws://your-server-address/api/streamData,这个地址应该替换为你实际的后端 WebSocket 地址。然后,我们监听连接打开、关闭、接收消息和错误等事件。

message 事件中,我们处理从服务器端实时传输过来的数据。这个数据可能是由 ResponseBodyEmitter 在后端逐行发送的。你可以根据你的需求,将这些数据渲染到页面上或者进行其他业务逻辑的处理。

确保你的后端代码正确处理 WebSocket 连接,以及在适当的时候关闭连接。这样,前端就能够通过 WebSocket 实时接收到后端发送的数据。

请注意:

  1. new WebSocket('ws://your-server-address/api/streamData') 中的 your-server-address 应该替换为你实际的后端服务器地址。如果你的后端支持 wss(WebSocket Secure),你应该使用 wss 而不是 ws
  2. 这个示例假设你的后端已经提供了 WebSocket 服务,并且在 /api/streamData 路径上提供了 WebSocket 端点。你需要确保后端正确处理 WebSocket 连接,并在数据准备好时通过 WebSocket 发送给客户端。
  3. message 事件中,你可以处理从服务器端收到的实时数据。你可以将这些数据渲染到页面上,或者进行其他业务逻辑的处理。

在实际应用中,你可能需要根据你的业务逻辑定制 WebSocket 的行为,并添加更多的错误处理和状态管理。

4、data 参数的含义

ResponseBodyEmitter 是用于在 Spring MVC 中异步发送响应数据的类。在这个场景下,data 参数中包含的数据是在后端逐行发送给前端的实时数据。

具体来说,data 包含的是每一行文本数据,这取决于后端代码如何使用 ResponseBodyEmitter 来发送数据。在先前的例子中,我们通过 emitter.send(line, MediaType.TEXT_PLAIN) 来发送每一行数据,而这个数据就是 line

举例来说,如果后端的逻辑是读取一个文本文件,逐行发送给前端,那么 data 就是文本文件中的每一行数据。如果后端的逻辑是调用某个 API 获取实时数据,那么 data 就是从该 API 获取到的每一行数据。

本站无任何商业行为
个人在线分享 » 想在controller里面把实时调第三方模型的实时返回的流式数据,按每句话用String类型return给前端
E-->