適時開始自己寫工具吧,騷年——XML和對象的轉化

來源:互聯網
上載者:User

        在匯入匯出的時候,我們可以選用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.代碼重複

         2.如果對xml想對page加一個屬性,那麼還需要改代碼

         現在我們需要做什麼改變呢?跟著我來看看吧,還是反射的應用~

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的classClass claszz=obj.getClass();  Field field = null;    do{     try{  //從類裡面擷取指定屬性field = claszz.getDeclaredField(propertyName);  }  catch(NoSuchFieldException e){//如果沒有擷取到,則設定為nullfield=null;  }//設定當前class為父classclaszz=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

裡面的值賦給一個對象,就是用的類似上面的方法。可當時還不知道反射可以這樣做,所以也不覺得那樣是重複。因

此,多看看項目源碼,多學下人家的技巧是很有必要的。


總結:

    好的代碼不是一次就寫出來的,一如前面我是在寫了之後,才覺得重複,然後才去改的。適當的重構自己的代

碼,你會學到更多~~~

         


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.