为什么我要使用模板引擎?JSP include和JSTL与Tiles、Freemarker、Velocity、Sitemesh相比有何优缺点?

94

我即将选择一种组织视图的方式(使用spring-mvc,但这并不重要)。

据我所知,有6个选项(虽然它们并不是互斥的):

  • Tiles
  • Sitemesh
  • Freemarker
  • Velocity
  • <jsp:include>
  • <%@ include file="..">

TilesSitemesh可以分为一组;同样,FreemarkerVelocity也可以分为一组。在每个组中使用哪个取决于情况,并不是本讨论的问题,关于这个问题已经有足够的问题和讨论了。

这篇文章很有趣,但并不能使我完全相信使用tiles。

我的问题是:这些框架提供了什么功能,而<@ include file="..">和JSTL无法胜任?主要观点(其中一些摘自文章):

  1. 包括页面的部分,例如页眉和页脚 - 这没有什么区别:

    <%@ include file="header.jsp" %>
    

    <tiles:insert page="header.jsp" />
    
  2. 在头部定义参数 - 如标题、元标签等,这非常重要,尤其是从SEO的角度来看。使用模板选项,您可以简单地定义每个页面应该定义的占位符。但是,您也可以在jsp中使用JSTL,使用<c:set>(在包含页面中)和<c:out>(在被包含的页面中)。

  3. 布局重组 - 如果您想将面包屑移到菜单上方,或者将登录框移到另一个侧边栏上方。如果页面包含(使用jsp)没有很好地组织,您可能需要更改每个单独的页面。但是,如果您的布局不是过于复杂,并且将常见的东西放在页眉/页脚中,就没有什么可担心的。

  4. 通用组件和特定内容之间的耦合 - 我认为这没有问题。如果您想重用某个片段,请将其移动到不包含任何页眉/页脚的页面中,并在需要时进行包含。

  5. 效率 - <%@ include file="file.jsp" %>比其他任何东西都更有效,因为它只编译一次。所有其他选项都会被解析/执行多次。

  6. 复杂性 - 所有非jsp解决方案都需要额外的xml文件、额外的包含、预处理器配置等。这既是一个学习曲线,也引入了更多的潜在故障点。此外,它使支持和更改更加繁琐-您必须检查许多文件/配置才能理解发生了什么。

  7. 占位符 - 与JSTL相比,velocity/freemarker提供了更多功能吗?在JSTL中,您放置占位符,并使用模型(由控制器放置在请求或会话范围内)填充这些占位符。

  8. 因此,说服我使用上述框架之一来代替/补充纯JSP。


我不确定该如何进行直接比较,但我已经使用 Stripes 布局模板一段时间了,我发现它比普通的 JSP 要好得多。我确实使用了一些 jsp:include 调用,但那些通常是相当特殊的情况。布局模板机制是一个非常方便和强大的工具。 - Pointy
3
我听说这些都是“方便和强大”的,但我没看到过。不过我看到的是不必要的复杂性和一堆配置文件。(我不是特指条纹,只是一般而言) - Bozho
1
请参见https://dev59.com/iHRB5IYBdhLWcg3weXOX。 - matt b
我相信 jsp:include 是非常高效的 - 它会被编译成包含 servlet 到被包含页面的方法调用。它产生的代码比 @include 更少,可能会因缓存效应而提高性能。 - Tom Anderson
StringTemplate 的开发者提出了我看过的最好的论据,它非常类似于最小能量原则 - Paul Sweatte
又一个与Spring-MVC兼容的模板引擎:Thymeleaf。(https://www.thymeleaf.org/)你可能应该开始掷骰子来决定要使用哪个模板引擎了。 - kiltek
7个回答

17

对于Velocity的一些论点(我没有使用Freemarker):

  • 可以重复使用模板,不仅限于Web环境,例如在发送电子邮件中使用
  • Velocity的模板语言语法比JSP EL或标签库简单得多
  • 将视图逻辑与任何其他类型的逻辑严格分离 - 没有可能降级到使用脚本标签并在模板中执行卑鄙的操作。

占位符 - Velocity / Freemarker是否提供了比JSTL更多的东西? 在JSTL中,您可以放置占位符,并使用控制器放置在请求或会话范围内的模型来填充这些占位符。

是的,references实际上是VTL的核心:

<b>Hello $username!</b>

或者

#if($listFromModel.size() > 1)
    You have many entries!
#end

效率 - <%@ include file="file.jsp" %>比其他任何选项都更高效,因为它只编译一次。所有其他选项都需要多次解析/执行。

我不太确定我是否同意或理解这个观点。Velocity有一个缓存模板的选项,这意味着它们被解析成的抽象语法树将被缓存而不是每次从磁盘读取。无论哪种方式(我没有确切的数字),Velocity对我来说一直感觉很快。

布局重组 - 如果要将导航栏放在菜单上面,或将登录框放在另一个侧边栏上面。如果页面包含(使用JSP)没有组织好,你可能需要在这些情况下更改每个页面。但如果您的布局不是过于复杂,并且将常见内容放置在页眉/页脚中,则没有什么可担心的。

区别在于,使用JSP方法,您是否需要在使用相同页眉/页脚的每个JSP文件中重新组织此布局?Tiles和SiteMesh允许您指定一个基本布局页面(JSP、Velocity模板等 - 两者在本质上都是JSP框架),在那里您可以指定任何您想要的内容,然后只需将 "内容" 片段/模板委派给主要内容即可。这意味着只需要一个文件来移动标题。


3
你给出的速度示例可以很容易地使用JSTL完成。 所谓效率,是指JSP被编译为Servlets,而没有任何解析。但缓存模板也是一个好的解决方案。 至于重新组织——不,我通常以一种只需修改包含文件而不是“包含者”的方式形成包含文件。也许在更复杂的情况下这是不可能的。 - Bozho
2
除了在Web上下文之外重用模板,Velocity还允许您在向客户端显示之前轻松获取渲染的Web页面。当您想将站点生成为HTML文件时,这非常有用。使用JSP没有简单的解决方案。这是我们从JSP转换到Velocity的主要原因。 关于速度-我进行了一些基准测试,发现Velocity渲染页面比JSP快2倍。因此速度不是问题。 现在,在使用Velocity几年后,我再也不会回到JSP了。它更简单、更轻巧、更清洁。 - serg
@serg555你有把那些基准测试发布在哪里吗?我很想看到更多关于这个的数据。我也很想看看你是如何进行基准测试的。我认为这对于其他考虑相同问题的人来说是有用的信息,即“Velocity vs JSP vs其他引擎”。 - matt b
我还没有发布结果。只是我转换了我们网站的几个页面,并在之前和之后测量了渲染时间。没有太科学 :) - serg
@serg555,JSP 的平台/Servlet 容器/版本是什么? - Bozho
@Bozho:winxp/tomcat 5.5/jsp 2.0。这大约是3年前的事了,也许JSP世界已经发生了一些变化。 - serg

12
选择使用jsp:includeTiles/Sitemesh/etc之间是开发人员经常面临的简单与强大之间的选择。当然,如果你只有几个文件或不希望布局经常变化,那么只需使用jstljsp:include即可。
但是应用程序往往会逐步增长,如果一开始不使用复杂的解决方案,很难证明需要"停止新的开发并改造tiles(或其他解决方案),以便更轻松地解决未来的问题"
如果您确定您的应用程序永远保持简单,或者您可以设定某个应用程序复杂度的基准,超过该基准时再集成更复杂的解决方案,则建议您不要使用tiles等解决方案。否则,从一开始就使用它。

5

我不打算说服你使用其他技术。就我所知,如果JSP适用于他们,那么每个人都应该坚持使用它。

我主要使用Spring MVC,我发现在SiteMesh的配合下,JSP 2+是完美的组合。

SiteMesh 2/3

提供修饰符,用于应用于视图中,类似于其他模板引擎中的继承工作方式。如今,这种功能是不可想象的。

JSP 2+

声称JSP将使难以避免在模板中使用Java代码是虚假的。你只需不这样做,而且使用此版本是没有必要这样做的。版本2支持使用EL调用方法,这是与早期版本相比的巨大优势。

使用JSTL标签,您的代码仍然看起来像HTML,因此不太尴尬。Spring通过标签库提供了很多对JSP的支持,这非常强大。

标签库也很容易扩展,因此自定义环境非常容易。


我认为SiteMesh没有任何好处。JSP标签提供了与SiteMesh相同的装饰功能,但具有更大的灵活性,更少的脆弱设置,并且我推测效率更高,因为不涉及后处理解析。 - Magnus

2

面对使用JSP,facelets(不在您的列表中,但我会提一下)最好的论据之一是编译与解释器集成,而不是委托给JSP编译器。这意味着我在JSF 1.1中遇到的最烦人的事情之一——必须更改周围JSF标记上的id属性,以便运行时引擎发现更改——消失了,使得编辑器中保存、浏览器中重新加载的循环回来,并且错误消息也更好。


是的,对于JSF面板,由于与解释器的紧密集成,它是“解决方案”。但在这里情况并非如此 :) - Bozho
我只是提到了这一点,以防这些中有任何一个具有相同的功能 - 对我来说,那将是一个决定性的特征。 - Thorbjørn Ravn Andersen

2
一个优秀的视图技术可以消除大部分烦人的if/switch/条件语句,而简单的include则不能。使用“复杂”的视图技术会产生一个“简单”的应用程序。

1
你没有提供关于你的应用程序具体信息。例如,我仅仅因为下面的原因而不使用JSP:
1. 在JSP模板中很难避免使用Java代码,这会破坏纯视图的概念,导致在视图和控制器等多个地方维护代码时会遇到困难。
2. JSP自动创建JSP上下文,建立会话。我可能想要避免它,但如果您的应用程序总是使用会话,则可能不是问题。
3. JSP需要编译,如果目标系统没有Java编译器,任何小的调整都需要使用其他系统,然后重新部署。
4. 最小的JSP引擎大约是500k的字节码加上JSTL,因此可能不适合嵌入式系统。
5. 模板引擎可以生成相同模型的不同内容类型,比如JSON有效负载、网页、电子邮件正文、CSV等等。
6. 非Java程序员可能难以使用JSP模板,而非技术人员却从未修改过常规模板。
我很久以前也问过同样的问题,并最终编写了我的框架(当然基于模板引擎),它不受其他解决方案中所有缺点的影响。不用说,它只有大约100k的字节码。

0

我明白这听起来像是一个聪明的回答,但事实上,如果你在当前项目中没有看到使用模板比代码有任何优势,那很可能是因为在你当前的项目中并没有这样的优势。

其中一部分是关于规模的问题。你可能认为包含文件和例如sitemesh一样强大,至少对于少量页面(大约100个)而言是正确的,但如果你有几千个页面,它将变得难以管理。(所以对于eBay来说不必要,对于Salesforce来说可能是必需的)

此外,正如之前提到的,freemarker和velocity并不仅限于Servlet。你可以将它们用于任何事情(邮件模板、离线文档等)。你不需要Servlet容器来使用freemarker或velocity。

最后,你的第五点只有部分正确。如果尚未编译,每次访问时都会重新编译。这意味着每当你更改了某些内容,你需要记住删除你的Servlet容器的“work”目录,以便重新编译JSP。使用模板引擎就不需要这样做。

TL;DR 模板引擎的编写是为了解决 JSP + JSTL 的一些(真实或虚构的)缺陷。您是否应该使用它们完全取决于您的要求和项目的规模。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接