diff --git a/.gitignore b/.gitignore
index 2a93184c8..d90ef8d15 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,3 +31,4 @@ build/
# system ignore
.DS_Store
Thumbs.db
+jte-classes/
diff --git a/hutool-extra/pom.xml b/hutool-extra/pom.xml
index 4d48008f9..ae520360c 100755
--- a/hutool-extra/pom.xml
+++ b/hutool-extra/pom.xml
@@ -37,6 +37,7 @@
2.3.32
5.1.3
3.1.2.RELEASE
+ 3.1.9
1.6.2
0.1.55
0.38.0
@@ -144,6 +145,13 @@
true
+
+ gg.jte
+ jte
+ ${jte.version}
+ compile
+ true
+
org.febit.wit
wit-core
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/template/engine/jte/JteEngine.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/template/engine/jte/JteEngine.java
new file mode 100644
index 000000000..ad7f4a702
--- /dev/null
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/template/engine/jte/JteEngine.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2023 looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * https://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+package org.dromara.hutool.extra.template.engine.jte;
+
+import gg.jte.CodeResolver;
+import gg.jte.ContentType;
+import gg.jte.resolve.DirectoryCodeResolver;
+import gg.jte.resolve.ResourceCodeResolver;
+import org.dromara.hutool.core.map.MapUtil;
+import org.dromara.hutool.core.text.StrUtil;
+import org.dromara.hutool.extra.template.Template;
+import org.dromara.hutool.extra.template.TemplateConfig;
+import org.dromara.hutool.extra.template.engine.TemplateEngine;
+
+import java.nio.file.Paths;
+
+/**
+ * jte实现
+ * 见:https://jte.gg/
+ *
+ * @author dy
+ */
+public class JteEngine implements TemplateEngine {
+
+ private TemplateConfig config = TemplateConfig.DEFAULT;
+ private gg.jte.TemplateEngine engine;
+ private final ContentType contentType = ContentType.Plain;
+
+ // --------------------------------------------------------------------------------- Constructor start
+
+ /**
+ * 默认构造
+ */
+ public JteEngine() {
+ }
+
+ /**
+ * 构造
+ *
+ * @param config 模板配置
+ */
+ public JteEngine(final TemplateConfig config) {
+ this.config = config;
+ createEngine();
+ }
+
+ /**
+ * 构造
+ *
+ * @param codeResolver {@link CodeResolver}
+ */
+ public JteEngine(final CodeResolver codeResolver) {
+ createEngine(codeResolver, contentType);
+ }
+ // --------------------------------------------------------------------------------- Constructor end
+
+ @Override
+ public TemplateEngine init(TemplateConfig config) {
+ if (config != null) {
+ this.config = config;
+ }
+ createEngine();
+ return this;
+ }
+
+ @Override
+ public Template getTemplate(String resource) {
+ if (TemplateConfig.ResourceMode.STRING.equals(config.getResourceMode())) {
+ if (!StrUtil.endWithAny(config.getPath(), ".jte", ".kte")) {
+ throw new RuntimeException("路径path需以.jte/.kte结尾");
+ }
+ createEngine(new SimpleStringCodeResolver(MapUtil.of(config.getPath(), resource)), contentType);
+ return new JteTemplate(engine, config.getPath());
+ } else {
+ return new JteTemplate(engine, resource);
+ }
+ }
+
+ @Override
+ public gg.jte.TemplateEngine getRaw() {
+ return this.engine;
+ }
+
+ /**
+ * 创建引擎 {@link gg.jte.TemplateEngine }
+ */
+ private void createEngine() {
+ switch (config.getResourceMode()) {
+ case CLASSPATH:
+ createEngine(new ResourceCodeResolver(config.getPath(), JteEngine.class.getClassLoader()), contentType);
+ break;
+ case FILE:
+ createEngine(new DirectoryCodeResolver(Paths.get(config.getPath())), contentType);
+ break;
+ case STRING:
+ // 这里无法直接创建引擎
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * 创建引擎 {@link gg.jte.TemplateEngine }
+ *
+ * @param codeResolver CodeResolver
+ * @param contentType ContentType
+ */
+ private void createEngine(CodeResolver codeResolver, ContentType contentType) {
+ this.engine = gg.jte.TemplateEngine.create(codeResolver, contentType);
+ }
+}
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/template/engine/jte/JteTemplate.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/template/engine/jte/JteTemplate.java
new file mode 100644
index 000000000..cb250a494
--- /dev/null
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/template/engine/jte/JteTemplate.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2023 looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * https://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+package org.dromara.hutool.extra.template.engine.jte;
+
+import gg.jte.TemplateEngine;
+import gg.jte.output.WriterOutput;
+import org.dromara.hutool.core.io.IoUtil;
+import org.dromara.hutool.core.io.file.FileUtil;
+import org.dromara.hutool.extra.template.Template;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+/**
+ * Jte模板实现
+ *
+ * @author dy
+ */
+public class JteTemplate implements Template, Serializable {
+
+ private static final long serialVersionUID = -2739915422007257186L;
+
+ private final TemplateEngine templateEngine;
+ private final String template;
+
+ public JteTemplate(TemplateEngine engine, String template) {
+ this.templateEngine = engine;
+ this.template = template;
+ }
+
+ @Override
+ public void render(Map, ?> bindingMap, Writer writer) {
+ templateEngine.render(template, bindingMap, new WriterOutput(writer));
+ }
+
+ @Override
+ public void render(Map, ?> bindingMap, OutputStream out) {
+ this.render(bindingMap, IoUtil.toWriter(out, StandardCharsets.UTF_8));
+ }
+
+ /**
+ * 将模板与绑定参数融合后输出到Writer
+ *
+ * @param model 实体类
+ * @param writer 输出
+ */
+ public void render(Object model, Writer writer) {
+ templateEngine.render(template, model, new WriterOutput(writer));
+ }
+
+ /**
+ * 将模板与绑定参数融合后输出到流
+ *
+ * @param model 实体类
+ * @param out 输出
+ */
+ public void render(Object model, OutputStream out) {
+ render(model, IoUtil.toWriter(out, StandardCharsets.UTF_8));
+ }
+
+ /**
+ * 写出到文件
+ *
+ * @param model 实体类
+ * @param file 输出到的文件
+ */
+ public void render(final Object model, final File file) {
+ BufferedOutputStream out = null;
+ try {
+ out = FileUtil.getOutputStream(file);
+ this.render(model, out);
+ } finally {
+ IoUtil.closeQuietly(out);
+ }
+ }
+
+ /**
+ * 将模板与绑定参数融合后返回为字符串
+ *
+ * @param model 实体类
+ * @return 融合后的内容
+ */
+ public String render(final Object model) {
+ final StringWriter writer = new StringWriter();
+ this.render(model, writer);
+ return writer.toString();
+ }
+}
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/template/engine/jte/SimpleStringCodeResolver.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/template/engine/jte/SimpleStringCodeResolver.java
new file mode 100644
index 000000000..b9a6b9563
--- /dev/null
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/template/engine/jte/SimpleStringCodeResolver.java
@@ -0,0 +1,39 @@
+package org.dromara.hutool.extra.template.engine.jte;
+
+import gg.jte.CodeResolver;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * {@link CodeResolver} 字符串实现形式
+ * 用于直接获取字符串模板
+ *
+ * @author cdy
+ * @since 6.0.0
+ */
+public class SimpleStringCodeResolver implements CodeResolver {
+
+ private final Map templates;
+
+ public SimpleStringCodeResolver(Map templates) {
+ this.templates = templates;
+ }
+
+ @Override
+ public String resolve(String name) {
+ return templates.get(name);
+ }
+
+ @Override
+ public long getLastModified(String name) {
+ return 0L;
+ }
+
+ @Override
+ public List resolveAllTemplateNames() {
+ return new ArrayList<>(templates.keySet());
+ }
+
+}
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/template/engine/jte/package-info.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/template/engine/jte/package-info.java
new file mode 100644
index 000000000..3581ff77a
--- /dev/null
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/template/engine/jte/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2023 looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * https://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+/**
+ * jte实现
+ * 见:https://jte.gg/
+ *
+ * @author dy
+ */
+package org.dromara.hutool.extra.template.engine.jte;
diff --git a/hutool-extra/src/test/java/org/dromara/hutool/extra/template/TemplateFactoryTest.java b/hutool-extra/src/test/java/org/dromara/hutool/extra/template/TemplateFactoryTest.java
index f97111dfb..dbfb09ffb 100644
--- a/hutool-extra/src/test/java/org/dromara/hutool/extra/template/TemplateFactoryTest.java
+++ b/hutool-extra/src/test/java/org/dromara/hutool/extra/template/TemplateFactoryTest.java
@@ -20,6 +20,7 @@ import org.dromara.hutool.extra.template.engine.TemplateEngineFactory;
import org.dromara.hutool.extra.template.engine.beetl.BeetlEngine;
import org.dromara.hutool.extra.template.engine.enjoy.EnjoyEngine;
import org.dromara.hutool.extra.template.engine.freemarker.FreemarkerEngine;
+import org.dromara.hutool.extra.template.engine.jte.JteEngine;
import org.dromara.hutool.extra.template.engine.pebble.PebbleTemplateEngine;
import org.dromara.hutool.extra.template.engine.rythm.RythmEngine;
import org.dromara.hutool.extra.template.engine.thymeleaf.ThymeleafEngine;
@@ -30,8 +31,7 @@ import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.io.File;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.*;
/**
* 模板引擎单元测试
@@ -158,6 +158,26 @@ public class TemplateFactoryTest {
Assertions.assertEquals("Hutool
", result);
}
+ @Test
+ public void jteEngineTest() {
+ // 字符串模板
+ TemplateEngine engine = TemplateEngineFactory.createEngine(
+ new TemplateConfig("templates.jte").setCustomEngine(JteEngine.class));
+ Template template = engine.getTemplate("@param java.util.HashMap map\n" +
+ "${map.get(\"message\")}
");
+ Map model = new HashMap<>();
+ model.put("message", "Hutool");
+ String result = template.render(model);
+ Assertions.assertEquals("Hutool
", result);
+
+ //ClassPath模板
+ engine = TemplateEngineFactory.createEngine(
+ new TemplateConfig("templates", ResourceMode.CLASSPATH).setCustomEngine(JteEngine.class));
+ template = engine.getTemplate("jte_test.jte");
+ result = template.render(model);
+ Assertions.assertEquals("Hutool
", result);
+ }
+
/**
* pebble template engine test
*/
diff --git a/hutool-extra/src/test/resources/templates/jte_test.jte b/hutool-extra/src/test/resources/templates/jte_test.jte
new file mode 100644
index 000000000..2538b6ec0
--- /dev/null
+++ b/hutool-extra/src/test/resources/templates/jte_test.jte
@@ -0,0 +1,2 @@
+@param java.util.HashMap map
+${map.get("message")}
\ No newline at end of file