为了账号安全,请及时绑定邮箱和手机立即绑定

使用Spring Boot进行服务器端渲染 (SSR)

标签:
SpringBoot SSM

理解项目设置中的共同步骤是至关重要的,在深入了解每种客户端增强技术的细节之前。我这边的要求(来自上一篇帖子)非常简单明了:

  • 我将以后端开发者的视角来看这个问题。

  • 无需使用TypeScript等前端构建工具,如压缩代码。

  • 所有依赖项都通过后端应用程序(比如Maven)管理。

重要的是要指出,我将详细介绍的技术,除了Vaadin之外的其他技术都采用了相似的途径。Vaadin因为其独特的方法,在这些技术中脱颖而出。

WebJars,即Webjar

WebJars,这项技术由詹姆斯·沃德在2012年设计,旨在处理这些具体需求。

WebJars是将客户端Web库(如jQuery和Bootstrap)打包成JAR(Java Archive)文件的格式。

明确且轻松地管理基于JVM的Web应用程序中的客户端依赖

使用基于JVM的构建工具(如Maven、Gradle、sbt等)下载客户端依赖

了解您正在使用的客户端依赖

传递依赖项会自动解析并可通过RequireJS加载

部署在Maven Central

公共CDN由JSDelivr提供

WebJars官网

WebJar 是一个普通的 JAR 文件,里面包含了 web 资源。将 WebJar 添加到项目的依赖中并不特别奇怪。

    <dependencies>  
        <dependency>  
            <groupId>org.webjars.npm</groupId>  
            <artifactId>alpinejs</artifactId>  
            <version>3.14.1</version>  
        </dependency>  
    </dependencies>

这是一个配置示例,展示了如何将Alpine.js作为一个依赖项添加到项目中。

框架的责任是让资源可以通过一个URL访问。例如,Spring Boot 在 WebMvcAutoConfiguration 类中完成这个功能。

    public void addResourceHandlers(ResourceHandlerRegistry registry) {  
      if (!this.resourceProperties.isAddMappings()) {  
        logger.debug("// 默认资源处理已关闭");  
        return;  
      }  
      addResourceHandler(registry, this.mvcProperties.getWebjarsPathPattern(),  
        "classpath:/META-INF/resources/webjars/");  
      addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {  
        registration.addResourceLocations(this.resourceProperties.getStaticLocations());  
        if (this.servletContext != null) {  
          ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);  
          registration.addResourceLocations(resource);  
        }  
      });  
    }
  1. 默认是 "/webjars/**"

在 JAR 文件内,你可以通过各自的路径和文件名访问资源。约定的存储结构为 resources/webjars/<库名>/<版本号>。以下是 alpinejs-3.14.1.jar 的内部结构:

META-INF 文件夹
  |- 包含一个 MANIFEST.MF 文件
  |- maven.org.webjars.npm.alpinejs 目录
  |- resources.webjars.alpinejs.3.14.1 目录,该目录下包含
    |- builds 文件夹
    |- dist 文件夹,该文件夹中包含
      |- cdn.js 文件
      |- cdn.min.js 文件
    |- src 文件夹
    |- package.json 文件

在 Spring Boot 中,你可以通过这个路径访问未压缩的原版:/webjars/alpinejs/3.14.1/dist/cdn.js

开发人员经常发布客户端库,这些库。当你在POM中更改依赖版本时,你可能需要在多个地方修改前端路径。这既枯燥又毫无意义,还可能遗漏某个更改。

WebJars 定位器项目旨在通过提供一个不包含版本号的路径来解决这些问题,例如 webjars/alpinejs/dist/cdn.js。你可以通过在你的项目中添加 webjars-locator JAR 来实现。

    <dependencies>  
        <dependency>  
            <groupId>org.webjars.npm</groupId>  
            <artifactId>alpinejs</artifactId>  
            <version>3.14.1</version>  
        </dependency>  
        <dependency>  
            <groupId>org.webjars</groupId>  
            <artifactId>webjars-locator</artifactId>  
            <version>0.52</version>  
        </dependency>  
    </dependencies>

我将对每一种前端技术框架或工具都采用这种方法。我还将引入Bootstrap CSS库,以提升用户界面的美观度。

ThymeLeaf 模板引擎

Thymeleaf 是一种服务器端的模板引擎。

Thymeleaf 是一个现代的服务器端Java模板引擎,适用于Web和独立的应用程序环境。

Thymeleaf的主要目标是将自然风格的HTML模板带入您的开发工作流程——可以在浏览器中正确显示的HTML,也可以作为静态原型使用,从而加强开发团队间的协作。

通过Spring框架的模块、与您喜爱工具的各种集成以及轻松集成您自定义的功能,Thymeleaf非常适合现代HTML5 JVM Web开发——虽然它还有许多其他用途。

Thymeleaf

当我第一次听说Thymeleaf时,我仍然是个顾问。那时,JSP已经接近尾声。JSF正试图取代它们,但在我看来,它们没能成功。

我觉得Thymeleaf是一个很酷的方案:它让你可以在设计时看到静态结果,开发时看到服务器上的结果。更酷的是,你可以在同一个文件里轻松切换这两种环境。我还从来没见这种功能被用过。

然而,Spring Boot 完全支持 Thymeleaf。真是好上加好:后者可以通过页面上的一个 HTML 命名空间获得。如果你对 JSF 不感冒(提示:我对它也不感冒),Thymeleaf 是今天最常用的 SSR(服务端渲染)模板语言。

这里有一个网站上的演示样本。

    <table>  
      <thead>  
        <tr>  
          <th th:text="#{msgs.headers.name}">名称:</th>  
          <th th:text="#{msgs.headers.price}">价格:</th>  
        </tr>  
      </thead>  
      <tbody>  
        <tr th:each="prod: ${allProducts}">  
          <td th:text="${prod.name}">橙</td>  
          <td th:text="${#numbers.formatDecimal(prod.price, 1, 2)}">0.99</td>  
        </tr>  
      </tbody>  
    </table>

如果你需要熟悉Thymeleaf,这里有一份Thymeleaf入门教程。

  • 当你打开 HTML 文件时,浏览器会显示标签中的默认值,即 NamePrice。当你在服务器端运行时,Thymeleaf 会介入并渲染从 th:text#{msgs.headers.name}#{msgs.headers.price} 计算后的值。
  • `# 使用Spring Boot进行服务器端渲染 (SSR)

理解项目设置中的共同步骤是至关重要的,在深入了解每种客户端增强技术的细节之前。我这边的要求(来自上一篇帖子)非常简单明了:

  • 我将以后端开发者的视角来看这个问题。

  • 无需使用TypeScript等前端构建工具,如压缩代码。

  • 所有依赖项都通过后端应用程序(比如Maven)管理。

重要的是要指出,我将详细介绍的技术,除了Vaadin之外的其他技术都采用了相似的途径。Vaadin因为其独特的方法,在这些技术中脱颖而出。

WebJars,即Webjar

WebJars,这项技术由詹姆斯·沃德在2012年设计,旨在处理这些具体需求。

WebJars是将客户端Web库(如jQuery和Bootstrap)打包成JAR(Java Archive)文件的格式。

明确且轻松地管理基于JVM的Web应用程序中的客户端依赖

使用基于JVM的构建工具(如Maven、Gradle、sbt等)下载客户端依赖

了解您正在使用的客户端依赖

传递依赖项会自动解析并可通过RequireJS加载

部署在Maven Central

公共CDN由JSDelivr提供

WebJars官网

WebJar 是一个普通的 JAR 文件,里面包含了 web 资源。将 WebJar 添加到项目的依赖中并不特别奇怪。

    <dependencies>  
        <dependency>  
            <groupId>org.webjars.npm</groupId>  
            <artifactId>alpinejs</artifactId>  
            <version>3.14.1</version>  
        </dependency>  
    </dependencies>

这是一个配置示例,展示了如何将Alpine.js作为一个依赖项添加到项目中。

框架的责任是让资源可以通过一个URL访问。例如,Spring Boot 在 WebMvcAutoConfiguration 类中完成这个功能。

    public void addResourceHandlers(ResourceHandlerRegistry registry) {  
      if (!this.resourceProperties.isAddMappings()) {  
        logger.debug("// 默认资源处理已关闭");  
        return;  
      }  
      addResourceHandler(registry, this.mvcProperties.getWebjarsPathPattern(),  
        "classpath:/META-INF/resources/webjars/");  
      addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {  
        registration.addResourceLocations(this.resourceProperties.getStaticLocations());  
        if (this.servletContext != null) {  
          ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);  
          registration.addResourceLocations(resource);  
        }  
      });  
    }
  1. 默认是 "/webjars/**"

在 JAR 文件内,你可以通过各自的路径和文件名访问资源。约定的存储结构为 resources/webjars/<库名>/<版本号>。以下是 alpinejs-3.14.1.jar 的内部结构:

META-INF 文件夹
  |- 包含一个 MANIFEST.MF 文件
  |- maven.org.webjars.npm.alpinejs 目录
  |- resources.webjars.alpinejs.3.14.1 目录,该目录下包含
    |- builds 文件夹
    |- dist 文件夹,该文件夹中包含
      |- cdn.js 文件
      |- cdn.min.js 文件
    |- src 文件夹
    |- package.json 文件

在 Spring Boot 中,你可以通过这个路径访问未压缩的原版:/webjars/alpinejs/3.14.1/dist/cdn.js

开发人员经常发布客户端库,这些库。当你在POM中更改依赖版本时,你可能需要在多个地方修改前端路径。这既枯燥又毫无意义,还可能遗漏某个更改。

WebJars 定位器项目旨在通过提供一个不包含版本号的路径来解决这些问题,例如 webjars/alpinejs/dist/cdn.js。你可以通过在你的项目中添加 webjars-locator JAR 来实现。

    <dependencies>  
        <dependency>  
            <groupId>org.webjars.npm</groupId>  
            <artifactId>alpinejs</artifactId>  
            <version>3.14.1</version>  
        </dependency>  
        <dependency>  
            <groupId>org.webjars</groupId>  
            <artifactId>webjars-locator</artifactId>  
            <version>0.52</version>  
        </dependency>  
    </dependencies>

我将对每一种前端技术框架或工具都采用这种方法。我还将引入Bootstrap CSS库,以提升用户界面的美观度。

ThymeLeaf 模板引擎

Thymeleaf 是一种服务器端的模板引擎。

Thymeleaf 是一个现代的服务器端Java模板引擎,适用于Web和独立的应用程序环境。

Thymeleaf的主要目标是将自然风格的HTML模板带入您的开发工作流程——可以在浏览器中正确显示的HTML,也可以作为静态原型使用,从而加强开发团队间的协作。

通过Spring框架的模块、与您喜爱工具的各种集成以及轻松集成您自定义的功能,Thymeleaf非常适合现代HTML5 JVM Web开发——虽然它还有许多其他用途。

Thymeleaf

当我第一次听说Thymeleaf时,我仍然是个顾问。那时,JSP已经接近尾声。JSF正试图取代它们,但在我看来,它们没能成功。

我觉得Thymeleaf是一个很酷的方案:它让你可以在设计时看到静态结果,开发时看到服务器上的结果。更酷的是,你可以在同一个文件里轻松切换这两种环境。我还从来没见这种功能被用过。

然而,Spring Boot 完全支持 Thymeleaf。真是好上加好:后者可以通过页面上的一个 HTML 命名空间获得。如果你对 JSF 不感冒(提示:我对它也不感冒),Thymeleaf 是今天最常用的 SSR(服务端渲染)模板语言。

这里有一个网站上的演示样本。

    <table>  
      <thead>  
        <tr>  
          <th th:text="#{msgs.headers.name}">名称:</th>  
          <th th:text="#{msgs.headers.price}">价格:</th>  
        </tr>  
      </thead>  
      <tbody>  
        <tr th:each="prod: ${allProducts}">  
          <td th:text="${prod.name}">橙</td>  
          <td th:text="${#numbers.formatDecimal(prod.price, 1, 2)}">0.99</td>  
        </tr>  
      </tbody>  
    </table>

如果你需要熟悉Thymeleaf,这里有一份Thymeleaf入门教程。

操作符用于查询模型中的 Spring bean。${prod.name} 等同于 model.getBean("prod").getName()

  • # 调用一个函数或方法。
  • th:each 可用于循环

将Thymeleaf与前端框架集成

大多数前端框架通常使用的是客户端模型。我们需要在服务器端和客户端模型之间建立连接。

下面是我的服务器端代码:

    data class Todo(val id: Int, var label: String, var completed: Boolean = false) //1 数据类

    fun 配置() = beans {  
      bean {  
        mutableListOf( // 可变列表
          Todo(1, "买杂货", false),  
          Todo(2, "遛遛狗", false),  
          Todo(3, "扔垃圾", false)  
        )  
      }  
      bean {  
        router {  
          GET("/") {  
            ok().render( // 渲染  
              "index", // 渲染模板
              mapOf("title" to "标题", "todos" to ref<List<Todo>>()) // 引用待办事项列表
            )  
          }  
        }  
      }  
    }
  1. 定义 Todo
  2. 向 bean 工厂添加一个内存列表。在常规应用中,你会使用一个 Repository 来从数据库读取数据
  3. 渲染一个 HTML 模板
  4. 模板位于 src/main/resources/templates/index.html,使用了 Thymeleaf 属性
  5. 将模型放入页面上下文中

Thymeleaf 在 <script> 标签上提供了 th:inline="javascript" 属性。它将服务器端的数据渲染成 JavaScript 变量。文档对此的解释比我所能做的要详细得多:

我们可以用内联脚本做的第一件事就是将表达式的值写入脚本中,例如:

<script th:inline="javascript">
/<![CDATA[/

var username = /[[${session.user.name}]]/ 'Sebastian';


/]]>/
</script>

这里的_/*[[...]]*/_语法让Thymeleaf去计算包含的表达式。但这里还有其他含义:

  • 由于是 JavaScript 注释 (/*...*/),当页面在浏览器中静态显示时,该表达式会被忽略。

  • 内联表达式后面的代码 ('Sebastian') 会在页面静态显示时执行。

  • Thymeleaf 会执行表达式并插入结果,同时,它还会移除内联表达式之后的代码(这部分会在页面静态显示时执行)。

Thymeleaf 文档

如果我们把上述做法应用于我们的代码,Spring传递给我们的模型的属性将如下所示:

<script th:inline="javascript">  
/*<![CDATA[*/  
  window.title = /*[[${title}]]*/ '标题'  
  window.todos = /*[[${todos}]]*/ [{ 'id': 1, 'label': '倒一趟垃圾', 'completed': false }]  
/*]]>*/  
</script>

这样在服务器端渲染时产生的结果是:

    <script>  
    /*<![CDATA[*/  
      window.title = "我的标题";  
      window.todos = [{"id":1,"label":"去超市","completed":false},{"id":2,"label":"遛狗","completed":false},{"id":3,"label":"倒垃圾","completed":false}]  
    /*]]>*/  
    </script>
概述.

在这篇文章里,我将介绍两个模块,它们将在后续文章中使用。

  • WebJars 可以帮助您在 Maven POM 中管理客户端依赖项
  • Thymeleaf 是一个与 Spring Boot 配套使用的优质模板引擎

该帖子的完整源代码可以在GitHub上找到。

更进一步!

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消