1. 程式人生 > >Struts2 調用非execute方法

Struts2 調用非execute方法

有一種 jsp頁面 edm map this 消息 type servle dojo

調用非execute方法

1)如果你的Action類是繼承自ActionSupport的話,確切的說是重寫了execute方法,ActionSupport裏的默認實現就是返回"success"視圖。因此,你可以不實現execute方法,只要你的struts.xml裏有"success"對應的result即可。

2)如果你的Action類沒有繼承ActionSupport,而你又沒有在struts.xml中對應<action>標簽中用method屬性指定你自己的方法的話,默認就要找execute方法,這時是必須要實現execute方法的,否則Struts2會找不到對應的方法而報錯。

不過,大部分情況下都是繼承ActionSupport的(比如輸入驗證、文件上傳等功能就要求必須繼承)。還有,不管你寫沒寫execute方法,還是可以用<action>標簽的method屬性指定其他方法的。

在前面有關Action的學習中,我們的Action中真正實現業務邏輯的只有execute方法,如果我們每個Action中都只有這麽一個方法的話,那麽當我們程序中需要的功能很多時,我們就不得不手動編寫很多的Action類了,這顯然是不合理的。前面我也說道了我們的Action類並不一定非得繼承某個類或者實現某個接口,我們可以使用POJO來作為我們的Action,並且我們的Action中也並不一定非得要有execute方法,如果我們使用的不是execute方法,那麽我們就需要在配置Action的是時候在action標簽上使用method屬性來指出我們需要使用的動作方法。

那麽我們也可以在一個Action中編寫多個用於實現業務邏輯的方法,他們分別執行不同的功能,但是做的工作又是有相似的地方。比如我們可以將所有與用戶相關的處理操作都寫在UserAction當中,那麽這樣我們就能夠更好的組織我們的代碼。同樣,我們只需要在struts.xml中為我們的action標簽指定我們要使用的method即可。

要實現在一個Action類中調用非execute方法有三種實現方式:

(1)使用method屬性

[java] view plain copy print?
  1. package action;
  2. import bean.User;
  3. import com.opensymphony.xwork2.ActionSupport;
  4. public class UserAction extends ActionSupport{
  5. private String userName;
  6. private String password;
  7. public String getUserName() {
  8. return userName;
  9. }
  10. public void setUserName(String userName) {
  11. this.userName = userName;
  12. }
  13. public String getPassword() {
  14. return password;
  15. }
  16. public void setPassword(String password) {
  17. this.password = password;
  18. }
  19. @Override
  20. public String execute() throws Exception {
  21. //僅用於顯示信息輸入頁面
  22. return INPUT;
  23. }
  24. //保存User
  25. public String save(){
  26. User user = new User();
  27. user.setUserName(userName);
  28. user.setPassword(password);
  29. //將user的信息保存到數據庫
  30. //UserDao.save(user)
  31. return SUCCESS;
  32. }
  33. }

這裏我們還需要一個User實體類,其實就是一個簡單的JavaBean即可。

[java] view plain copy print?
  1. package bean;
  2. public class User {
  3. private String userName;
  4. private String password;
  5. public String getUserName() {
  6. return userName;
  7. }
  8. public void setUserName(String userName) {
  9. this.userName = userName;
  10. }
  11. public String getPassword() {
  12. return password;
  13. }
  14. public void setPassword(String password) {
  15. this.password = password;
  16. }
  17. }

然後在struts.xml中對我們的Action進行配置

<package name="default" namespace="/" extends="struts-default">

<action name="userAdd" class="action.UserAction">

<resultname="input">/input.jsp</result>

</action>

<action name="userSave" class="action.UserAction" method="save">

<result name="success">/success.jsp</result>

</action>

</package>

Input.jsp

<form action="userSave.action" method="post">

username : <input type="text" name="userName"/><br/>

password :<input type="password" name="password"><br/>

<input type="submit" value="submit"/>

</form>

success.jsp

<body>

hello ${userName }<br/>

your password is ${password }

</body>

我們在瀏覽器中測試一下:

我們直接在瀏覽器中訪問userAdd.action,可以看到顯示了信息輸入頁面

技術分享

技術分享

提交之後正確的顯示除了success結果頁面,說明我們的配置沒有問題。

(2)使用通配符

除了使用上面說到的方法外,我們也可以不用在struts.xml中對Action中的每一個動作方法都進行配置,我們可以之配置一個,在這個actin中使用通配符來指定將要執行哪個方法。

<package name="default" namespace="/" extends="struts-default">

<action name="*User" class="action.UserAction" method="{1}">

<result name="input">/input.jsp</result>

<result name="success">success.jsp</result>

</action>

</package>

在UserAction中增加一個add方法,直接返回”input”,將input.jsp中form的action屬性修改為”saveUser.action”。我們在瀏覽器中測試一下:

直接訪問addUser.action,瀏覽器將會顯示信息輸入頁面,說明調用了UserAction中的add方法:

技術分享

技術分享

頁面提交到saveUser.action,調用了UserAction的save方法並呈現success結果頁面.

註:通配符的方式也可以應用在result標簽上。

(3)動態方法調用

除了上面介紹的方法,struts2中還有一種實現方法——動態方法調用。使用動態方法調用的格式為 action!method即使用”!”來連接我們配置的action和要執行的方法,使用這種方式我們不需要為acttion標簽指定method屬性。

<package name="default" namespace="/" extends="struts-default">

<action name="user" class="action.UserAction">

<result name="input">/input.jsp</result>

<result name="success">success.jsp</result>

</action>

</package>

然後我們要對input.jsp做一些修改,將form的action屬性修改為”user!save”:

<form action="user!save" method="post">

username : <input ype="text" name="userName"/><br/>

password :<input type="password" name="password"><br/>

<input type="submit" value="submit"/>

</form>

修改完成之後我們在瀏覽器中直接訪問http://localhost/action/user!add

技術分享

Input.jsp頁面被呈現,說明UserAction的add方法被調用。

技術分享

提交到user!save後success.jsp被呈現,說明UserAction的save方法被調用。

註意:對於使用通配符的方法來說,Struts2會認為我們將這些匹配到的方法就像是硬編碼在struts.xml中一樣,因此我們可以為這些進行匹配的action做一些其他處理,比如數據驗證、本地消息和類型轉換等。但是使用動態方法調用的方式,struts2知道我們調用了同一個action,只是執行了非execute方法,因此使用這種方式,這些動作方法都會共享一個Action的配置。所以從這個角度上來說,通配符的方式優於動態方法調用的方式。我們可以在struts.xml中通過配置來決定是否啟用動態方法調用。

<constant name="struts.enable.DynamicMethodInvocation"value="false"/>

向對象傳遞數據

上面我們接觸到的Action類都有一個共同的特性,那就是在action中使用屬性來接收請求中的參數。我們定義了一個User類,專門由於表示User實體,但是在我們的Action類中我們都是手動的new一個User實體對象,然後使用set方法將接收到的值設置到User實體對象上,那麽能不能直接使用User對象類接收請求中的參數,我們在動作方法中就可以直接操作User實體對象呢,答案是肯定的。實現的方式有兩種。

(1) 對象支持的javabean屬性

我們已經知道Strtus2中的params攔截器會自動將請求中的數據轉移到動作對象屬性上。那麽我們也可以直接使用實體對象作為動作對象的屬性,這樣Struts2就能自動將請求中的數據填充到我們的實體對象上。為了實現這個功能,我們需要在jsp頁面中多做一些工作:

[java] view plain copy print?
  1. public class UserAction extends ActionSupport{
  2. private User user;
  3. public User getUser() {
  4. return user;
  5. }
  6. public void setUser(User user) {
  7. this.user = user;
  8. }
  9. public String add() throws Exception {
  10. //僅用於顯示信息輸入頁面
  11. return INPUT;
  12. }
  13. //保存User
  14. public String save(){
  15. //將user的信息保存到數據庫
  16. //UserDao.save(user)
  17. return SUCCESS;
  18. }
  19. }

input.jsp

<form action="user!save" method="post">

username : <input type="text" name="user.userName"/><br/>

password :<input type="password" name="user.password"><br/>

<input type="submit" value="submit"/>

</form>

Success.jsp

<body>

hello ${user.userName }<br/>

your password is ${user.userName }

</body>

運行瀏覽器進行測試,其結果和前面的測試相同,頁面均能正常執行。

需要註意的是,我們的User對象並不需要我們手動實例化,Strtus2會自動實例化user,並且裝配上面的屬性。要實現這個功能,我們需要在結果視圖中明確指出Action類中的實體(域)對象。下面學習的第二種方法我們的jsp頁面可以不做任何改變,就和全部使用javabean一樣。

(1) ModelDriven動作

要使用ModelDriven動作需要我們的動作實現com.opensymphony.xwork2.ModelDriven接口,在該接口中定義了一個getModel方法,我們要在Action類中實現這個方法,並在其中將我們的域對象返回。該接口支持泛型。需要註意的就是我們在返回域對象時要確保這個域對象已經實例化了。

[java] view plain copy print?
  1. public class UserAction extends ActionSupport implements ModelDriven<User> {
  2. private User user = new User();
  3. public String add() throws Exception {
  4. // 僅用於顯示信息輸入頁面
  5. return INPUT;
  6. }
  7. public User getModel() {
  8. return user;
  9. }
  10. // 保存User
  11. public String save() {
  12. // 將user的信息保存到數據庫
  13. // UserDao.save(user)
  14. return SUCCESS;
  15. }
  16. }

要做的改變就是這些,結果視圖裏面和最初使用純JavaBean實現時相同。

運行瀏覽器進行測試,可以看到得出的結果和前面相同。其實現原理是通過攔截器來調用,查看defaultStack攔截器棧,會看到其中有一個ModelDriven攔截器:

<interceptor-stack ame="defaultStack">

<interceptor-ref name="exception"/>

<interceptor-ref name="alias"/>

<interceptor-ref name="servletConfig"/>

<interceptor-ref name="i18n"/>

<interceptor-ref name="prepare"/>

<interceptor-ref name="chain"/>

<interceptor-ref name="scopedModelDriven"/>

<interceptor-ref name="modelDriven"/>

<interceptor-ref name="fileUpload"/>

<interceptor-ref name="checkbox"/>

<interceptor-ref name="multiselect"/>

<interceptor-ref name="staticParams"/>

<interceptor-ref name="actionMappingParams"/>

<interceptor-ref name="params">

<param name="excludeParams">dojo\..*,^struts\..*</param>

</interceptor-ref>

<interceptor-ref name="conversionError"/>

<interceptor-ref name="validation">

<param name="excludeMethods">input,back,cancel,browse</param>

</interceptor-ref>

<interceptor-ref name="workflow">

<param name="excludeMethods">input,back,cancel,browse</param>

</interceptor-ref>

<interceptor-ref name="debugging"/>

</interceptor-stack>

這個攔截器在params攔截器之前,那麽會在參數傳遞到到Action對象上之前將通過getModel獲取到的域對象壓入valueStack中,以供params攔截器將參數設置上去。查看文檔可以知道modeldriven攔截器的實現類是com.opensymphony.xwork2.interceptor. ModelDrivenInterceptor

查看該攔截器的interceptor方法源碼:

public Stringintercept(ActionInvocation invocation)throws Exception {

Object action = invocation.getAction();

if (actioninstanceof ModelDriven) {

ModelDriven modelDriven =(ModelDriven) action;

ValueStack stack =invocation.getStack();

Object model =modelDriven.getModel();

if (model != null) {

stack.push(model);

}

if (refreshModelBeforeResult) {

invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven,model));

}

}

return invocation.invoke();

}

可以清晰看出這個攔截器對域對象所做的處理。從這裏也可以看出,我們的域對象必須先實例化,才能產生效果。

總結:雖然使用實體對象保存請求數據看起來比較不錯,不過在實際使用中還是直接使用javabean屬性接收數據的方式比較多,這種方式操作簡單,也比較容易控制。

Struts2 調用非execute方法