夜雨聆风学习资料网

ARTICLE · 1144127

轻量,动态JSON模板引擎JJTemplate

轻量,动态JSON模板引擎JJTemplate
《Spring Boot 3实战案例锦集》PDF电子书已更新至130篇!
🎉🎉《Spring Boot实战案例合集》目前已更新236个案例,我们将持续不断的更新。文末有电子书目录。→ 现在就订阅合集

环境:Spring Boot 3.5.0


1. 简介

JJTemplate 是一款轻量级模板引擎,旨在实现最短的渲染时间,并支持与 JSON 兼容的输入/输出。JJT 代表 Java JSON Template。JJTemplate 将模板编译为优化的抽象语法树(AST),以实现快速执行,同时保证生成的结果为有效的 JSON。

2.实战案例
2.1 快速入门
引入依赖
<dependency>  <groupId>io.github.sibmaks.jjtemplate</groupId>  <artifactId>jjtemplate-parser</artifactId>  <version>1.0.2</version></dependency><dependency>  <groupId>io.github.sibmaks.jjtemplate</groupId>  <artifactId>jjtemplate-compiler</artifactId>  <version>1.0.2</version></dependency>
Java代码定义模板
var script = TemplateScript.builder()    .template(Map.of(        "id", "{{ .id }}",         "name", "{{ .name }}"      )    ).build();var compiler = TemplateCompiler.getInstance();var compiled = compiler.compile(script);Map<String, Object> data = new HashMap<>() ;data.put("id", 666) ;data.put("name", "Pack_xg") ;var result = compiled.render(data);System.err.println(result) ;
输出结果
{id=666, name=Pack_xg}
2.2 JJT语法

JJT 保持 JSON 结构的可见性。四种插值形式涵盖了替换、条件插入和展开。

  • 访问变量

从渲染上下文和定义中读取根值或嵌套值。语法:

.user.name
  • 替换

直接插入类型化的结果:布尔值仍为布尔值,数值仍为数值。语法:

{{ expression }}
  • 条件插入

当表达式计算结果为 null 时,跳过该对象的字段或数组项。语法:

{{? expression }}
  • 展开

将对象展开为对象,或将集合中的值展开为数组。语法:

{{. expression }}
  • 管道

将左侧的值传递给一个函数,并组合变换。语法:

.value | string:trim
  • 三元运算

在行内选择一个值;分支中可以包含调用、管道和嵌套表达式。语法:

.ready ? 'yes' : 'no'
  • 安全访问

当属性或匹配的方法不存在时,返回 null;将其与 default 结合使用以实现备选方案。语法:

.repository?.foo('bar')
2.3 语法示例
  • 条件插入

var script = TemplateScript.builder()    .template(List.of(        "{{? .sex1 }}",         "{{? .sex2 }}",        "{{? .sex3 }}"      )    ).build();var compiler = TemplateCompiler.getInstance();var compiled = compiler.compile(script);Map<String, Object> data = new HashMap<>() ;data.put("sex1", "男") ;data.put("sex2", "女") ;data.put("sex3", null) ;var result = compiled.render(data);System.err.println(result) ;
输出
[男, 女]
  • 展开
var script = TemplateScript.builder()    .template(Map.of(        "name", "{{? .name }}",         "{{. .extra }}", true      )    ).build();var compiler = TemplateCompiler.getInstance();var compiled = compiler.compile(script);Map<String, Object> data = new HashMap<>() ;data.put("name", "Pack_xg") ;data.put("extra", Map.of("role", "admin")) ;var result = compiled.render(data);System.err.println(result) ;
输出
{role=admin, name=Pack_xg}
  • 范围
Definition defintion = new Definition() ;defintion.put("{{ rows range item,index of .items }}", Map.of("position", "{{ .index }}", "value", "{{ .item }}")) ;var script = TemplateScript.builder()    .definitions(List.of(defintion))    .template("{{ .rows }}")    .build();var compiler = TemplateCompiler.getInstance();var compiled = compiler.compile(script);Map<String, Object> data = new HashMap<>() ;data.put("items", List.of("A", "B", "C")) ;var result = compiled.render(data);System.err.println(result) ;
输出
[  {position=0, value=A},   {position=1, value=B},   {position=2, value=C}]
  • Switch
Definition defSwitch = new Definition() ;defSwitch.put("{{ message switch .status }}", Map.of("ok", "成功", "fail", "失败", "{{ else }}", "未知")) ;var script = TemplateScript.builder()    .definitions(List.of(defSwitch))    .template("{{ .message }}")    .build();var compiler = TemplateCompiler.getInstance();var compiled = compiler.compile(script);Map<String, Object> data = new HashMap<>() ;data.put("status", "fail") ;var result = compiled.render(data);System.err.println(result) ;
输出
失败
  • 安全访问
var script = TemplateScript.builder()    .template(Map.of(          "name", "{{ default .user?.name, '未知' }}"        ))    .build();var compiler = TemplateCompiler.getInstance();var compiled = compiler.compile(script);Map<String, Object> data = new HashMap<>() ;data.put("user", Map.of("name", "Pack_xg")) ;var result = compiled.render(data);System.err.println(result) ;
输出
{name=Pack_xg} 或者 {name=未知} // 当上下文中不存在 user时
2.4 使用函数

函数按命名空间分组。全局逻辑函数则特意省略了命名空间。

示例:
var script = TemplateScript.builder()    .template(Map.of(          "name", "{{ .name?.substring(1) }}",          "hobbySize", "{{ list:len .hobbies }}",          "extras", "{{ map:new 'head', 'xxx', 'tail', 'ooo' }}",          "birth", "{{ date:parse 'yyyy-MM-dd', .birth }}",          "rate", "{{ math:div .left, .right }}"        ))    .build();var compiler = TemplateCompiler.getInstance();var compiled = compiler.compile(script);Map<String, Object> data = new HashMap<>() ;data.put("name", "Pack_xg") ;data.put("hobbies", List.of("足球", "篮球", "排球")) ;data.put("birth", "2026-10-05") ;data.put("left", 460) ;data.put("right", 100) ;var result = compiled.render(data);System.err.println(result) ;
输出
{  extras={head=xxx, tail=ooo},   name=ack_xg,   rate=4,   birth=2026-10-05,   hobbySize=3}
以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏
Redis Search:比Elasticsearch快5倍

Fesod:下一代高性能 Java Excel 读写库

性能分析!利用Spring AOP构建方法执行耗时树状图

高级开发!弃用@ControllerAdvice,这种异常处理方式性能更佳

基于 Spring Boot 实现自定义二进制数据传输协议

强大!JSON解析神器,再复杂也不怕了

通过Spring AOP + 多线程 + 批量实现强大的智能审计功能

Spring Boot中记录JDBC、JPA及MyBatis执行SQL及参数的正确姿势

5种实现方式配置Spring Boot API接口超时时间

技术专家!Spring Boot 自定义注解@LockTransactional轻松实现分布式锁与事务管理

相关学习资料