3.7. 自定义资源加载器

如果模板资源来自其他地方,如数据库,或者混合了数据库和物理文件,或者模板是加密的,则需要自定义一个资源加载器。资源加载器需要实现ResourceLoader类。如下:

  1. public interface ResourceLoader{
  2. /**
  3. * 根据key获取Resource
  4. *
  5. * @param key
  6. * @return
  7. */
  8. public Resource getResource(String key);
  9. /** 检测模板是否更改,每次渲染模板前,都需要调用此方法,所以此方法不能占用太多时间,否则会影响渲染功能
  10. * @param key
  11. * @return
  12. */
  13. public boolean isModified(Resource key);
  14. /**
  15. * 关闭ResouceLoader,通常是GroupTemplate关闭的时候也关闭对应的ResourceLoader
  16. */
  17. public void close();
  18. /** 一些初始化方法
  19. * @param gt
  20. */
  21. public void init(GroupTemplate gt);
  22. /** 用于include,layout等根据相对路径计算资源实际的位置.
  23. * @param resource 当前资源
  24. * @param key
  25. * @return
  26. */
  27. public String getResourceId(Resource resource, String key);
  28. }

如下是一个简单的内存ResourceLoader

  1. public class MapResourceLoader implements ResourceLoader{
  2. Map data;
  3. public MapResourceLoader(Map data){
  4. this.data = data;
  5. }
  6. @Override
  7. public Resource getResource(String key){
  8. String content = (String) data.get(key);
  9. if (content == null)
  10. return null;
  11. return new StringTemplateResource(content, this);
  12. }
  13. @Override
  14. public boolean isModified(Resource key){
  15. return false;
  16. }
  17. @Override
  18. public boolean exist(String key){
  19. return data.contain(key);
  20. }
  21. @Override
  22. public void close(){
  23. }
  24. @Override
  25. public void init(GroupTemplate gt){
  26. }
  27. @Override
  28. public String getResourceId(Resource resource, String id){
  29. //不需要计算相对路径
  30. return id;
  31. }
  32. }

init方法可以初始化GroupTemplate,比如读取配置文件的root属性,autoCheck属性,字符集属性,以及加载functions目录下的所有模板方法 如FileResourceLoader 的 init方法

  1. @Override
  2. public void init(GroupTemplate gt){
  3. Map<String, String> resourceMap = gt.getConf().getResourceMap();
  4. if (this.root == null){
  5. this.root = resourceMap.get("root");
  6. }
  7. if (this.charset == null){
  8. this.charset = resourceMap.get("charset");
  9. }
  10. if (this.functionSuffix == null){
  11. this.functionSuffix = resourceMap.get("functionSuffix");
  12. }
  13. this.autoCheck = Boolean.parseBoolean(resourceMap.get("autoCheck"));
  14. File root = new File(this.root, this.functionRoot);
  15. this.gt = gt;
  16. if (root.exists()){
  17. readFuntionFile(root, "", "/".concat(functionRoot).concat("/"));
  18. }
  19. }

readFuntionFile 方法将读取functions下的所有模板,并注册为方法

  1. protected void readFuntionFile(File funtionRoot, String ns, String path){
  2. String expected = ".".concat(this.functionSuffix);
  3. File[] files = funtionRoot.listFiles();
  4. for (File f : files){
  5. if (f.isDirectory()){
  6. //读取子目录
  7. readFuntionFile(f, f.getName().concat("."), path.concat(f.getName()).concat("/"));
  8. } else if (f.getName().endsWith(functionSuffix)){
  9. String resourceId = path + f.getName();
  10. String fileName = f.getName();
  11. fileName = fileName.substring(0, (fileName.length() - functionSuffix.length() - 1));
  12. String functionName = ns.concat(fileName);
  13. FileFunctionWrapper fun = new FileFunctionWrapper(resourceId);
  14. gt.registerFunction(functionName, fun);
  15. }
  16. }
  17. }

Resource类需要实现OpenReader方法,以及isModified方法。对于模板内容存储在数据库中,openReader返回一个Clob,isModified 则需要根据改模板内容对应的lastUpdate(通常数据库应该这么设计)来判断模板是否更改

  1. public abstract class Resource{
  2. /**
  3. * 打开一个新的Reader
  4. *
  5. * @return
  6. */
  7. public abstract Reader openReader();
  8. /**
  9. * 检测资源是否改变
  10. *
  11. * @return
  12. */
  13. public abstract boolean isModified();

参考例子可以参考beetl自带的ResourceLoader