随笔 - 32, 文章 - 1, 评论 - 5, 引用 - 0
数据加载中……

利用Java反射读取XML配置文件

背景:项目配置文件分散,有FTP、文件格式、数据库等。且单个任务配置都不一样。故有了统一配置文件的想法,由统一的工具类生成配置对象。

使用:dom4j,Java ioc

首先是XML文件的定义,懒得写schema,直接手写了。配置项由于很多,且分类明确,所以一开始就打算将其分为多个Java类配置。

 1<?xml version="1.0" encoding="UTF-8"?>
 2<Config id="STAT1">
 3    <Stat>
 4        <Property name="configName" value="custconfig" />
 5        <Property name="descrption" value="企业信息处理" />
 6        <Property name="taskType" value="1" />
 7        <Property name="expiredMonth" value="6" />
 8        <Property name="batchNum" value="500" />
 9    </Stat>
10    <Ftp>
11        <Property name="host" value="127.0.0.1" />
12        <Property name="user" value="stateg"/>
13        <Property name="password" value="stateg"/>
14        <Property name="port" value="14147"/>
15        <Property name="remoteDir" value="/cust"/>
16        <Property name="localDir" value="D:/ldata_eg/cu-udr"/>
17        <Property name="fileNamePattern" value="CUST_\d{6}.TXT"/>
18        <Property name="interval" value="10"/>
19        <Property name="reserve" value="true"/>
20        <Property name="maxFileCount" value="100"/>
21        <Property name="checkInterval" value="7200"/>
22    </Ftp>
23    <Table>
24        <Record>
25            <Property name="tablename" value="T_CU_TABLE_NAME" />
26            <Property name="separator" value=" " />
27            <Property name="startrow" value="1" />
28            <Property name="endCol" value="5" />
29        </Record>
30        <Column order="0" prop="ID" type="VARCHAR2" length="32" key="yes" />
31        <Column order="1" prop="CUSTNAME" type="VARCHAR2" length="128" emtpy="yes" />
32        <Column order="2" prop="CUSTAREA" type="VARCHAR2" length="128" emtpy="yes" />
33        <Column order="3" prop="CREATEDATE" type="DATE"/>
34        <Column order="4" prop="PARENTID" type="VARCHAR2" length="32" emtpy="yes" />
35        <Column order="4" prop="UPDATETIME" type="DATE"/>
36    </Table>
37</Config>
38


接下来,就是XML文件的读取了。使用dom4j是无疑的,可参见http://www.blogjava.net/colorfire/articles/338764.html。

 1/**
 2     * 获取配置对象
 3     * @return
 4     * @throws DocumentException
 5     */

 6    public StatConfig getConfigInfo() throws DocumentException {
 7        SAXReader saxReader = new SAXReader();
 8        Document document = saxReader.read("META-INFO/xml/StatConfigInfo.xml");
 9
10        // 配置入库参数
11        StatConfig statConfig = (StatConfig) reflectConfig(warpPropertyMap(document
12                .selectNodes("//Config/Stat/Property")), StatConfig.class);
13
14        // 配置FTP客户端参数
15        FtpConfig ftpConfig = (FtpConfig) reflectConfig(warpPropertyMap(document.selectNodes("//Config/Ftp/Property")),
16                FtpConfig.class);
17
18        // 配置数据库
19        TableConfig tableConfig = (TableConfig) reflectConfig(warpPropertyMap(document
20                .selectNodes("//Config/Table/Record/Property")), TableConfig.class);
21        List list = document.selectNodes("//Config/Table/Column");
22        Iterator iter = list.iterator();
23        Map<String, ColumnType> colMap = new HashMap<String, ColumnType>();
24        while (iter.hasNext()) {
25            Element element = (Element) iter.next();
26            Map<String, String> configMap = warpAttributeMap(element.attributeIterator());
27            ColumnType colum = (ColumnType) reflectConfig(configMap, ColumnType.class);
28            colMap.put(Integer.toString(colum.getOrder()), colum);
29        }

30        tableConfig.setColMap(colMap);
31
32        statConfig.setFtpConfig(ftpConfig);
33        statConfig.setTableConfig(tableConfig);
34        return statConfig;
35    }

由于XML分块,将数据封装单独抽取成方法。

1private Map<String, String> warpPropertyMap(List list) {
2        Map<String, String> configMap = new HashMap<String, String>();
3        Iterator iter = list.iterator();
4        while (iter.hasNext()) {
5            Element element = (Element) iter.next();
6            configMap.put(element.attributeValue("name").toLowerCase(), element.attributeValue("value").toLowerCase());
7        }

8        return configMap;
9    }

最后就是将配置数据封装进对象,这里用反射再合适不过了。

 1public Object reflectConfig(Map<String, String> configMap, Class cls) {
 2        Object config = null;
 3        try {
 4            config = cls.newInstance();
 5            Field[] fields = cls.getDeclaredFields();
 6            for (int i = 0; i < fields.length; i++{
 7                String fieldName = fields[i].getName();
 8                Class fieldType = fields[i].getType();
 9                Method method = cls.getMethod("set" + genMethodName(fieldName), fieldType);
10                String valueString;
11                if ((valueString = configMap.get(fieldName.toLowerCase())) != null{
12                    if (fieldType.equals(String.class)) {
13                        method.invoke(config, valueString);
14                    }
 else if (fieldType.equals(Integer.class)) {
15                        method.invoke(config, Integer.parseInt(valueString));
16                    }
 else if (fieldType.equals(Long.class)) {
17                        method.invoke(config, Long.parseLong(valueString));
18                    }
 else if (fieldType.equals(Boolean.class)) {
19                        method.invoke(config, Boolean.parseBoolean(valueString));
20                    }
 else if (fieldType.equals(Character.class)) {
21                        method.invoke(config, valueString.toCharArray()[0]);
22                    }
 else {
23                        throw new NoSuchFieldException("FtpConfig没有定义的数据类型");
24                    }

25                }

26            }

27        }
 catch (Exception e) {
28            e.printStackTrace();
29        }

30        return config;
31    }

完成,想测试一下,单独写个测试方法吧。
 1/**
 2     * 测试方法
 3     * @param obj
 4     * @return
 5     */

 6    public static StringBuffer testPOJO(Object obj) {
 7        Class cls = obj.getClass();
 8        Field[] fields = cls.getDeclaredFields();
 9        StringBuffer resultBuf = new StringBuffer();
10        try {
11            for (int i = 0; i < fields.length; i++{
12                String fieldName = fields[i].getName();
13                Class fieldType = fields[i].getType();
14                Method method;
15                if (fieldType.equals(Boolean.class)) {
16                    method = cls.getMethod("is" + genMethodName(fieldName));
17                }
 else {
18                    method = cls.getMethod("get" + genMethodName(fieldName));
19                }

20                Object res;
21                if ((res = method.invoke(obj)) != null{
22                    String result = res.toString();
23                    resultBuf.append("[" + fieldName + "] = " + result + "\n");
24                }
 else {
25                    resultBuf.append("[" + fieldName + "] = NULL \n");
26                }

27            }

28        }
 catch (Exception e) {
29            e.printStackTrace();
30        }

31        return resultBuf;
32    }


总结:本来考虑的是统一配置后,丢弃ibatis,直接动态生成sql语句执行。但字段名与类属性值匹配又是个麻烦,这里用反射的话就太影响性能了。没想出好方法,再考虑考虑。
后续把测试类改成递归的。

posted on 2010-11-23 17:17 colorfire 阅读(789) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问