上次遗留下来的XMLUtil的问题
·在上周留下了一个关于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的问题的更多相关文章
- 从DOM操作看Vue&React的前端组件化,顺带补齐React的demo
前言 接上文:谈谈我对前端组件化中“组件”的理解,顺带写个Vue与React的demo 上次写完博客后,有朋友反应第一内容有点深,看着迷迷糊糊:第二是感觉没什么使用场景,太过业务化,还不如直接写Vue ...
- python网络编程
Socket是网络编程的一个抽象的概念. 通常我们用一个Socket表示"打开了一个网络链接",而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可. 套 ...
- C阶段【01】 - C基础
一.进制 进位方法:逢几进一(也就是几进制) 举例:十进制 12 : 二进制 0b(计算机前缀) 0b1011 : 八进制 0 073 :十六进制 0x 0xABCDEF 十进 ...
- iOS应用架构谈 网络层设计方案
网络层在一个App中也是一个不可缺少的部分,工程师们在网络层能够发挥的空间也比较大.另外,苹果对网络请求部分已经做了很好的封装,业界的AFNetworking也被广泛使用.其它的ASIHttpRequ ...
- ectouch第十讲 之ecshop中 dwt, lbi 文件详解
原文:http://www.yunmoban.cn/article-241.html Ecshop包括的文件夹有admin.api.cert.data.images.includes.js. lang ...
- Web开发从零单排之二:在自制电子请帖中添加留言板功能,SAE+PHP+MySql
在上一篇博客中介绍怎样在SAE平台搭建一个html5的电子请帖网站,收到很多反馈,也有很多人送上婚礼的祝福,十分感谢! web开发从零学起,记录自己学习过程,各种前端大神们可以绕道不要围观啦 大婚将至 ...
- 修改ecshop模板体会
在上一篇中给大家带来了ecshop的总体的框架.从总体上看ecshop,相信大家的思路应该很清楚.作为一个对开源项目修改者你来说,能对ecshop有个初步的了解就行了,下面我会给大家带来我在修改ecs ...
- [转] iOS应用架构谈 网络层设计方案
原文地址:http://casatwy.com/iosying-yong-jia-gou-tan-wang-luo-ceng-she-ji-fang-an.html iOS应用架构谈 开篇 iOS应用 ...
- 需要我们了解的SQL Server阻塞原因与解决方法
需要我们了解的SQL Server阻塞原因与解决方法 上篇说SQL Server应用模式之OLTP系统性能分析.五种角度分析sql性能问题.本章依然是SQL性能 五种角度其一“阻塞与死锁” 这里通过连 ...
随机推荐
- 国内外常用的DNS服务器
国内外常用的DNS服务器 DNS,全称Domain Name System,即域名解析系统,帮助用户在互联网上寻找路径,它在互联网的作用是把域名转换成为网络可以识别的IP地址. 国外DNS服务器地址: ...
- Service 与 Thread 的区别
很多时候,你可能会问,为什么要用 Service,而不用 Thread 呢,因为用 Thread 是很方便的,比起 Service 也方便多了,下面我详细的来解释一下. 1). Thread:Thre ...
- Spring集成JPA提示Not an managed type
在做Spring与JPA集成时,出现问题如下: Caused by: java.lang.IllegalArgumentException: Not an managed type: class co ...
- PostgreSQL 8.1 中文文档(转)
PostgreSQL 8.1 中文文档(转) http://www.php100.com/manual/PostgreSQL8/ 或者点击下面链接 PostgreSQL 8.1 中文文档
- JSON和JSONP区别和联系
由于Sencha Touch 2这种开发模式的特性,基本决定了它原生的数据交互行为几乎只能通过AJAX来实现. 当然了,通过调用强大的PhoneGap插件然后打包,你可以实现100%的Socket通讯 ...
- 浅谈全区全服架构的SNS游戏后台
版权声明:本文由梁本志原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/198 来源:腾云阁 https://www.qclo ...
- Java_Ant 详解
1,什么是antant是构建工具2,什么是构建概念到处可查到,形象来说,你要把代码从某个地方拿来,编译,再拷贝到某个地方去等等操作,当然不仅与此,但是主要用来干这个3,ant的好处跨平台 --因为 ...
- CSS:static/relative/absolute
static - default and this is the FLOW. ------------------------------------------------------------- ...
- [maven] 常用仓库地址
共有的仓库 http://mvnrepository.com/ http://repo1.maven.org/maven2/ http://repository.jboss.com/maven2/ h ...
- OC 实例方法和类方法区别
Objective-C里面既有实例方法也类方法.类方法(Class Method) 有时被称为工厂方法(Factory Method)或者方便方法(Convenience method).工 ...