·在上周留下了一个关于XMLUtil的问题,问题大概是这样的,需要通过读取一个XML文件,然后在内存中生成一个对应的javaBean。之前写的那个很是糟糕,照着一个XML去写了一个"Util",拓展性,可维护性几乎为0,所有的东西全都写死,完全就写了一个"不伦不类"的"Util",很是郁闷,点击查看之前的代码,所以痛定思痛,打算在本周对上次的Util进行重写,一直拖到今天才花了几个小时写好,不得不感叹我的拖延至之严重!

·下面贴出代码,先是两个实体类

Student(学生类)

package com.taoyuan.entity.custom;

/**
* @ClassName: Student
* @Description: TODO Student实体类设计
* @author: Han
* @date: 2016-3-31 下午4:54:04
*/
public class Student { private int id;
private String name; public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
} @Override
public String toString() { return "this student`s id is " + this.id + " and name is " + this.name;
}
}

Class(班级类)可以明显看到两个类是关联关系,在Class类中含有一个Student的集合

package com.taoyuan.entity.custom;

import java.util.List;

/**
* @ClassName: Class
* @Description: TODO Class班级实体类设计
* @author: Han
* @date: 2016-3-31 下午4:58:21
*/
public class Class { private int id;
private String className;
private List<Student> student; public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public List<Student> getStudents() {
return student;
}
public void setStudents(List<Student> student) {
this.student = student;
} @Override
public String toString() { return "This class`s id is " + this.id + " and name is " + this.className
+ "\t\nit`s students are " + this.student;
}
}

XML文件

<?xml version="1.0" encoding="UTF-8"?>
<Entity>
<Class classPath="com.taoyuan.entity.custom.Class"> <Int name="id">1</Int>
<String name="className">软件工程</String>
<Student name="student" type="list"> <!-- Student数组 -->
<Student classPath="com.taoyuan.entity.custom.Student">
<Int name="id">1</Int>
<String name="name">李明</String>
</Student>
<Student classPath="com.taoyuan.entity.custom.Student">
<Int name="id">2</Int>
<String name="name">狗蛋</String>
</Student>
</Student>
</Class>
</Entity>

XMLUtil利用反射,递归等实现的Util,较之前有了很大的改动,再也不用对着一个Util狂改,把通用性将到了0...现在只需要修改XML和Java实体类就可以了

package com.taoyuan.utils;

import java.io.File;
import java.io.FileNotFoundException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader; /**
* @ClassName: XMLUtil
* @Description: TODO XML工具类
* @author: Han
* @date: 2016-3-22 下午3:09:03
*/
public class XMLUtil { /**
* @Title: toEntity
* @Description: TODO 将XML文件转换为一个entity
* @param xmlPath
* @return
* @throws Exception
* @return: Object
*/
public static Object toEntity(String xmlPath) throws Exception{ //初始化,将XML文件读入内存,生成Document
Document _document = init(xmlPath); //获取根目录节点
Element _rootEle = _document.getRootElement();
String _rootName = ""; if(_rootEle != null){ //根目录节点名字
_rootName = _rootEle.getName();
} if(!_rootName.equals("Entity")){ throw new Exception("请确认根节点名字是否为Entity");
} List<Element> elements = _rootEle.elements(); //在Entity节点中无子节点
if(elements.size() == 0){ return null;
} return getEntity(elements.get(0));
} /**
* 获取根据节点Element获取对应的Entity
* @param element
* @return
* @throws ClassNotFoundException
* @throws InstantiationException
* @throws IllegalAccessException
*/
@SuppressWarnings("rawtypes")
private static Object getEntity(Element element)
throws ClassNotFoundException, InstantiationException,
IllegalAccessException { //获取classPath
String _classPath = element.attributeValue("classPath"); //获取Class的字节码文件
Class _clazz = Class.forName(_classPath);
//根据字节码文件进行实例化
Object _object = _clazz.newInstance(); Field[] _fields = _clazz.getDeclaredFields(); setMember(_object, element, _fields); return _object;
} /**
* 设置成员变量
* @param object
* @param element
* @param fields 成员变量数组
*/
private static void setMember(Object object, Element element, Field[] fields) { //获取当前Element获得的子节点迭代器
Iterator<Element> _elements = element.elementIterator();
while(_elements.hasNext()){ Element _childElement = _elements.next(); //当前正在设置的成员变量
Field _field = null;
//获取变量类型
String _type = _childElement.getName(); //获取变量名
String _name = _childElement.attributeValue("name");
//获取变量值
String _value = _childElement.getTextTrim(); //找到当前正在设置的成员变量
for(int i = 0;i < fields.length;i ++ ){ if(fields[i].getName().equals(_name)){ _field = fields[i];
break;
}
} if(_field == null){ throw new RuntimeException("没找到该成员变量" + _name);
} //此时可以访问私有成员变量
_field.setAccessible(true); if(!setBaseTypeMember(object, _field, _type, _value)){ //当前成员变量不是基本类型,则为引用类型成员变量
setReferenceTypeMember(_childElement, object, _field);
}
}
} /**
* 设置引用类型成员变量
* @param element
* @param object
* @param field
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private static void setReferenceTypeMember(Element element, Object object, Field field) { try {
//若为list,则表示当前元素为一个list集合
String _memberType = element.attributeValue("type"); if(_memberType.equals("list")){ List _list = new ArrayList(); Iterator<Element> _iterator = element.elementIterator();
while(_iterator.hasNext()){ Element _childEle = _iterator.next(); //递归获取该元素,并加入集合中
Object _entity = getEntity(_childEle);
_list.add(_entity);
} field.set(object, _list);
return;
} //单元素的引用类型
Object _entity = getEntity(element);
field.set(object, _entity);
} catch (Exception e) { throw new RuntimeException(e);
}
} /**
* 设置基本类型成员变量
* @param object
* @param field
* @param type
* @param value
* @return
*/
private static boolean setBaseTypeMember(Object object, Field field,
String type, String value) { try {
if(type.equals("Int")){ //int型成员变量
field.setInt(object, Integer.parseInt(value));
}else if(type.equals("Double")){ //double型成员变量
field.setDouble(object, Double.parseDouble(value));
}else if(type.equals("Float")){ //float型成员变量
field.setFloat(object, Float.parseFloat(value));
}else if(type.equals("Long")){ //long型成员变量
field.setLong(object, Long.parseLong(value));
}else if(type.equals("Char")){ //char型成员变量
field.setChar(object, value.charAt(0));
}else if(type.equals("String")){ //string型成员变量
field.set(object, value);
}else{ return false;
}
} catch (Exception e) { throw new RuntimeException(e);
} return true;
} /**
* @Title: init
* @Description: TODO 初始化,将XML读入内存
* @param xmlPath
* @return Document节点
* @throws FileNotFoundException
* @return: Document
*/
private static Document init(String xmlPath) throws FileNotFoundException { //获取XML文件路径.是根据当前classPath去寻找,例如文件a.xml是放在根目录下,则需要输入的路径便是a.xml
//还有另外一种方法是通过class.getResource("/" + xmlPath)效果是一样的
//关于java中的路径问题还是没有搞得很清楚,下来还需要多看
String _filePath = XMLUtil.class.getClassLoader().getResource(xmlPath).getPath(); File _file = new File(_filePath); //如果文件存在
if(_file.exists()){ //利用dom4j返回该XML的document
SAXReader _reader = new SAXReader(); try { Document _document = _reader.read(_file); return _document; } catch (DocumentException e) { e.printStackTrace();
}
}else{ throw new FileNotFoundException("您输入的XML文件地址未查到");
} return null;
} }

测试方法

    @Test
public void testXMLUtil() throws Exception{ System.out.println(XMLUtil.toEntity("Class.xml"));
}

结果输出

Ok,测试成功

代码已经更新至GitHub

·总结一下:

1.下回再也不写那么逗的Util了,每次写Util之前先思考思考如何才能写成一个自己以后还能用到的真正的工具类。

2.对于这个版本自己还是有一些不满意的地方,每个成员变量我都是在XML文件里面声明了它的类型,比如<String ...>,既然我都已经通过反射拿到了成员变量的数组,为什么不用成员变量对象去判断它的类型呢??这个是可以改进的地方。

3.这次变量命名和注释相较于上一次已经有了很大的进步,自己还是比较满意的。

4.有什么理由可以不努力呢??哈哈

上次遗留下来的XMLUtil的问题的更多相关文章

  1. 从DOM操作看Vue&React的前端组件化,顺带补齐React的demo

    前言 接上文:谈谈我对前端组件化中“组件”的理解,顺带写个Vue与React的demo 上次写完博客后,有朋友反应第一内容有点深,看着迷迷糊糊:第二是感觉没什么使用场景,太过业务化,还不如直接写Vue ...

  2. python网络编程

    Socket是网络编程的一个抽象的概念. 通常我们用一个Socket表示"打开了一个网络链接",而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可. 套 ...

  3. C阶段【01】 - C基础

    一.进制 进位方法:逢几进一(也就是几进制) 举例:十进制 12  :  二进制  0b(计算机前缀)  0b1011  :  八进制  0   073  :十六进制  0x  0xABCDEF 十进 ...

  4. iOS应用架构谈 网络层设计方案

    网络层在一个App中也是一个不可缺少的部分,工程师们在网络层能够发挥的空间也比较大.另外,苹果对网络请求部分已经做了很好的封装,业界的AFNetworking也被广泛使用.其它的ASIHttpRequ ...

  5. ectouch第十讲 之ecshop中 dwt, lbi 文件详解

    原文:http://www.yunmoban.cn/article-241.html Ecshop包括的文件夹有admin.api.cert.data.images.includes.js. lang ...

  6. Web开发从零单排之二:在自制电子请帖中添加留言板功能,SAE+PHP+MySql

    在上一篇博客中介绍怎样在SAE平台搭建一个html5的电子请帖网站,收到很多反馈,也有很多人送上婚礼的祝福,十分感谢! web开发从零学起,记录自己学习过程,各种前端大神们可以绕道不要围观啦 大婚将至 ...

  7. 修改ecshop模板体会

    在上一篇中给大家带来了ecshop的总体的框架.从总体上看ecshop,相信大家的思路应该很清楚.作为一个对开源项目修改者你来说,能对ecshop有个初步的了解就行了,下面我会给大家带来我在修改ecs ...

  8. [转] iOS应用架构谈 网络层设计方案

    原文地址:http://casatwy.com/iosying-yong-jia-gou-tan-wang-luo-ceng-she-ji-fang-an.html iOS应用架构谈 开篇 iOS应用 ...

  9. 需要我们了解的SQL Server阻塞原因与解决方法

    需要我们了解的SQL Server阻塞原因与解决方法 上篇说SQL Server应用模式之OLTP系统性能分析.五种角度分析sql性能问题.本章依然是SQL性能 五种角度其一“阻塞与死锁” 这里通过连 ...

随机推荐

  1. strcpy, memcpy, memset函数

    一. strcpy函数 原型声明:char *strcpy(char* dest, const char *src);   头文件:#include <string.h> 和 #inclu ...

  2. 脱壳脚本_手脱壳ASProtect 2.1x SKE -&gt; Alexey Solodovnikov

    脱壳ASProtect 2.1x SKE -> Alexey Solodovnikov 用脚本.截图 1:查壳 2:od载入 3:用脚本然后打开脚本文件Aspr2.XX_unpacker_v1. ...

  3. 升级MySQL支持utf8mb4字符集详细步骤

    原文:http://lib.csdn.net/article/mysql/4607 第一步:全备份所有数据库 [root@openfire1 mysql]# mysqldump -u root -p ...

  4. ORA-12705: Cannot access NLS data files or invalid environment specified

    ASM实例无法启动 [grid@data ~]$ sqlplus / as sysasm SQL*Plus: Release 11.2.0.4.0 Production on Fri Sep 11 0 ...

  5. 队列 - 从零开始实现by C++

    参考链接:数据结构探险-队列篇 数据结构太重要了,不学好是没法进行软件开发的. C++写数据结构基本套路:一个.h文件写该数据结构类的接口:一个.cpp文件写接口的具体实现:一个main.cpp用于测 ...

  6. DialogFragment 自定义弹窗

    layout文件 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:a ...

  7. VB6 GDI+ 入门教程[1] GDI+介绍

    http://vistaswx.com/blog/article/category/tutorial/page/2 VB6 GDI+ 入门教程[1] GDI+介绍 2009 年 6 月 18 日 17 ...

  8. 联想G480笔记本安装系统

    联想G480笔记本安装系统 联想G480笔记本,配置i5双核四线程处理器,4G内存,500G硬盘,USB3.0接口,NVIDIA GeForce GT 610M+Intel HD Graphics 3 ...

  9. 在Fedora 20下使用TexturePacker

    TexturePacker应该是最流行的图片合并工具吧,它把多个小图组合成一个大图,以减少网络请求次数,还有利于内存的充分利用.在游戏开发和网页开发时经常会用到它,CanTK(https://gith ...

  10. <mvc:annotation-driven />

    <mvc:annotation-driven/>相当于注册了DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter两个 ...