一直以来,有个目标是:使用Beetl的时候,如果web root 里有模板文件,则beetl从web root里加载。如果没有,则从jar里加载,或者从Db里加载。

这样,工程里大量相同的模板模板可以共用(当你的应用,有N个客户的时候,特别需要这个,更新一个jar,重启一下即可)。

最后确认CompositeResourceLoader 无法满足自己的需求。于是磕磕碰碰的自己实现了一个ResourceLoader,自定义加载模板。

直接贴代码吧

package com.jfinal.ext.beetl;

import java.io.File;

import java.net.URL;

import java.util.Map;

import org.beetl.core.GroupTemplate;

import org.beetl.core.Resource;

import org.beetl.core.ResourceLoader;

import org.beetl.core.misc.BeetlUtil;

/**

* 自定义的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 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;

}

}

AppResourceLoader基本复制之前org.beetl.core.resource.WebAppResourceLoader的。init 注册函数的时候,还是仅仅读取web root里的目录。因为我自己的是代码里注册了,所以,也没去实现从jar加载function

package com.jfinal.ext.beetl;

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 org.beetl.core.Resource;

import org.beetl.core.ResourceLoader;

import org.beetl.core.exception.BeetlException;

import com.jfinal.kit.PathKit;

/**

* 模板资源读取,支持从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;

try

{//从文件里读取,一般的web root里

file = new File(PathKit.getWebRootPath() + root, id);

if (file.exists() && fromFile) {

is = new FileInputStream(file);

}

//从数据库里读取,暂未实现

if (is == null && fromDb) {

}

//从jar 或者classpath里读取

if (is == null && fromJar) {

ClassLoader cs = loader.getClassLoader();

URL url = cs.getResource(root + id);

if(url==null){

//兼容以前的写法

url = resourceLoader.getClass().getResource(root + id);

}

if (url == null)

{

BeetlException be = new BeetlException(BeetlException.TEMPLATE_LOAD_ERROR);

be.resourceId = this.id;

throw be;

}

is = url.openStream();

}

if (is == null) {

BeetlException be = new BeetlException(BeetlException.TEMPLATE_LOAD_ERROR, " 模板不存在: " + loader.getInfo());

be.resourceId = this.id;

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.resourceId = this.id;

throw be;

} catch (IOException e) {

// TODO Auto-generated catch block

BeetlException be = new BeetlException(BeetlException.TEMPLATE_LOAD_ERROR, " 模板根目录为 " + loader.getRoot());

be.resourceId = this.id;

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;

}

}

暂时未用到从db加载,所以没去实现了。不过也很简单了。AppResource 主要是 openReader 里面判断资源从哪里加载。

博客粗略记录一下,希望对大家有用,欢迎交流,微信:netsafer

java引入resource下的模板_Beetl自定义ResourceLoader,实现特殊的模板加载需求相关推荐

  1. android 在自定义的listview(有刷新加载项)列表中,数据过少时不能铺满整个屏幕时,header和footer同时显示问题...

    android  在自定义的listview(有刷新加载项)列表中,数据过少时,当刷新时,加载项也会显示,这是很头疼的一个问题,查阅了一些资料,总结了一个比较不错的方法: 原来代码: 1 @Overr ...

  2. 一个常用的自定义弹框封装(适配 AndroidX),加载 ProgressDialog,状态显示的 StatusDialog 和自定义 Toast,全部支持背景颜色,圆角,边框和文字的自定义,构建者模

    MNProgressHUD 项目地址:maning0303/MNProgressHUD  简介: 一个常用的自定义弹框封装(适配 AndroidX),加载 ProgressDialog,状态显示的 S ...

  3. win7下计划任务schtasks使用详解及错误:无法加载列资源的解决方法1

    win7下计划任务schtasks使用详解及"错误:无法加载列资源"的解决方法1 2011-12-10 20:33 schtasks 命令简述: 安排命令和程序,使其定期运行或在指 ...

  4. Android 自定义WaveProgressView满足你所有水波纹加载需求

    自定义WaveProgressView满足你所有水波纹加载需求

  5. linux配置文件重新加载失败,linux下为什么每次修改完配置文件之后都需要重新加载配置文件...

    解释了 linux下为什么每次修改完配置文件之后都需要重新加载配置文件 目录一.关于inode 二.inode的作用 二.为什么每次修改完服务器配置文件之后,都需要重新加载一下配置文件? 一.关于in ...

  6. [JAVA]引入目录下所有jar包等问题

    2019独角兽企业重金招聘Python工程师标准>>> 一.引入目录下所有的包 java命令用可用-cp引入jar包,但是不支持通配符.通常这些jar包都在一个目录下,可用使用-Dj ...

  7. java 自定义classloader_编写自定义classloader实现类的动态加载

    目标:实现类的动态加载 原理:使用java的自定义classloader机制实现类的动态加载. 代码实现://自定义classloader public class StrategyClassLoad ...

  8. 使用自定义的item、Adapter和AsyncTask、第三方开源框架PullToRefresh联合使用实现自定义的下拉列表(从网络加载图片显示在item中的ImageView)...

    AsyncTask使用方法详情:http://www.cnblogs.com/zzw1994/p/4959949.html 下拉开源框架PullToRefresh使用方法和下载详情:http://ww ...

  9. 如何在MyEclipse中添加 用户自定义类库 以及将自定义的类库加入工程的加载目录...

    2019独角兽企业重金招聘Python工程师标准>>> 但真正解决问题的是下面几句而已: 您是不是没有将common.jar文件导入buildPath 如果没有 选中你所在的项目 右 ...

最新文章

  1. 【Codeforces】967C Stairs and Elevators (二分)。
  2. CSS使用display:incline与float:left的区别:脱离文档流 参差不齐
  3. rpm安装的mysql如何数据迁移_linux下mysql数据库的rpm安装步骤及常见问题的解决
  4. 实验5 编写、调试具有多个段的程序
  5. php正则学习,php中正则表达式的学习及应用
  6. php创建mysql分区,MySql创建分区表
  7. t–sql pl–sql_SQL串联正确完成–第1部分–可疑做法
  8. Asp.Net Web API 2第十四课——Content Negotiation(内容协商)
  9. SecureCRT安装与使用
  10. 计算机操作系统第一章测试题及答案
  11. 二叉树查找结点及父结点
  12. 启动优化之一——启动分析及优化方案
  13. 简单提取iOS13的ipsw固件的内置壁纸(或文件)
  14. Codeforces Round #521 (Div. 3) E - Thematic Contests (二分 + STL)
  15. 人工智能对医疗和健康产业的冲击和革命——意识上传技术展望
  16. flea-db使用之JPA接入
  17. 修改Element UI自带的小图标,替换成自己的(类似自定义Element UI图标)
  18. 学习笔记:新技术与新趋势(演讲者:王煜全-海银资本合伙人)
  19. 《如何让你爱的人爱上你》第三部分:自尊
  20. 营业执照注册编码 15与18位的java实现

热门文章

  1. grafana授权公司内部邮箱登录 ldap配置
  2. 基于注解风格的Spring-MVC的拦截器
  3. 关于竖表转横表的问题
  4. symbian c++ 开发环境Carbide.c++搭建
  5. 自己的路 php,生活感悟的句子:走自己的路,做自己的事
  6. 安川最小巧机器人_2020工博会,安川展品前瞻(机器人篇)
  7. php5.4 mysql connect_php5.4 Call to undefined function mysql_connect()
  8. 1461B. Find the Spruce
  9. php科学计数法转string,php如何将科学计数法转数字
  10. csp真题 202109-2非零段划分C++代码(100分)