2012年1月6日 星期五
GTAC 2011: Closing Keynote - Secrets of World Class Software Organizations
世界級軟體公司的秘辛
演講者 Steve McConnell (經典書籍 Code Complete 的作者)
提到的公司有 Microsoft (1990年代的MS), Google (講google有專用Bus原因時超酸滴...XDDD), MDA (講者作為顧問奉命解決這公司專案預估的能力, 講者看完後說你們是我看過最好的公司之一, 到底有什麼問題 ? 這公司說他們"只有"93%的專案能依預期達成, 所以他們想找出剩下的7%專案是怎麼回事...現場的觀眾都大笑...), NASA, Boeing, Symantec 等.
很有趣的一場演講, 值得一聽.
2011年9月30日 星期五
apache tiles 2 學習筆記
Apache tiles是一個版型模組化的工具.
通常網頁至少會將版型切割為4個區塊, 例如下圖:
tiles 的定義檔如下:
而頁面變更的時候, 通常都只是更換整頁中的某一個區塊, 其它區塊不需要變化.
例如登入時, 只需要將右邊的區塊變更為登入頁.
登入頁 tiles 的設定如下, 只要更換 title 及 browse 二個變數的定義即可.
但考慮更複雜一點的情況呢?
例如電子商務中常見的, 點擊商品目錄.
此時商品目錄會展開, 且右邊會列出該目錄下的所有商品.
示意圖如下:
這時候就得在同一個 controller 裡處理商品及目錄的邏輯.
然後分別放入不同的 tiles 變數中.
等一下下...似乎有點奇怪, 目錄跟商品雖然有關係, 但畢竟各自有不同的處理邏輯.
放在同一個 controller 內處理似乎怪怪的...
如果再回頭看一下登入頁的例子, 目錄的頁面雖然不需變動, 但此時目錄頁應呈現第一層目錄結構.
第一層目錄結構的邏輯, 跟登入有什麼關係呢 ?
是否有辦法將各區塊的內容獨立處理, 讓彼此不相干的邏輯不要混在一起呢?
還好, tiles 提供了 View Preparer 來處理這種情況.
通常網頁至少會將版型切割為4個區塊, 例如下圖:
<tiles-definitions>
<definition name="indexTemplate" template="/WEB-INF/views/tiles/indexTemplate.jsp">
<put-attribute name="title" value="Welcome" />
<put-attribute name="header" value="/WEB-INF/views/tiles/header.jsp" />
<put-attribute name="category" value="/WEB-INF/views/tiles/category.jsp" />
<put-attribute name="browse" value="/WEB-INF/views/tiles/browse.jsp" />
<put-attribute name="footer" value="/WEB-INF/views/tiles/footer.jsp" />
</definition>
</tiles-definitions>
<definition name="indexTemplate" template="/WEB-INF/views/tiles/indexTemplate.jsp">
<put-attribute name="title" value="Welcome" />
<put-attribute name="header" value="/WEB-INF/views/tiles/header.jsp" />
<put-attribute name="category" value="/WEB-INF/views/tiles/category.jsp" />
<put-attribute name="browse" value="/WEB-INF/views/tiles/browse.jsp" />
<put-attribute name="footer" value="/WEB-INF/views/tiles/footer.jsp" />
</definition>
</tiles-definitions>
而頁面變更的時候, 通常都只是更換整頁中的某一個區塊, 其它區塊不需要變化.
例如登入時, 只需要將右邊的區塊變更為登入頁.
登入頁 tiles 的設定如下, 只要更換 title 及 browse 二個變數的定義即可.
<!-- Login Page -->
<definition name="login" extends="indexTemplate">
<put-attribute name="title" value="Login Page" />
<put-attribute name="browse" value="/WEB-INF/views/tiles/login.jsp" />
</definition>
<definition name="login" extends="indexTemplate">
<put-attribute name="title" value="Login Page" />
<put-attribute name="browse" value="/WEB-INF/views/tiles/login.jsp" />
</definition>
但考慮更複雜一點的情況呢?
例如電子商務中常見的, 點擊商品目錄.
此時商品目錄會展開, 且右邊會列出該目錄下的所有商品.
示意圖如下:
這時候就得在同一個 controller 裡處理商品及目錄的邏輯.
然後分別放入不同的 tiles 變數中.
等一下下...似乎有點奇怪, 目錄跟商品雖然有關係, 但畢竟各自有不同的處理邏輯.
放在同一個 controller 內處理似乎怪怪的...
如果再回頭看一下登入頁的例子, 目錄的頁面雖然不需變動, 但此時目錄頁應呈現第一層目錄結構.
第一層目錄結構的邏輯, 跟登入有什麼關係呢 ?
是否有辦法將各區塊的內容獨立處理, 讓彼此不相干的邏輯不要混在一起呢?
還好, tiles 提供了 View Preparer 來處理這種情況.
2011年9月28日 星期三
Spring MVC 的怪事一椿
今天遇到怪事一椿, 其實已經困擾我一陣子了, 只是今天才發現原因所在.
Spring MVC 的 @RequestMapping 註解可用來標示 Url, 例如:
如果同時有二個相同的註解, spring 會報錯, 訊息如下:
但有一個例外, 就是 / , 一般看到網站的 / 會參考 tomcat 的 web.xml中 welcome-file 的設定.
若是下面的寫法, spring 不會報錯, welcome-file也不會生效, 但會連到那個 URL 就不知道了...
Spring MVC 的 @RequestMapping 註解可用來標示 Url, 例如:
@RequestMapping(value={"index"}, method=RequestMethod.POST)
public ModelAndView index(HttpSession session) {
...
}
如果同時有二個相同的註解, spring 會報錯, 訊息如下:
2318 [main] ERROR org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping#0': Initialization of bean failed; nested exception is java.lang.IllegalStateException: Cannot map handler 'xxxxController' to URL path [/index]: There is already handler of type [class yyyyController$$EnhancerByCGLIB$$349da4f8] mapped.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:580)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:900)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:455)
at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:294)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:215)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4206)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4705)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
at org.apache.catalina.core.StandardService.start(StandardService.java:525)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)
at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
但有一個例外, 就是 / , 一般看到網站的 / 會參考 tomcat 的 web.xml中 welcome-file 的設定.
若是下面的寫法, spring 不會報錯, welcome-file也不會生效, 但會連到那個 URL 就不知道了...
@RequestMapping(value={"/", "index"})
public ModelAndView index(HttpSession session) {
...
}
@RequestMapping(value={"/", "login"})
public ModelAndView index(HttpSession session) {
...
}
@RequestMapping(value={"/", "login"})
public ModelAndView login(HttpSession session) {
...
}
2011年9月20日 星期二
動態載入圖示 Animated Logo
今天才知道, 原來常見的動態載入小圖示, 如圖:

有個名字, 叫做 Throbber
還有網站可以幫忙製作呢.
搭配 jQuery 的 BlockUI Plugin
可以很快做出不錯的效果.
範例如下:
實際操作的時候, 發現圖常常出不來, 應是圖片載入過慢, 需將圖檔做預載(pre-load)處理, 作法如下:

有個名字, 叫做 Throbber
還有網站可以幫忙製作呢.
搭配 jQuery 的 BlockUI Plugin
可以很快做出不錯的效果.
範例如下:
$.blockUI({ message: '<h3><img src="/images/ajax-loader.gif" /> Please wait...</h3>' });
實際操作的時候, 發現圖常常出不來, 應是圖片載入過慢, 需將圖檔做預載(pre-load)處理, 作法如下:
$(document).ready(function() {
throbber = new Image() ;
throbber.src = "/images/ajax-loader.gif" ;
}) ;
throbber = new Image() ;
throbber.src = "/images/ajax-loader.gif" ;
}) ;
2011年9月5日 星期一
tomcat jsessionid url problem
Spring MVC 可以 cache static content, 例如圖檔, js, css...
參考文件
但我之前遇到一個問題, 就是原本應顯示為 /appbased/static-1.0.0/images/xxx 的 URL
在第一次執行時, URL 卻會變成 /appbased/static-1.0.0?jsessionid=481AFDE46F818357ED2096824F250AFF/images/xxx
需重新 reload 一次才回復正常.
當時我的作法是, 在首次登入頁面的 jsp 前面加一行
但最近又遇到另一個問題, 就是首頁有可能是登入狀態, 也有可能是未登入狀態, 總不能老是把 session 抓出來幹掉裝作沒事, 故查了一下解法.
參考文件
但我之前遇到一個問題, 就是原本應顯示為 /appbased/static-1.0.0/images/xxx 的 URL
在第一次執行時, URL 卻會變成 /appbased/static-1.0.0?jsessionid=481AFDE46F818357ED2096824F250AFF/images/xxx
需重新 reload 一次才回復正常.
當時我的作法是, 在首次登入頁面的 jsp 前面加一行
<% request.getSession(true).invalidate(); %>
即可.但最近又遇到另一個問題, 就是首頁有可能是登入狀態, 也有可能是未登入狀態, 總不能老是把 session 抓出來幹掉裝作沒事, 故查了一下解法.
2011年8月11日 星期四
Country & Province/State 國家代表表及省/州代碼表
找了好久. 這種東西很多地方需要啊.
OpenCart 有附 SQL, 不過國家只有 239 個, 與目前 iso 3166定義的 249 個國家有點差距.
iso 也沒提供 3166-2 的資料, 要買才有.
還好這邊有, 資料看起來挺新, 還可以下載, 也有 city & currency 的資料, 真是佛心來著.
我已把資料轉成 SQL 檔並修正一些亂碼, 有需要請自行取用 iso3166_1.sql (Country)
iso3166_2.sql (Subdivision: Province/State)
OpenCart 有附 SQL, 不過國家只有 239 個, 與目前 iso 3166定義的 249 個國家有點差距.
iso 也沒提供 3166-2 的資料, 要買才有.
還好這邊有, 資料看起來挺新, 還可以下載, 也有 city & currency 的資料, 真是佛心來著.
我已把資料轉成 SQL 檔並修正一些亂碼, 有需要請自行取用 iso3166_1.sql (Country)
iso3166_2.sql (Subdivision: Province/State)
2011年8月8日 星期一
Spring internationalization (i18n) 學習筆記
Spring 提供了下列幾種 MessageSource 給 i18n 用.
StaticMessageSource
ResourceBundleMessageSource
ReloadableResourceBundleMessageSource
使用及設定上3者都差不多, ReloadableResourceBundleMessageSource 的設定檔不需要放在 classpath 內, 且可以指定 cache, 故我選擇它實作.
實作環境Spring 3.1.0M1
StaticMessageSource
ResourceBundleMessageSource
ReloadableResourceBundleMessageSource
使用及設定上3者都差不多, ReloadableResourceBundleMessageSource 的設定檔不需要放在 classpath 內, 且可以指定 cache, 故我選擇它實作.
實作環境Spring 3.1.0M1
2011年7月22日 星期五
Spring Transcation 學習筆記
參考來源: Transaction Management
* 使用預設的Proxy mode時, @Transactional 只能用在 public method 上. 除非改用 AspectJ mode.
* Spring 不建議 @Transactional 用於 interface 上. (除非你使用 interface-based proxy )
* 預設只有在發生 Unchecked Exception 時才會自動 rollback, 可以指定Exception來Rollback.
ex @Transactional(rollbackFor=Exception.class)
* TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 可以手動rollback
* eclipse 似乎無法 auto import Annotation 中的變數, 當使用 Propagation 時會出現 Propagation cannot be resolved to a variable 的錯誤, 手動 import org.springframework.transaction.annotation.Propagation; 即可.
* 使用預設的Proxy mode時, @Transactional 只能用在 public method 上. 除非改用 AspectJ mode.
* Spring 不建議 @Transactional 用於 interface 上. (除非你使用 interface-based proxy )
* 預設只有在發生 Unchecked Exception 時才會自動 rollback, 可以指定Exception來Rollback.
ex @Transactional(rollbackFor=Exception.class)
* TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 可以手動rollback
* eclipse 似乎無法 auto import Annotation 中的變數, 當使用 Propagation 時會出現 Propagation cannot be resolved to a variable 的錯誤, 手動 import org.springframework.transaction.annotation.Propagation; 即可.
2011年6月24日 星期五
Final Fantasy XIII 感想
(圖片來自http://www.square-enix.co.jp/fabula/ff13/)
其實已經破關一段時間了, 看到 FF XIII-2 快出了, 來寫一下心得.
玩到遊戲中期(尤其是 Snow 救 Hope 那段)時, 感覺這也許是繼 FF VIII、FF X之後, 讓我再次喜歡上 FF 的一款遊戲.
戰鬥系統很棒, 雖然玩到後來, 喜歡的陣形跟攻擊模式大致會固定. 但遇到某些特定敵人仍不得不改變戰略. 讓佔 rpg 遊戲最多時間的戰鬥玩起來一點也不枯燥乏味. GJ.
萬萬沒想到, 後來整個爛尾啊...前面鋪陳繭與下界的恩怨情仇都是假的, 反正衝進去幹掉最後頭目就對了...更...
我猜也許是因為要順應 online game 的風潮, 所以主線弄比較短, 但任務很多...
這是本末倒置了...
對 FF XIII - 2 不抱什麼期待~~~
其實已經破關一段時間了, 看到 FF XIII-2 快出了, 來寫一下心得.
玩到遊戲中期(尤其是 Snow 救 Hope 那段)時, 感覺這也許是繼 FF VIII、FF X之後, 讓我再次喜歡上 FF 的一款遊戲.
戰鬥系統很棒, 雖然玩到後來, 喜歡的陣形跟攻擊模式大致會固定. 但遇到某些特定敵人仍不得不改變戰略. 讓佔 rpg 遊戲最多時間的戰鬥玩起來一點也不枯燥乏味. GJ.
萬萬沒想到, 後來整個爛尾啊...前面鋪陳繭與下界的恩怨情仇都是假的, 反正衝進去幹掉最後頭目就對了...更...
我猜也許是因為要順應 online game 的風潮, 所以主線弄比較短, 但任務很多...
這是本末倒置了...
對 FF XIII - 2 不抱什麼期待~~~
到頭來,我們記住的,不是敵人的攻擊,而是朋友的沉默
最近很多人轉的影片.
片中那位德佬真是令人感動.
除了引用聖經請服務生 Don't Judge 外.
也用馬丁.路德.金的名言"到頭來,我們記住的,不是敵人的攻擊,而是朋友的沉默"來鼓勵那家人.
查了原文是 In the end, we will remember not the words of our enemies but the silence of our friends
太帥了~~~
片中那位德佬真是令人感動.
除了引用聖經請服務生 Don't Judge 外.
也用馬丁.路德.金的名言"到頭來,我們記住的,不是敵人的攻擊,而是朋友的沉默"來鼓勵那家人.
查了原文是 In the end, we will remember not the words of our enemies but the silence of our friends
太帥了~~~
訂閱:
文章 (Atom)


