2014年10月23日 星期四

jsf valueChangeListener bug

這個問題我認為是個BUG...
就是當 select 來valueChangeListener時,切換bean的資料,
會發現很詭異的inputtext...

假設案例是selector onchange時, 要同時把 OOO(inputtext)改成 "bala"~


當OOO是disable="true" 時,資料會寫上去,有bala~
但是普通輸入時不會(diabled="false")...沒有bala~然後在頁面把內容output出來是沒改的!!
這鬼恐怖的地方在於,在某些頁面(相對簡單)是會動的...
但是有些頁面又不會動....

查了很久~總算看到一個應該是比較好的解就是~
http://stackoverflow.com/questions/14171493/how-to-get-updated-model-values-in-a-valuechangelistener-method

public void changeSelector(ValueChangeEvent event) {
        if(event == null || event.getNewValue() == null)  {
            return ;
        }
       
        if (event.getPhaseId() != PhaseId.INVOKE_APPLICATION) {
            event.setPhaseId(PhaseId.INVOKE_APPLICATION);
            event.queue();
            return;
        }
       
    // Do your original job here. 
    // It will only be entered when current phase ID is INVOKE_APPLICATION.
 
        String key = (String)event.getNewValue();
        this.setXXX(key);
        this.setOOO("bala");
}

另外select (selectOneMenu)
有些鬼是,明明選了項目,但是它鬼資料就是不會跳到你選的選項~
(鬼打牆一直跳在第一個)
注意它的 id 必須要和 bean裡面的property naming 一模一樣!!
感覺很有鬼~但是沒辦法~它就是爛~___~|||
<ice:selectOneMenu id="selector" value="#{bean.selector}" ....



2014年10月14日 星期二

iceface jsf 日期 少一天問題

因為他是個BUG嗎?....

總之因為當初他在 convertDateTime 的實作裡,把時區寫死成GMT還UTC忘了(總之就是格林威治時間)...
所以造成了很多很多很多很多的困擾...

話說找這問題的關鍵字還蠻難猜的~ 後來總算找到是..."jsf convertdatetime one day less"

解法是蠻多種的~但是....卡版本就要哭哭了...

看起來是JSF 2.0以上的版本可以用設定檔改成主機時區
<context-param>
    <param-name>javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE</param-name>
    <param-value>true</param-value>
</context-param>
 
或是基本的...直接寫死時區(timeZone大小寫要對喔,寫錯還不會出來=_=|||)~
但是看偶幾十頁要全重改一次就是很不爽一x一...
<f:convertDateTime pattern="yyyy/MM/dd" timeZone="GMT+8" /> 

然後用這個的除了文字顯示外,還有小日曆要一起修的問題~
所以就很不爽(假裝很厲害)的去寫了一個converter出來...
此法也只適用於jsf 1.6以上的樣子,看討論是因為
<f:converter converterId="XXXXXXXX" />
這種寫法, 1.6後才支援...
 
重點大概是~一定要繼承 DateTimeConverter,小日曆裡才吃得進去!!
改掉萬惡的時區。
getAsObject裡,一定要回傳java.util.Date,不然小日曆就擺臭臉給你看....

然後既然都自己刻了,就也順便修一下原本沒事就亂丟NullPointerException的問題...

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.DateTimeConverter;

public class DateInputConverter extends DateTimeConverter implements Converter {
 
 SimpleDateFormat sf = new SimpleDateFormat("yyyy/MM/dd");

 public Object getAsObject(FacesContext context, UIComponent component, String value) {
  java.util.Date re = null;
  try  {
   if(value != null && value.length() > 0)  {
    re = sf.parse(value);
   }
  }  catch(Exception e)  {
   
  }
  return re;
 }

 public String getAsString(FacesContext context, UIComponent component, Object value) {
  String re = "";
  try {
   if (value != null) {
    // format Timestamp
    if (value instanceof Timestamp || value instanceof java.util.Date) {     
     re = sf.format(value);
    }
   }
  }
  catch (Exception e) {
   e.printStackTrace();
  }
  return re;
 }
 
 public TimeZone getTimeZone()  {
  return TimeZone.getDefault();
 }
}

face設定檔裡面也要加自定的converter
<converter>
    <description>小日曆輸入 yyyy/MM/dd</description>
    <converter-id>formatDateInput</converter-id>
    <converter-class>XXXXXXX.DateInputConverter</converter-class>
</converter> 

前端page
<ice:selectInputDate id="birthday" renderMonthAsDropdown="true" 
    renderYearAsDropdown="true" renderWeekNumbers="true"
    value="#{bean.birthday}" title=""                             
    renderAsPopup="true">
        <f:converter converterId="formatDateInput" />
</ice:selectInputDate>  


2014年10月3日 星期五

jsf + iceface

老實說~第一次寫前端寫到爆氣都是因為這種很難用的東西....
用後端寫前端~講得好聽是少學一種語言,但是多學一個不通用(有BUG)的語言更痛苦!
剛想起來,應該不只多一個語言的量,還包含tag function/el/logic/selector....

目前發現到的主要問題在於,submit時有時候他會lose掉內部存的bean資料(看到一堆資料莫名的被清空~會哭阿T_T~FF的出現率比IE高很多~Orz...不知道是不是跟cache還什麼有關)~看看討論,有人說用immediate來處理,但是好像還是無法完全避免(偶爾發生,偶爾不會~|||Orz)

另外就是排版問題~因為無法去設定該原件在前端是個什麼樣子,有些元件的width調了也沒用(可能有些是span, 有些是div)問題是不大,但是在某些硬要排出來的情況就會哭了~加上偶這系統是完全以table為主切的~span/div在td內的行為有些本來就會不正常。在顯示或隱藏時,有時候得再多包一兩層的table去讓他變成期望的樣子,老實說有點不爽....(小時後受過古早IE的table摧殘,現在正是發揮作用的時候嗎T^T)

至於因為是tag...所以本身支援的function與operator就比較少,有時候想到一個什麼大家都有的,像if/else這種東西很基本的在上面硬要寫就又讓人不爽=_=...雖然還是可以找繞遠路或長落落的寫法來處理~但就是會不爽~ (當年tag是為了美編設計而發想的設計,但是我覺得那些rule反而比一般程式的還難,美編要是學得會還不如當前端工程師算了!)

因為該架構是用iceface的擴充版~沒聽錯的話,偶這程式是1.8的樣子...
reference sample url :
http://component-showcase.icesoft.org/component-showcase/showcase.iface 

iceface的reference很重要~要先看範例再問問題比較好....因為有很多浪費很多時間的問題~其實只要選對屬性就好了...但是還是浪費了很多時間在找解....
另外是擴充版也好幾個版本~直接問google常翻到別人的解一.一|||也沒屁用....

註記幾個用到的,不一定純ice或純jsf

###小日曆輸入
很妙的這個,在FF上看寫英文(Sun),用IE寫中文(星期日)~後端只吃java.util.Date
這東西的缺點在排版上,他產生時大概是個div...所以後面的字會被換行=_=...只好硬生生的又做了個sub table包起來~
<ice:selectInputDate id="myDate" renderMonthAsDropdown="true" renderYearAsDropdown="true" renderWeekNumbers="true"
                             value="#{bean.myDate}"
                             title=""
                             renderAsPopup="true">
                    <f:convertDateTime pattern="yyyy/MM/dd" />
                </ice:selectInputDate>

###檔案上傳
不知道是好用還是難用的東西,屬性設定變化就能有很大的不同,好用。但是屬性內的width看起來是壞了,設定不是中間的input變短,而是直接切掉,若像我是用加按鈕才上傳的話,按鈕被切掉是要怎麼傳啦=_=a...

另外上傳的路徑就直接設定在tag裡了,不知道該說好用還難用(不管你要不要這個檔,他都直接寫上Server)...後端是直接處理實體file了,而不是stream! 另外測試~中文檔名也可以正確的寫出來還不算笨~在此~相信apache的FileUtils會是個很好的搭檔~

submitOnUpload最好依情況設定比較好
<ice:inputFile id="inputFileName1" autoUpload="false" label="上傳"
                       uploadDirectory="/upload/temp/" submitOnUpload="postUpload"
                       actionListener="#{bean.uploadFile1}"
                       immediate="true"/>

public void uploadFile1(ActionEvent event) {
        InputFile inputFile = (InputFile) event.getSource();
        FileInfo fi1 = inputFile.getFileInfo();
        String absPath = fi1.getFile().getParentFile().getAbsolutePath();
        if(checkUploadFile1(fi1))  {
            try  {
                FileUtils.copyFile(fi1.getFile(), new File( absPath+"/"+ afterName));               
            }  catch(Exception ee)  {
                ee.printStackTrace();
            }
            ........   
        }
    }

###datatable group by
為了找個顯示上的解法,花了半天google,結果發現只要寫一個屬性~真是給它無言...
其實這個就是把值相同的欄位做 rowspan
groupOn的內容值,可以不等於底下的output,可以把id2想成是一個hidden的欄位~
<ice:column groupOn="#{row.id2}">
                                    <f:facet name="header">XXX</f:facet>
                                    <h:outputText value="#{row.id}" />
                                </ice:column>

###datatable 不同行換顏色
跟上面的原本是差不多的意思,只不過因為後來覺得有做rowspan,大家的眼睛不會看花之後,就沒有來搞顏色區分了~不同解法有看到就是了~
基本上就是rowClasses,用","隔開,就會出來了~
<ice:dataTable rowClasses="row_odd, row_even" ...