1.普通文本消息的發送和接收
@GetMapping("/stream")public SseEmitter streamResponse() {SseEmitter emitter = new SseEmitter(0L); // 0L 表示永不超時Executors.newSingleThreadExecutor().execute(() -> {try {for (int i = 1; i <= 5; i++) {emitter.send("消息 " + i);Thread.sleep(1000); // 模擬延遲}emitter.complete();} catch (Exception e) {emitter.completeWithError(e);}});return emitter;}
async function fetchStreamData() {const response = await fetch("/api/chat/stream");// 確保服務器支持流式數據if (!response.ok) {throw new Error(`HTTP 錯誤!狀態碼: ${response.status}`);}const reader = response.body.getReader();const decoder = new TextDecoder("utf-8");// 讀取流式數據while (true) {const { done, value } = await reader.read();if (done) break;// 解碼并輸出數據const text = decoder.decode(value, { stream: true });console.log("收到數據:", text);}console.log("流式傳輸完成");
}
// 調用流式請求
fetchStreamData().catch(console.error);
2.使用流式消息發送多個文件流,實現多個文件的傳輸
//這里相當于每個drawCatalogue對象會創建一個文件流,然后發送過去,list中有幾個對象就會發送幾個文件
//之所以要每個屬性都手動write一下,是因為我的每個ajaxResult數據量都特別大,容易內存溢出。如果沒有我這種特殊情況的話,直接使用JSONObject.toJSONString(drawCatalogue)就可以,不需要去手動寫入每個屬性。
public SseEmitter getAllDrawDataThree(String cadCode) {SseEmitter sseEmitter = new SseEmitter(Long.MAX_VALUE); // 設置超時時間為最大值,防止自動結束try {Long code = Long.parseLong(cadCode);DrawExcelList drawExcelList = new DrawExcelList();drawExcelList.setCadCode(code);List<DrawCatalogue> drawCatalogueList = drawExcelListService.treeTableCatalogue(drawExcelList);int splitSize = 20;List<DrawCatalogue> newDrawCatalogueList = splitDrawCatalogueList(drawCatalogueList, splitSize);for (int i = 0; i < newDrawCatalogueList.size(); i++) {String filePath = "drawCatalogue" + i + ".json"; // 文件路徑DrawCatalogue drawCatalogue = newDrawCatalogueList.get(i);try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {writer.write("["); // 開始寫入最外層JSON數組writer.write("{");writer.write("\"id\": \"" + drawCatalogue.getId() + "\",");writer.write("\"drawName\": \"" + drawCatalogue.getDrawName() + "\",");writer.write("\"drawType\": \"" + drawCatalogue.getDrawType() + "\",");writer.write("\"combineOutType\": \"" + drawCatalogue.getCombineOutType() + "\",");writer.write("\"num\": \"" + drawCatalogue.getNum() + "\",");writer.write("\"children\": ");writer.write("["); // 開始寫入childrenJSON數組boolean first = true; // 用于判斷是否是第一個元素List<DrawCatalogue> children = drawCatalogue.getChildren();for (DrawCatalogue child : children) {DrawingMain drawingMain = new DrawingMain();drawingMain.setCadCode(code);drawingMain.setDrawName(child.getCombineOutType());drawingMain.setDrawType(child.getDrawType());AjaxResult ajaxResult = drawingMainService.imgListShow(drawingMain);if (!first) {writer.write(","); // 如果不是第一個元素,寫入逗號分隔}String tabletJson = JSONObject.toJSONString(ajaxResult);// 逐個屬性寫入文件流writer.write("{");writer.write("\"id\": \"" + child.getId() + "\",");writer.write("\"drawName\": \"" + child.getDrawName() + "\",");writer.write("\"combineOutType\": \"" + child.getCombineOutType() + "\",");writer.write("\"drawType\": \"" + child.getDrawType() + "\",");writer.write("\"tabletJson\": " + tabletJson);writer.write("}");first = false; // 標記已經寫入了一個元素}writer.write("]"); // 結束children數組writer.write("}");writer.write("]"); // 結束最外層JSON數組} catch (IOException e) {sseEmitter.completeWithError(e);}// 讀取并發送文件流//byte[] fileData = Files.readAllBytes(Paths.get(filePath));// 分塊讀取文件并發送(防止一次性讀取的文件過大導致內存溢出)Path path = Paths.get(filePath);ByteArrayOutputStream outputStream = new ByteArrayOutputStream();byte[] buffer = new byte[8192]; // 8KB buffertry (InputStream in = Files.newInputStream(path)) {int bytesRead;while ((bytesRead = in.read(buffer)) != -1) {outputStream.write(buffer, 0, bytesRead);}}byte[] fileData = outputStream.toByteArray();sseEmitter.send(fileData, MediaType.APPLICATION_OCTET_STREAM);}sseEmitter.complete();} catch (Exception e) {sseEmitter.completeWithError(e);} finally {sseEmitter.complete();}return sseEmitter;}
前端代碼,在方法中調用,后端返回幾個文件就會彈出幾個下載窗口
const eventSource = new EventSource('http://127.0.0.1:1801/tablet/getAllDrawDataThree');eventSource.onmessage = function(event) {try {const fileData = event.data;const blob = new Blob([fileData], { type: 'application/octet-stream' });const url = window.URL.createObjectURL(blob);const a = document.createElement('a');a.style.display = 'none';a.href = url;a.download = 'file.json'; // 設置下載文件名document.body.appendChild(a);a.click();window.URL.revokeObjectURL(url);document.body.removeChild(a);} catch (error) {console.error('Error processing event data:', error);}};eventSource.onerror = function(event) {console.error('SSE error:', event);};