在导入导出的时候,我们可以选用excel、xml。
但当出现父子结构的样子时,用excel来处理未免就有点乏力了。这里就需要用更强大的xml来进行处理了。下面看下这个xml的结构吧。
<?xml version="1.0" encoding="UTF-8"?> <!-- name:名称 sn:英文标识 priority:优先级 url:页面网址 description:描述 module:项目中的模块 permission:操作权限——1:查看,2:增加,3:删除,4:修改 --> <system> <module name="模块1" sn="mk1" priority="1" description="这是第一个模块" > <permission id="1" name="查看"/> <page name="页面1" sn="" priority="1" url="http://" description="这里第一个模块里面的页面"> <permission id="1" name="查看"/> <permission id="2" name="增加"/> </page> </module> <module name="模块2" sn="mk2" priority="2" description="这是第二个模块" > <permission id="1" name="查看"/> <page name="页面2" sn="qwer" priority="1" url="http://" description="这里第二个模块里面的页面"> <permission id="1" name="查看"/> <permission id="2" name="增加"/> </page> </module> </system>
那么对应要转成的对象是什么样子呢?
public class Tree<T>{ private String id; private String name; private T parent; private List<T>children; private boolean isleaf; } public class Module extends Tree<Module>{ private String url; private String description; private String sn; private Integer priority = 99; private List<Permission> permissions ; private String organizationid; }
现在要通过xml进行导入,xml中写的page和module都是Module类型的。
方法一:
通过dom4j,获取每个Element,然后对Attribute进行取,如(程序用到的代码较多,我只写一下核心部分):
Document dom=new SAXReader().read("读的xml文件"); List moduleXML=dom.selectNodes("/system/module"); List modules=new ArrayList(); for(Iteartor moduleIter=moduleXML.iteartor();moduleIter.hasNext();){ Element moduleEle=moduleIter.next(); Module module=new Module(); module.setName(moduleEle.attribute("name")); module.setSn(moduleEle.attribute("sn")); module.setPriority(Integer.parseInt(moduleEle.attribute("priority"))); …… List pageXML=moduleEle.elements("page"); List pages=new ArrayList(); for(Iteartor pageIter=pageXML.iteartor();pageIter.hasNext();){ Element pageEle=pageIter.next(); Module page=new Module(); page.setName(pageEle.attribute("name")); page.setSn(pageEle.attribute("sn")); page.setPriority(Integer.parseInt(pageEle.attribute("priority"))); …… pages.add(page); } module.setChildren(pages); modules.add(module); }
你是否看出了上面代码的坏味道呢?
1.代码重复
现在我们需要做什么改变呢?跟着我来看看吧,还是反射的应用~
public class Dom2Object { public static Object transfAtt2Obj(Class<?> clazz,Element element){ Object obj = null; try { obj=clazz.newInstance(); for (Iterator iterator = element.attributeIterator(); iterator.hasNext();) { Attribute attribute = (Attribute) iterator.next(); setFieldValueInAllSuper(obj,attribute.getName(),attribute.getValue()); } } catch (Exception e) {e.printStackTrace();} return obj; } private static void setFieldValueInAllSuper(Object obj,String propertyName,Object value){ //获取当前Object的class Class claszz=obj.getClass(); Field field = null; do{ try{ //从类里面获取指定属性 field = claszz.getDeclaredField(propertyName); } catch(NoSuchFieldException e){//如果没有获取到,则设置为null field=null; } //设置当前class为父class claszz=claszz.getSuperclass(); } while(field==null&&claszz!=null); //当field为空且class不为空时,进行下次循环 //如果field为空,说明没有此字段,返回空 if(field==null) return; //如果不为空,设置可见性,然后返回 field.setAccessible(true); try { //将要赋的值转到实体需要的类型,不然会报异常(例如String转Integer) Object val; //通过获取字段类型的构造函数来完成此操作(字段类型必须是包装类哦) val = field.getType().getConstructor(String.class).newInstance(value); field.set(obj,val); } catch (Exception e) { e.printStackTrace(); } } }
首先,是写一个为对象某属性赋值的方法,而属性是通过反射得到的。然后通过dom4j里的Attribute的API获取name和value,这样就可以动态的为对象的参数进行赋值了。
Document dom=new SAXReader().read("读的xml文件"); List moduleXML=dom.selectNodes("/system/module"); List modules=new ArrayList(); for(Iteartor moduleIter=moduleXML.iteartor();moduleIter.hasNext();){ Element moduleEle=moduleIter.next(); Module module=(Module)transfAtt2Obj(Module.class,moduleEle); List pageXML=moduleEle.elements("page"); List pages=new ArrayList(); for(Iteartor pageIter=pageXML.iteartor();pageIter.hasNext();){ Element pageEle=pageIter.next(); Module page=(Module)transfAtt2Obj(Module.class,pageEle); pages.add(page); } module.setChildren(pages); modules.add(module); }
应该很容易就看出来变化吧,那么这样写比前面那样写,优点在哪里呢?
1.复用性强,只要别人转的xml的时候,对象的属性在xml中都是以某标签的属性形式存在(可以扩展成标签也可以),那么这个方法就可以重用,因为这个抽取的方法和业务逻辑一点关系也没有。
2.扩展性好,一如前面说的,现在isleaf这个属性不必在xml中进行配置,但如果发现需要配置了,那么只需要在page这个标签的属性上加上isleaf="true"即可,代码可以完全不用动。
这么看是好处多多,那么又该注意什么呢?
1.用反射终究肯定会下降,不过当今时代的硬件,不用你考虑这个问题了
2.对于不常封装的我们来说,可能会碰到各种各样的问题,写这个方法用的时间,你写循环其实早写完了。不过对于现在的我们来说,还是可以接受的,通过项目学习、巩固基础嘛~~
3.自己写的工具类代码最好自己保留好,因为如果你看过我写的编程语言中的各种反射,你会发现
setFieldValueInAllSuper这个方法和那篇文章中的getFieldValueInAllSuper几乎一样,只不过一个是获取,一个是赋值。所以说代码经验的积累必不可少。
4.把握好度,够用就好。记住,你不是在写一个类库,够你用就好了,不然你的项目就可能延期了。一如我们用
的是将属性写在xml标签中的属性的位置上,而不是将属性以标签的形式展现,所以我就可以不考虑那种情况,如果
再去做两种兼容,那么可能一天也未必能弄出来。
5.嗅觉很重要,但见识更重要。一如曾经我们刚接触Java的时候,依然还记得将数据库中查出来的ResultSet
里面的值赋给一个对象,就是用的类似上面的方法。可当时还不知道反射可以这样做,所以也不觉得那样是重复。因
此,多看看项目源码,多学下人家的技巧是很有必要的。
总结:
好的代码不是一次就写出来的,一如前面我是在写了之后,才觉得重复,然后才去改的。适当的重构自己的代
码,你会学到更多~~~
原文链接:https://www.f2er.com/xml/299103.html