Beetl自定义ResourceLoader,实现特殊的模板加载需求。
如:加载jar里面的模板文件,解决“找不到指定模板或者加载模板错(TEMPLATE_LOAD_ERROR)”问题。
1.问题:
找不到指定模板或者加载模板错(TEMPLATE_LOAD_ERROR)
2.解决方案:
自定义ResourceLoader,支持从别的jar文件里面加载模板。(跨jar文件加载模板)
public static void generate(String templateFilePath, String outputFilePath, Map<String, Object> bindAttrs) throws IOException {
// ClasspathResourceLoader resourceLoader = new ClasspathResourceLoader("template");
// FileResourceLoader resourceLoader = new FileResourceLoader(getPath(templateFilePath));
AppResourceLoader resourceLoader = new AppResourceLoader(getPath(templateFilePath));
Configuration cfg = Configuration.defaultConfiguration();
GroupTemplate groupTemplate = new GroupTemplate(resourceLoader, cfg);
Template template = groupTemplate.getTemplate(getFile(templateFilePath));
template.fastBinding(bindAttrs);
File outputFile = new File(outputFilePath);
FileWriterWithEncoding writer = new FileWriterWithEncoding(outputFile, "utf-8");
template.renderTo(writer);
}
3.具体代码:
AppResourceLoader
import org.beetl.core.GroupTemplate;
import org.beetl.core.Resource;
import org.beetl.core.ResourceLoader;
import org.beetl.core.misc.BeetlUtil;
import java.io.File;
import java.net.URL;
import java.util.Map;
/**
* 自定义的ResourceLoader,用于支持从文件,jar和数据库里加载模板。
*
* @author Neoman
*/
public class AppResourceLoader implements ResourceLoader {
private String root = null;
boolean autoCheck = false;
//模板来自文件
boolean fromFile = true;
//模板来自Db
boolean fromDb = false;
//模板来自jar包
boolean fromJar = false;
protected String charset = "UTF-8";
String functionRoot = "functions";
GroupTemplate gt = null;
String functionSuffix = "fn";
ClassLoader classLoader = null;
/**
* 使用加载beetl.jar的classloader,以及默认root为根目录
*/
public AppResourceLoader() {
//保留,用于通过配置构造一个ResouceLoader
classLoader = this.getClass().getClassLoader();
this.root = "";
}
/**
* 使用指定的classloader
*
* @param classLoader
*/
public AppResourceLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
this.root = "";
}
/**
* 使用指定的classloader和root
*
* @param classLoader
* @param root 模板路径,如/com/templates/
*/
public AppResourceLoader(ClassLoader classLoader, String root) {
this.classLoader = classLoader;
this.root = root;
}
/**
* @param classLoader
* @param root
* @param charset
*/
public AppResourceLoader(ClassLoader classLoader, String root, String charset) {
this(classLoader, root);
this.charset = charset;
}
/**
* @param root ,/com/templates/如其后的resourceId对应的路径是root+"/"+resourceId
*/
public AppResourceLoader(String root) {
this();
if (root.equals("/")) {
this.root = "";
} else {
this.root = root;
}
}
public AppResourceLoader(String root, String charset) {
this(root);
this.charset = charset;
}
/*
* (non-Javadoc)
*
* @see org.beetl.core.ResourceLoader#getResource(java.lang.String)
*/
@Override
public Resource getResource(String key) {
AppResource resource = new AppResource(root, key, this);
resource.setFromFile(fromFile);
resource.setFromDb(fromDb);
resource.setFromJar(fromJar);
return resource;
}
/*
* (non-Javadoc)
*
* @see org.beetl.core.ResourceLoader#close()
*/
@Override
public void close() {
// TODO Auto-generated method stub
}
@Override
public boolean isModified(Resource key) {
if (this.autoCheck) {
return key.isModified();
} else {
return false;
}
}
public boolean isAutoCheck() {
return autoCheck;
}
public void setAutoCheck(boolean autoCheck) {
this.autoCheck = autoCheck;
}
public String getRoot() {
return root;
}
@Override
public void init(GroupTemplate gt) {
Map<String, String> resourceMap = gt.getConf().getResourceMap();
if (resourceMap.get("root") != null) {
String temp = resourceMap.get("root");
if (temp.equals("/") || temp.length() == 0) {
} else {
if (this.root.endsWith("/")) {
this.root = this.root + resourceMap.get("root");
} else {
this.root = this.root + "/" + resourceMap.get("root");
}
}
}
if (this.charset == null) {
this.charset = resourceMap.get("charset");
}
this.functionSuffix = resourceMap.get("functionSuffix");
this.autoCheck = Boolean.parseBoolean(resourceMap.get("autoCheck"));
this.functionRoot = resourceMap.get("functionRoot");
//初始化functions
URL url = classLoader.getResource("");
this.gt = gt;
if (url != null && url.getProtocol().equals("file")) {
File fnRoot = new File(url.getFile() + File.separator + root + File.separator + this.functionRoot);
if (fnRoot.exists()) {
String ns = "";
String path = "/".concat(this.functionRoot).concat("/");
BeetlUtil.autoFileFunctionRegister(gt, fnRoot, ns, path, this.functionSuffix);
}
}
}
@Override
public boolean exist(String key) {
URL url = this.classLoader.getResource(root + key);
if (url == null) {
//兼容以前的
url = this.classLoader.getClass().getResource(root + key);
}
return url != null;
}
public String getCharset() {
return charset;
}
public void setCharset(String charset) {
this.charset = charset;
}
@Override
public String getResourceId(Resource resource, String id) {
if (resource == null)
return id;
else
return BeetlUtil.getRelPath(resource.getId(), id);
}
public ClassLoader getClassLoader() {
return classLoader;
}
public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public String getInfo() {
return "ClassLoader:" + this.classLoader + " Path:" + root;
}
public boolean isFromFile() {
return fromFile;
}
public void setFromFile(boolean fromFile) {
this.fromFile = fromFile;
}
public boolean isFromDb() {
return fromDb;
}
public void setFromDb(boolean fromDb) {
this.fromDb = fromDb;
}
public boolean isFromJar() {
return fromJar;
}
public void setFromJar(boolean fromJar) {
this.fromJar = fromJar;
}
}
AppResource
import org.beetl.core.Resource;
import org.beetl.core.ResourceLoader;
import org.beetl.core.exception.BeetlException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* 模板资源读取,支持从db,文件,classpath,jar 里读取模板资源:
* 先从webroot的文件里读取,如果没有,则读取数据库,如何还找不到,读取jar或者classpath里的
*
* @author Neoman
*/
public class AppResource extends Resource {
String root = null;
File file = null;
long lastModified = 0;
//模板来自文件
boolean fromFile = true;
//模板来自Db
boolean fromDb = false;
//模板来自jar包
boolean fromJar = false;
public AppResource(String root, String key, ResourceLoader resourceLoader) {
super(key, resourceLoader);
this.root = root;
}
@Override
public Reader openReader() {
InputStream is = null;
Reader br;
AppResourceLoader loader = (AppResourceLoader) this.resourceLoader;
String filepath = root + File.separator + id;
try { //从文件里读取,一般的web root里
// file = new File(PathKit.getWebRootPath() + root, id);
file = new File(filepath);
if (file.exists() && fromFile) {
is = new FileInputStream(file);
}
//从数据库里读取,暂未实现
if (is == null && fromDb) {
}
//从jar 里读取
if (is == null && filepath.contains(".jar!")) {
String[] split = filepath.split("!");
// 模板路径
String filename = split[1];
filename = filename.replace("\\", "/");
filename = filename.replace("//", "/");
if (filename.startsWith("/")) {
filename = filename.substring(1);
}
// jar 路径
String jarPath = split[0];
jarPath = jarPath.replace("file:", "");
JarFile jarFile = new JarFile(jarPath);
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (entry.getName().equals(filename)) {
is = jarFile.getInputStream(entry);
}
}
// jarFile.close();
}
//从jar 或者classpath里读取
if (is == null && fromJar) {
ClassLoader cs = loader.getClassLoader();
URL url = cs.getResource(filepath);
if (url == null) {
//兼容以前的写法
url = resourceLoader.getClass().getResource(filepath);
}
if (url == null) {
BeetlException be = new BeetlException(BeetlException.TEMPLATE_LOAD_ERROR);
be.pushResource(this);
throw be;
}
is = url.openStream();
}
if (is == null) {
BeetlException be = new BeetlException(BeetlException.TEMPLATE_LOAD_ERROR, " 模板不存在: " + loader.getInfo());
be.pushResource(this);
throw be;
}
br = new BufferedReader(new InputStreamReader(is, loader.charset));
return br;
} catch (UnsupportedEncodingException e) {
return null;
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
BeetlException be = new BeetlException(BeetlException.TEMPLATE_LOAD_ERROR, " 模板根目录为 " + loader.getRoot());
be.pushResource(this);
throw be;
} catch (IOException e) {
// TODO Auto-generated catch block
BeetlException be = new BeetlException(BeetlException.TEMPLATE_LOAD_ERROR, " 模板根目录为 " + loader.getRoot());
be.pushResource(this);
throw be;
}
}
/**
* 目前,只能跟踪文件的变化
*/
@Override
public boolean isModified() {
if (fromFile && file != null && file.exists()) {
return file.lastModified() != this.lastModified;
}
// String refresh = SysConfig.dao.queryConfig("beetl.template.refresh", "0");
// if (!"0".equals(refresh)) {//不等于0,刷新模板
// SysConfig.dao.updateConfig("beetl.template.refresh", "0");
// return true;
// }
//jar里,肯定要重启了
if (fromJar) {
return false;
}
//db里 判断时间--暂未 实现
if (fromDb) {
return false;
}
return false;
}
@Override
public String getId() {
return id;
}
public boolean isFromFile() {
return fromFile;
}
public void setFromFile(boolean fromFile) {
this.fromFile = fromFile;
}
public boolean isFromDb() {
return fromDb;
}
public void setFromDb(boolean fromDb) {
this.fromDb = fromDb;
}
public boolean isFromJar() {
return fromJar;
}
public void setFromJar(boolean fromJar) {
this.fromJar = fromJar;
}
}
CommonUtils
import com.central.generator.utils.AppResourceLoader;
import org.apache.commons.io.output.FileWriterWithEncoding;
import org.apache.commons.lang3.StringUtils;
import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.util.Map;
public class CommonUtils {
public CommonUtils() {
}
public static String getPath(String filePath) {
String path = "";
if (StringUtils.isNotBlank(filePath)) {
path = filePath.substring(0, filePath.lastIndexOf("/") + 1);
}
return path;
}
public static String getFile(String filePath) {
String file = "";
if (StringUtils.isNotBlank(filePath)) {
file = filePath.substring(filePath.lastIndexOf("/") + 1);
}
return file;
}
public static void generate(String templateFilePath, String outputFilePath, Map<String, Object> bindAttrs) throws IOException {
// ClasspathResourceLoader resourceLoader = new ClasspathResourceLoader("template");
// FileResourceLoader resourceLoader = new FileResourceLoader(getPath(templateFilePath));
AppResourceLoader resourceLoader = new AppResourceLoader(getPath(templateFilePath));
Configuration cfg = Configuration.defaultConfiguration();
GroupTemplate groupTemplate = new GroupTemplate(resourceLoader, cfg);
Template template = groupTemplate.getTemplate(getFile(templateFilePath));
template.fastBinding(bindAttrs);
File outputFile = new File(outputFilePath);
FileWriterWithEncoding writer = new FileWriterWithEncoding(outputFile, "utf-8");
template.renderTo(writer);
}
public static void main(String[] args) throws Exception {
String templateFilePath = "file:D:\\tools_new\\maven\\config-3.0.0-20240702.031116-17.jar!\\template\\Entity.java.btl";
// String templateFilePath = "D:/tools_new/maven/config-3.0.0-20240702.031116-17.jar!/template/Entity.java.btl";
// String templateFilePath = "D:\\tools_new\\maven\\config-3.0.0-20240702.031116-17.jar!\\template\\Entity.java.btl";
// File file = new File(templateFilePath);
// Reader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "utf-8"));
// System.out.println(br);
AppResourceLoader resourceLoader = new AppResourceLoader(getPath(templateFilePath));
BufferedReader reader = (BufferedReader) resourceLoader.getResource(getFile(templateFilePath)).openReader();
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
}
}
部分代码来源: