注解+反射+PropertiesProxy 读取配置文件

一.问题的引入

在做项目时有一个文件(数据表),里面的内容全部是类似于key-value的形式,如果一个字段一个字段的从文件或者数据表中将数据加载到内存中,一旦数据较多,将是一个比较繁琐的工作,那么我们怎样在程序编译时就能确保所有的字段都加载到内存中,并自动转换成自己想要的数据格式?(如八大基本数据类型,Map,List等),关于这个问题,我采用了以下的做法,希望有大牛指出更为巧妙的方法。

二.问题的解决

1.假定数据库中有一张名称为init的数据表,里面包含了大量的key-value数据。

2.我们先编写注解Init.java,代码如下:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Init {
	// 别名-如果文件中的key名字过长,便于自己重命名
	String otherName() default "";

	// 数据类型的转换方法
	String transMethod() default "";
}
3.编写我们对应的数据实体类ConfigData.java:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ConfigData {
	@Init
	public static String name;
	@Init
	public static int age;
	@Init
	public static float money;
	@Init
	public static double rate;
	@Init(transMethod = "toList")
	public static List<String> awards;
	@Init(transMethod = "toMap")
	public static Map<String, Integer> items;
	@Init(otherName = "faiid")
	public static double familysAndPersonalIDNumber;

	public ConfigData() {

	}

	// 类型转换方法
	public List<String> toList(String confString) {
		List<String> list = new ArrayList<>();
		String[] pairStrings = confString.split(";");
		for (String str : pairStrings) {
			list.add(str);
		}
		return list;
	}

	// 类型转换方法
	public Map<String, Integer> toMap(String confString) {
		Map<String, Integer> map = new HashMap<>();
		String[] pairStrings = confString.split(";");
		for (String str : pairStrings) {
			String[] str2 = str.split(":");
			map.put(str2[0], Integer.parseInt(str2[1]));
		}
		return map;
	}
}
4.编写解析工具类ConfigUtil.java:

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.nutz.ioc.impl.PropertiesProxy;

public class ConfigUtil {
	/**
	 * 配置文件的转换
	 * 
	 * @param prop
	 *            配置文件
	 * @param classPath
	 *            数据实体类名
	 */
	public static void change(PropertiesProxy prop, String classPath) {
		try {
			// 获取配置类
			Class<?> paramSetClass = Class.forName(classPath);
			ConfigData cd = (ConfigData) paramSetClass.newInstance();
			// 设置配置字段
			Field[] fields = paramSetClass.getDeclaredFields();
			for (Field field : fields) {
				field.setAccessible(true);
				// 字段上是否有注解
				boolean hasAnnotation = field.isAnnotationPresent(Init.class);
				if (hasAnnotation) {
					// 获取字段类型名称
					String filedTypeStr = field.getType().getName();
					Init keyValueAnnotation = field.getAnnotation(Init.class);
					// 获取别名
					String filedName = keyValueAnnotation.otherName();
					// 获取解析方法
					String parseMethodName = keyValueAnnotation.transMethod();
					String filedValue = getFieldValue(prop, field, filedName);
					try {
						setValue(cd, field, filedTypeStr, parseMethodName,
								filedValue);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取配置文件中字段的值
	 * 
	 * @param prop
	 *            配置文件
	 * @param field
	 *            字段属性
	 * @param filedName
	 *            字段名称
	 * @return
	 * @throws Exception
	 */
	private static String getFieldValue(PropertiesProxy prop, Field field,
			String filedName) throws Exception {
		String filedValue = null;
		// 如果是别名,获取真实名称
		if (filedName.equals("")) {
			filedValue = prop.get(field.getName());
		} else {
			filedValue = prop.get(filedName);
		}
		if (filedValue == null) {
			throw new Exception("config Field '" + field.getName()
					+ "'  not find");
		}
		return filedValue;
	}

	/**
	 * 设置数据实体的名称,类型,值
	 * 
	 * @param cd
	 *            数据实体类
	 * @param field
	 *            字段属性
	 * @param filedTypeStr
	 *            字段类型名称
	 * @param parseMethodName
	 *            解析方法名称
	 * @param filedValue
	 *            字段值
	 * @throws Exception
	 */
	private static void setValue(ConfigData cd, Field field,
			String filedTypeStr, String parseMethodName, String filedValue)
			throws Exception {
		switch (filedTypeStr) {
		case "short":
			field.set(cd, Short.parseShort(filedValue));
			break;
		case "int":
			field.set(cd, Integer.parseInt(filedValue));
			break;
		case "float":
			field.set(cd, Float.parseFloat(filedValue));
			break;
		case "double":
			field.set(cd, Double.parseDouble(filedValue));
			break;
		case "long":
			field.set(cd, Long.parseLong(filedValue));
			break;
		case "boolean":
			field.set(cd, Boolean.parseBoolean(filedValue));
			break;
		case "java.lang.String":
			field.set(cd, filedValue);
			break;
		// 针对对象类型,如:map,list等
		default:
			if (parseMethodName.equals("")) {
				throw new Exception(
						"非short,int,float,double,long,String类型,必须指定解析方法");
			}
			Method method = cd.getClass().getMethod(parseMethodName,
					String.class);
			Object obj = method.invoke(cd, filedValue);
			field.set(cd, obj);
			break;
		}
	}
}
注意在以上代码片中我们使用了Nutz框架的PropertiesProxy,一个比Java的Properties更强大的键值配置类,感兴趣的朋友可以了解一下Nutz框架,号称是SSH的一个替代品。

5.读取配置文件:的方法:

public void load() {
		// 定义数据库工具,这里我们采用Nutz的Dao
		NutDao dao;
		// 获取数据
		List<Record> list = dao.query("init", null);
		PropertiesProxy prop = new PropertiesProxy();
		for (Record record : list) {
			prop.put(record.getString("key"), record.getString("value"));
		}
		//自动加载配置
		ConfUtil.change(prop, ConfigData.class.getName());
	}
本人Java初学,如果有更好的方法,欢迎交流!






  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值