This commit is contained in:
Looly 2023-03-31 12:49:36 +08:00
parent 1083cd3835
commit 9ad764c05e
6 changed files with 111 additions and 63 deletions

View File

@ -28,8 +28,6 @@ import java.util.Map;
public class EnjoyTemplate implements Template, Serializable { public class EnjoyTemplate implements Template, Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final com.jfinal.template.Template rawTemplate;
/** /**
* 包装Enjoy模板 * 包装Enjoy模板
* *
@ -40,6 +38,8 @@ public class EnjoyTemplate implements Template, Serializable {
return (null == EnjoyTemplate) ? null : new EnjoyTemplate(EnjoyTemplate); return (null == EnjoyTemplate) ? null : new EnjoyTemplate(EnjoyTemplate);
} }
private final com.jfinal.template.Template rawTemplate;
/** /**
* 构造 * 构造
* *

View File

@ -1,62 +1,88 @@
/*
* 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:
* http://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 cn.hutool.extra.template.engine.pebble; package cn.hutool.extra.template.engine.pebble;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.reflect.TypeReference; import cn.hutool.core.reflect.TypeReference;
import cn.hutool.extra.template.Template; import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateException; import cn.hutool.extra.template.TemplateException;
import cn.hutool.extra.template.engine.velocity.VelocityTemplate;
import java.io.*; import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Map; import java.util.Map;
/** /**
* @authorzooooooooy * Pebble模板实现
*
* @author zooooooooy
* @since 6.0.0
*/ */
public class PebbleTemplate implements Template { public class PebbleTemplate implements Template {
private final io.pebbletemplates.pebble.template.PebbleTemplate template;
public PebbleTemplate(io.pebbletemplates.pebble.template.PebbleTemplate template) {
this.template = template;
}
/** /**
* 包装pebbleTemplate模板 * 包装pebbleTemplate模板
* @param template *
* @return * @param template {@link io.pebbletemplates.pebble.template.PebbleTemplate}
* @return PebbleTemplate
*/ */
public static PebbleTemplate wrap(final io.pebbletemplates.pebble.template.PebbleTemplate template) { public static PebbleTemplate wrap(final io.pebbletemplates.pebble.template.PebbleTemplate template) {
return (null == template) ? null : new PebbleTemplate(template); return (null == template) ? null : new PebbleTemplate(template);
} }
private final io.pebbletemplates.pebble.template.PebbleTemplate template;
/**
* 构造
*
* @param template {@link io.pebbletemplates.pebble.template.PebbleTemplate}
*/
public PebbleTemplate(final io.pebbletemplates.pebble.template.PebbleTemplate template) {
this.template = template;
}
/** /**
* 渲染对象 * 渲染对象
*
* @param bindingMap 绑定的参数此Map中的参数会替换模板中的变量 * @param bindingMap 绑定的参数此Map中的参数会替换模板中的变量
* @param writer 输出 * @param writer 输出
*/ */
@Override @Override
public void render(Map<?, ?> bindingMap, Writer writer) { public void render(final Map<?, ?> bindingMap, final Writer writer) {
final Map<String, Object> map = Convert.convert(new TypeReference<Map<String, Object>>() {}, bindingMap); final Map<String, Object> map = Convert.convert(new TypeReference<Map<String, Object>>() {
}, bindingMap);
try { try {
this.template.evaluate(writer, map); this.template.evaluate(writer, map);
} catch (Exception e) { } catch (final Exception e) {
throw new TemplateException("pebble template parse failed, cause by: ", e); throw new TemplateException("pebble template parse failed, cause by: ", e);
} }
} }
/** /**
* 渲染对象 * 渲染对象
*
* @param bindingMap 绑定的参数此Map中的参数会替换模板中的变量 * @param bindingMap 绑定的参数此Map中的参数会替换模板中的变量
* @param out 输出 * @param out 输出
*/ */
@Override @Override
public void render(Map<?, ?> bindingMap, OutputStream out) { public void render(final Map<?, ?> bindingMap, final OutputStream out) {
final Map<String, Object> map = Convert.convert(new TypeReference<Map<String, Object>>() {}, bindingMap); final Map<String, Object> map = Convert.convert(new TypeReference<Map<String, Object>>() {
}, bindingMap);
try { try {
this.template.evaluate(new OutputStreamWriter(out), map); this.template.evaluate(new OutputStreamWriter(out), map);
} catch (Exception e) { } catch (final Exception e) {
throw new TemplateException("pebble template parse failed, cause by: ", e); throw new TemplateException("pebble template parse failed, cause by: ", e);
} }

View File

@ -1,5 +1,18 @@
/*
* 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:
* http://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 cn.hutool.extra.template.engine.pebble; package cn.hutool.extra.template.engine.pebble;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.io.file.FileUtil; import cn.hutool.core.io.file.FileUtil;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.extra.template.Template; import cn.hutool.extra.template.Template;
@ -8,9 +21,7 @@ import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateException; import cn.hutool.extra.template.TemplateException;
import io.pebbletemplates.pebble.PebbleEngine; import io.pebbletemplates.pebble.PebbleEngine;
import io.pebbletemplates.pebble.error.PebbleException; import io.pebbletemplates.pebble.error.PebbleException;
import io.pebbletemplates.pebble.loader.ClasspathLoader; import io.pebbletemplates.pebble.loader.*;
import io.pebbletemplates.pebble.loader.FileLoader;
import io.pebbletemplates.pebble.loader.StringLoader;
import org.beetl.core.GroupTemplate; import org.beetl.core.GroupTemplate;
/** /**
@ -20,24 +31,33 @@ public class PebbleTemplateEngine implements TemplateEngine {
private PebbleEngine engine; private PebbleEngine engine;
/**
* 构造不初始化
*/
public PebbleTemplateEngine() { public PebbleTemplateEngine() {
} }
public PebbleTemplateEngine(TemplateConfig config) { /**
* 构造
*
* @param config 配置
*/
public PebbleTemplateEngine(final TemplateConfig config) {
init(config); init(config);
} }
@Override @Override
public TemplateEngine init(TemplateConfig config) { public TemplateEngine init(final TemplateConfig config) {
init(createEngine(config)); init(createEngine(config));
return this; return this;
} }
/** /**
* 初始化引擎 * 初始化引擎
*
* @param engine 引擎 * @param engine 引擎
*/ */
private void init(PebbleEngine engine){ private void init(final PebbleEngine engine) {
this.engine = engine; this.engine = engine;
} }
@ -52,60 +72,49 @@ public class PebbleTemplateEngine implements TemplateEngine {
config = TemplateConfig.DEFAULT; config = TemplateConfig.DEFAULT;
} }
PebbleEngine pebbleEngine; Loader<?> loader = null;
switch (config.getResourceMode()) { switch (config.getResourceMode()) {
case CLASSPATH: case CLASSPATH:
ClasspathLoader classpathLoader = new ClasspathLoader(); loader = new ClasspathLoader();
classpathLoader.setPrefix(StrUtil.addSuffixIfNot(config.getPath(), "/")); loader.setPrefix(StrUtil.addSuffixIfNot(config.getPath(), StrUtil.SLASH));
pebbleEngine = new PebbleEngine.Builder()
.loader(classpathLoader)
.autoEscaping(false)
.build();
break; break;
case FILE: case FILE:
FileLoader fileLoader = new FileLoader(); loader = new FileLoader();
fileLoader.setPrefix(StrUtil.addSuffixIfNot(config.getPath(), "/")); loader.setPrefix(StrUtil.addSuffixIfNot(config.getPath(), StrUtil.SLASH));
pebbleEngine = new PebbleEngine.Builder()
.loader(fileLoader)
.autoEscaping(false)
.build();
break; break;
case WEB_ROOT: case WEB_ROOT:
fileLoader = new FileLoader(); loader = new FileLoader();
fileLoader.setPrefix(StrUtil.addSuffixIfNot(FileUtil.getAbsolutePath(FileUtil.file(FileUtil.getWebRoot(), config.getPath())), "/")); loader.setPrefix(StrUtil.addSuffixIfNot(
pebbleEngine = new PebbleEngine.Builder() FileUtil.getAbsolutePath(FileUtil.file(FileUtil.getWebRoot(), config.getPath())), StrUtil.SLASH));
.loader(fileLoader)
.autoEscaping(false)
.build();
break; break;
case STRING: case STRING:
StringLoader stringLoader = new StringLoader(); loader = new StringLoader();
stringLoader.setPrefix(StrUtil.addSuffixIfNot(config.getPath(), "/"));
pebbleEngine = new PebbleEngine.Builder()
.loader(stringLoader)
.autoEscaping(false)
.build();
break; break;
case COMPOSITE:
loader = new DelegatingLoader(ListUtil.of(
new ClasspathLoader(),
new FileLoader(),
new StringLoader()
));
default: default:
classpathLoader = new ClasspathLoader(); // 默认null表示使用DelegatingLoader
classpathLoader.setPrefix(StrUtil.addSuffixIfNot(config.getPath(), "/"));
pebbleEngine = new PebbleEngine.Builder()
.loader(classpathLoader)
.autoEscaping(false)
.build();
break; break;
} }
return pebbleEngine; return new PebbleEngine.Builder()
.loader(loader)
.autoEscaping(false)
.build();
} }
/** /**
* 通过路径获取对应模板操作类 * 通过路径获取对应模板操作类
*
* @param resource 资源根据实现不同此资源可以是模板本身也可以是模板的相对路径 * @param resource 资源根据实现不同此资源可以是模板本身也可以是模板的相对路径
* @return * @return {@link Template}
*/ */
@Override @Override
public Template getTemplate(String resource) { public Template getTemplate(final String resource) {
if (null == this.engine) { if (null == this.engine) {
init(TemplateConfig.DEFAULT); init(TemplateConfig.DEFAULT);

View File

@ -1,3 +1,15 @@
/*
* 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:
* http://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.
*/
/** /**
* pebble template实现模板引擎介绍见https://github.com/PebbleTemplates/pebble * pebble template实现模板引擎介绍见https://github.com/PebbleTemplates/pebble
* *

View File

@ -18,3 +18,4 @@ cn.hutool.extra.template.engine.enjoy.EnjoyEngine
cn.hutool.extra.template.engine.thymeleaf.ThymeleafEngine cn.hutool.extra.template.engine.thymeleaf.ThymeleafEngine
cn.hutool.extra.template.engine.wit.WitEngine cn.hutool.extra.template.engine.wit.WitEngine
cn.hutool.extra.template.engine.jetbrick.JetbrickEngine cn.hutool.extra.template.engine.jetbrick.JetbrickEngine
cn.hutool.extra.template.engine.pebble.PebbleTemplateEngine

View File

@ -153,13 +153,13 @@ public class TemplateUtilTest {
TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("templates").setCustomEngine(PebbleTemplateEngine.class)); TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("templates").setCustomEngine(PebbleTemplateEngine.class));
Template template = engine.getTemplate("<h3>{{ message }}</h3>"); Template template = engine.getTemplate("<h3>{{ message }}</h3>");
String result = template.render(Dict.of().set("message", "Hutool")); String result = template.render(Dict.of().set("message", "Hutool"));
Assert.assertEquals("<h3>Hutool</h3>", result); Assertions.assertEquals("<h3>Hutool</h3>", result);
//ClassPath模板 //ClassPath模板
engine = TemplateUtil.createEngine(new TemplateConfig("templates", ResourceMode.CLASSPATH).setCustomEngine(PebbleTemplateEngine.class)); engine = TemplateUtil.createEngine(new TemplateConfig("templates", ResourceMode.CLASSPATH).setCustomEngine(PebbleTemplateEngine.class));
template = engine.getTemplate("pebble_test.peb"); template = engine.getTemplate("pebble_test.peb");
result = template.render(Dict.of().set("name", "Hutool")); result = template.render(Dict.of().set("name", "Hutool"));
Assert.assertEquals("hello, Hutool", result); Assertions.assertEquals("hello, Hutool", result);
} }
@Test @Test