2014年8月26日 星期二

簡易解析struts property tag 取值

起因在於有莫名的堅持要弄一個純"Tag"的網頁...因為這郭系統是不做js/ajax的,很傳統的java網站(就是輸入值都要submit到server做檢查的那種~~)
然後講一講後端邏輯的部分不改,就只改前端的view.....造成只好要用自訂tag( custom tag)包掉原本的資料~

原本的資料本來就是動態的撈出來的~所以原本值就已經被struts的tag包起來,學struts包struts那樣子,想說包兩層應該很簡單(包兩層只要一個用小撇('),一個用("),他就會分出來了)~

可是我忘了偶自己寫的不是struts tag阿阿阿阿阿~~~~~
實作自訂Tag時,JSP也很乖的送了一字不漏的struts tag的文字進來了Orz...
最後想不出辦法來,只好硬解tag內容抓值了,就以會傳入的型式自己寫parser了Orz...

1. 先解析struts tag,反正就只抓property 的value
2. 輸入值抓出來後,就依其定義在JSP裡面抓值,只處理像這種情況的取值result.startDt.substring(0, 4),只有一層bean,也不處理array情況,bean也只能get一次,原本的定義應該是用while loop可以一直抓下去的~
request.getAttribute() --> bean --> getter --> substring
3. 前端呼叫的寫法
<my:year format='YYYY' value='<s:property value="result.startDt.substring(0, 4)" />' />
4. tld別忘了要做tag設定才會被讀入~

String getStrutsPropertyValue(String val)  {
        String re = "";
        Document doc = null;
       
        ByteArrayInputStream bis = null;
        try  {
            val = "<root>"+val+"</root>"; //append to a normal xml format
            bis = new ByteArrayInputStream(val.getBytes());
           
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            doc = dBuilder.parse(bis);
           
            NodeList nl = doc.getElementsByTagName("s:property");
            if(nl.getLength() > 0)  {
                String theValue = nl.item(0).getAttributes().getNamedItem("value").getNodeValue();
              
               String[] sp =  StringUtils.split(theValue,".");
                if(sp.length > 0)  {
                    Object obj0 = pageContext.getRequest().getAttribute(sp[0]);
                    if(obj0 != null && sp.length > 1)  { //attribute is bean
                        String getter = "get"+sp[1].substring(0,1).toUpperCase()+sp[1].substring(1);
                        Object obj1 = obj0.getClass().getMethod(getter).invoke(obj0, null);
                        if(obj1 != null)  {
                            re = obj1.toString();
                        }
                        if(sp.length > 2 && obj1 != null)  {  //string operation with bean property
                            if(sp[2].indexOf("substring") >= 0)  {  //support substring
                                String[] agrs = StringUtils.split(sp[2].substring( sp[2].indexOf("(")+1, sp[2].indexOf(")")),",");
                                Object obj2 = null;
                                if(agrs.length == 1)  {
                                    obj2 = obj1.getClass().getMethod("substring", int.class).invoke(obj1, Integer.parseInt(agrs[0].trim()));
                                }  else if(agrs.length == 2)  {
                                    obj2 = obj1.getClass().getMethod("substring", int.class, int.class).invoke(obj1, Integer.parseInt(agrs[0].trim()), Integer.parseInt(agrs[1].trim()));
                                }
                                if(obj2 != null)  {
                                    re = obj2.toString();
                                }
                            }
                           
                        }
                       
                    }  else if(obj0 != null)  {  //only attribute value
                        re = obj0.toString();
                    }
                }
            }
           
        }  catch(Exception e)  {
            e.printStackTrace();
        }  finally  {
            if(bis != null)  {
                try  {  bis.close();  }  catch(Exception ee)  {}
            }
        }
        return re;
    }

很久沒用java.lang.reflect,是有點手癢XD...那個package真的很有意思~~

PS:雖然說 jdk後來同意 Integer, int 這種變數的型態可以互通,就是寫程式的時候大I,小i亂塞是被complire認同的~但是在Class的定義上~ Integer.class =/= int.class~所以在找method的時候~ 還是得用正確的型態才能找到喔!

PS:java內建的split還是常常不好用,用apache.commons.lang.StringUtils安定!

PS:原本也想直接找struts的Tag做繼承,不過它看起來還是得自己去解tag字串,要仿做一個完整的就變成要去研究它的source code和呼叫關係才行~這~實在有點麻煩就先用爛解處理了一.一a...反正能動就好!

沒有留言: