struts2簡明教程

不設限發表於2011-12-20
Struts2簡明教程


本教程整個過程中都以例子貫穿始終,輔助以解釋說明.


1.web.xml中配置struts2


要在專案中使用struts首先要在web.xml中把struts2配置進來,而struts2是作為filter被配置進來的
<filter>
    <filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>


<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>


2.設定開發模式<constant name="struts.devMode" value="true" />


對於開發階段的專案來說,把struts設定為開發模式有很大的好處,這樣就不需要每次修改了struts.xml檔案之後重新啟動容器了,容器會自動檢測struts.xml檔案的狀態,有了修改之後容器會自動的從新載入


3.配置struts2的包名,名稱空間


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


struts2的包名和名稱空間實際上只是一個代表符號,尤其是package的name屬性,其實完全可以不設定的,但是為了是檔案看起來更加的規範化,更加的容易理解,我們一般都是按照Action所在的src下的包的名字來命名的,而實際上namespace也最好遵循同樣的方式,這樣無論何時,程式看起來都非常的規範,而且看到了包名我們就知道它的名稱空間,就知道它在src目錄下所對應的包的位置,這種良好的習慣在開發大型的系統的時候將會顯示出巨大的好處,當然namespace並不是可有可無的,因為在你訪問某一個Action的時候,你必須要指定namespace,否則容器哪裡知道你要訪問哪一個Action呢?


4.配置Action


<package name="front" extends="struts-default" namespace="/">
        <action name="index" class="dada.test.FirstAction">
            <result name="success">/success.jsp</result>
        </action>
</package>


action的配置需要放在某一個package下面,這樣做的目的是為了解決不同包下的Action命名衝突的問題,而配置Action需要指定名字,和class的位置,method為可選選項,class的配置是以src目錄為根目錄進行配置的比如src目錄下有dada.test包,裡有FirstAction的Action,那麼你配置class的位置時就是:class="dada.test.FirstAction"為什麼呢?為什麼不把src給加進來呢?其實類似的問題還有就是webContent我們不用指明它是因為它們是被作為預設的位置的,程式找得時候就直接去它下面找的,這是一種大家都預設的規範,我們都遵循同樣的標準,,要不然你配在專案裡面再重新新增一個原始碼包,然後在裡面新增Action,這個時候在你把這個Action配置到struts.xml裡面的時候,你必須要把原始碼包的名字也帶上,否則程式肯定檢測不到,而且就返回結果來說它也是根據你Action裡面所呼叫方法返回值進行匹配的,比如返回的是success那麼就匹配success,實際上success不用配置,預設的沒有name屬性的result就是success


Action類的標準:


(1)具體檢視的返回可以由使用者自己定義的Action來決定
(1)具體的手段是根據返回的字串找到對應的配置項,來決定檢視的內容
(3)具體Action的實現可以是一個普通的java類,裡面有public String execute方法即可,或者實現Action介面
(4)不過最常用的是從ActionSupport繼承,好處在於可以直接使用Struts2封裝好的方法<br />


5.Action的路徑問題


struts2中的路徑問題是根據action的路徑而不是jsp路徑來確定,所以儘量不要使用相對路徑。
雖然可以用redirect方式解決,但redirect方式並非必要。
解決辦法非常簡單,統一使用絕對路徑。
使用:String path = request.getContextPath();獲取webapp的路徑
使用:String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";獲取基礎路徑


6.Action的方法指定


Action執行的時候並不一定要執行execute方法
(1)可以在配置檔案中配置Action的時候用method="xxx"來指定執行哪個方法
<package name="front" extends="struts-default" namespace="/">
        <action name="index" class="dada.test.FirstAction" method="add">
            <result name="success">/success.jsp</result>
        </action>
</package>


(2)也可以在url地址中動態指定(動態方法呼叫DMI)(推薦)
<a href="<%=context %>/user/user!add">新增使用者</a>
前者會產生太多的action,所以不推薦使用


7.萬用字元配置


(1)使用一個萬用字元


<action name="Student*" class="dada.action.StudentAction" method="{1}">
    <result>/Student{1}_success.jsp</result>
<result name="error">/Student{1}_error.jsp</result>
</action>


或者


<action name="*add" class="dada.action.{1}Action" method="add">
    <result>/{1}_add_success.jsp</result>
<result name="error">/{1}_add_error.jsp</result>
</action>


這兩種方式都是隻使用了一個萬用字元,它們的好處在於:
->前者可以動態的指定方法
->後者可以動態指定Action
但是畢竟還是不能完全實現對Action和方法的雙重的動態指定要實現就需要使用兩個萬用字元


(2)使用兩個萬用字元
<action name="*_*" class="com.bjsxt.struts2.action.{1}Action" method="{2}">
    <result>/{1}_{2}_success.jsp</result>
    <result name="error">/{1}_{2}_error.jsp</result>        
</action>


當你使用兩個或者更多個的時候,你就可以動態的指定Action的名字和方法的名字了,這種指定方式要求就是:
(1)所有的Action在同一個目錄下面(因為不在同一包裡面肯定不可以這麼寫的)
(2)所有的Action和返回的結果都要遵循同樣的命名的方式,比如Action的名字拿本例子來說都要遵循的是名字的後半部分都要以Action結尾,而返回的結果都要使用兩個"_"把動態指定的名字給分割開來,否則無法實現動態指定


(3)使用三個萬用字元


<action name="*_*_*" class="com.bjsxt.struts2.{1}.{2}Action" method="{3}">
    <result>/{2}_{3}_success.jsp</result>
</action>


如果你使用三個萬用字元的話,你就可以實現對包的動態指定了,不過雖然很動態,但是問題是這樣在真正使用的時候也會帶來問題,就是我們在實際訪問過程中要為每一個萬用字元指定對於的名稱的時候就會變得非常的麻煩,容易讓人暈頭轉向,實際上也沒有什麼反正從後往前推,第一個是包名,第二個是Action名,第三個是方法名,不過總體來看,使用兩個萬用字元就已經夠方便了,使用三個有可能會得不償失.


8.Action類的自動裝配


(1)一般屬性裝配,對於一般屬性的裝配,只需要在Action中提供被裝配屬性的get和set方法即可,在請求傳送過來的時候,strust會自動幫我們把屬性給賦值給Action裡面的屬性


請求URL寫法:url="<%=request.getContextPath()%>/dada/User_add?name=dada&age=23"


public class UserAction extends ActionSupport {

private String name;
private int age;

public String add() {
System.out.println("name=" + name);
System.out.println("age=" + age);
return SUCCESS;
}


public String getName() {
return name;
}


public void setName(String name) {
this.name = name;
}


public int getAge() {
return age;
}


public void setAge(int age) {
this.age = age;
}

}


(2)物件屬性裝配,對於一般屬性的裝配,只需要在Action中提供被裝配物件的get和set方法即可


注意Action物件屬性類的要求:


只要是重寫一個類的構造方法,就必須要為這個類保留空的構造方法  
因為框架預設的都會去呼叫無參的空的構造方法


被裝配物件(被裝配物件裡面的屬性也需要提供get和set方法,其實就是一種鏈式的get和set方法呼叫):
請求URL寫法:url=href="user/user!add?user.name=a&user.age=8"
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}


Action類
public class UserAction extends ActionSupport {

private User user;
public String add() {
System.out.println("name=" + user.getName());
System.out.println("age=" + user.getAge());
return SUCCESS;
}


public User getUser() {
return user;
}


public void setUser(User user) {
this.user = user;
}
}




9.編碼問題


<constant name="struts.i18n.encoding" value="UTF-8" />
使用這句話可以對編碼進行處理,但是問題是如果jsp頁面使用的是ISO-8859-1,就算你配置了這一句話也沒有用,具體也許可以通過一種方式轉換過來但是那畢竟還是麻煩,最簡單的辦法就是把所有用到了字元編碼的地方全部都設定成為UTF-8這樣你基本上就不會出現問題了.


10.簡單的資料驗證


Action類處理:


public class UserAction extends ActionSupport {
private String name;

public String add() {
if(name == null || !name.equals("admin")) {
this.addFieldError("name", "name is error");
this.addFieldError("name", "name is too long");
return ERROR;

return SUCCESS;
}


public String getName() {
return name;
}


public void setName(String name) {
this.name = name;
}
}


jsp接受:


返回jsp的錯誤資訊是以陣列的形式返回過來的


(1)使用<s:property value=""/>標籤直接的接受


<s:property value="errors.name[0]"/>


(2)使用<s:fielderror fieldName="name" theme="simple"/>標籤對結果的展現形式進行美化


<s:fielderror fieldName="name" theme="simple">
  <s:property value="errors.name[0]"/>
</s:fielderror>


11.Action中獲取request,session,application的方式


(1)
public class LoginAction1 extends ActionSupport {
private Map request;
private Map session;
private Map application;

public LoginAction1() {
request = (Map)ActionContext.getContext().get("request");
session = ActionContext.getContext().getSession();
application = ActionContext.getContext().getApplication();
}

public String execute() {
request.put("r1", "r1");
session.put("s1", "s1");
application.put("a1", "a1");
return SUCCESS; 
}
}


(2)
public class LoginAction2 extends ActionSupport implements RequestAware,SessionAware, ApplicationAware {

private Map<String, Object> request;
private Map<String, Object> session;
private Map<String, Object> application;


public String execute() {
request.put("r1", "r1");
session.put("s1", "s1");
application.put("a1", "a1");
return SUCCESS; 
}


@Override
public void setRequest(Map<String, Object> request) {
this.request = request;
}


@Override
public void setSession(Map<String, Object> session) {
this.session = session;
}


@Override
public void setApplication(Map<String, Object> application) {
this.application = application;
}
}


(3)
public class LoginAction3 extends ActionSupport {

private HttpServletRequest request;
private HttpSession session;
private ServletContext application;

public LoginAction3() {
request = ServletActionContext.getRequest();
session = request.getSession();
application = session.getServletContext();
}

public String execute() {
request.setAttribute("r1", "r1");
session.setAttribute("s1", "s1");
application.setAttribute("a1", "a1");
return SUCCESS; 
}
}


(4)
public class LoginAction4 extends ActionSupport implements ServletRequestAware {
private HttpServletRequest request;
private HttpSession session;
private ServletContext application;

public String execute() {
request.setAttribute("r1", "r1");
session.setAttribute("s1", "s1");
application.setAttribute("a1", "a1");
return SUCCESS; 
}


@Override
public void setServletRequest(HttpServletRequest request) {
this.request = request;
this.session = request.getSession();
this.application = session.getServletContext();
}
}


12.把struts.xml中包含其他配置檔案的方法


<struts>
    <include file="login.xml" />
</struts>


13.配置預設的Action在你沒有指定具體的Action的時候,程式自動跳轉到的Action


<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="index"></default-action-ref>
<action name="index">
<result>/default.jsp</result>
</action>
</package>


14.Action的返回型別


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

<action name="r1">
<result type="dispatcher">/r1.jsp</result>
</action>

<action name="r2">
<result type="redirect">/r2.jsp</result>
</action>

<action name="r3">
<result type="chain">r4</result>
</action>
<!-- chain和redirectAction的區別在於chain是伺服器端的跳轉而redirectAction是客戶端跳轉 -->

<action name="r4">
<result type="redirectAction">r2</result>
</action>
   
</package>


(1)結果型別中redirect和redirectAction的區別
redirect是在處理完當前Action之後,重定向到另外一個實際的物理資源
redirectAction也是重定向,但它重定向到的是另外一個Action
只要是重定向,那麼之前凡是儲存在request裡面的東西就全都消失了
因為重定向實際是傳送第二個請求,故請求中的東西也就不會出現在第二個請求裡面了
也就是說重定向是不共享request的東西,重定向後的頁面中無法接收request裡的東西
另外dispatcher結果型別的default屬性為TRUE,故<result-type/>預設為dispatcher
所以如果沒有設定type屬性的話,那麼預設的是請求轉發,即瀏覽器顯示的是*.action
但是在設定type="redirect"屬性後,就可以重定向了,即瀏覽器顯示的是/login2.jsp


(2)chain和redirectAction區別
Struts2的Action處理鏈
從一個Action跳轉到另一個Action,有兩種辦法,即將type設定為chain或者redirectAction
chain結果型別表示將多個Action作為一個鏈來處理
而使用chain和redirectAction的好處就是:它會按照框架的預設字尾去自動匹配字尾
而chain和redirectAction的區別與dispatcher和redirect的區別是一樣的
即同樣是跳轉到一個Action上,但chain是伺服器跳轉,而redirectAction是客戶端跳轉
伺服器跳轉的過程中,可以共享資料,這時後面的Action就可以接收前面Action中的屬性資訊進行二次處理


15.global-results


原理:它的作用就是在Action中返回了一個結果,可是這個結果卻在對應的Action或者是package裡面,沒有定義,可是它還是要去找的,這個時候就需要向上去查詢有沒有這個結果的定義了,本Action沒有向上一級,找,上一級沒有就去繼承的包裡面找,如果一直找不到那就出錯了


注意要使用:global-results需要把當前的包設定為:extends="struts-default",如果沒有這句話,那麼程式是不會去自動的去global-results裡面去匹配的,而且包之間是可以進行繼承的,子包可以使用父包裡面的global-results裡面的資源


<struts>
    <constant name="struts.devMode" value="true" />
    <package name="user" namespace="/user" extends="struts-default">  
   
    <global-results>
    <result name="mainpage">/main.jsp</result>
    </global-results>
   
    <action name="index">
    <result>/index.jsp</result>
    </action>
   
   <action name="user" class="dada.user.action.UserAction">
    <result>/user_success.jsp</result>
    <result name="error">/user_error.jsp</result>
   </action>    
    </package>
    
    <package name="admin" namespace="/admin" extends="user">
    <action name="admin" class="dada.user.action.AdminAction">
    <result>/admin.jsp</result>
    </action>
    </package>


</struts>


16.動態指定返回的結果


Action裡面的操作


public class UserAction extends ActionSupport {
private int type;
private String r;


public String getR() {
return r;
}


public void setR(String r) {
this.r = r;
}


public int getType() {
return type;
}


public void setType(int type) {
this.type = type;
}


@Override
public String execute() throws Exception {
if(type == 1) r="/user_success.jsp";
else if (type == 2) r="/user_error.jsp";
return "success";
}
}


配置檔案裡面的處理:


<package name="user" namespace="/user" extends="struts-default">
<!--這裡使用的也是OGNL表示式來獲取值的,而且這個時候就不需要你為它指定result的名字和型別了而是使用預設的success做為name-->
    <result>${r}</result>
   </action>    
</package>


這裡其實把變數r當做了一個屬性,因為它是可以被設定和獲取的,因此,當返回結果的時候,OGNL表示式就可以獲取它的值,然後返回動態的結果


注意點:獲取返回的結果時不要忘了"$"符號


17.三個路徑的區別


<a href="/test/a1?type=1">path1</a> 
瀏覽器中顯示:http://localhost:8080/test/index.jsp
解釋:"/"在url中代表的是當前的容器的路徑,所以顯示的路徑裡面就把當前專案的路徑給丟掉了


<a href="test/a1?type=2">path2</a>
瀏覽器中顯示:http://localhost:8080/Struts2_1700_DynamicResult_1/test/index.jsp
解釋:當url前面沒有"/"的時候預設的是加上當前的專案的根目錄


<a href="<%=request.getContextPath() %>/test/a1?type=2">path3</a>
瀏覽器中顯示:http://localhost:8080/Struts2_1700_DynamicResult_1/test/index.jsp
解釋:<%=request.getContextPath() %>獲取的是當前的專案所在的根目錄,後邊加上要訪問的Action的namespace和Action的名字


struts.xml result返回頁面的配置<result>/ognl.jsp</result>這個裡面使用了"/"這裡的"/"代表的是當前web應用的根目錄


18.返回帶引數的結果


後臺Action:


public class UserAction extends ActionSupport {
private int type;

public int getType() {
return type;
}


public void setType(int type) {
this.type = type;
}


@Override
public String execute() throws Exception {
return "success";
}
}


struts.xml檔案配置:


<struts>
    <constant name="struts.devMode" value="true" />
    <package name="user" namespace="/user" extends="struts-default">
   <action name="user" class="com.bjsxt.struts2.user.action.UserAction">
    <result type="redirect">/user_success.jsp?t=${type}</result>
   </action>    
    </package>    
</struts>


其實原理還是一樣的,跟 16 中所講述的動態指定返回結果是一樣的道理,都是使用的OGNL表示式的取值方法不再累述


19.OGNL表示式的使用
要使用OGNL表示式呼叫方法就需要在struts.xml中配置如下常量
<struts>
  <constant name="struts.enable.DynamicMethodInvocation" value="false" />
    <constant name="struts.devMode" value="true" />
    <constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
<package name="ognl" extends="struts-default" namespace="/ognl">
<action name="ognlAction" class="com.dada.test.OgnlAction">
<result>/ognl.jsp</result>
</action>

<action name="test" class="com.dada.test.TestAction">
<result type="chain">ognlAction</result>
</action>
</package>


</struts>    


使用OGNL表示式


<p>訪問值棧中的Action的普通屬性:username=<s:property value="username"/> </p>
  <p>訪問值棧中物件普通屬性(get,set方法):<s:property value="user.age"/>|<s:property value="user['age']"/>|<s:property value="user[\"age\"]"/> </p>
  <p>訪問值棧中物件普通屬性(get,set方法):<s:property value="cat.friend.name"/></p>
  <p>訪問值棧中物件普通方法:<s:property value="password.length()"/></p>
  <p>訪問值棧中物件普通方法:<s:property value="cat.miaomiao()"/></p>
  <p>訪問值棧中Action的普通方法:<s:property value="m()"/> </p>
  <hr/>
<!--兩個@之間的部分是類所在的位置第二個@後邊表示的是靜態的方法名字或者屬性名-->
  <p>訪問靜態方法:<s:property value="@com.dada.test.S@s"/> </p>
  <p>訪問靜態屬性:<s:property value="@com.dada.test.S@STR"/></p>
  <!-- 這裡之所以這麼寫是因為Math類在lang包裡面,所以不需要引入類名字 -->
  <p>訪問Math類靜態方法:<s:property value="@@max(2,3)"/></p>
  <hr/>
  <p>訪問普通類的構造方法:<s:property value="new com.dada.test.Dog(\"dog created by jsp\")"/></p>
  <hr/>
  <p>訪問List:<s:property value="users"/></p>
  <p>訪問List中的某一個元素:<s:property value="users[0]"/></p>
  <p>訪問List中的某一個屬性集合:<s:property value="users.{age}"/></p>
  <p>訪問List中的某一個屬性集合中的特定的值:<s:property value="users.{age}[0]"/>|<s:property value="users[0].age"/> </p>
 
  <p>訪問Set<s:property value="dogs"/> </p>
  <p>訪問Set中某一個元素:<s:property value="dogs[0].age"/>???好像這邊是有問題的 </p>
 
  <p>訪問Map:<s:property value="dogMap"/></p>
  <p>訪問Map中的某一個元素:<s:property value="dogMap.d1"/></p>
  <p>訪問Map中的所有Key:<s:property value="dogMap.keys"/></p>
  <p>訪問Map中的所有Key:<s:property value="dogMap.values"/></p>
  <p>訪問Map容器大小:<s:property value="dogMap.size()"/>|<s:property value="users.size()"/> </p>
 
  <hr/>
  <p>投影(過濾)<s:property value="users.{?#this.age==1}[0]"/></p>
  <p>投影:<s:property value="users.{^#this.age>0}.{age}"/></p>
  <p>投影:<s:property value="users.{$#this.age>1}.{age}"/></p>
  <p>投影:<s:property value="users.{$#this.age>1}.{age}==null"/></p>
 
  a.“?#”:投影(過濾)所有符合條件的集合,如:users.{?#this.age > 19};
b.“^#”:投影(過濾)第一個符合條件的元素,如:users.{^#this.age > 19};
c.“$#”:投影(過濾)最後一個符合條件的元素,如:users.{$#this.age > 19} 。
 
  <hr/>
  <p>[]:<s:property value="[0].username"/> </p>




20.strust theme設定


(1).在struts.xml中控制theme,預設為xhtml,可以設定為:simple/css_html/ajax


<ol>
<li>
<s:form >
<div class="formFieldError">
<s:fielderror />
</div>
<s:textfield name='aaa'></s:textfield>
</s:form>
</li>
</ol>


(2).用CSS控制顯示


<html>
<style type="text/css">
.formFieldError {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 12px;
color: #FF3300;
vertical-align: bottom;
}


.formFieldError ul {
/*list-style-type: none*/
    margin: 0px;
    padding: 3px;
    vertical-align: middle;
}


.formFieldError ul li{
list-style-type: none
   
}
</style>


</head>
<body>
<ol>
<li>
<s:form >
<div class="formFieldError">
<s:fielderror />
</div>
<s:textfield name='aaa'></s:textfield>
</s:form>
</li>
</ol>
</body>
</html>


(3).在struts.xml檔案中指定


<struts>
    <constant name="struts.ui.theme" value="simple" />
<package name="theme" extends="struts-default">
        <action name="theme" class="com.bjsxt.struts2.theme.ThemeAction">
            <result>/theme.jsp</result>
        </action>
    </package>
</struts>


(4).指定自己的css
    
<struts>
    <constant name="struts.ui.theme" value="mytheme" />
<package name="theme" extends="struts-default">
        <action name="theme" class="com.bjsxt.struts2.theme.ThemeAction">
            <result>/theme.jsp</result>
        </action>
    </package>
</struts>







































相關文章