性能排名第一的模板引擎 JTE 在 Spring Boot 中的应用

开发 前端
FreeMarker通过特定的语法,如${参数},将数据注入模板中,实现动态内容的生成。它适用于生成复杂格式的Excel文件、PDF文档等。

1. 简介

模板引擎是为了解决用户界面(显示)与业务数据(内容)分离而产生的,它可以生成特定格式的文档,如HTML、XML等。常见的模板引擎有FreeMarker和Thymeleaf等。

FreeMarker通过特定的语法,如${参数},将数据注入模板中,实现动态内容的生成。它适用于生成复杂格式的Excel文件、PDF文档等。

Thymeleaf则提供标准和Spring标准两种方言,可以直接套用模板实现JSTL、OGNL表达式效果。它特别适用于与SpringMVC集成的项目。

JTE(Java Template Engine)是一个轻量级的模板引擎,专为Java应用设计。它采用了独特的DSL(领域特定语言)来简化模板编写过程,使得模板更加简洁易读。JTE支持强大的继承和组合机制,这不仅有助于构建复杂的页面结构,还能有效减少重复代码。此外,JTE还提供了良好的错误报告功能,帮助开发者快速定位和解决问题,提高了开发效率。总之,无论是小型网站还是大型企业级应用,JTE都能提供灵活且高效的解决方案,是值得尝试的一款模板引擎。

JTE性能

按设计,jte 提供了非常快的输出速度。这是一个包含了 jte 的 mbosecke/template-benchmark 的分支版本,在 AMD Ryzen 5950X(单线程)上运行。

图片图片

mbosecke/template-benchmark github地址如下:https://github.com/casid/template-benchmark/

高并发

这是与上面相同的基准测试,但线程数被设置为@Threads(16),以充分利用所有核心。jte几乎没有序列化瓶颈,并且在具有多个CPU核心的服务器上能够非常高效地并发运行:

图片图片

2. 实战案例

2.1 快速入门

定义数据模型

public class Page {
  private String title ;
  private String description ;
  // getters, setters
}

定义jte模板

@import com.pack.jte.test.Page
@param Page page
<html>
  <head>
    <meta charset="UTF-8">
      @if(page.getDescription() != null)
          <meta name="description" content="${page.getDescription()}">
      @endif
      <title>${page.getTitle()}</title>
  </head>
  <body>
      <h1>${page.getTitle()}</h1>
      <p>欢迎使用JTE模板引擎</p>
  </body>
</html>
  • @import 直接转换为 Java 或 Kotlin 的导入语句,在这种情况下,使得 com.pack.jte.test.Page 被模板识别。
  • @param Page page 是需要传递给此模板的参数。
  • @if / @endif 构成了一个条件块。括号内的内容 (page.getDescription() != null) 是标准的 Java 代码。
  • ${} 将内容写入底层模板输出,类似于其他多种模板引擎中的用法。

渲染模板

CodeResolver codeResolver = new DirectoryCodeResolver(Path.of("target/classes/templates/jte")) ;
TemplateEngine templateEngine = TemplateEngine.create(codeResolver, ContentType.Html) ;
StringOutput so = new StringOutput();
templateEngine.render("test.jte", new Page("xxxooo", "这里是馍馍社交"), so) ;
System.err.println(so.toString()) ;

控制台输出结果

图片图片

上面代码中的TemplateEngine实现有很多,你可根据不同的场景选择合适的输出模板。

2.2 模板语法

数据显示

要在模板中显示数据,请用 ${} 将其包裹起来:

@import my.Model
@param Model model


Hello ${model.name}!

而对应的模型Model则如下:

package my ;
public class Model {
  public String name = "Pack" ;
}

上述模板的输出将是 Hello Pack!

${} 可用来输出以下类型:

  • String
  • Enum
  • boolean,byte,short,int,long,float,double,char
  • 任意实现了gg.jte.Content的类

注意:出于安全考虑,不会自动进行 .toString() 转换。不支持的类型会产生编译错误。

if语句块

你可以使用关键字 @if、@elseif、@else 和 @endif 来构造 if 语句。这些关键字可直接转换为 Java 对应的关键字:

@if(model.entries.isEmpty())
  I have no entries!
@elseif(model.entries.size() == 1)
  I have one entry!
@else
  I have ${model.entries.size()} entries!
@endif

自 Java 14+ 起,还可以对 instanceof 使用模式匹配:

@if (model instanceof SubModel subModel)
  ${subModel.getSpecial()}
@endif

就像写Java代码一样。

循环

除了 if 语句,jte 还提供了 @for 和 @endfor 关键字,用于循环遍历可迭代数据。同样,@for 可以直接转换为 Java 或 Kotlin 的对应关键字:

@for(Entry entry : model.entries)
  <li>${entry.title}</li>
@endfor


@for(var entry : model.entries)
  <li>${entry.title}</li>
@endfor


@for(int i = 0; i < 10; ++i)
  <li>i is ${i}</li>
@endfor

循环时,你可以使用 gg.jte.support.ForSupport 类获取有关循环的信息,例如你是在循环的第一次迭代还是最后一次迭代。

@import gg.jte.support.ForSupport
@for(var entryLoop : ForSupport.of(model.entries))
<tr class="${(entryLoop.getIndex() + 1) % 2 == 0 ? "even" : "odd"}">
  ${entryLoop.get()}
</tr>
@endfor

自 jte 3.0 起,可以在 @endfor 之前使用 @else。如果循环中没有遍历任何元素,@else 内容就会渲染。这对显示空列表状态非常有用,无需额外的 @if。例如

@for(var item : datas)
  <tr>
    <td>${item.getName()}</td>
    <td>${item.getQuantity()}</td>
  </tr>
@else
  <tr>
    <td colspan="2">本月销售总数</td>
  </tr>
@endfor

这功能不错误。

注释

jte 允许你在模板中定义注释。

<%-- 这里是注释信息 --%>

注意:模板输出中不包含 jte 注释。

模板调用

要在模板之间共享共同功能,可以调用其他模板。所有模板都必须位于 jte 根目录下。

通用模板定义templates/jte/common.jte

@import com.pack.jte.test.Entry
@param Entry entry
@param boolean verbose


<h2>${entry.getTitle()}</h2>
@if(verbose)
  <h3>xxxooo</h3>
@endif

在其它模板中调用该模板。

@template.common(page.getEntry(), false)

这里@template后面是你要调用模板的完整路径。类似方法调用,该模板中需要什么数据,直接在这里传入。

模板渲染示例:

CodeResolver codeResolver = new DirectoryCodeResolver(Path.of("target/classes/templates/jte")) ;
TemplateEngine templateEngine = TemplateEngine.create(codeResolver, ContentType.Html) ;
TemplateOutput so = new StringOutput();
Page page = new Page("xxxooo", "这里是馍馍社交");
page.setEntry(new Entry("你好中国")) ;

以上我们介绍了常用的一些语法,还有其它如需要了解可以查看官网。

2.3 在Spring Boot中的应用

我们只需要引入以下的依赖即可,根据你使用Spring Boot的版本,支持2.x、3.x

<dependency>
  <groupId>gg.jte</groupId>
  <artifactId>jte</artifactId>
  <version>3.1.12</version>
</dependency>
<dependency>
  <groupId>gg.jte</groupId>
  <artifactId>jte-spring-boot-starter-3</artifactId>
  <version>3.1.12</version>
</dependency>

配置文件如下配置

gg:
  jte:
    developmentMode: true
    # 生产环境设置,与上面的不能同时设置
    usePrecompiledTemplates: false
    # 注意这里的路径,如果你打成的jar运行,则你应该在你当前jar所在目录同级建立对应的目录
    templateLocation: target/classes/templates/jte
    templateSuffix: .jte

设置了模板文件的路径及文件的后缀。同时设置了当前为开发模式。

我们这里以上面的test.jte为例演示

@Controller
@RequestMapping("/jte")
public class TestController {


  @GetMapping("") 
  public String view(Model model, HttpServletResponse response) {
    Page page = new Page("xxxooo", "这里是馍馍社交");
    page.setEntry(new Entry("你好中国")) ;
    model.addAttribute("page", page);
    return "test";
  }
}

页面展示:

图片图片

除了要注意模板路径问题外,其它就像以前一样该怎么写就怎么写,模板数据模型的使用方式都一样的。

责任编辑:武晓燕 来源: Spring全家桶实战案例源码
相关推荐

2024-10-07 08:40:56

Spring应用程序Java

2024-01-22 00:20:00

2016-10-10 17:17:16

戴尔

2014-09-30 11:28:14

戴尔

2016-12-26 18:04:01

戴尔

2015-10-26 16:18:19

2016-03-11 17:11:32

金蝶云之家

2014-08-15 14:47:03

游久华为应用市场

2009-09-23 10:46:40

供应链管理博科资讯

2012-03-06 09:28:32

Android移动浏览器Opera

2011-07-29 14:34:13

2009-07-16 08:52:07

500强微软

2024-09-30 11:51:07

2020-06-05 09:57:26

编程语言C语言Java

2021-11-01 14:28:06

新华三

2014-06-24 17:21:55

戴尔
点赞
收藏

51CTO技术栈公众号