• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
    • 軟件測試技術
    • 軟件測試博客
    • 軟件測試視頻
    • 開源軟件測試技術
    • 軟件測試論壇
    • 軟件測試沙龍
    • 軟件測試資料下載
    • 軟件測試雜志
    • 軟件測試人才招聘
      暫時沒有公告

    字號: | 推薦給好友 上一篇 | 下一篇

    怎樣真正的在Struts框架下使用時間類型

    發布: 2007-6-08 17:25 | 作者: 網絡轉載 | 來源: 網絡 | 查看: 226次 | 進入軟件測試論壇討論

    領測軟件測試網
    使用時間類型,這誰不會,不就是java.util下的幾個類嗎,再加上java.sql和java.text下的幾個類,這會有什么問題嗎?Struts要是連時間都處理不了,那還能干嘛?

    在實際應用中,我就發現Struts確實連有些簡單的時間都處理不了(不知是我使用的方法不對還是Struts確實沒有考慮到)。順便你也能了解Struts是怎么把form里的請求參數populate到ActionForm里面的。

    今天下午同事告訴我把有java.util.Date類型屬性的類存入數據庫時出錯,把這個屬性刪除就沒有問題了。當時我就想到是RequestProcessor在processPopulate()時出錯了,因此在它的這個方法設了斷點并跟蹤了進去。

    當然,它最先要調用ActionForm的reset()方法,然后調用實際處理populate(將請求參數傳給ActionForm)的RequestUtils.populate()方法。RequestUtils的這個靜態方法最先是處理Multipart的(即文件上傳等多部分)的方法,然后將所有的請求都放在叫properties的HashMap里并循環處理它:
    
    names = request.getParameterNames();
    while (names.hasMoreElements())
    {
    String name = (String) names.nextElement();
    String stripped = name;
    if (prefix != null)
    {
    if (!stripped.startsWith(prefix))
    {
    continue; 
    }
    stripped = stripped.substring
    (prefix.length());
    }
    if (suffix != null)
    {
    if (!stripped.endsWith(suffix))
    {
    continue;
    }
    stripped = stripped.substring
    (0, stripped.length() 
    - suffix.length());
    }
    if (isMultipart)
    {
    properties.put(stripped, 
    multipartParameters.get(name));
    }
    else 
    {
    properties.put
    (stripped, request.getParameterValues(name));
    } 
    }
    

    實際處理它們的是下面的:BeanUtils.populate(bean, properties);其中bean就是接受數據的ActionForm,而properties里面則是所有的請求的鍵-值對(鍵和值都是字符串,http協議的特點)。

    再看看BeanUtils的靜態(類)方法populate是怎么處理的:

    
    // Loop through the property 
    name/value pairs to be set
    Iterator names =
    properties.keySet().iterator(); 
    while (names.hasNext())
    {
    // Identify the property name
    and value(s) to be assigned
    String name = (String) names.next(); 
    if (name == null)
    { 
    continue;
    }
    Object value = properties.get(name);
    // Perform the assignment for this property
    setProperty(bean, name, value);
    }
    



    它是循環所有的請求參數,把實際的工作又交給了setProperty方法。這個類就是:一上來20多行都在一個if (log.isTraceEnabled()){}里面。建議在寫Action 的execute()或被execute()調用的業務方法中使用Commons Logging 來代替System.out.println()——當要你把成百上千的System.out.println()去掉的時候你就會覺得Commons Logging有多好用了。它的用法是:

    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory; 
    private/protected static Log log = 
    LogFactory.getLog(DispatchAction.class);
    



    如果你用的是DispatchAction,那你就不要自己定義Log的實例了,因為它已經有一個protected的Log實例,直接使用即可。使用方法是:

    
    if (log.isInfoEnabled())
    {
    log.Info("some information.");
    }
    



    Logging把消息分為6種級別,debug,error,fatal,info,trace,warn。比如,你想記錄一條消息,它只是為了給用戶一個警告,則可以使用warn。為什么在每個log.Info()前做一次判斷呢?難道如果log級別不允許Info,log.Info()仍然能Info嗎?當然不是。它的作用是提高效率。

    比如有個消息是計算前一萬個自然數的和(這種消息可能少見)。用直接log.Info()

    
    int sum=0;
    for(int i=0;i<10000;i++)
    {
    sum+=i; 
    }
    log.Info("the sum of form 1 to 10000 is : "_sum);
    



    如果log.Info是不允許的,那求10000個數的和就白求的。當然如果你的計算機很快或和高斯一樣聰明,直接log.Info()也每什么問題。

    閑話少說,回到180多行的BeanUtils.setProperty()方法。這個方法先是處理nested屬性,也就是xxx.xxx的請求參數。我們只看看處理簡單屬性的必須過程。下面這端代碼有點長,但它只做了一件事:將字符串的請求參數轉成ActionForm的類型。

    比如:你在ActionForm里有個Integer userAge;然后HTTP請求參數里可能會有http://localhost:8080/xxx.do?userAge=21。傳入的是字符串,目標是專程Integer。首先它當然會根據userAge這個字符串查找相應的ActionForm,如果這個ActionForm有個屬性也叫userAge,然后就會把這個userAge的類型存到type里,type的定義是:

    
    Class type = null;
    


    得到type的代碼很長,這是因為要它考慮很多情況,例如DynaActionForm。

    
    // Convert the specified value to
    the required type
    Object newValue = null; 
    if (type.isArray() && (index < 0))
    {
    // Scalar value into array
    if (value == null)
    {
    String values[] = new String[1];
    values[0] = (String) value;
    newValue = ConvertUtils.convert
    ((String[]) values, type);
    }
    else if (value instanceof String)
    { 
    String values[] = new String[1];
    values[0] = (String) value;
    newValue = ConvertUtils.convert
    ((String[]) values, type);
    }
    else if (value instanceof String[]) 
    {
    newValue = ConvertUtils.convert
    ((String[]) value, type);
    }
    else
    { 
    newValue = value;
    }
      }
      else if (type.isArray()) 
      {
      // Indexed value into array
      if (value instanceof String) 
      {
      newValue = ConvertUtils.convert((String) 
      value, type.getComponentType());
      } 
      else if (value instanceof String[])
      {
      newValue = ConvertUtils.convert
      (((String[]) value)[0], 
      type.getComponentType()); 
      } 
      else 
      {  
      newValue = value;  
      }  
      }
      else
      {
      // Value into scalar 
      if ((value instanceof String)
      || (value == null))
      { 
      newValue = ConvertUtils.convert
      ((String) value, type);
      }
      else if (value instanceof String[])
      { 
      newValue = ConvertUtils.convert
      (((String[]) value)[0], type);
      }
      else if 
      (ConvertUtils.lookup(value.getClass())
      != null)
      {                
      newValue =
      ConvertUtils.convert(value.toString(), type);
      // Here is my program's break point 
      }
      else 
      { 
      newValue = value;
      } 
      }
    



    最后是:調用PropertyUtils的一些方法設置值。下面代碼的第一種情況是有索引的,即你在請求參數里傳了field[0]=123之類的參數,第二種是Map類型的,傳的是map(key)=value之類的參數,最一般的就是調用第三個方法:

    
    if (index >= 0) 
    { 
    PropertyUtils.setIndexedProperty
    (target, propName, index, newValue); 
    } else if (key != null)     
    {
    PropertyUtils.setMappedProperty
    (target, propName, key, newValue); 
    }
    else
    { 
    PropertyUtils.setProperty
    (target, propName, newValue); 
    }
    



    當然還可以在跟蹤下去,不過和這個主題沒什么關系了。大概的流程是:setProperty()方法再調用setNestedProperty()方法(還是代理),在調用setSimpleProperty(),最后通過java.lang.reflect包調用你在ActionForm里寫的setXXX()方法,如setUserAge(Integer userAge)等。

    現在說說為什么不能populate java.util.Date類型的數據。關鍵是ConvertUtils.convert(),即上文有注釋的地方。如果這個方法返回的是一個java.util.Date類型的對象,當然后面都不會有問題。但我發現實際運行的結果是,newValue還是String類型的,因此在后面通過reflection調用setXXX時出錯。

    你或許會奇怪ConvertUtils包竟然連java.util.Date都不支持,我也覺得不可思異。我還以為是我使用的不對,然后進入這個類一看,確實是不支持。

    另外,會不會即時是字符串的,org.apache.commons.beanutils.PropertyUtils.setProperty()也有能力處理呢?于是又寫了個小程序測試

    
    public class SetSimplePropertyTest
    { 
    public SetSimplePropertyTest()
    {
    }  
    public static void main(String[] args)
    { 
    SetSimplePropertyTest
    setSimplePropertyTest1 = 
    new SetSimplePropertyTest();  
    String dateStr="2004-01-01 19:00:00"; 
    test.DataBean dataBean=new DataBean();
    try 
    { 
    org.apache.commons.beanutils.
    PropertyUtils.setProperty(dataBean,
    "receiveTime", dateStr);
    }
    catch (Exception e)
    {
    e.printStackTrace(); 
    }
    System.out.println
    (dataBean.getReceiveTime().toString());
    }
    



    運行是拋出異常,證明處理不了。

    問題找到了,那該怎么解決呢?當然最簡單的方法就是使用ConvertUtils能轉的java.sql.DateTime等,比較復雜一點的方法就是自己寫一個ConvertUtils。當然,如果你把日前存成String,那更沒問題,但如果要將它存入數據庫,還得轉。

    尤其在使用DAO模式時,我們可能用BeanUtils.CopyProperties()方法實現將一個ActionForm拷貝到一個DTO(or VO)對象中時會很麻煩。

    還有一個比較好的方法是,屬性定義成java.util.Date,但為Struts提高另一個getter/setter方法。這種方法是在middlegen自動生成的JSP頁面看到的。例如:

    
    private java.util.Date saveDate;
    //普通的set/get方法
    public void setSaveDate
    (java.util.Date saveDate)
    {
    this.saveDate=saveDate;
    } 
    public java.util.Date getSaveDate()
    {
    return this.saveDate;
    }
    //為Struts準備的方法,
    時期的格式假定是 2000-12-31 23:59:59 
    public void setSaveDateAsString
    (String saveDate)
    {
    java.text.DateFormat dateFormat 
    =new java.text.SimpleDateFormat
    ("yyyy-MM-dd HH:mm:ss");                 
    this.saveDate=dateFormat.parse(saveDate); 
    }
    public String getSaveDateAsString()
    { 
    java.text.DateFormat dateFormat =new 
    java.text.SimpleDateFormat
    ("yyyy-MM-dd HH:mm:ss");
    return dateFormat.Format(this.saveDate);  
    }
    



    然后在JSP中使用:

    
    <html:form action="xxx.do">
    <html:text property="saveDateAsString"/>
    </html:form>
    

    延伸閱讀

    文章來源于領測軟件測試網 http://www.kjueaiud.com/

    TAG: struts 框架 類型 使用 怎樣 真正 時間


    關于領測軟件測試網 | 領測軟件測試網合作伙伴 | 廣告服務 | 投稿指南 | 聯系我們 | 網站地圖 | 友情鏈接
    版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
    北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備10010545號-5
    技術支持和業務聯系:info@testage.com.cn 電話:010-51297073

    軟件測試 | 領測國際ISTQBISTQB官網TMMiTMMi認證國際軟件測試工程師認證領測軟件測試網

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>