21.2 約定大於配置
21.2.1約定大於配置的HelloWorld
先來做一個示例,讓大家體會一下什麼是約定大於配置。
1:Convention Plugin
從Struts2.1版本起,Struts2官方就推薦使用Convention Plugin替換Codebehind Plugin來實現零配置。相對Codebehind Plugin而言,Convention Plugin有如下一些特點:
通過包的命名習慣來指定Action的位置
通過命名習慣來約定Result(包括Jsp、FreeMarker等)的路徑
類名對應於URL的約定轉換
包名對應於命名空間的約定轉換
遵循SEO規範的鏈接地址,比如:使用test-action來替換TestAction
基於註解的Action名稱約定
基於註解的攔截器約定
基於註解的命名空間約定
基於註解的XWork包
默認action以及默認的Result
等等。總之,使用Convention Plugin來實現零配置,會更靈活、更徹底,基本上可以做到不需要struts.xml來進行配置,甚至不需要註解進行配置,完全由Struts2依靠約定進行自動配置即可。
2:設置環境
要使用Convention Plugin,需要把struts2-convention-plugin-2.1.8.1.jar包拷貝到web工程的WEB-INF\lib包裏面。
3:最簡單的HelloWorld
要示範零配置,當然首先去掉struts.xml文件,缺省情況下,Convention Plugin會約定所有的結果頁面都存放在WEB-INF\content文件夾下。
在WEB-INF文件夾下新建一個content文件夾,然後在content文件夾下新建一個名稱爲helloworld.jsp的文件,內容示例如下:
訪問的方式是:在web上下文後面直接訪問這個頁面,不用加後綴,直接用名字就可以了,也就是URL爲:http://localhost:9080/helloworld/helloworld,運行結果如下:
圖21.1 約定配置示例
4:說明
在這個HelloWorld裏面,根本就沒有寫Action,當然也不存在struts.xml文件,完全是按照Convention Plugin的約定來運行,直接到WEB-INF/content文件夾下面,根據請求的url來找到對應的helloworld.jsp,然後直接運行這個頁面就得到了如上的運行結果。
那麼對於Convention Plugin來說,到底有哪些約定呢?
21.2.2常見的約定
1:默認把所有的結果頁面都存儲在WEB-INF/content文件夾下,這個值可以通過在struts.xml或者struts.properties文件中設置struts.convention.result.path這個屬性的值來改變到其他路徑。示例如下:
這樣就將默認的result頁面路徑設置到了WEB-INF/mypage文件夾裏面。
2:在應用啓動的時候,Convention插件會自動搜索位於action、actions、struts、struts2的包及其子包下的所有Java類,以搜索Action類。
可以通過在struts.xml或者struts.properties文件中設置struts.convention.package.locators這個屬性的值來改變搜索的文件夾。示例如下:
上面的示例定義了:在項目中,包路徑中包含web和s2的將被視爲包含Action類的路徑而被搜索。
3:在應用啓動的時候,Convention插件在上述包及其子包的路徑下搜索滿足如下條件的類來作爲Action類:
(1) 實現com.opensymphony.xwork2.Action的類
(2) 類名以Action結尾的Java類
比如:在cn.javass.testproject.action包下面,有一個HelloAction的類,那麼Convention插件會自動把這個HelloAction類當作Action來進行處理。
4:在映射Action的名稱的時候,通常遵循如下規則:
(1) 如果該Action類名以Action作爲後綴,那麼會將後綴的Action去掉,其他的不做處理。
(2) 如果該Action類名採用駝峯式的寫法,也就是每個單詞首字母大寫的寫法,那麼需要把所有字母變成小寫,單詞與單詞之間以中畫線隔開。
比如有一個Action的名稱爲HelloWorldAction,那麼對應的映射資源的名稱爲hello-world。
(3) 如果是單個詞的Action名稱,那麼把它的所有字母變成小寫,作爲對應的映射資源的名稱。比如Action類名爲HelloAction,它是以Action作爲後綴的,那麼對應的映射資源的名稱爲先去掉Action後綴,得到Hello,又是單個詞的名稱,變成小小,那麼最終對應的映射資源的名稱爲hello。
5:命名空間:
從定義的package.locators開始到包結束的部分,就是命名空間。比如有一個Action類位於如下包中:cn.javass.testproject.action.t1.t2,那麼命名空間就是/t1/t2。
命名空間對應着訪問的url中的path部分,位於web上下文之後,具體的資源名稱之前的部分,比如訪問的url爲:http://localhost:9080/helloworld/t1/t2/hello-world,其中的helloworld就是web上下文,而後面的hello-world就是要訪問的資源的名稱,中間的/t1/t2就是url的path部分。
命名空間還對應着WEB-INF/content文件夾下的子文件夾路徑,如果命名空間爲/t1/t2,那就以爲着對應的result頁面,應該放在WEB-INF/content/t1/t2文件夾下。
6:對應resutl頁面的約定:
(1) Result頁面默認的都以WEB-INF/content作爲定位的起點。
(2) 如果沒有對應的Action存在,那麼訪問資源的名稱就直接和頁面的名稱對應,要注意都是小寫的
(3) 如果有對應的Action存在,那麼對應的方式是:優先按照“Action的URL+Result的字符串+文件類型的後綴”的方式進行對應,如果沒有對應的頁面,那麼也可以按照“Action的URL+文件類型的後綴”的方式進行對應。
7:Action鏈的約定
如果一個Action執行完成後,希望進入到另外一個Action,從而形成Action鏈,基本的約定如下:
(1) 第一個Action返回的result沒有對應的頁面存在。
(2) 第二個Action和第一個Action在同一個包中,而且第二個Action映射的URL爲:第一個Action映射的URL+返回的result字符串,而且名稱採用駝峯式的寫法,也就是首字母大寫。
21.2.3 示例常見的約定
看了上面的約定,感覺如何,很糟糕是不是,這些約定的規則太抽象了,具體怎麼使用呢?接下來就通過示例來說明。
1:沒有Action的時候,就如同前面約定大於配置的HelloWorld那樣,訪問的URL爲:http://localhost:9080/helloworld/helloworld,由於沒有對應的Action,因此直接到WEB-INF的content文件夾下面,尋找名稱爲“helloworld”,後綴可以爲“.jsp”、“.htm”、“.html”等的頁面,找到後就直接運行。
2:如果有如下的包結構和類的定義:
圖21.2 示例的包結構
(1)如果要運行HelloWorldAction的話,對應的URL應該爲:http://localhost:9080/helloworld/t1/t2/hello-world,而且在content文件夾下應該有t1文件夾,t1文件夾下應該有t2文件夾,t2文件夾下應該有相應的result頁面,如下圖:
圖21.3 t2文件夾示例
像這個示例中,同時存在hello-world-success.jsp和hello-world.jsp,那麼會優先匹配到hello-world-success.jsp,如果不存在hello-world-success.jsp才匹配hello-world.jsp。
(2)先看看ConventionAction的實現,示例代碼如下:
此時在content文件夾下,有如下圖所示的頁面:
圖21.4 content文件夾
如果運行的URL爲:http://localhost:9080/helloworld/convention?userId=22,那麼會匹配到ConventionAction這個類,運行結束後,返回success。接下來到content文件夾下去優先匹配到convention-success.jsp,然後運行這個頁面,展示給用戶。
如果運行的URL爲:http://localhost:9080/helloworld/convention,那麼會匹配到ConventionAction這個類,運行結束後,返回toadd。接下來到content文件夾下去優先匹配到convention-toadd.jsp,然後運行這個頁面,展示給用戶。
如果此時把convention-toadd.jsp文件去掉,然後再次運行,運行的URL同樣爲:
http://localhost:9080/helloworld/convention,那麼會匹配到ConventionAction這個類,運行結束後,返回toadd。接下來到content文件夾下去尋找匹配的頁面,沒有能匹配上的,那麼就會到ConventionAction這個類的同包下,尋找是否有ConventionToaddAction這個類,有這個類,那麼就會運行這個類,相當於是Action鏈了。
From : http://sishuok.com/forum/blogPost/list/0/4184.html