模板引擎的发展 及 thymeleaf

一、模板引擎的发展

1、后端模板渲染

前端与后端最初的渲染方式是后端模板渲染,就是由后端使用模板引擎渲染好 html 后,返回给前端,前端再用 js 去操作 dom 或者渲染其他动态的部分。

这个过程大致分成以下几个步骤:

  1. 前端请求一个地址 url
  2. 后端接收到这个请求,然后根据请求信息,从数据库或者其他地方获取相应的数据
  3. 使用模板引擎(如 java > jspphp > smarty)将这些数据渲染成 html
  4. 将 html 文本返回给前端

在这个过程中,前端的 html 代码需要嵌入到后端代码中(如 javaphp),并且在很多情况下,前端源代码和后端源代码是在一个工程里的。

所以,不难看出,这种方式的有这样的几个不足:

  1. 前后端杂揉在一起,不方便本地开发、本地模拟调试,也不方便自动化测试
  2. 前端被约束在后端开发的模式中,不能充分使用前端的构建生态,开发效率低下
  3. 项目难以管理和维护,也可能会有前后端职责不清的问题

尽管如此,但因为这种方式是最早出现的方式,并且这种渲染方式有一个好处,就是前端能够快速呈现服务器端渲染好的页面,而不用等客户端渲染,这能够提供很好的用户体验与 SEO 友好,所以当下很多比较早的网站或者需要快速响应的展示性网站仍然是使用这种方式。

2、客户端渲染

随着前端工程化与前后端分离的发展,以及前端组件化技术的出现,如 reactvue 等,客户端渲染已经慢慢变成了主要的开发方式了。

与后端模板渲染刚好相反,客户端渲染的页面渲染都是在客户端进行,后端不负责任何的渲染,只管数据交互。

这个过程大致分成以下几个步骤:

  1. 前端请求一个地址 url
  2. 后端接收到这个请求,然后把相应的 html 文件直接返回给前端
  3. 前端解析 js 后,然后通过 ajax 向后台获取相应的数据
  4. 然后由 js 将这些数据渲染成页面

这样一来,前端与后端将完全解耦,数据使用全 ajax 的方式进行交互,如此便可前后端分离了。

其实,不难看出,客户端渲染与前后端分离有很大的好处:

  1. 前端独立出来,可以充分使用前端生态的强大功能
  2. 更好的管理代码,更有效率的开发、调试、测试
  3. 前后端代码解耦之后,能更好的扩展、重构

所以,客户端渲染与前后端分离现在已经是主流的开发方式了。

但这种方式也有一些不足:

  1. 首屏加载缓慢,因为要等 js 加载完毕后,才能进行渲染
  2. SEO 不友好,因为 html 中几乎没有可用的信息

3、node 中间层

为了解决客户端渲染的不足,便出现了 node 中间层的理念。

传统的 B/S 架构中,是 浏览器 -> 后端服务器 -> 浏览器,上文所讲的都是这种架构。

而加入了 node 中间层之后,就变成 浏览器 -> node -> 后端服务器 -> node -> 浏览器

这个过程大致分成以下几个步骤:

  1. 前端请求一个地址 url
  2. node 层接收到这个请求,然后根据请求信息,向后端服务器发起请求,获取数据
  3. 后端服务器接收到请求,然后根据请求信息,从数据库或者其他地方获取相应的数据,返回给 node 层
  4. node 层根据这些数据渲染好首屏 html
  5. node 层将 html 文本返回给前端

一个典型的 node 中间层应用就是后端提供数据、node 层渲染模板、前端动态渲染。

这个过程中,node 层由前端开发人员掌控,页面中哪些页面在服务器上就渲染好,哪些页面在客户端渲染,由前端开发人员决定。

这样做,达到了以下的目的:

  1. 保留后端模板渲染、首屏快速响应、SEO 友好
  2. 保留前端后分离、客户端渲染的功能(首屏服务器端渲染、其他客户端渲染)

但这种方式也有一些不足:

  1. 增加了一个中间层,应用性能有所降低
  2. 增加了架构的复杂度、不稳定性,降低应用的安全性
  3. 对开发人员要求高了很多

4、服务器端渲染(ssr)

大部分情况下,服务器端渲染(ssr)与 node 中间层是同一个概念。

服务器端渲染(ssr)一般特指,在上文讲到的 node 中间层基础上,加上前端组件化技术在服务器上的渲染,特别是 react 和 vue

reactvueangular 等框架的出现,让前端组件化技术深入人心,但在一些需要首屏快速加载与 SEO 友好的页面就陷入了两难的境地了。

因为前端组件化技术天生就是给客户端渲染用的,而在服务器端需要被渲染成 html 文本,这确实不是一件很容易的事,所以服务器端渲染(ssr)就是为了解决这个问题。

好在社区一直在不断的探索中,让前端组件化能够在服务器端渲染,比如 next.jsnuxt.jsrazzlereact-serverbeidou 等。

一般这些框架都会有一些目录结构、书写方式、组件集成、项目构建的要求,自定义属性可能不是很强。

以 next.js 为例,整个应用中是没有 html 文件的,所有的响应 html 都是 node 动态渲染的,包括里面的元信息、css, js 路径等。渲染过程中,next.js 会根据路由,将首页所有的组件渲染成 html,余下的页面保留原生组件的格式,在客户端渲染。

5、建议

  1. 不需要首屏快速加载、SEO 友好的,用全客户端渲染
  2. 需要首屏快速加载、SEO 友好的,如果用了如 reactvue 等组件化技术,将不得不用 node 中间层与服务器端渲染
  3. 如果技术团队不支持,不建议在需要首屏快速加载、SEO 友好的地方使用如 reactvue 等组件化技术。如果你的技术团队出色且支持,而且又需要快速渲染和SEO优化,且用了react,vue等技术,那你可以尝试搭建SSR渲染架构
  4. 前后端分离之后也可以做后端模板渲染,这样前端的调试可以搭配 handlebarsejs 等模板引擎进行本地调试,而后端的调试则需要到测试机了

二、不使用模板引擎的示例

这里我们通过一个例子来更加直白的了解模板引擎。

首先我们需要实现这样的一个界面

有如下要求: - 数据必须来源一个指定的数组 - 具有动态性,不能写死数据。

如果不使用模板引擎,希望最终HTML页面跟数据绑定的话常见的实现有两种。

1、字符串拼接

直接上相关代码,其实就是将HTML作为字符串一个个拼出来:

var songs =[
        {name:'刚刚好', singer:'薛之谦', url:'http://music.163.com/xxx'},
        {name:'最佳歌手', singer:'许嵩', url:'http://music.163.com/xxx'},
        {name:'初学者', singer:'薛之谦', url:'http://music.163.com/xxx'},
        {name:'绅士', singer:'薛之谦', url:'http://music.163.com/xxx'},
        {name:'我们', singer:'陈伟霆', url:'http://music.163.com/xxx'},
        {name:'画风', singer:'后弦', url:'http://music.163.com/xxx'},
        {name:'We Are One', singer:'郁可唯', url:'http://music.163.com/xxx'} 

    ]

    //拼接字符串,有一定恶意脚本注入风险 遍历

    var html = '';
    html +='<div class="song-list">'
    html +='  <h1>热歌榜</h1>'
    html +='  <ol>'
    for(var i=0;i<songs.length;i++){
        html += '<li>'+songs[i].name+' - '+songs[i].singer+'</li>'
    }
    html +='  </ol>'
    html +='</div>'

    document.body.innerHTML =html;

2、构造DOM对象

借助DOM对象和数据源来操作

    // 构造DOM对象 遍历 缺点复杂;
    var elDiv = document.createElement('div')
    elDiv.className = 'song-list';
    var elH1 =document.createElement('h1')
    elH1.appendChild(document.createTextNode('热歌榜'))
    var elList = document.createElement('ol')
    for(var i = 0; i<songs.length;i++){
        var li = document.createElement('li')
        li.textContent = songs[i].name +' - ' + songs[i].singer
        elList.appendChild(li)

    }
    elDiv.appendChild(elH1);
    elDiv.appendChild(elList);

    document.body.appendChild(elDiv);

可以看到上述两种方式虽然可以达成需求,但是尤其繁琐且缺乏规范,很容易出错。

我们这样思考,其实这些数据替换的地方都是固定的也有一定的逻辑,那能不能将这个替换逻辑抽离出来形成规范,来统一进行处理呢?

 

三、使用模板引擎的方式

1、置换型模板引擎

这种模板引擎原理比较直观,实现也相对简单,我们先来看一下:

var template = '<p>Hello,my name is <%name%>. I am  <%age%> years old.</p>';

    var data ={
        name:'zyn',
        age:31
    }

    var TemplateEngine = function (tpl,data){

        var regex = /<%([^%>]+)?%>/g;
        while(match = regex.exec(tpl)){
            tpl = tpl.replace(match[0],data[match[1]])
        }
        return tpl
    }
    var string = TemplateEngine(template,data)
    console.log(string);

这里其实就是把模板中需要替换的字符串做了个标记,这里是以<%...%>作为标记,然后替换时基于正则捕捉该标记并进行数据源的替换(通过同一个key进行)

模板文件: var template = '<p>Hello,my name is <%name%>. I am  <%age%> years old.</p>';

数据:  var data ={
        name:'zyn',
        age:31
    }

模板引擎: var TemplateEngine = function (tpl,data){
        var regex = /<%([^%>]+)?%>/g;
        while(match = regex.exec(tpl)){
            tpl = tpl.replace(match[0],data[match[1]])
        }
        return tpl
    }

HTML文件:
 var string=TemplateEngine(template,data)
    document.body.innerHTML= string

2、JS代码函数型模板语法与dom-based模板引擎

参考:模板引擎的整理归纳 - 知乎 (zhihu.com),这里不再赘述。

三、模板引擎是什么

首先我们来了解什么是模板,模板就我个人理解而言其产生的目的是为了解决展示与数据的耦合,简单来说模板还是一段字符,只不过其中有一些片段跟数据相关,实际开发中根据数据模型与模板来动态生成最终的HTML(或者其他类型片段,本文都以HTML 为例子)。

而模板引擎就是可以简化该拼接过程,通过一些声明与语法或格式的工具,尽可能让最终HTML的生成简单且直观。搬一下网上的概念:模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的文档。

模板引擎的核心原理就是两个字:替换。将预先定义的标签字符替换为指定的业务数据,或者根据某种定义好的流程进行输出。

模板引擎就是通过写一个页面模板,比如有些值是动态的,需要写一些表达式。把这个模板和数据交给模板引擎,模板引擎将表达式解析后,把数据填充到指定的位置,将数据内容显示出来。不管是jsp还是其他模板引擎,都是这个思想。只不过不同模板引擎之间,语法不一样。

四、Thymeleaf 介绍

从官方的介绍来看,Thymeleaf的目标很明确:

  • Thymeleaf的主要目标是为您的开发工作流程带来优雅自然的模板-HTML可以在浏览器中正确显示,也可以作为静态原型工作,从而可以在开发团队中加强协作。
  • Thymeleaf拥有适用于Spring Framework的模块,与您喜欢的工具的大量集成以及插入您自己的功能的能力,对于现代HTML5 JVM Web开发而言,Thymeleaf是理想的选择——尽管它还有很多工作要做。

并且随着市场使用的验证Thymeleaf也达到的它的目标和大家对他的期望,在实际开发有着广泛的应用。Thymeleaf作为被Springboot官方推荐的模板引擎,一定有很多过人和不寻同之处:

  • 动静分离: Thymeleaf选用html作为模板页,这是任何一款其他模板引擎做不到的!Thymeleaf使用html通过一些特定标签语法代表其含义,但并未破坏html结构,即使无网络、不通过后端渲染也能在浏览器成功打开,大大方便界面的测试和修改。
  • 开箱即用: Thymeleaf提供标准和Spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、改JSTL、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。
  • Springboot官方大力推荐和支持,Springboot官方做了很多默认配置,开发者只需编写对应html即可,大大减轻了上手难度和配置复杂度。

五、动静分离

你可能还是不明白什么才是真正的动静分离,其实这个主要是由于Thymeleaf模板基于html,后缀也是.html,所以这样就会产生一些有趣的灵魂。

对于传统jsp或者其他模板来说,没有一个模板引擎的后缀为.html,就拿jsp来说jsp的后缀为.jsp,它的本质就是将一个html文件修改后缀为.jsp,然后在这个文件中增加自己的语法、标签然后执行时候通过后台处理这个文件最终返回一个html页面。

浏览器无法直接识别.jsp文件,需要借助网络(服务端)才能进行访问;而Thymeleaf用html做模板可以直接在浏览器中打开。开发者充分考虑html页面特性,将Thymeleaf的语法通过html的标签属性来定义完成,这些标签属性不会影响html页面的完整性和显示。如果通过后台服务端访问页面服务端会寻找这些标签将服务端对应的数据替换到相应位置实现动态页面!大体区别可以参照下图:

上图的意思就是:

如果直接打开这个html那么浏览器会对th等标签忽视而显示原始的内容。

如果通过服务端访问那么服务端将先寻找th标签将服务端储存的数据替换到对应位置。

具体效果可以参照下图,下图即为一个动静结合的实例。

  • 右上角为动态页面通过服务端访问,数据显示为服务端提供的数据,样式依然为html的样式
  • 右下角为静态页面可通过浏览器直接打开,数据为初始的数据

 动态页面每次修改打开都需要重新启动程序、输入链接,这个过程其实是相对漫长的。如果界面设计人员用这种方式进行页面设计时间成本高并且很麻烦,可通过静态页面设计样式,设计完成通过服务端访问即可达成目标UI的界面和应用,达到动静分离的效果。这个特点和优势是所有模板引擎中Thymeleaf所独有的!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

种麦南山下

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值