Browse Source

fix template bug

Looly 5 years ago
parent
commit
0781be4e1c

+ 1 - 0
CHANGELOG.md

@@ -13,6 +13,7 @@
 * 【core   】     修复DataUtil.parseLocalDateTime无时间部分报错问题(issue#I1B18H@Gitee)
 * 【core   】     修复NetUtil.isUsableLocalPort()判断问题(issue#765@Github)
 * 【poi    】     修复ExcelWriter写出多个sheet错误的问题(issue#766@Github)
+* 【extra  】     修复模板引擎自定义配置失效问题(issue#767@Github)
 
 -------------------------------------------------------------------------------------------------------------
 

+ 1 - 1
hutool-core/src/main/java/cn/hutool/core/lang/loader/AtomicLoader.java

@@ -21,7 +21,7 @@ public abstract class AtomicLoader<T> implements Loader<T>, Serializable {
 	private static final long serialVersionUID = 1L;
 
 	/** 被加载对象的引用 */
-	private final AtomicReference<T> reference = new AtomicReference<T>();
+	private final AtomicReference<T> reference = new AtomicReference<>();
 
 	/**
 	 * 获取一个对象,第一次调用此方法时初始化对象然后返回,之后调用此方法直接返回原对象

+ 25 - 9
hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeUtil.java

@@ -1,6 +1,6 @@
 package cn.hutool.core.lang.tree;
 
-import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.lang.tree.parser.DefaultNodeParser;
 import cn.hutool.core.lang.tree.parser.NodeParser;
 
@@ -8,7 +8,7 @@ import java.util.List;
 import java.util.stream.Collectors;
 
 /**
- * 树工具类 可参考  cn.hutool.core.lang.TreeTest
+ * 树工具类
  *
  * @author liangbaikai
  */
@@ -16,6 +16,9 @@ public class TreeUtil {
 
 	/**
 	 * 树构建
+	 *
+	 * @param list 源数据集合
+	 * @return List
 	 */
 	public static List<Tree<Integer>> build(List<TreeNode<Integer>> list) {
 		return build(list, 0);
@@ -23,13 +26,25 @@ public class TreeUtil {
 
 	/**
 	 * 树构建
+	 *
+	 * @param <E>      ID类型
+	 * @param list     源数据集合
+	 * @param parentId 最顶层父id值 一般为 0 之类
+	 * @return List
 	 */
-	public static <T> List<Tree<T>> build(List<TreeNode<T>> list, T parentId) {
+	public static <E> List<Tree<E>> build(List<TreeNode<E>> list, E parentId) {
 		return build(list, parentId, TreeNodeConfig.DEFAULT_CONFIG, new DefaultNodeParser<>());
 	}
 
 	/**
 	 * 树构建
+	 *
+	 * @param <T>        转换的实体 为数据源里的对象类型
+	 * @param <E>        ID类型
+	 * @param list       源数据集合
+	 * @param parentId   最顶层父id值 一般为 0 之类
+	 * @param nodeParser 转换器
+	 * @return List
 	 */
 	public static <T, E> List<Tree<E>> build(List<T> list, E parentId, NodeParser<T, E> nodeParser) {
 		return build(list, parentId, TreeNodeConfig.DEFAULT_CONFIG, nodeParser);
@@ -38,22 +53,23 @@ public class TreeUtil {
 	/**
 	 * 树构建
 	 *
+	 * @param <T>            转换的实体 为数据源里的对象类型
+	 * @param <E>            ID类型
 	 * @param list           源数据集合
 	 * @param parentId       最顶层父id值 一般为 0 之类
 	 * @param treeNodeConfig 配置
-	 * @param nodeParser        转换器
-	 * @param <T>            转换的实体 为数据源里的对象类型
+	 * @param nodeParser     转换器
 	 * @return List
 	 */
 	public static <T, E> List<Tree<E>> build(List<T> list, E parentId, TreeNodeConfig treeNodeConfig, NodeParser<T, E> nodeParser) {
-		List<Tree<E>> treeNodes = CollectionUtil.newArrayList();
+		List<Tree<E>> treeNodes = CollUtil.newArrayList();
 		for (T obj : list) {
 			Tree<E> treeNode = new Tree<>(treeNodeConfig);
 			nodeParser.parse(obj, treeNode);
 			treeNodes.add(treeNode);
 		}
 
-		List<Tree<E>> finalTreeNodes = CollectionUtil.newArrayList();
+		List<Tree<E>> finalTreeNodes = CollUtil.newArrayList();
 		for (Tree<E> treeNode : treeNodes) {
 			if (parentId.equals(treeNode.getParentId())) {
 				finalTreeNodes.add(treeNode);
@@ -75,7 +91,7 @@ public class TreeUtil {
 	 */
 	private static <T> void innerBuild(List<Tree<T>> treeNodes, Tree<T> parentNode, int deep, Integer maxDeep) {
 
-		if (CollectionUtil.isEmpty(treeNodes)) {
+		if (CollUtil.isEmpty(treeNodes)) {
 			return;
 		}
 		//maxDeep 可能为空
@@ -89,7 +105,7 @@ public class TreeUtil {
 			if (parentNode.getId().equals(childNode.getParentId())) {
 				List<Tree<T>> children = parentNode.getChildren();
 				if (children == null) {
-					children = CollectionUtil.newArrayList();
+					children = CollUtil.newArrayList();
 					parentNode.setChildren(children);
 				}
 				children.add(childNode);

+ 1 - 1
hutool-core/src/test/java/cn/hutool/core/lang/TreeTest.java

@@ -43,8 +43,8 @@ public class TreeTest {
 		TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
 		// 自定义属性名 都要默认值的
 		treeNodeConfig.setWeightKey("order");
-		treeNodeConfig.setDeep(3);
 		treeNodeConfig.setIdKey("rid");
+		treeNodeConfig.setDeep(3);
 
 		//转换器
 		List<Tree<String>> treeNodes = TreeUtil.build(nodeList, "0", treeNodeConfig,

+ 87 - 60
hutool-extra/src/main/java/cn/hutool/extra/template/TemplateConfig.java

@@ -2,45 +2,58 @@ package cn.hutool.extra.template;
 
 import java.io.Serializable;
 import java.nio.charset.Charset;
+import java.util.Objects;
 
 import cn.hutool.core.util.CharsetUtil;
 
 /**
  * 模板配置
- * 
+ *
  * @author looly
  * @since 4.1.0
  */
 public class TemplateConfig implements Serializable {
 	private static final long serialVersionUID = 2933113779920339523L;
 
-	/** 编码 */
+	public static final TemplateConfig DEFAULT = new TemplateConfig();
+
+	/**
+	 * 编码
+	 */
 	private Charset charset;
-	/** 模板路径,如果ClassPath或者WebRoot模式,则表示相对路径 */
+	/**
+	 * 模板路径,如果ClassPath或者WebRoot模式,则表示相对路径
+	 */
 	private String path;
-	/** 模板资源加载方式 */
+	/**
+	 * 模板资源加载方式
+	 */
 	private ResourceMode resourceMode;
+	/**
+	 * 自定义引擎,当多个jar包引入时,可以自定使用的默认引擎
+	 */
+	private Class<? extends TemplateEngine> customEngine;
 
 	/**
 	 * 默认构造,使用UTF8编码,默认从ClassPath获取模板
 	 */
 	public TemplateConfig() {
-		this((String)null);
+		this(null);
 	}
-	
+
 	/**
 	 * 构造,默认UTF-8编码
-	 * 
+	 *
 	 * @param path 模板路径,如果ClassPath或者WebRoot模式,则表示相对路径
 	 */
 	public TemplateConfig(String path) {
 		this(path, ResourceMode.STRING);
 	}
-	
+
 	/**
 	 * 构造,默认UTF-8编码
-	 * 
-	 * @param path 模板路径,如果ClassPath或者WebRoot模式,则表示相对路径
+	 *
+	 * @param path         模板路径,如果ClassPath或者WebRoot模式,则表示相对路径
 	 * @param resourceMode 模板资源加载方式
 	 */
 	public TemplateConfig(String path, ResourceMode resourceMode) {
@@ -49,9 +62,9 @@ public class TemplateConfig implements Serializable {
 
 	/**
 	 * 构造
-	 * 
-	 * @param charset 编码
-	 * @param path 模板路径,如果ClassPath或者WebRoot模式,则表示相对路径
+	 *
+	 * @param charset      编码
+	 * @param path         模板路径,如果ClassPath或者WebRoot模式,则表示相对路径
 	 * @param resourceMode 模板资源加载方式
 	 */
 	public TemplateConfig(Charset charset, String path, ResourceMode resourceMode) {
@@ -62,21 +75,21 @@ public class TemplateConfig implements Serializable {
 
 	/**
 	 * 获取编码
-	 * 
+	 *
 	 * @return 编码
 	 */
 	public Charset getCharset() {
 		return charset;
 	}
-	
+
 	/**
 	 * 获取编码
-	 * 
+	 *
 	 * @return 编码
 	 * @since 4.1.11
 	 */
 	public String getCharsetStr() {
-		if(null == this.charset) {
+		if (null == this.charset) {
 			return null;
 		}
 		return this.charset.toString();
@@ -84,7 +97,7 @@ public class TemplateConfig implements Serializable {
 
 	/**
 	 * 设置编码
-	 * 
+	 *
 	 * @param charset 编码
 	 */
 	public void setCharset(Charset charset) {
@@ -93,7 +106,7 @@ public class TemplateConfig implements Serializable {
 
 	/**
 	 * 获取模板路径,如果ClassPath或者WebRoot模式,则表示相对路径
-	 * 
+	 *
 	 * @return 模板路径
 	 */
 	public String getPath() {
@@ -102,7 +115,7 @@ public class TemplateConfig implements Serializable {
 
 	/**
 	 * 设置模板路径,如果ClassPath或者WebRoot模式,则表示相对路径
-	 * 
+	 *
 	 * @param path 模板路径
 	 */
 	public void setPath(String path) {
@@ -111,7 +124,7 @@ public class TemplateConfig implements Serializable {
 
 	/**
 	 * 获取模板资源加载方式
-	 * 
+	 *
 	 * @return 模板资源加载方式
 	 */
 	public ResourceMode getResourceMode() {
@@ -120,7 +133,7 @@ public class TemplateConfig implements Serializable {
 
 	/**
 	 * 设置模板资源加载方式
-	 * 
+	 *
 	 * @param resourceMode 模板资源加载方式
 	 */
 	public void setResourceMode(ResourceMode resourceMode) {
@@ -128,59 +141,73 @@ public class TemplateConfig implements Serializable {
 	}
 
 	/**
+	 * 获取自定义引擎,null表示系统自动判断
+	 *
+	 * @return 自定义引擎,null表示系统自动判断
+	 * @since 5.2.1
+	 */
+	public Class<? extends TemplateEngine> getCustomEngine() {
+		return customEngine;
+	}
+
+
+	/**
+	 * 设置自定义引擎,null表示系统自动判断
+	 *
+	 * @param customEngine 自定义引擎,null表示系统自动判断
+	 * @return this
+	 * @since 5.2.1
+	 */
+	public TemplateConfig setCustomEngine(Class<? extends TemplateEngine> customEngine) {
+		this.customEngine = customEngine;
+		return this;
+	}
+
+	/**
 	 * 资源加载方式枚举
-	 * 
+	 *
 	 * @author looly
 	 */
 	public enum ResourceMode {
-		/** 从ClassPath加载模板 */
+		/**
+		 * 从ClassPath加载模板
+		 */
 		CLASSPATH,
-		/** 从File目录加载模板 */
+		/**
+		 * 从File目录加载模板
+		 */
 		FILE,
-		/** 从WebRoot目录加载模板 */
+		/**
+		 * 从WebRoot目录加载模板
+		 */
 		WEB_ROOT,
-		/** 从模板文本加载模板 */
+		/**
+		 * 从模板文本加载模板
+		 */
 		STRING,
-		/** 复合加载模板(分别从File、ClassPath、Web-root、String方式尝试查找模板) */
+		/**
+		 * 复合加载模板(分别从File、ClassPath、Web-root、String方式尝试查找模板)
+		 */
 		COMPOSITE
 	}
 
 	@Override
-	public int hashCode() {
-		final int prime = 31;
-		int result = 1;
-		result = prime * result + ((charset == null) ? 0 : charset.hashCode());
-		result = prime * result + ((path == null) ? 0 : path.hashCode());
-		result = prime * result + ((resourceMode == null) ? 0 : resourceMode.hashCode());
-		return result;
-	}
-
-	@Override
-	public boolean equals(Object obj) {
-		if (this == obj) {
+	public boolean equals(Object o) {
+		if (this == o){
 			return true;
 		}
-		if (obj == null) {
+		if (o == null || getClass() != o.getClass()){
 			return false;
 		}
-		if (getClass() != obj.getClass()) {
-			return false;
-		}
-		TemplateConfig other = (TemplateConfig) obj;
-		if (charset == null) {
-			if (other.charset != null) {
-				return false;
-			}
-		} else if (!charset.equals(other.charset)) {
-			return false;
-		}
-		if (path == null) {
-			if (other.path != null) {
-				return false;
-			}
-		} else if (!path.equals(other.path)) {
-			return false;
-		}
-		return resourceMode == other.resourceMode;
+		TemplateConfig that = (TemplateConfig) o;
+		return Objects.equals(charset, that.charset) &&
+				Objects.equals(path, that.path) &&
+				resourceMode == that.resourceMode &&
+				Objects.equals(customEngine, that.customEngine);
+	}
+
+	@Override
+	public int hashCode() {
+		return Objects.hash(charset, path, resourceMode, customEngine);
 	}
 }

+ 12 - 4
hutool-extra/src/main/java/cn/hutool/extra/template/TemplateEngine.java

@@ -2,17 +2,25 @@ package cn.hutool.extra.template;
 
 /**
  * 引擎接口,通过实现此接口从而使用对应的模板引擎
- * 
+ *
  * @author looly
  */
 public interface TemplateEngine {
-	
+
+	/**
+	 * 使用指定配置文件初始化模板引擎
+	 *
+	 * @param config 配置文件
+	 * @return this
+	 */
+	TemplateEngine init(TemplateConfig config);
+
 	/**
 	 * 获取模板
-	 * 
+	 *
 	 * @param resource 资源,根据实现不同,此资源可以是模板本身,也可以是模板的相对路径
 	 * @return 模板实现
 	 */
 	Template getTemplate(String resource);
-	
+
 }

+ 9 - 2
hutool-extra/src/main/java/cn/hutool/extra/template/engine/TemplateFactory.java

@@ -1,5 +1,6 @@
 package cn.hutool.extra.template.engine;
 
+import cn.hutool.core.util.ReflectUtil;
 import cn.hutool.core.util.ServiceLoaderUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.extra.template.TemplateConfig;
@@ -35,9 +36,15 @@ public class TemplateFactory {
 	 * @return {@link Engine}
 	 */
 	private static TemplateEngine doCreate(TemplateConfig config) {
-		final TemplateEngine engine = ServiceLoaderUtil.loadFirstAvailable(TemplateEngine.class);
+		final Class<? extends TemplateEngine> customEngineClass = config.getCustomEngine();
+		final TemplateEngine engine;
+		if(null != customEngineClass){
+			engine = ReflectUtil.newInstance(customEngineClass);
+		}else{
+			engine = ServiceLoaderUtil.loadFirstAvailable(TemplateEngine.class);
+		}
 		if(null != engine){
-			return engine;
+			return engine.init(config);
 		}
 
 		throw new TemplateException("No template found ! Please add one of template jar to your project !");

+ 24 - 8
hutool-extra/src/main/java/cn/hutool/extra/template/engine/beetl/BeetlEngine.java

@@ -23,15 +23,13 @@ import cn.hutool.extra.template.TemplateEngine;
  */
 public class BeetlEngine implements TemplateEngine {
 
-	private final GroupTemplate engine;
+	private GroupTemplate engine;
 
 	// --------------------------------------------------------------------------------- Constructor start
 	/**
 	 * 默认构造
 	 */
-	public BeetlEngine() {
-		this(new TemplateConfig());
-	}
+	public BeetlEngine() {}
 
 	/**
 	 * 构造
@@ -39,7 +37,7 @@ public class BeetlEngine implements TemplateEngine {
 	 * @param config 模板配置
 	 */
 	public BeetlEngine(TemplateConfig config) {
-		this(createEngine(config));
+		init(config);
 	}
 
 	/**
@@ -48,12 +46,30 @@ public class BeetlEngine implements TemplateEngine {
 	 * @param engine {@link GroupTemplate}
 	 */
 	public BeetlEngine(GroupTemplate engine) {
-		this.engine = engine;
+		init(engine);
 	}
 	// --------------------------------------------------------------------------------- Constructor end
-	
+
+
+	@Override
+	public TemplateEngine init(TemplateConfig config) {
+		init(createEngine(config));
+		return this;
+	}
+
+	/**
+	 * 初始化引擎
+	 * @param engine 引擎
+	 */
+	private void init(GroupTemplate engine){
+		this.engine = engine;
+	}
+
 	@Override
 	public Template getTemplate(String resource) {
+		if(null == this.engine){
+			init(TemplateConfig.DEFAULT);
+		}
 		return BeetlTemplate.wrap(engine.getTemplate(resource));
 	}
 
@@ -65,7 +81,7 @@ public class BeetlEngine implements TemplateEngine {
 	 */
 	private static GroupTemplate createEngine(TemplateConfig config) {
 		if (null == config) {
-			config = new TemplateConfig();
+			config = TemplateConfig.DEFAULT;
 		}
 
 		switch (config.getResourceMode()) {

+ 26 - 12
hutool-extra/src/main/java/cn/hutool/extra/template/engine/enjoy/EnjoyEngine.java

@@ -1,17 +1,14 @@
 package cn.hutool.extra.template.engine.enjoy;
 
-import org.beetl.core.GroupTemplate;
-
-import com.jfinal.template.source.FileSourceFactory;
-
 import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.lang.Assert;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.extra.template.Template;
 import cn.hutool.extra.template.TemplateConfig;
 import cn.hutool.extra.template.TemplateConfig.ResourceMode;
 import cn.hutool.extra.template.TemplateEngine;
+import com.jfinal.template.source.FileSourceFactory;
+import org.beetl.core.GroupTemplate;
 
 /**
  * Enjoy库的引擎包装
@@ -29,9 +26,7 @@ public class EnjoyEngine implements TemplateEngine {
 	/**
 	 * 默认构造
 	 */
-	public EnjoyEngine() {
-		this(new TemplateConfig());
-	}
+	public EnjoyEngine() {}
 
 	/**
 	 * 构造
@@ -39,8 +34,7 @@ public class EnjoyEngine implements TemplateEngine {
 	 * @param config 模板配置
 	 */
 	public EnjoyEngine(TemplateConfig config) {
-		this(createEngine(config));
-		this.resourceMode = config.getResourceMode();
+		init(config);
 	}
 
 	/**
@@ -49,12 +43,33 @@ public class EnjoyEngine implements TemplateEngine {
 	 * @param engine {@link com.jfinal.template.Engine}
 	 */
 	public EnjoyEngine(com.jfinal.template.Engine engine) {
-		this.engine = engine;
+		init(engine);
 	}
 	// --------------------------------------------------------------------------------- Constructor end
 
 	@Override
+	public TemplateEngine init(TemplateConfig config) {
+		if(null == config){
+			config = TemplateConfig.DEFAULT;
+		}
+		this.resourceMode = config.getResourceMode();
+		init(createEngine(config));
+		return this;
+	}
+
+	/**
+	 * 初始化引擎
+	 * @param engine 引擎
+	 */
+	private void init(com.jfinal.template.Engine engine){
+		this.engine = engine;
+	}
+
+	@Override
 	public Template getTemplate(String resource) {
+		if(null == this.engine){
+			init(TemplateConfig.DEFAULT);
+		}
 		if (ObjectUtil.equal(ResourceMode.STRING, this.resourceMode)) {
 			return EnjoyTemplate.wrap(this.engine.getTemplateByString(resource));
 		}
@@ -68,7 +83,6 @@ public class EnjoyEngine implements TemplateEngine {
 	 * @return {@link GroupTemplate}
 	 */
 	private static com.jfinal.template.Engine createEngine(TemplateConfig config) {
-		Assert.notNull(config, "Template config is null !");
 		final com.jfinal.template.Engine engine = com.jfinal.template.Engine.create("Hutool-Enjoy-Engine-" + IdUtil.fastSimpleUUID());
 		engine.setEncoding(config.getCharsetStr());
 

+ 24 - 6
hutool-extra/src/main/java/cn/hutool/extra/template/engine/freemarker/FreemarkerEngine.java

@@ -26,9 +26,7 @@ public class FreemarkerEngine implements TemplateEngine {
 	/**
 	 * 默认构造
 	 */
-	public FreemarkerEngine() {
-		this(new TemplateConfig());
-	}
+	public FreemarkerEngine() {}
 
 	/**
 	 * 构造
@@ -36,7 +34,7 @@ public class FreemarkerEngine implements TemplateEngine {
 	 * @param config 模板配置
 	 */
 	public FreemarkerEngine(TemplateConfig config) {
-		this(createCfg(config));
+		init(config);
 	}
 
 	/**
@@ -45,12 +43,32 @@ public class FreemarkerEngine implements TemplateEngine {
 	 * @param freemarkerCfg {@link Configuration}
 	 */
 	public FreemarkerEngine(Configuration freemarkerCfg) {
-		this.cfg = freemarkerCfg;
+		init(freemarkerCfg);
 	}
 	// --------------------------------------------------------------------------------- Constructor end
-	
+
+	@Override
+	public TemplateEngine init(TemplateConfig config) {
+		if(null == config){
+			config = TemplateConfig.DEFAULT;
+		}
+		init(createCfg(config));
+		return this;
+	}
+
+	/**
+	 * 初始化引擎
+	 * @param freemarkerCfg Configuration
+	 */
+	private void init(Configuration freemarkerCfg){
+		this.cfg = freemarkerCfg;
+	}
+
 	@Override
 	public Template getTemplate(String resource) {
+		if(null == this.cfg){
+			init(TemplateConfig.DEFAULT);
+		}
 		try {
 			return FreemarkerTemplate.wrap(this.cfg.getTemplate(resource));
 		} catch(IOException e) {

+ 25 - 7
hutool-extra/src/main/java/cn/hutool/extra/template/engine/rythm/RythmEngine.java

@@ -21,9 +21,7 @@ public class RythmEngine implements TemplateEngine {
 	/**
 	 * 默认构造
 	 */
-	public RythmEngine() {
-		this(new TemplateConfig());
-	}
+	public RythmEngine() {}
 
 	/**
 	 * 构造
@@ -31,7 +29,7 @@ public class RythmEngine implements TemplateEngine {
 	 * @param config 模板配置
 	 */
 	public RythmEngine(TemplateConfig config) {
-		this(createEngine(config));
+		init(config);
 	}
 
 	/**
@@ -40,13 +38,33 @@ public class RythmEngine implements TemplateEngine {
 	 * @param engine {@link org.rythmengine.RythmEngine}
 	 */
 	public RythmEngine(org.rythmengine.RythmEngine engine) {
-		this.engine = engine;
+		init(engine);
 	}
 	// --------------------------------------------------------------------------------- Constructor end
-	
+
+	@Override
+	public TemplateEngine init(TemplateConfig config) {
+		if(null == config){
+			config = TemplateConfig.DEFAULT;
+		}
+		init(createEngine(config));
+		return this;
+	}
+
+	/**
+	 * 初始化引擎
+	 * @param engine 引擎
+	 */
+	private void init(org.rythmengine.RythmEngine engine){
+		this.engine = engine;
+	}
+
 	@Override
 	public Template getTemplate(String resource) {
-		return RythmTemplate.wrap(engine.getTemplate(resource));
+		if(null == this.engine){
+			init(TemplateConfig.DEFAULT);
+		}
+		return RythmTemplate.wrap(this.engine.getTemplate(resource));
 	}
 
 	/**

+ 24 - 6
hutool-extra/src/main/java/cn/hutool/extra/template/engine/thymeleaf/ThymeleafEngine.java

@@ -28,9 +28,7 @@ public class ThymeleafEngine implements TemplateEngine {
 	/**
 	 * 默认构造
 	 */
-	public ThymeleafEngine() {
-		this(new TemplateConfig());
-	}
+	public ThymeleafEngine() {}
 
 	/**
 	 * 构造
@@ -38,8 +36,7 @@ public class ThymeleafEngine implements TemplateEngine {
 	 * @param config 模板配置
 	 */
 	public ThymeleafEngine(TemplateConfig config) {
-		this(createEngine(config));
-		this.config = config;
+		init(config);
 	}
 
 	/**
@@ -48,12 +45,33 @@ public class ThymeleafEngine implements TemplateEngine {
 	 * @param engine {@link org.thymeleaf.TemplateEngine}
 	 */
 	public ThymeleafEngine(org.thymeleaf.TemplateEngine engine) {
-		this.engine = engine;
+		init(engine);
 	}
 	// --------------------------------------------------------------------------------- Constructor end
 
 	@Override
+	public TemplateEngine init(TemplateConfig config) {
+		if(null == config){
+			config = TemplateConfig.DEFAULT;
+		}
+		this.config = config;
+		init(createEngine(config));
+		return this;
+	}
+
+	/**
+	 * 初始化引擎
+	 * @param engine 引擎
+	 */
+	private void init(org.thymeleaf.TemplateEngine engine){
+		this.engine = engine;
+	}
+
+	@Override
 	public Template getTemplate(String resource) {
+		if(null == this.engine){
+			init(TemplateConfig.DEFAULT);
+		}
 		return ThymeleafTemplate.wrap(this.engine, resource, (null == this.config) ? null : this.config.getCharset());
 	}
 

+ 23 - 5
hutool-extra/src/main/java/cn/hutool/extra/template/engine/velocity/VelocityEngine.java

@@ -21,9 +21,7 @@ public class VelocityEngine implements TemplateEngine {
 	/**
 	 * 默认构造
 	 */
-	public VelocityEngine() {
-		this(new TemplateConfig());
-	}
+	public VelocityEngine() {}
 
 	/**
 	 * 构造
@@ -31,7 +29,7 @@ public class VelocityEngine implements TemplateEngine {
 	 * @param config 模板配置
 	 */
 	public VelocityEngine(TemplateConfig config) {
-		this(createEngine(config));
+		init(config);
 	}
 
 	/**
@@ -40,10 +38,27 @@ public class VelocityEngine implements TemplateEngine {
 	 * @param engine {@link org.apache.velocity.app.VelocityEngine}
 	 */
 	public VelocityEngine(org.apache.velocity.app.VelocityEngine engine) {
-		this.engine = engine;
+		init(engine);
 	}
 	// --------------------------------------------------------------------------------- Constructor end
 
+	@Override
+	public TemplateEngine init(TemplateConfig config) {
+		if(null == config){
+			config = TemplateConfig.DEFAULT;
+		}
+		init(createEngine(config));
+		return this;
+	}
+
+	/**
+	 * 初始化引擎
+	 * @param engine 引擎
+	 */
+	private void init(org.apache.velocity.app.VelocityEngine engine){
+		this.engine = engine;
+	}
+
 	/**
 	 * 获取原始的引擎对象
 	 * 
@@ -56,6 +71,9 @@ public class VelocityEngine implements TemplateEngine {
 
 	@Override
 	public Template getTemplate(String resource) {
+		if(null == this.engine){
+			init(TemplateConfig.DEFAULT);
+		}
 		return VelocityTemplate.wrap(engine.getTemplate(resource));
 	}
 

+ 25 - 10
hutool-extra/src/test/java/cn/hutool/extra/template/TemplateUtilTest.java

@@ -27,11 +27,17 @@ public class TemplateUtilTest {
 
 	@Test
 	public void createEngineTest() {
-		// 默认模板引擎,此处为Beetl
+		// 字符串模板, 默认模板引擎,此处为Beetl
 		TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig());
 		Template template = engine.getTemplate("hello,${name}");
 		String result = template.render(Dict.create().set("name", "hutool"));
 		Assert.assertEquals("hello,hutool", result);
+
+		// classpath中获取模板
+		engine = TemplateUtil.createEngine(new TemplateConfig("templates", ResourceMode.CLASSPATH));
+		Template template2 = engine.getTemplate("beetl_test.btl");
+		String result2 = template2.render(Dict.create().set("name", "hutool"));
+		Assert.assertEquals("hello,hutool", result2);
 	}
 
 	@Test
@@ -52,7 +58,8 @@ public class TemplateUtilTest {
 	@Test
 	public void rythmEngineTest() {
 		// 字符串模板
-		TemplateEngine engine = new RythmEngine(new TemplateConfig("templates"));
+		TemplateEngine engine = TemplateUtil.createEngine(
+				new TemplateConfig("templates").setCustomEngine(RythmEngine.class));
 		Template template = engine.getTemplate("hello,@name");
 		String result = template.render(Dict.create().set("name", "hutool"));
 		Assert.assertEquals("hello,hutool", result);
@@ -66,13 +73,15 @@ public class TemplateUtilTest {
 	@Test
 	public void freemarkerEngineTest() {
 		// 字符串模板
-		TemplateEngine engine = new FreemarkerEngine(new TemplateConfig("templates", ResourceMode.STRING));
+		TemplateEngine engine = TemplateUtil.createEngine(
+				new TemplateConfig("templates", ResourceMode.STRING).setCustomEngine(FreemarkerEngine.class));
 		Template template = engine.getTemplate("hello,${name}");
 		String result = template.render(Dict.create().set("name", "hutool"));
 		Assert.assertEquals("hello,hutool", result);
 		
 		//ClassPath模板
-		engine = new FreemarkerEngine(new TemplateConfig("templates", ResourceMode.CLASSPATH));
+		engine = TemplateUtil.createEngine(
+				new TemplateConfig("templates", ResourceMode.CLASSPATH).setCustomEngine(FreemarkerEngine.class));
 		template = engine.getTemplate("freemarker_test.ftl");
 		result = template.render(Dict.create().set("name", "hutool"));
 		Assert.assertEquals("hello,hutool", result);
@@ -81,13 +90,15 @@ public class TemplateUtilTest {
 	@Test
 	public void velocityEngineTest() {
 		// 字符串模板
-		TemplateEngine engine = new VelocityEngine(new TemplateConfig("templates", ResourceMode.STRING));
+		TemplateEngine engine = TemplateUtil.createEngine(
+				new TemplateConfig("templates", ResourceMode.STRING).setCustomEngine(VelocityEngine.class));
 		Template template = engine.getTemplate("你好,$name");
 		String result = template.render(Dict.create().set("name", "hutool"));
 		Assert.assertEquals("你好,hutool", result);
 		
 		//ClassPath模板
-		engine = new VelocityEngine(new TemplateConfig("templates", ResourceMode.CLASSPATH));
+		engine = TemplateUtil.createEngine(
+				new TemplateConfig("templates", ResourceMode.CLASSPATH).setCustomEngine(VelocityEngine.class));
 		template = engine.getTemplate("templates/velocity_test.vtl");
 		result = template.render(Dict.create().set("name", "hutool"));
 		Assert.assertEquals("你好,hutool", result);
@@ -97,13 +108,15 @@ public class TemplateUtilTest {
 	@Test
 	public void enjoyEngineTest() {
 		// 字符串模板
-		TemplateEngine engine = new EnjoyEngine(new TemplateConfig("templates"));
+		TemplateEngine engine = TemplateUtil.createEngine(
+				new TemplateConfig("templates").setCustomEngine(EnjoyEngine.class));
 		Template template = engine.getTemplate("#(x + 123)");
 		String result = template.render(Dict.create().set("x", 1));
 		Assert.assertEquals("124", result);
 
 		//ClassPath模板
-		engine = new EnjoyEngine(new TemplateConfig("templates", ResourceMode.CLASSPATH));
+		engine = new EnjoyEngine(
+				new TemplateConfig("templates", ResourceMode.CLASSPATH).setCustomEngine(EnjoyEngine.class));
 		template = engine.getTemplate("enjoy_test.etl");
 		result = template.render(Dict.create().set("x", 1));
 		Assert.assertEquals("124", result);
@@ -112,13 +125,15 @@ public class TemplateUtilTest {
 	@Test
 	public void thymeleafEngineTest() {
 		// 字符串模板
-		TemplateEngine engine = new ThymeleafEngine(new TemplateConfig("templates"));
+		TemplateEngine engine = TemplateUtil.createEngine(
+				new TemplateConfig("templates").setCustomEngine(ThymeleafEngine.class));
 		Template template = engine.getTemplate("<h3 th:text=\"${message}\"></h3>");
 		String result = template.render(Dict.create().set("message", "Hutool"));
 		Assert.assertEquals("<h3>Hutool</h3>", result);
 		
 		//ClassPath模板
-		engine = new ThymeleafEngine(new TemplateConfig("templates", ResourceMode.CLASSPATH));
+		engine = TemplateUtil.createEngine(
+				new TemplateConfig("templates", ResourceMode.CLASSPATH).setCustomEngine(ThymeleafEngine.class));
 		template = engine.getTemplate("thymeleaf_test.ttl");
 		result = template.render(Dict.create().set("message", "Hutool"));
 		Assert.assertEquals("<h3>Hutool</h3>", result);