24小时留言板
核心效果如图所示

代码解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| # 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. 事件广播机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 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数据流接口
1 2 3 4 5 6 7 8 9 10 11
| @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操作实现
创建待办事项
1 2 3 4 5 6
| @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)模式
删除待办事项
1 2 3 4 5 6 7
| @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. 视图渲染引擎
查看模式渲染
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 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操作)
编辑模式渲染(未使用)
1 2 3
| private String renderItemEditing(Todo t) { \\ 包含表单和按钮 }
|
6. 安全机制
1 2 3 4 5 6 7
| \\ 输入转义 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)
- 预留编辑模式渲染器
优化建议
时间戳改进:
1 2 3 4 5
| \\ 当前使用服务器当前时间 LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))
\\ 建议:使用Todo创建时间 t.getCreatedAt().format(DateTimeFormatter.ofPattern("HH:mm:ss"))
|
事件完整性保证:
1 2
| \\ 增加错误处理 .doOnError(e -> log.error("Event broadcast failed", e))
|
集群支持增强:
1 2 3 4 5
| \\ 当前事件ID格式 "global_" + todo.getId() + "_" + System.currentTimeMillis()
\\ 建议增加实例标识 "node1_" + todo.getId() + "_" + System.currentTimeMillis()
|
编辑功能集成:
可启用预留的renderItemEditing方法实现编辑功能
自动清理机制:
增加定时任务清理24小时前的待办事项
该系统实现了基于响应式编程和Redis发布\订阅的高效实时应用,兼顾了性能和安全,代码结构清晰且扩展性强,是实时应用开发的优秀范例。
1 2
| ##GITHUb仓库 https:\\github.com\qingyun201908\HTMXANDSpringWebflux
|
