文档章节

关于Thymeleaf的真相

闲大赋
 闲大赋
发布于 2017/08/09 21:59
字数 3071
阅读 4615
收藏 23

Thymeleaf 一直以来都是个使用小众的模板引擎,在2.0以前,最为人吐槽的是性能跌到无底线。甚至朋友的项目因为Thymeleaf性能慢,影响到整个项目慢。Stackoveflow 社区也有很多人吐槽影响了自己的系统性能。 总所周知,系统单纯某一方面性能慢很难影响整个系统性能,如果系统慢,最有可能的是数据存取出问题,然而Thymeleaf能导致系统奇慢无比,确实是开源软件头一遭。 如果你不相信Thymeleaf2.0性能慢,可以参考 mbosecke/template-benchmark,或者国内的一个评测 https://my.oschina.net/smile622/blog/339884 (顺便提一下,这俩个性能基准测试,beetl都是最高的)

输入图片说明

据说Thymeleaf3.0性能成倍的提高了,在我用上面的基准测试汇总,Thymeleaf3.0仍然比最慢的Freemaker还慢很多。希望3.0不会影响到系统性能

输入图片说明

关于性能这一块,并不是我打算揭示的真相,毕竟这一块,早有定论。我要揭示的Thymeleaf真相,是它宣称的浏览器能直接打开,适合前端开发这个特点,还有他宣称所谓的优雅语法,以及谣言它是Spring Boot 默认模板引擎

浏览器直接能打开模板?

Thymeleaf 网站首页重点介绍的是使用Thymeleaf编写的模板能直接用浏览器打开,所以适合前端开发使用。这是因果关系。可我认为,这个因也错了,果也错了。

Thymeleaf编写的模板并不是所有都可以用浏览器打开,简单的模板页面可以。这点Beetl也能做到。复杂的模板页面,Thymeleaf编写的模板用浏览器打开照样没有效果。

Thymeleaf官网首页忽悠出来的第一个例子举例子吧

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

这个模板给人的感觉似乎确实能让浏览器打开。因为他使用了th:text 属性,浏览器会忽略这个属性。所以浏览器打开,看的像一个静态的html页面。

如果所有的模板页面都是这么简单,那么beetl也能做到这点,比如定义beetl的定界符为

<!--:    -->

类似beetl的模板是这样

<table>
  <thead>
    <tr>
      <th >${local("headers.name")}</th>
      <th >${local("headers.price")}</th>
    </tr>
  </thead>
  <tbody>
    <!--: for(prod in allProducts){ -->
    <tr >
      <td >${prod.name}</td>
      <td >${prod.price,".##"}</td>
    </tr>
  <!--: } -->
  </tbody>
</table>

这段beetl改写的代码照样能用浏览器打开,你也许会认为,beetl模板打开后出现了占位符,貌似比Thymeleaf差一点,但我却认为,如果浏览器打开Thymeleaf模板的都是静态文本,你都不清楚哪儿是静态文本,哪儿是动态文本需要关注,这点还真不如Beetl更适合。

Beetl当然不是为了所谓能浏览器打开的模板设计的模板语言,只是尽力做到了浏览器能打开,比如Beetl的include标签实际上就努力尝试在重用模板的时候,又可以尽量让前端人员理解include内容,比如

<!--: include("/common/header.btl"){ -->
<script src="common.js" />
<script src="ext.js" />
<!--: } -->

这就是内置的include,为什么会带有{},从beetl设计刚开始的愿景就是能让前端团队尽量理解模板引擎。 然而,我知道,光靠浏览器能打开并不能做到这一点,况且,我认为Thymeleaf在这个功能宣传上过于夸大,并不能做到。

比如,还是上面这个例子,我需要根据条件判断以确定<td></td> 里显示的内容,那么我可能这么写

  <tr>
      <th th:text="#{msgs.headers.name}">Name</th>
      <th th:text="#{msgs.headers.price}">Price</th>
    </tr>
  </thead>
  <tbody>
    <tr th:each="prod: ${allProducts}">
        <td th:text="'****'"  >Oranges</td>
       <td th:text="${prod.name}" th:if="${admin==true}>Oranges</td>
      <td th:text="${#numbers.formatDecimal(prod.price, 1, 2)}">0.99</td>
    </tr>
  </tbody>

上述增加了一个if语句,比如admin情况下,可以显示名称。这样,一个tr下会出现三个td,这显然与th不对应,这样的Thymeleaf会显示成什么样呢?显然不是Thymeleaf所宣称的那个样子

再以Thymeleaf官网文档switch例子说明,如下一个switch语句用法,你真希望在浏览器显示3个段落吗?显然不是。

<div th:switch="${user.role}">
  <p th:case="'admin'">User is an administrator</p>
  <p th:case="#{roles.manager}">User is a manager</p>
  <p th:case="*">User is some other thing</p>
</div>

尽管Thymeleaf做了最大的努力,但遇到复杂的模板,我的意思是,在我们项目,哪怕最简单的一个项目,Thymeleaf模板都不可能实现他所谓的浏览器打开,这是个美好的愿望,Beetl 从7年前开始研发哪一天也有这样的愿望,但我深知是做不到的,Thymeleaf在努力做,花费了巨大的代价(庞大的奇怪的语法,会在后面提到),但不可能做到。

浏览器能预览模板又能怎么样?

Thymeleaf一直宣传的优势是能浏览器打开模板,前面已经说道,不可能实现。那么问题来了,就算简单的模板,浏览器打开了,对前端开发人员有多大意义(这里潜台词是前后分离方案)

我在Thymeleaf官网没有看到Thymeleaf对前后端分离的具体措施,也没有看到互联网上任何文档说明如何使用Thymeleaf做前后分离,反到是Beetl,提供了充分的前后端分离方案。

作为前端人员,如果他真的用Thymeleaf编写模板,他最大的需要并不是Thymeleaf反复提及的能在浏览器打开模板就行,这并不能保证模板是万无一失,可以放心交给后端人员集成了。他最需要的是能模拟后端各种数据,对模板做各种测试,好像模板真的经过后端渲染一样。这才是分离开发,这才前端人员真正需要的。 Beetl才能真正做到这一点,Beetl使用前端人员熟悉的JS语法和HTML扩展标签编写模板,Beetl的WebSimulate 插件能让前端人员去模拟后台数据,模拟出各种数据,各种分支情况,像真的后台调用一样。这时候,前端人员,打开浏览器访问,这才是真正的终极“浏览器打开模板”,而不是Thymeleaf那种假的“浏览器能预览模板”

Thymeleaf为这种假的“浏览器能预览模板” 付出了巨大的语法代价,如果你浏览Thymeleaf技术文档,你会发现,不可能让前端人员掌握Thymeleaf语法,你看看我的一个Thymeleaf部分语法贴图你就知道了 输入图片说明

这部分语法只占Thymeleaf整体语法的5-10%。Thymeleaf的推崇者,你们确定以及肯定前端人员会去使用吗?Beetl不仅仅能前段后端分离,语法比这少多了,而且,都是前端人员熟悉的类似JS的语法。孰优孰劣,一看就知道。

所谓Thymeleaf的优雅语法

国内的Thymeleaf推崇者认为它的语法优雅。恕我直言,我实在欣赏不来Thymeleaf语法,我会列举出官网文档的语法例子,各位看官凭直觉看一看

Variable Expressions: ${...}
Selection Variable Expressions: *{...}
Message Expressions: #{...}
Link URL Expressions: @{...}
Fragment Expressions: ~{...}

以上表达式共同特点都是有{}符号,但不同的是前面有不同的符号,表示不同的意思,我这里懒得解释,因为Thymeleaf我也是新手..... 不小心非常容易出错,Beetl则只有一个标准的${} 引用。

如果你认为{} 符号很明确的话,那你就大错特错了,

{}
{{}}

{{}} 又完全是另外一个意思,这不符合程序员直觉,因为所有语言里,{} 和 {{}} 效果是一样的,Thymeleaf却表达了不同的含义。

Thymeleaf显然喜欢组合不同的符号来完成特定的模板渲染,其他模板语言则通常使用更为常见的函数调用,格式化函数来完成。一个模板渲染引擎,真没有必要搞那么复杂语法。

如果这只是恶心到你,但并没有让你混乱,那我们接着看看Thymeleaf更多的语法

<div th:if="${user.isAdmin()} == false"> 

<div th:if="${user.isAdmin() == false}"> ..

这俩种是不同写法,但是等价的,前提是前者使OGNL引擎,后者使用了SpringEL引擎。在Spring上下文里,Thymeleaf的表现有很大不同,所以你要非常清楚,不同的引擎,Thymeleaf应该怎么去写。

你也许有点混乱了,不知道下面的写法是不是更为混乱(都是官网的例子)

<span th:text="${onevar} + ' ' + |${twovar}, ${twovar}|">

<div th:with="isEven=(${prodStat.count} % 2 == 0)">

第一段如果你没看懂它的意思,我也不会解释。 至于第二段代码,意义较为明确,但如果我想扩展这个表达式,增加一个变量,那我应该是下面那种写法呢?

<div th:with="isEven=(${prodStat.count+rate} % 2 == 0)">

或者

<div th:with="isEven=( (${prodStat.count}+${rate} )% 2 == 0)">

我并不清楚,Thymeleaf怎么写,更体会不到Thymeleaf的优雅了。 如果是beetl模板,就很明确,就是一个类似js的表达式,在占位符里${ } 随意书写

<div style= "${ (prodStat.count+rate)%2==0?"event":"odd" } >

如你所见,Thymeleaf语法体系非常混乱,而且语法庞大,我上面的那个贴图不过Thymeleaf的语法5%左右,还有更多的Thymeleaf等待那些所谓的推崇者去挖掘,去写博客介绍,去介绍“回字的四种写法”(来自鲁迅的《孔乙己》)

Beetl很少有使用者写博客介绍Beetl,这是因为Beetl足够简单,普通功能真没有写博客介绍的必要。

Spring Boot 所谓内置Thymeleaf

国内有些Thymeleaf推崇者试图以Spring Boot 所谓内置Thymeleaf来表明使用Thymeleaf是一条很正确的道路。实际上并不是这样

首先,Spring Boot 每一类型技术,都会集成几种技术,比如Cache, 集成了自家的Redis,也有EhCache,Hazelcast,Spring Boot 并没有明确说出来,Spring Boot 推荐使用哪种技术。Spring Boot提供了多种选择。这非常公平

其次,Spring Boot 默认配置并不是代表最好。以REST Template为例子,Spring Boot默认使用的是JDK URL Connection,这难道比其他可选的HTTPClient,OKHttp更好吗?显然不是,还有Spring Boot提供的数据库连接池,是Tomcat的一款,这难道会比Druid,HikariCP更好,显然也不是

最后,Spring Boot为什么会在模板引擎里集成除了Freemaker,Groovy外,还会集成Thymeleaf呢,我想最大的原因是Thymeleaf深度使用了Spring技术,比如上一节提到的Spring SpEL(相当于其核心使用了SpEL),还有未提到,Thymeleaf官网说的Conversion Service 。正是因为这种如此深度集成,才使得Spring Boot 会选择Thymeleaf作为其中的一个模板引擎候选。而Velocity作为Apache体系技术,且7年不维护(恰好今天2.0发布了),当然不会作为候选。

Beetl是我7年前开始研发的模板语言,广泛在国内使用,客户有一流的互联网公司,国内大型企业,也有小型的创业公司,个人用户。Beetl是真正经得起考验的技术。很长时间来,我在模板引擎领域积累的经验足以使我对Thymeleaf有一个基本判断。 我都在犹豫是否要写一篇这样的文章来让更多的人了解Thymeleaf真相,毕竟有“利益”冲突,怕难以服众和被嘲笑。真心希望看了此文的开发人员支持我的化能点赞留言支持,不支持我的化请说出你的明确观点。

最后,想对Thymeleaf说一句们我们行业内的一句经常调侃的话,“老外的东西,只有到了中国好使,那才是真正的好使”。

© 著作权归作者所有

共有 人打赏支持
闲大赋

闲大赋

粉丝 1121
博文 86
码字总数 81146
作品 10
西城
架构师
加载中

评论(115)

闲大赋
闲大赋

引用来自“12138”的评论

beetl到底好不好这个先不说。
之所以了解到beetl这个东西,就是看到这个作者在各种地方贬低其他开源项目,和各种人对骂。
在心理学上来讲这是完全的没有自信的人,才会用最大的声音想让别人听到自己。
如果你的beetl真的那么好,用户的眼睛是雪亮的,你的用户群自然会壮大,你的口碑自然会好,这个不是靠贬低其他人就能够得到的。如果你真的有自信对于你的质疑都是子虚乌有,那你有何必咬回去呢,又不是狗。
你看到我评价别的模板引擎,却没有看到是其他模板引擎先评价Beetl,如果这些模板引擎有些自信,为何要先发问刁难Beetl,你可以找出任何一个我所谓的贬低别的开源项目的文章,我都可以找到这些率先犯难的文章
只有狗才不辩是否,如果我反击的文章有那里不对,麻烦指出来,不要像狗一样只会叫唤。

希望你看了我对你的评价唉,不必咬回来,给我做个示范
12138
12138
beetl到底好不好这个先不说。
之所以了解到beetl这个东西,就是看到这个作者在各种地方贬低其他开源项目,和各种人对骂。
在心理学上来讲这是完全的没有自信的人,才会用最大的声音想让别人听到自己。
如果你的beetl真的那么好,用户的眼睛是雪亮的,你的用户群自然会壮大,你的口碑自然会好,这个不是靠贬低其他人就能够得到的。如果你真的有自信对于你的质疑都是子虚乌有,那你有何必咬回去呢,又不是狗。
暴雪首席执行官
暴雪首席执行官
vue + node 后台Java,谁还闲的蛋疼去管其他的那些东西。
土坡兔兔
我用beetl用的很舒服,而且有问题提问作者也是很及时的回复。支持beetl。
j
joydon

引用来自“一只小桃子”的评论

原来是beetl的作者,难怪这么黑别人,哦呵呵
你才知道啊。这家伙只会吹beetl 来黑 thyleaf,freemark 。太恶心了。
w
wanzidianxia

引用来自“李嘉图”的评论

OSC什么时候成喷子的天堂了,看一篇文章,不论干货,不论懂不懂,也不自知啥水平,上来就撕,生怕别人不知道自己是一条狗,大赋作为模板作者,精通antlr,完全有资格,你们是啥?
五百万个骑士
目前没有模板需求的飘过(前后端完全分离),纯粹是看评论而来,这评论NB。。
时间红
时间红

引用来自“时间红”的评论

文章写得不错,受益匪浅,beetl也准备尝试下~~~~

不过,弱弱的说一下,看了好几个人的帖子,尤其是萝卜头头和jeegit的帖子,我感觉你反应过激了,有点太愤青了。
很小的讨论上升到撕逼的境地,我感觉完全没必要。

100个人眼里有100个哈利波特,作为用户来讲,有人欣赏beetl,自然有人不喜欢,所以说什么是你控制不了的,你作为作者和用户撕逼感觉自降身份,而且很累,要撕也得和jfinal,freeamker等的作者撕,这才是一个等量级的嘛

引用来自“闲大赋”的评论

不累啊,别人打你,你会因为不是一个量级就不还手?
你说话老道,但你这个账号是刚注册的吧?男人还弄一个女人都想,你不觉得烦?
别别别,我纯看热闹的。。。

你知道这个女人是谁不?百度搜图有真相...
闲大赋
闲大赋

引用来自“时间红”的评论

文章写得不错,受益匪浅,beetl也准备尝试下~~~~

不过,弱弱的说一下,看了好几个人的帖子,尤其是萝卜头头和jeegit的帖子,我感觉你反应过激了,有点太愤青了。
很小的讨论上升到撕逼的境地,我感觉完全没必要。

100个人眼里有100个哈利波特,作为用户来讲,有人欣赏beetl,自然有人不喜欢,所以说什么是你控制不了的,你作为作者和用户撕逼感觉自降身份,而且很累,要撕也得和jfinal,freeamker等的作者撕,这才是一个等量级的嘛
不累啊,别人打你,你会因为不是一个量级就不还手?
你说话老道,但你这个账号是刚注册的吧?男人还弄一个女人都想,你不觉得烦?
时间红
时间红
文章写得不错,受益匪浅,beetl也准备尝试下~~~~

不过,弱弱的说一下,看了好几个人的帖子,尤其是萝卜头头和jeegit的帖子,我感觉你反应过激了,有点太愤青了。
很小的讨论上升到撕逼的境地,我感觉完全没必要。

100个人眼里有100个哈利波特,作为用户来讲,有人欣赏beetl,自然有人不喜欢,所以说什么是你控制不了的,你作为作者和用户撕逼感觉自降身份,而且很累,要撕也得和jfinal,freeamker等的作者撕,这才是一个等量级的嘛
关于Themleaf学习总结

此篇记录学习Themleaf测试的相关用例: study01 Thymeleaf 的HelloWorld级别的例子 简单介绍Thymeleaf的工作流程 study02 使用的方式让静态资源热部署; 使用插件让静态资源和文件热部署。 ...

mr_伍先生
2017/09/17
0
0
Thymeleaf教程 (一) 简介

Thymeleaf是什么? Thymeleaf是一个Java库。它是一个XML / XHTML / HTML5模板引擎,能够应用于转换模板文件,以显示您的应用程序产生的数据和文本。 它尤其适合于基于XHTML / HTML5的web服务应用...

wangxinxx
2016/12/13
665
0
(三)SpringBoot——模板引擎thymeleaf

一、SpringBoot支持的模板引擎 1、Thymeleaf(官方推荐) 2、FreeMarker 3、Groovy 4、mustache SpringBoot为什么不推荐使用JSP呢? 1、JSP对页面的侵入性较强。 2、web容器版本的的管理问题...

solidwang
04/19
0
0
SpringBoot页面展示Thymeleaf

开发传统Java WEB工程时,我们可以使用JSP页面模板语言,但是在SpringBoot中已经不推荐使用了。SpringBoot支持如下页面模板语言 Thymeleaf FreeMarker Velocity Groovy JSP 上面并没有列举所...

Coding小聪
04/05
0
0
Spring Boot 12之 thymeleaf

整体步骤: (1) 在pom.xml中引入thymeleaf; (2) 如何关闭thymeleaf缓存 (3) 编写模板文件.html spring Boot默认就是使用thymeleaf模板引擎的,所以只需要在pom.xml加入依赖即可: 1、 ...

小鸟也疯狂
2016/12/15
42
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

iOS开发用到的图片尺寸汇总

启动图 型号 竖屏 横屏 iPhone SE 640px × 1136px 1136px × 640px iPhone 6s 750px × 1334px 1334px × 750px iPhone 6s Plus 1242px × 2208px 2208px × 1242px iPhone 7 750px × 1334......

业界小白
32分钟前
0
0
浅谈redis

redis是一个开源,内存式的健值存储数据库,也被称为健值存储的字典服务器。健值类型有字符串,hash(哈希类型),set(集合),list(列表) 和有序集合 特征细节: 内存式:redis将健值存储在主...

拐美人
39分钟前
0
0
无限扩容,按需使用!ZStack推出基于阿里云NAS的文件存储服务

日前,ZStack发布2.6.0版本,正式宣布推出基于阿里云NAS的文件存储服务。得益于业界领先的阿里云分布式存储架构,融合NAS后的ZStack 2.6.0拥有高性能、高可靠、容量无限扩展、一键操作、按需...

ZStack社区版
41分钟前
1
0
崛起于Springboot2.X之Mongodb多数据源处理(35)

多数据源:4个mongodb库! 目录结构图: 1、添加pom依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId>......

木九天
47分钟前
0
0
如何获取显示器的EDID信息

Q1: 为什么要写这篇文章? A1:在最近的工作中遇到了不少问题,其中很多都是和EDID相关的。可以说,作为一家以“显示”为生的企业,我们时时刻刻在与EDID打交道。EDID这东西很简单,但是如果...

DB_Terrill
48分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部