Browse Source

sse 实现 chat gpt 打字机效果

James 2 years ago
parent
commit
ad3997449a
1 changed files with 122 additions and 0 deletions
  1. 122 0
      src/main/java/com/jfinal/kit/SseEmitter.java

+ 122 - 0
src/main/java/com/jfinal/kit/SseEmitter.java

@@ -0,0 +1,122 @@
+/**
+ * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.kit;
+
+import com.jfinal.core.Const;
+import com.jfinal.log.Log;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * sse 实现 chat gpt 打字机效果
+ */
+public class SseEmitter {
+
+    private final HttpServletResponse response;
+    private boolean complete;
+
+    public SseEmitter(HttpServletResponse response) {
+        this.response = response;
+        this.complete = false;
+        this.initResponse();
+    }
+
+    private void initResponse() {
+        response.setContentType("text/event-stream");
+        response.setCharacterEncoding(Const.DEFAULT_ENCODING);
+        response.setHeader("Content-Type", "text/event-stream; charset:utf-8");
+        response.setHeader("Cache-Control", "no-cache");
+        response.setHeader("Connection", "keep-alive");
+    }
+
+    /**
+     * sse 等待中
+     * @param sleepMillis 睡觉毫秒时长
+     */
+    public void waiting(int sleepMillis) {
+        if (sleepMillis <= 0) {
+            sleepMillis = 100;
+        }
+        while (!complete) {
+            try {
+                Thread.sleep(sleepMillis);
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        System.out.println("Waiting finished");
+    }
+
+    /**
+     * 响应 sse 自动转 json
+     * @param data 推送给客户端的数据
+     */
+    public void sendMessage(Object data) {
+        sendMessage(data == null ? null : JsonKit.toJson(data));
+    }
+
+    /**
+     * 响应 sse 自动转 json
+     * @param data        推送给客户端的文本
+     * @param retryMillis 多长毫秒时间让客户端重试
+     */
+    public void sendMessage(Object data, int retryMillis) {
+        sendMessage(data == null ? null : JsonKit.toJson(data), retryMillis);
+    }
+
+    /**
+     * 响应 sse
+     * @param data 推送给客户端的文本
+     */
+    public void sendMessage(String data) {
+        sendMessage(data, 0);
+    }
+
+    /**
+     * 响应 sse
+     * @param data        推送给客户端的文本
+     * @param retryMillis 多长毫秒时间让客户端重试
+     */
+    public void sendMessage(String data, int retryMillis) {
+        try {
+            PrintWriter writer = response.getWriter();
+            String dataStr = retryMillis > 0 ? "retry: %s\ndata: %s\n\n" : "data: %s\n\n";
+            if (data == null) {
+                data = "";
+            }
+            writer.write(retryMillis > 0 ? String.format(dataStr, retryMillis, data) : String.format(dataStr, data));
+            writer.flush();
+        } catch (IOException e) {
+            Log.getLog(getClass()).error(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 结束 sse
+     */
+    public void complete() {
+        try (PrintWriter writer = response.getWriter()) {
+            writer.write("event:complete\ndata:\n\n");
+            writer.flush();
+        } catch (IOException e) {
+            Log.getLog(getClass()).error(e.getMessage(), e);
+        } finally {
+            complete = true;
+        }
+    }
+}