<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><pre name="code" class="java">
學習了Struts2 中的Action,把常用到的地方記錄下來。Struts2的Action在MVC的設計模式中充當了controller的角色,用于接受參數,處理部分邏輯等,相當于Servlet。其部分使用講解如下:
一、Action的配置在struts.xml中進行Action的配置,具體可參看here。
二、Action的三種寫法(Action都要在struts中配置映射)
1、自己編寫普通的Java類來作為Action。
這裡在類中隻需要聲明一個傳回類型為String的public方法。
public void actionMethod(){
System.out.println("Action ActionMethod called!");
return success;
}
要注意的是,如果方法的名字不為execute,那麼要在struts.xml中的action節點配置method屬性(Action預設調用的方法)才可以調用到本方法,否則struts報找不到execute錯誤。
<action name="first" class="com.tas.strutslearn.Action1" method="<span style="font-family: Arial, Helvetica, sans-serif;">actionMethod</span>">
<result>/index.jsp</result>
</action>
2、編寫Java類并實作com.opensymphony.xwork2.Action接口,然後重寫execute方法。
package com.tas.strutslearn;
import com.opensymphony.xwork2.Action;
public class Action2 implements Action{
@Override
public String execute() throws Exception {
System.out.println("Action2 execute called!");
return SUCCESS;
}
}
3、編寫Java類并繼承com.opensymphony.xwork2.ActionSupport類,檢視ActionSupport源碼可知,本類實作了Action接口,并實作了一些其他的方法,是以在通常的使用中,會采取這種方法來編寫Action。
package com.tas.strutslearn;
import com.opensymphony.xwork2.ActionSupport;
public class Action3 extends ActionSupport{
@Override
public String execute() throws Exception {
System.out.print("Action3 execute called!!");
return SUCCESS;
}
}
三、 Action的動态方法調用
如果一個Action中有多個方法,如下:
package com.tas.strutslearn;
import com.opensymphony.xwork2.ActionSupport;
public class Action3 extends ActionSupport{
@Override
public String execute() throws Exception {
System.out.print("Action3 execute called!!");
return SUCCESS;
}
public String delete(){
System.out.print("Action3 delete called!!");
return SUCCESS;
}
public String add(){
System.out.print("Action3 add called!!");
return SUCCESS;
}
}
那麼如果指定調用哪個方法呢?以前我都是采用的在struts.xml中配置多個Action,用method區分的方法來實作:
<!-- 調用Action3的delete方法 -->
<action name="thirddelete" class="com.tas.strutslearn.Action3" method="delete">
<result>/index.jsp</result>
</action>
<!-- 調用Action3的add方法 -->
<action name="thirdadd" class="com.tas.strutslearn.Action3" method="add">
<result>/index.jsp</result>
</action>
在struts2中,還有一種方法可以實作,那就是“動态方法調用”,解決了一個Action有多個請求需要配置太多的問題。使用如下:
(1)在struts中配置常量
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
這個常量在struts2-core-2.3.4.jar/org.apache.struts2/default.properties中可以找到,發現其預設為true,是以這個常量一般不用配置(為false則關閉了動态方法調用)
(2)通路時隻需要在通路路徑後+“!方法名”即可,如下:
如我這裡通路http://localhost:8080/002_struts2.3.4_ActionUse/third!add就可以看到方法add被調用。
注意:我們知道,早package節點配置namespace屬性的時候,如果配置成“/”或“”,則在通路的路徑中action前加上什麼都可以通路到如http://localhost:8080/002_struts2.3.4_ActionUse/sdfsdf/dsdf//third。可是如果在這些東西中有!的話,那麼struts2會認為這是動态方法調用,就會報錯。是以官網上邊還是不推薦使用動态方法調用這種辦法。好在2.3.4版本及以後版本修複了本bug,是以,如果你使用的是2.3.4版本以前的版本,請盡量不要使用動态方法調用。
四、Action使用通配符的通路方式
通過第三部分我們發現,方法太多的時候,使用單個method屬性配置麻煩,使用動态方法調用的方式又可能不安全,struts2提供了第三種方法--通配符比對通路。通配方式不用多說,就是按照順序出現的*和後面的按順序的數字相比對。
(1)struts.xml如下
<action name="third_*" class="com.tas.strutslearn.Action3" method="{1}">
<result>/index.jsp</result>
</action>
通路時輸入http://localhost:8080/002_struts2.3.4_ActionUse/third_delete。則通路了delete方法。
(2)struts.xml如下
<action name="*_*" class="com.tas.strutslearn.{1}" method="{2}">
<result>/index.jsp</result>
</action>
通路時輸入http://localhost:8080/002_struts2.3.4_ActionUse/Action3_add則通路了add方法。
其他的比對方式自己想想就可以寫出來。
五、預設的Action
如果在浏覽器上亂輸入位址,如http://localhost:8080/002_struts2.3.4_ActionUse/sdfsfdsd/dfsdf,struts肯定會找不到“Action dfsdf的,這時,如果配置了預設的action,則不會報出錯誤,頁面會跳轉到預設的Action上邊去。預設的action節點屬性為<default-action-ref>
struts.xml
<default-action-ref name="error"></default-action-ref>
<action name="error">
<result>/error.jsp</result>
</action>
這樣,當找不到action的時候就會跳轉到error.jsp中去。 需要注意的是<default-action-ref> 節點必須放在error的前面(直接就作為namespace下的第一個節點吧),否則會報錯。
六、Action的參數傳遞
這部分是struts2的重點。
(1)第一種方式是通過屬性的驅動。
action寫法如下:
package com.tas.strutslearn;
import java.util.Date;
import com.opensymphony.xwork2.ActionSupport;
public class UserAction extends ActionSupport{
private String username;
private String password;
private int age;
private Date birthday;
public void setUsername(String username) {
System.out.println("UserAction setUsername called!!");
this.username = username;
}
public void setPassword(String password) {
System.out.println("UserAction setPassword called!!");
this.password = password;
}
public void setAge(int age) {
System.out.println("UserAction setAge called!!");
this.age = age;
}
public void setBirthday(Date birthday) {
System.out.println("UserAction setBirthday called!!");
this.birthday = birthday;
}
@Override
public String execute() throws Exception {
// TODO Auto-generated method stub
return super.execute();
}
public String getUser(){
System.out.println("username:"+username);
System.out.println("password:"+password);
System.out.println("age:"+age);
System.out.println("birthday:"+birthday);
return SUCCESS;
}
}
表單的寫法如下:
<form action="/002_struts2.3.4_ActionUse/user_getUser" method="post">
使用者名:<input type="text" name="username"><br>
密 碼:<input type="password" name="password"><br>
年 齡:<input type="text" name="age"><br>
生 日:<input type="text" name="birthday"><br>
<input type="submit" value="送出">
</form>
表單的元素的name屬性一定要和Action中的屬性名稱一緻。運作過程如下
可以看到其中的屬性都是通過屬性對應的set方法設定上去的,是以在Action中必須要寫上屬性的set方法。
(2)模型驅動
第一種通過屬性驅動的方式,我們可以看到這種方式不利于軟體項目的分層,面向對象的設計應該是盡量地将屬性封裝起來。
這種方式需要實作接口ModelDriven<User>,UserAction1.java(User類的建立省略):
package com.tas.strutslearn;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.tas.strutslean.entity.User;
public class UserAction1 extends ActionSupport implements ModelDriven<User>{
private User user;
@Override
public String execute() throws Exception {
// TODO Auto-generated method stub
return super.execute();
}
public String getUserInf(){
System.out.println("username:"+user.getUsername());
System.out.println("password:"+user.getPassword());
System.out.println("age:"+user.getAge());
System.out.println("birthday:"+user.getBirthday());
return SUCCESS;
}
@Override
public User getModel() {
if(user==null){
user = new User();
}
return user;
}
}
user.jsp:
<form action="/002_struts2.3.4_ActionUse/user_getUserInf" method="post">
使用者名:<input type="text" name="username"><br>
密 碼:<input type="password" name="password"><br>
年 齡:<input type="text" name="age"><br>
生 日:<input type="text" name="birthday"><br>
<input type="submit" value="送出">
</form>
由此可以發現,User對象的建立已交由getModel方法執行。
(3)現在問題來了,屬性驅動麻煩,這種ModelDriver由隻能實作一個對象的資料傳遞,所有都還是有缺陷,是以需要第三種方法:
UserBookAction.java:
package com.tas.strutslearn;
import com.opensymphony.xwork2.ActionSupport;
import com.tas.strutslean.entity.Book;
import com.tas.strutslean.entity.User;
public class UserBookAction extends ActionSupport{
private User user;
private Book book;
public User getUser() {
System.out.println("UserBookAction getUser called!!");
return user;
}
public void setUser(User user) {
System.out.println("UserBookAction setUser called!!");
this.user = user;
}
public Book getBook() {
System.out.println("UserBookAction getBook called!!");
return book;
}
public void setBook(Book book) {
System.out.println("UserBookAction setBook called!!");
this.book = book;
}
public String getUserBookInf(){
System.out.println("username:"+user.getUsername());
System.out.println("password:"+user.getPassword());
System.out.println("age:"+user.getAge());
System.out.println("birthday:"+user.getBirthday());
System.out.println("author:"+book.getAuthor());
System.out.println("bookname:"+book.getBookname());
return SUCCESS;
}
}
表單:
<form action="/002_struts2.3.4_ActionUse/userbook" method="post">
使用者名:<input type="text" name="user.username"><br>
密 碼:<input type="password" name="user.password"><br>
年 齡:<input type="text" name="user.age"><br>
生 日:<input type="text" name="user.birthday"><br>
作 者:<input type="text" name="book.author"><br>
書 名:<input type="text" name="book.bookname"><br>
<input type="submit" value="送出">
</form>
運作程式如下:
通過結果我們可以發現struts給傳遞對象并封裝的過程:是否存在對象--》不存在new一個--》指派一個屬性--》擷取對象--》指派第二個屬性--》擷取對象。。。。
補充:(1)我們并沒有設定程式的編碼為中文,可是我們表單送出上來的資料沒有亂碼,這個是怎麼做到的呢?這個也是struts已經設定好了的,在default.properties(目錄上面有圖)中可以看到有常量struts.i18n.encoding=UTF-8。
(2)我們傳遞過來的參數隻是String,可是到了背景卻變成了int,Date等,這個也是由struts處理好了的。再也不用像Servlet裡的那樣,要request.getParameter()擷取屬性,然後再轉換類型。
寫完了,我現在好開心。