Skip to content

HTML 代码片段 (HTML Fragments)

HTMXHotwire Turbo 强调一种“HTML 经由网络”(HTML-over-the-wire)的方法。在这种模式下,客户端接收的是服务器更新的 HTML 片段,而不是 JSON 数据。这使得开发者可以在不编写(或极少编写)JavaScript 的情况下,获得类似单页应用(SPA)的用户体验。

核心实现

在传统的 Spring MVC 视图渲染中,通常一个请求对应一个视图和一个模型。但在 HTML-over-the-wire 模式下,一个常见的需求是发送多个 HTML 片段来更新页面的不同部分。

1. 返回集合 (Collection ModelAndView )

控制器方法可以返回 ModelAndView 的集合。

java
@GetMapping("/updates")
public List<ModelAndView> handle() {
    return List.of(
        new ModelAndView("posts"), 
        new ModelAndView("comments")
    );
}
kotlin
@GetMapping("/updates")
fun handle(): List<ModelAndView> {
    return listOf(
        ModelAndView("posts"), 
        ModelAndView("comments")
    )
}

2. FragmentsRendering

Spring MVC 还提供了一个专门的类型 FragmentsRendering 来简化这一过程。

java
@GetMapping("/updates")
public FragmentsRendering handle() {
    return FragmentsRendering.fragment("posts")
            .fragment("comments")
            .build();
}

每个片段都可以拥有独立的模型,且该模型会继承请求中的共享模型属性。

流式更新 (Streaming Updates)

HTMX 和 Hotwire Turbo 支持通过 SSE (Server-Sent Events) 进行流式更新。控制器可以使用 SseEmitter 为每个事件发送一个 ModelAndView 片段。

java
@GetMapping("/stream-updates")
public SseEmitter handle() {
    SseEmitter emitter = new SseEmitter();
    // 在后台线程中发送
    startWorkerThread(() -> {
        try {
            emitter.send(SseEmitter.event().data(new ModelAndView("posts")));
            emitter.send(SseEmitter.event().data(new ModelAndView("comments")));
        } catch (IOException ex) {
            // 取消发送
        }
    });
    return emitter;
}

也可以通过返回 Flux<ModelAndView> 来实现响应式的片段流。


补充教学

1. 为什么要重返 HTML?

在经历了数年“重客户端 JS 框架”的流行后,行业发现许多 CRUD 应用其实并不需要极其复杂的 JS 逻辑。

  • HTMX/Turbo:将逻辑保留在后端(熟悉的 Java/Spring),前端只负责“局部替换”。
  • 优势:极大地降低了前后端联调的成本,SEO 友好,且初次加载速度极快。

2. 状态同步问题

在这种模式下,客户端的状态(如输入框的内容)是由 HTML 标记本身维持的。当服务器返回新片段时,HTMX 等库会智能地进行 DOM Diff 算法合并,以保留客户端的临时状态(如焦点、滚动位置)。

3. 应用场景建议

非常适合:管理后台、仪表盘、实时通知更新、无限滚动列表。 不适合:需要极高性能交互的图形编辑器、大型在线协作工具。

Based on Spring Framework.