一起因:
1)最近,有个小的工具需进行数据库操作,用到Jfinal的ActiveRecord,但是发现若要从配置文件中读取参数的,Jfinal中相应的代码都在JFinalConfig中。最后只能把相关的代码抽取出来来实现配置参数的读取。
2)一个基于Jfinal的项目中有不少配置参数,个人有个喜好,就是一个配置文件只干一件事情,比如database.properties里面只存取几个数据库连接信息。router.properties里面只存储路由相关信息。个人不喜欢将所有配置都塞到一个类似app.properties的文件里。
重构目标:
1)将从配置文件中读取参数相关代码从JFinalConfig中移除,专门建立一个类来做此事,方便单独需要ActiveRecord模块的场合使用,提高灵活性。
2)支持从多个properties文件中读取配置,并能通过统一的接口来获取这些文件中的所有配置信息。
上代码:
public abstract class JFinalConfig {
/**
* Config constant
*/
public abstract void configConstant(Constants me);
/**
* Config route
*/
public abstract void configRoute(Routes me);
/**
* Config plugin
*/
public abstract void configPlugin(Plugins me);
/**
* Config interceptor applied to all actions.
*/
public abstract void configInterceptor(Interceptors me);
/**
* Config handler
*/
public abstract void configHandler(Handlers me);
/**
* Call back after JFinal start
*/
public void afterJFinalStart(){};
/**
* Call back before JFinal stop
*/
public void beforeJFinalStop(){};
}
新建的PropertyConfig类代码,
1)允许多文件读取
2)除了兼容JFianl从WEB-INF读取配置信息外,也允许从classpath中读取配置信息。
3)单例模式运行。
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.jfinal.kit.PathKit;
import com.jfinal.kit.StringKit;
/**
*
* PropertyConfig: read properties file
* file path: ../WEB-INFO/ or classpath
*
*/
public class PropertyConfig {
private ConcurrentMap<String, Object> properties = new ConcurrentHashMap<String, Object>();
private static PropertyConfig config = new PropertyConfig();
private PropertyConfig(){}
public static PropertyConfig me(){
return config;
}
public void loadPropertyFile(String file){
Properties property = new Properties();
if (StringKit.isBlank(file))
throw new IllegalArgumentException("Parameter of file can not be blank");
if (file.contains(".."))
throw new IllegalArgumentException("Parameter of file can not contains \"..\"");
InputStream inputStream = null;
String fullFile; // String fullFile = PathUtil.getWebRootPath() + file;
if (file.startsWith(File.separator))
fullFile = PathKit.getWebRootPath() + File.separator + "WEB-INF" + file;
else
fullFile = PathKit.getWebRootPath() + File.separator + "WEB-INF" + File.separator + file;
try {
inputStream = new FileInputStream(new File(fullFile));
property.load(inputStream);
} catch (Exception eOne) {
try {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
property.load(loader.getResourceAsStream(file));
} catch (IOException eTwo) {
throw new IllegalArgumentException("Properties file loading failed: " + eTwo.getMessage());
}
}
finally {
try {if (inputStream != null) inputStream.close();} catch (IOException e) {e.printStackTrace();}
}
if (property != null){
for(Entry<Object,Object> entry : property.entrySet()){
this.properties.put(entry.getKey().toString(), entry.getValue());
}
}
}
public String getProperty(String key) {
if(this.properties.containsKey(key)){
return properties.get(key).toString();
}
return null;
}
public String getProperty(String key, String defaultValue) {
if(this.properties.containsKey(key)){
return properties.get(key).toString();
}
return defaultValue;
}
public Integer getPropertyToInt(String key) {
Integer resultInt = null;
String resultStr = this.getProperty(key);
if (resultStr != null)
resultInt = Integer.parseInt(resultStr);
return resultInt;
}
public Integer getPropertyToInt(String key, Integer defaultValue) {
Integer result = getPropertyToInt(key);
return result != null ? result : defaultValue;
}
public Boolean getPropertyToBoolean(String key) {
String resultStr = this.getProperty(key);
Boolean resultBool = null;
if (resultStr != null) {
if (resultStr.trim().equalsIgnoreCase("true"))
resultBool = true;
else if (resultStr.trim().equalsIgnoreCase("false"))
resultBool = false;
}
return resultBool;
}
public Boolean getPropertyToBoolean(String key, boolean defaultValue) {
Boolean result = getPropertyToBoolean(key);
return result != null ? result : defaultValue;
}
}
使用例子:
public void configConstant(Constants me) {
//加载数据库配置文件
PropertyConfig.me().loadPropertyFile("database.properties");
PropertyConfig.me().loadPropertyFile("app.properties");
//设定为开发者模式
me.setDevMode(PropertyConfig.me().getPropertyToBoolean("jfinal.devmode", false));
public void configPlugin(Plugins me) {
//从配置文件中获取数据库配置项
PropertyConfig config = PropertyConfig.me();
String driver = config.getProperty("dataSource.driverClass");
String jdbcUrl = config.getProperty("dataSource.url");
String username = config.getProperty("dataSource.userName");
String password = config.getProperty("dataSource.password");
打完收工。
评论(16)
引用来自“王仁辉(java)”的评论
@JFinal @玛雅牛 关于这个加载文件的配置 其实没有必要搞得这个复杂 还修改了用户使用方式 我是这样写的自定义一个Config类 extends com.jfinal.config.JFinalConfig,然后修改里面的loadPropertyFile方法
<code>//判断是否带有文件分隔符
boolean startStuff = file.startsWith(File.separator);
if (startStuff)
fullFile = PathKit.getWebRootPath() + File.separator + "WEB-INF" + file;
else
fullFile = PathKit.getWebRootPath() + File.separator + "WEB-INF" + File.separator + file;
File propFile = new File(fullFile);
//判断文件是否存在WebInf
if (!propFile.exists()) {
if (startStuff)
fullFile = PathKit.getRootClassPath() + file;
else
fullFile = PathKit.getRootClassPath() + File.separator + file;
propFile = new File(fullFile);
//判断文件是否存在class
if (!propFile.exists()) {
throw new IllegalArgumentException("Properties file not found: " + fullFile);
}
}
</code>
引用来自“王仁辉(java)”的评论
@JFinal @玛雅牛 关于这个加载文件的配置 其实没有必要搞得这个复杂 还修改了用户使用方式 我是这样写的
自定义一个Config类 extends com.jfinal.config.JFinalConfig,然后修改里面的loadPropertyFile方法
<code>//判断是否带有文件分隔符
boolean startStuff = file.startsWith(File.separator);
if (startStuff)
fullFile = PathKit.getWebRootPath() + File.separator + "WEB-INF" + file;
else
fullFile = PathKit.getWebRootPath() + File.separator + "WEB-INF" + File.separator + file;
File propFile = new File(fullFile);
//判断文件是否存在WebInf
if (!propFile.exists()) {
if (startStuff)
fullFile = PathKit.getRootClassPath() + file;
else
fullFile = PathKit.getRootClassPath() + File.separator + file;
propFile = new File(fullFile);
//判断文件是否存在class
if (!propFile.exists()) {
throw new IllegalArgumentException("Properties file not found: " + fullFile);
}
}
</code>
自定义一个Config类 extends com.jfinal.config.JFinalConfig,然后修改里面的loadPropertyFile方法
<code>//判断是否带有文件分隔符
boolean startStuff = file.startsWith(File.separator);
if (startStuff)
fullFile = PathKit.getWebRootPath() + File.separator + "WEB-INF" + file;
else
fullFile = PathKit.getWebRootPath() + File.separator + "WEB-INF" + File.separator + file;
File propFile = new File(fullFile);
//判断文件是否存在WebInf
if (!propFile.exists()) {
if (startStuff)
fullFile = PathKit.getRootClassPath() + file;
else
fullFile = PathKit.getRootClassPath() + File.separator + file;
propFile = new File(fullFile);
//判断文件是否存在class
if (!propFile.exists()) {
throw new IllegalArgumentException("Properties file not found: " + fullFile);
}
}
</code>
for(Entry<Object,Object> entry : property.entrySet()){
this.properties.put(entry.getKey().toString(), entry.getValue());
}
直接putAll就OK了吧?
引用来自“玛雅牛”的评论
引用来自“JFinal”的评论
正常来说是应该分离出来的,这样的代码也更清晰,但jfinal也有一些考虑,例如目前的实现方式可以省些代码这是一点,另外jfinal就是希望做到极简,引入PropertyConfig这个类虽然简单,但也还是需要了解学习怎么用的。还有一点jfinal目前的设计是可以支持加载多个属性文件的,可以多次调用loadPropertyFile方法,这样可以在不同地方调用就可以使用不同的配置文件
引用来自“玛雅牛”的评论
引用来自“JFinal”的评论
正常来说是应该分离出来的,这样的代码也更清晰,但jfinal也有一些考虑,例如目前的实现方式可以省些代码这是一点,另外jfinal就是希望做到极简,引入PropertyConfig这个类虽然简单,但也还是需要了解学习怎么用的。还有一点jfinal目前的设计是可以支持加载多个属性文件的,可以多次调用loadPropertyFile方法,这样可以在不同地方调用就可以使用不同的配置文件
引用来自“JFinal”的评论
正常来说是应该分离出来的,这样的代码也更清晰,但jfinal也有一些考虑,例如目前的实现方式可以省些代码这是一点,另外jfinal就是希望做到极简,引入PropertyConfig这个类虽然简单,但也还是需要了解学习怎么用的。还有一点jfinal目前的设计是可以支持加载多个属性文件的,可以多次调用loadPropertyFile方法,这样可以在不同地方调用就可以使用不同的配置文件