🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 2.7 自定义资源加载器 如果模板资源来自其他地方,如数据库,或者混合了数据库和物理文件,或者模板是加密的,则需要自定义一个资源加载器。资源加载器需要实现ResourceLoader类。如下: ```java public interface ResourceLoader{ /** * 根据key获取Resource * * @param key * @return */ public Resource getResource(String key); /** 检测模板是否更改,每次渲染模板前,都需要调用此方法,所以此方法不能占用太多时间,否则会影响渲染功能 * @param key * @return */ public boolean isModified(Resource key); /** * 关闭ResouceLoader,通常是GroupTemplate关闭的时候也关闭对应的ResourceLoader */ public void close(); /** 一些初始化方法 * @param gt */ public void init(GroupTemplate gt); /** 用于include,layout等根据相对路径计算资源实际的位置. * @param resource 当前资源 * @param key * @return */ public String getResourceId(Resource resource, String key); } ``` 如下是一个简单的内存ResourceLoader ```java public class MapResourceLoader implements ResourceLoader{ Map data; public MapResourceLoader(Map data){ this.data = data; } @Override public Resource getResource(String key){ String content = (String) data.get(key); if (content == null) return null; return new StringTemplateResource(content, this); } @Override public boolean isModified(Resource key){ return false; } @Override public boolean exist(String key){ return data.contain(key); } @Override public void close(){ } @Override public void init(GroupTemplate gt){ } @Override public String getResourceId(Resource resource, String id){ //不需要计算相对路径 return id; } } ``` init方法可以初始化GroupTemplate,比如读取配置文件的root属性,autoCheck属性,字符集属性,以及加载functions目录下的所有模板方法 如FileResourceLoader 的 init方法 ```java @Override public void init(GroupTemplate gt){ Map<String, String> resourceMap = gt.getConf().getResourceMap(); if (this.root == null){ this.root = resourceMap.get("root"); } if (this.charset == null){ this.charset = resourceMap.get("charset"); } if (this.functionSuffix == null){ this.functionSuffix = resourceMap.get("functionSuffix"); } this.autoCheck = Boolean.parseBoolean(resourceMap.get("autoCheck")); File root = new File(this.root, this.functionRoot); this.gt = gt; if (root.exists()){ readFuntionFile(root, "", "/".concat(functionRoot).concat("/")); } } ``` readFuntionFile 方法将读取functions下的所有模板,并注册为方法 ```java protected void readFuntionFile(File funtionRoot, String ns, String path){ String expected = ".".concat(this.functionSuffix); File[] files = funtionRoot.listFiles(); for (File f : files){ if (f.isDirectory()){ //读取子目录 readFuntionFile(f, f.getName().concat("."), path.concat(f.getName()).concat("/")); } else if (f.getName().endsWith(functionSuffix)){ String resourceId = path + f.getName(); String fileName = f.getName(); fileName = fileName.substring(0, (fileName.length() - functionSuffix.length() - 1)); String functionName = ns.concat(fileName); FileFunctionWrapper fun = new FileFunctionWrapper(resourceId); gt.registerFunction(functionName, fun); } } } ``` Resource类需要实现OpenReader方法,以及isModified方法。对于模板内容存储在数据库中,openReader返回一个Clob,isModified 则需要根据改模板内容对应的lastUpdate(通常数据库应该这么设计)来判断模板是否更改 ```java public abstract class Resource{ /** * 打开一个新的Reader * * @return */ public abstract Reader openReader(); /** * 检测资源是否改变 * * @return */ public abstract boolean isModified(); ``` 参考例子可以参考beetl自带的ResourceLoader