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

一直以来,有个目标是:使用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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/436737.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【转】ABP源码分析十:Unit Of Work

ABP以AOP的方式实现UnitOfWork功能。通过UnitOfWorkRegistrar将UnitOfWorkInterceptor在某个类被注册到IOCContainner的时候,一并添加到该类在容器中对应的ComponentModel的Interceptors集合中。总结一句话就是,UOW的功能是通过自定义Castle拦截器来实现…

java光标位置无效_java - java.sql.SQLException:无效的光标位置 - 堆栈内存溢出

我创建了一个简单的应用程序,使用户可以购买门票。 但是,每当我尝试购买“ n”张门票时,都会遇到此错误。 现在,我知道在使用数据库进行操作时需要crs.next()语句,我已经使用了很多次,但是由于某种原因&…

【转】C#命名空间大全详细教程

www.51rgb.com System 命名空间包含了定义数据类型、事件和事件处理程序等基本类; System.Data 命名空间包含了提供数据访问功能的命名空间和类; System.IO 命名空间包含了数据流读写相关功能的类; System.Windows.Forms 命名空间包含了W…

java构造方法的签名_如何在 Java 中构造对象(学习 Java 编程语言 034)

1. 构造器Java 对象都是在堆中构造的。先看看 Employee 类的构造器:public class Employee {private String name;private double salary;private LocalDate hireDay;public Employee(String name, double salary, int year, int month, int day) {this.name name;…

【转】ABP源码分析十一:Timing

Timing这个简单实用的功能主要用来以统一的方式表示时间。因为ABP中有大量的module,另外还支持自定义module,所以将时间统一表示为local时间(默认)或utc时间是必要的。 IClockProvider:提供获取当前时间和标准化时间的接口。 UtcClockProvide…

java更改背景_java – 使用jquery更改menue的背景颜色

我正在尝试用Zenphoto建立一个照片库.他们使用PHP,可以添加这样的自定义菜单:PHP printCustomMenu(main_menue); ?>我改变了sylesheet中整个事物的外观,看起来像这样:#navmenu {width: 1000px;height: 42px;margin: 0px auto 30px auto;font-family:…

【转】ABP源码分析十二:本地化

本文逐个分析ABP中涉及到localization的接口和类,以及他们之间的关系。本地化主要涉及两个方面:一个是语言(Language)的管理,这部分相对简单。另一个是语言对应得本地化资源(Localization)的管理…

pandas 批量修改列名_pandas修改DataFrame列名的方法

在做数据挖掘的时候,想改一个DataFrame的column名称,所以就查了一下,总结如下:数据如下:>>>import pandas as pd>>>a pd.DataFrame({A:[1,2,3], B:[4,5,6], C:[7,8,9]})>>> aA B C0 1 4 7…

【转】ABP源码分析十三:缓存Cache实现

ABP中有两种cache的实现方式:MemoryCache 和 RedisCache. 如下图,两者都继承自ICache接口(准确说是CacheBase抽象类)。ABP核心模块封装了MemoryCache 来实现ABP中的默认缓存功能。 Abp.RedisCache这个模块封装RedisCache来实现缓存…

java 酒店预定 app_Android应用源码酒店在线预定app项目全套

【实例简介】Android应用源码酒店在线预定app项目全套【实例截图】【核心代码】package com.bn.summer;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;…

java peer_Java PeerConnection.getStats方法代码示例

import org.webrtc.PeerConnection; //导入方法依赖的package包/类Overridepublic void onIceServers(List iceServers) {factory new PeerConnectionFactory();MediaConstraints pcConstraints appRtcClient.pcConstraints();pcConstraints.optional.add(new MediaConstrain…

【转】ABP源码分析十四:Entity的设计

IEntity<TPrimaryKey>: 封装了PrimaryKey&#xff1a;Id,这是一个泛型类型 IEntity: 封装了PrimaryKey&#xff1a;Id,这是一个int类型 Entity<TPrimaryKey> &#xff1a;支持主键是泛型类型的Entity Entity&#xff1a;支持主键是int类型的Entity IHasCreation…

【转】ABP源码分析十五:ABP中的实用扩展方法

类名 扩展的类型 方法名 参数 作用 XmlNodeExtensions XmlNode GetAttributeValueOrNull attributeName Gets an attributes value from an Xml node. JsonExtensions object ToJsonString bool camelCase bool indented Converts given object to JSON …

php计算经纬度距离,php经纬度计算距离

/*** 计算两点地理坐标之间的距离* param Decimal $longitude1 起点经度* param Decimal $latitude1 起点纬度* param Decimal $longitude2 终点经度* param Decimal $latitude2 终点纬度* param Int $unit 单位 1:米 2:公里* param Int $decimal 精度…

【转】ABP源码分析十六:DTO的设计

IDTO:空接口&#xff0c;用于标注Dto对象。 ComboboxItemDto&#xff1a;用于combobox/list中Item的DTO NameValueDto<T>/NameValueDto:用于name value键值对的DTO&#xff0c; name为string类型&#xff0c; value为泛型或string类型。 Entity Dto IEntityDto<TPri…

php session 机制,Cookie、Session机制详解及PHP中Session处理

会话机制Cookie/Session&#xff1a;在web应用中&#xff0c;常用的会话追踪机制是Cookie和Session。而Cookie是通过在浏览器里记录确定用户身份&#xff0c;Session在服务器端记录信息确定用户身份。Http协议&#xff1a;http协议本身是无状态的&#xff0c;也就是说我们无法通…

【转】ABP源码分析十七:DTO 自动校验的实现

对传给Application service对象中的方法的DTO参数&#xff0c;ABP都会在方法真正执行前自动完成validation&#xff08;根据标注到DTO对象中的validate规则&#xff09;。 ABP是如何做到的? 思路无外乎通过Castle的拦截器实现AOP。本文主要分析ABP是如何设计。 Ivalidate: 空…

php扇形分布图,php生成扇形比例图的实例代码

本节内容&#xff1a;PHP GD库生成扇形比例图。实现功能&#xff1a;一些图形的百分比显示图&#xff0c;像三个地区所占地多少或成绩等。这里分享一段php生成的扇形比例百分比显示程序代码&#xff0c;需要phpGD库支持。代码&#xff1a;复制代码 代码示例:/*** 生成扇形比例图…

【转】ABP源码分析十八:UI Inputs

以下图中描述的接口和类都在Abp项目的Runtime/Validation, UI/Inputs目录下的。在当前版本的ABP&#xff08;0.83&#xff09;中这些接口和类并没有实际使用到。阅读代码时可以忽略&#xff0c;无需浪费时间去寻找其是如何被ABP使用的(本文的目的)。 这些接口和类最终都是通过…

php鼠标点击图片后换图片,鼠标滑过改变图片

jQuery中attr()函数不支持delay函数控制延迟&#xff0c;把attr函数加在animate的回调函数中jQuery(function(){jQuery(.avia_p_w_picpath).hover(function() {urlss jQuery(this).attr("src").replace("1.jpg","2.jpg");jQuery(this).stop().a…