title: 24小時留言板
date: 2025-06-25 23:32:53
tags: 代碼工具
24小時留言板
核心效果如圖所示
代碼解析
# TodoController 代碼解析## 整體架構
這是一個基于Spring WebFlux的響應式控制器,結合Redis發布\訂閱機制實現實時更新的待辦事項系統。關鍵組件包括:
- **TodoRepo**:數據訪問層接口
- **ReactiveRedisTemplate**:Redis響應式操作模板
- **ChannelTopic**:Redis消息通道
- **Sinks.Many**:Project Reactor的事件分發器## 核心功能解析### 1. Redis發布\訂閱初始化
```java
public TodoController(TodoRepo repo, ReactiveRedisTemplate<String, String> redisTemplate) {this.repo = repo;this.redisTemplate = redisTemplate;redisTemplate.listenTo(todoTopic).map(msg -> msg.getMessage()).filter(message -> !StringUtils.isEmpty(message)).subscribe(eventSink::tryEmitNext);
}
- 功能:控制器啟動時自動訂閱Redis頻道
- 處理流程:
- 監聽
todo_events
頻道 - 提取消息內容
- 過濾空消息
- 將消息推送到事件流(Sinks)
- 監聽
2. 事件廣播機制
private void broadcastEvent(String eventType, Todo todo) {String messageId = "global_" + todo.getId() + "_" + System.currentTimeMillis();String payload = "";\\ 事件類型處理switch (eventType) {case "create":case "update":payload = String.format("id:%s\nevent:%s\ndata:%s\n\n",messageId, eventType, renderItem(todo));break;case "delete":payload = String.format("id:%s\nevent:delete\ndata:%d\n\n",messageId, todo.getId());break;}\\ Redis發布if (StringUtils.hasLength(payload)) {redisTemplate.convertAndSend(todoTopic.getTopic(), payload).subscribe();}
}
- 事件格式:符合SSE規范,包含:
id
:全局唯一事件ID(含時間戳)event
:事件類型(create\update\delete)data
:有效載荷
- 安全設計:廣播前檢查消息有效性
3. SSE數據流接口
@GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> list() {Flux<String> initialFlux = repo.findAllByOrderByIdDesc().map(todo -> String.format("id:init_%d\nevent:create\ndata:%s\n\n",todo.getId(), renderItem(todo)));return Flux.merge(initialFlux, eventSink.asFlux()).filter(payload -> !StringUtils.isEmpty(payload));
}
- 實現策略:
- 加載初始數據并轉換為SSE格式(init前綴)
- 合并實時事件流(Redis訂閱)
- 過濾空消息
- SSE規范:
id: [event_id]
event: [event_type]
data: [payload]
- 消息以雙換行結束
4. CRUD操作實現
創建待辦事項
@PostMapping
public Mono<String> create(@ModelAttribute Form form) {return repo.save(new Todo(null, HtmlUtils.htmlEscape(form.getContent()))).doOnSuccess(todo -> broadcastEvent("create", todo)).thenReturn("");
}
- 安全特性:HTML內容轉義防御XSS
- 響應策略:空字符串實現PRG(Post-Redirect-Get)模式
刪除待辦事項
@PostMapping(path = "\{id}\delete", produces = MediaType.TEXT_HTML_VALUE)
public Mono<String> delete(@PathVariable Long id) {return repo.findById(id).doOnSuccess(todo -> broadcastEvent("delete", todo)).then(repo.deleteById(id)).thenReturn("");
}
- 關鍵流程:
- 先查詢再刪除(確保廣播正確的todo數據)
- 廣播刪除事件
- 執行刪除操作
5. 視圖渲染引擎
查看模式渲染
private String renderItem(Todo t) {return """<li id="todo-%d" class="message-item"><div class="message-content">%s<div class="message-extra"><div class="message-time"><i class="far fa-clock"><\i> %s<\div><\div><\div><div class="message-actions"><button class="delete-btn" onclick="handleDelete(%d)"><i class="fas fa-trash-alt"><\i><\button><\div><\li>""";
}
- 元素結構:
- 唯一ID綁定:
todo-{id}
- 內容顯示區
- 時間戳(當前服務器時間)
- 刪除按鈕(綁定JavaScript操作)
- 唯一ID綁定:
編輯模式渲染(未使用)
private String renderItemEditing(Todo t) {\\ 包含表單和按鈕
}
- 潛在擴展點:提供編輯功能時可復用
6. 安全機制
\\ 輸入轉義
HtmlUtils.htmlEscape(form.getContent())\\ 輸出轉義
private String escapeHtml(String s) {return HtmlUtils.htmlEscape(s);
}
- 雙保險策略:輸入輸出雙重轉義防御XSS攻擊
- 規范實踐:使用Spring內置HtmlUtils工具類
設計亮點
-
響應式架構:
- Flux\Mono異步處理
- 背壓支持(onBackpressureBuffer)
-
實時廣播系統:
- Redis發布\訂閱
- 多級事件分發(Sinks->Flux)
-
客戶端驅動更新:
- HTML片段直接注入頁面
- 無JavaScript框架依賴
-
優雅降級策略:
- 事件ID前綴區分初始化\實時事件
- 空消息過濾保證穩定性
-
擴展性設計:
- 事件類型支持(create\update\delete)
- 預留編輯模式渲染器
優化建議
-
時間戳改進:
\\ 當前使用服務器當前時間 LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))\\ 建議:使用Todo創建時間 t.getCreatedAt().format(DateTimeFormatter.ofPattern("HH:mm:ss"))
-
事件完整性保證:
\\ 增加錯誤處理 .doOnError(e -> log.error("Event broadcast failed", e))
-
集群支持增強:
\\ 當前事件ID格式 "global_" + todo.getId() + "_" + System.currentTimeMillis()\\ 建議增加實例標識 "node1_" + todo.getId() + "_" + System.currentTimeMillis()
-
編輯功能集成:
可啟用預留的renderItemEditing
方法實現編輯功能 -
自動清理機制:
增加定時任務清理24小時前的待辦事項
該系統實現了基于響應式編程和Redis發布\訂閱的高效實時應用,兼顧了性能和安全,代碼結構清晰且擴展性強,是實時應用開發的優秀范例。
## GITHUb倉庫
https:\\github.com\qingyun201908\HTMXANDSpringWebflux