this.uid = this.uid;
this.uid = this.uid;
這是甚麼爛Code呀…基本上,拿著這句Code去見工,被踢出門口是理所當然的事。在公司寫這句Code,被老細炒魷魚也是很自然的事。
但這句神奇的Code解決了我的問題,簡直匪夷所思!
我用了Tapestry 5.0.14這個Framework。Tapestry很強調一件事,就是當進行Form POST之後Server會Response一個Statue Code 302,使Browser對自己進行Redirect。這樣做的原因是防止Ugly URL以及避免User進行Refresh Page時會重新做多一次Form POST的動作。
而Tapestry呢,每個Page都會有一堆Local variable,Life Cycle是一個HTTP Request。所以,基本上再進行Form POST到另一個Page後再來一個302 Redirect,那堆要POST過去的value是會死掉的(即Life Cycle完結)。
Tapestry對於Life Cycle的問題是以@Persist去解決的。對一個variable加上@Persist,就是說延長其Life Cycle直至永久,加上@Persist(”flash”)就是可以生存兩個HTTP Request,很明顯就是為了要把Form Data從一個Page帶到另一個Page去的(Form POST + 302 Redirect = 2 HTTP Request)。至於@Persist(”cookie”)等就不作討論。
前言完,而如圖中所見,現在我有一堆Object在Page A的Scope內。我希望由Page A進行Form POST到Page B,再由Page B Form POST回到Page A後,那堆Object還在。(注意︰中間過程那堆Object的Life Cycle有否完結我並不在乎,只要到最後那堆Object還是那堆value就好)
主要可以用Client-side或者Server-side的去解決︰
- Client-side
- Form hidden field︰這是最常見亦最可行的方案。把那堆Object在Page B的Form裏用hidden field記好,然後再POST回Page A。不過首先那堆Object能否Serialize是首個問題(在我的情況是可以的,不過會費一番功夫…),其次假如那堆Object是Dynamic(每次的Object數目、Type都不一樣)那也有一番麻煩。但總之是可以解決問題的方法。
- Cookie︰根本不用考慮。首先同樣會有Serialize的麻煩(雖然@Persist(”cookie”)的話好像可以把麻煩丟給Tapestry),其次我們無從得知那堆Object的容量有多大。總沒可能有10Mb的Cookie吧?加上Cookie這種隨意被User改動的東西基本上不能100%信任的,個人認為。
- HTTP GET Parameter︰就是把整個Object放進URL裏。同樣有Serialize的麻煩,加上Ugly URL、URLencode等等麻煩…更容易被User改動,還有某些Browser對URL長度有限制,不作考慮。
- Server-side
- Server-side-session︰就是@Persist了。由於@Persist(”flash”)在進行(2)302後早就死掉了,在(3)Form POST時根本幫不上忙。使用@Persist連把Object pass過Page B也不用,是最簡單的解決問題方法。只不過,他的Life Cycle是優點也是缺點︰他不會自己死!簡單點說就是要人手去控制那堆Object的Life Cycle(總不能一直Persist吧!?),在複雜的System下還真是叫救命。加上User有些Action是Out of system control的,例如Browser refresh、手動輸入URL等等,要一併Handle的話,well…
最可行的方法似乎就是Form hidden field了吧。不過我還是死心不息的想搞Server-side-session。其實@Persist(”flash”)本來是最好的選擇,因為他自己會死掉嘛,如果@Persist(”flash”)能夠生存三個HTTP Request就好了,一切的麻煩都可以解決。在(1)Form POST時的Object在(3)Form POST回去時還在,而且自行在Page B死亡,真好。
逆轉思考︰要控制variable何時死實在麻煩,但要控制一個variable在何時應該繼續生存,似乎就簡單多了。
又再細想︰@Persist(”flash”)的Life Cycle是兩個HTTP Request,然而是怎麼開始計算的呢?在這裏我就做了一個假設︰從variable被Assign value那一刻開始,variable可以生存兩個HTTP Request。
這就有趣了,所以我在(1)Form POST完結後加上了一句爛Code︰
@Persist("flash")
private Integer uid;
...
this.uid = this.uid;
結果這個uid成功地由Page A pass過Page B,並且成功生存至(3)Form POST並在(4)302 Redirect中pass回Page A。這句爛Code的作用,就是令variable的壽命延長,達到簡單解決問題的效果。
好神奇!