(轉(zhuǎn)載)http://www.aygfsteel.com/youxia/archive/2009/02/11/248051.html
在SpringSide 3 中,使用的MVC框架是Struts 2。Struts 2
向?qū)τ赟truts 1 來說,具有相當(dāng)多的優(yōu)點(diǎn),有很多人都說,用過Struts 2之后,再也不想看Struts
1了。然而,任何東西都有它的復(fù)雜性,Struts 2也不例外,SpringSide 3做了很多工作來簡化Struts 2 的使用。
先來說說Struts 2的特點(diǎn):
1、
編寫Action變得簡單了,Action變成了簡單的POJO,再也不用和ActionForm、ActionForward打交道了,返回的時(shí)候直接
返回字符串即可。如果要訪問Servlet API,則直接使用ServletActionContext類的靜態(tài)方法。
2、Struts
2提供了插件機(jī)制,允許我們自己為它編寫插件,當(dāng)然,要我自己寫是不現(xiàn)實(shí)的,但是面對別人寫的琳瑯滿目的插件,我一樣會昏頭。再網(wǎng)上隨便一搜,就可以發(fā)現(xiàn)
40多種Struts 2插件。SpringSide 3選擇的CodeBehind,就是一種Struts 2插件,它的目的是為了簡化配置。
3、Struts 2提供了攔截器機(jī)制,之所以編寫Action的任務(wù)那么簡單,靠的都是這些攔截器,比如它們可以自動解析Web表單和URL參數(shù),把它們注入到Action中。
4、Struts 2提供了豐富的taglib,當(dāng)然,豐富也代表著我們要化更多的時(shí)間去學(xué)習(xí)。
5、Struts 2依然提供了Validator和i18n支持。
等等...
下面,我們來看看SpringSide 3是怎么使用Struts 2的吧。SpringSide 3的主要目標(biāo)是降低我們使用Struts 2的復(fù)雜性,所以,它選擇了這些辦法:
1、沒有使用Validator和i18n,對數(shù)據(jù)的驗(yàn)證交給了JQuery,這變成了表現(xiàn)層的任務(wù),而且JQuery也可以使用AJAX從服務(wù)器端進(jìn)行驗(yàn)證。至于i18n,江南白衣說小網(wǎng)站用不上。
2、沒有使用Struts 2的UI標(biāo)簽,當(dāng)然也就沒有使用FreeMaker或SiteMesh了。
當(dāng)然,省掉了一些東西,就省掉了我們不少的學(xué)習(xí)時(shí)間。對于Struts 2核心的一些東西,我們看看它是怎么做的:
1、
使用CodeBehind插件來簡化配置。使用CodeBehind后,我們就可以不用配置result了,它可以根據(jù)我們Action的返回值自動猜測
返回的視圖頁面,它猜測的規(guī)則是這樣的:返回頁面的路徑為struts.codebehind.pathPrefix + package
namespace + action name + action returnvalue + .jsp,action
returnvalue為success時(shí),值為空,為其他時(shí),值為"-" + return type。我們來看看SpringSide
3生成的項(xiàng)目中關(guān)于Struts 2的配置文件:
其
中struts.codebehind.pathPrefix設(shè)置為“/WEB-INF/jsp/”,package的namespace沒有設(shè)置,所
以,如果我們的Action為UserAction,則返回success時(shí),就會返回到/WEB-INF/jsp/user.jsp,如果返回
input,則返回到/WEB-INF/jsp/user-input.jsp。這里江南白衣玩了一個(gè)狡猾,他把所有的jsp頁面放到WEB-INF目錄
中,別人就沒有辦法直接訪問了,這樣就可以簡化Acegi的配置工作。
2、關(guān)于攔截器棧
在上面講Struts
2的特點(diǎn)時(shí),我已經(jīng)說了Struts
2中攔截器的重要作用,在上面的截圖中,package的配置沒有做別的什么事,主要就是配置了攔截器棧。那么攔截器棧是怎么使用的呢?它是在
Action類中通過@ParentPackage指定的,如下面的代碼:
下面,我來具體說一下攔截器有什么作用。
例子一、我們知道Struts 2中的Action是和Servlet API解耦的,那么如果我們要在Action中訪問Servlet API怎么辦呢?一種辦法就是使用ServletActionContext,如下圖:
另外一種辦法,就是讓我們的Action實(shí)現(xiàn)ServletRequestAware接口,如下代碼:
private HttpServletRequest request;
public void setServletRequest(HttpServletRequest request) {
this .request = request;
}
public String execute() throws Exception {
// do the work using the request
return Action.SUCCESS;
}
}
例子二、ParametersInterceptor 攔截器會自動解析web表單或URL參數(shù),并把它們注入到Action中。但是很多時(shí)候,我們不愿意我們的Action具有太多的屬性,因?yàn)橐淮蠖训? get、set方法看起來太亂糟糟,我們希望有一個(gè)專門的Model對象來存儲這些值,而且剛好我們?yōu)镠ibernate設(shè)計(jì)的Entity類用來做 Model正合適。這時(shí),我們可以讓我們的Action實(shí)現(xiàn)ModelDriven接口,讓getModel()方法返回我們的entity對象即可。這正是SpringSide 3采取的方法,如下圖的代碼片斷:
這時(shí)候,ModelDrivenInterceptor攔截器就會幫助我們把解析的URL參數(shù)或表單數(shù)據(jù)注入到entity的屬性中,而不是Action中。
例子三、Preparable 接口聯(lián)合PrepareInterceptor攔截器一起工作,可以讓action在執(zhí)行execute() 方法前, 執(zhí)行一個(gè)prepare()方法,這也正是SpringSide 3的工作方式。
3、關(guān)于Action
有了上面對CodeBehind的理解和對攔截器棧的理解后,再來理解SpringSide 3中的Action就再簡單不過了,SpringSide 3中Action的繼承樹如下:
其中ActionSupport類是Struts 2提供的,另外兩個(gè)類是白衣自己擴(kuò)展的。其中SimpleActionSupport主要是提供了一些繞過jsp頁面直接輸出字符串的方法,不值一談。而CRUDActionSupport就比較復(fù)雜,如下:
/**
* 進(jìn)行CUD操作后,以redirect方式重新打開action默認(rèn)頁的result名.
*/
public static final String RELOAD = "reload";
/**
* Action函數(shù),默認(rèn)action函數(shù),默認(rèn)指向list函數(shù).
*/
@Override
public String execute() throws Exception {
return list();
}
/**
* Action函數(shù),顯示Entity列表.
* return SUCCESS.
*/
public abstract String list() throws Exception;
/**
* Action函數(shù),新增或修改Entity.
* return RELOAD.
*/
public abstract String save() throws Exception;
/**
* Action函數(shù),刪除Entity.
* return RELOAD.
*/
public abstract String delete() throws Exception;
/**
* 在save()前執(zhí)行二次綁定.
*/
public void prepareSave() throws Exception {
prepareModel();
}
/**
* 在input()前執(zhí)行二次綁定.
*/
public void prepareInput() throws Exception {
prepareModel();
}
/**
* 屏蔽公共的二次綁定.
*/
public void prepare() throws Exception {
}
/**
* 等同于prepare()的內(nèi)部函數(shù).
*/
protected abstract void prepareModel() throws Exception;
}
第
一,它做了把CRUD操作放到了同一個(gè)Action中的操作,這樣可以少寫幾個(gè)Action。這個(gè)工作難度不大,我覺得白衣此舉,主要是為了規(guī)范CRUD
函數(shù)的命名。在Struts
2中,如果我們要訪問的不是默認(rèn)的excute方法,可以使用如/user!save.action的格式,這樣訪問的就是UserAction的
save方法。
第二,它實(shí)現(xiàn)了ModelDriven接口和Preparable接
口,關(guān)于這兩個(gè)接口,我在前面講攔截器的時(shí)候已經(jīng)提到過了,所以很容易理解。我們可以把我們?yōu)镠ibernate設(shè)計(jì)的entity類作為Model,也
可以把初始化這些entity的工作放到prepareSave()和prepareInput()方法中,這兩個(gè)方法將會在save()和
input()方法執(zhí)行前自動執(zhí)行。
第三,它定義了一個(gè)靜態(tài)變量RELOAD,定義這個(gè)變量的目的是為了定義一個(gè)result的需要。CodeBehind中,大部分的result可以自己猜測,對于不能猜測的,需要使用@Results指定,如下代碼:
好 了,對SpringSide 3中Struts 2的分析就寫到這里了。總之,使用SpringSide 3時(shí),對于Action這一塊非常簡單,如果不設(shè)及到CRUD操作,就繼承SimpleActionSupport,如果涉及到CRUD操作,就繼承 CRUDActionSupport,并在getModel()"save()"prepareSave"input()"prepareInput() 等框框中填入適當(dāng)?shù)拇a即可。