struts2教程&實例


1.第一個struts2項目

參考官方配置 http://struts.apache.org/getting-started/

github地址:https://github.com/unbelievableme/maven_hibernate-struts-spring/tree/master/struts2/first

建議:參考官方配置操作一遍,因為技術不斷更新,不同版本的struts的類可能不同,老版本的多個類可能在新版本中集成了一個

2.struts2工作流程原理

2.1步驟

1.創建Web Project

2.導入Jar(使用maven控制的話,配置pom.xml)

3.在web.xml配置struts2的過濾器

<filter>
       <filter-name>struts2</filter-name>
<!--該類會因struts版本不同而變化,在struts2.0-2.1.2為org.apache.struts2.dispatcher.FilterDispatcher,在之后版本為下述-->       
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
       <filter-name>struts2</filter-name>
       <!-- 所有的url都會被url過濾器解析 -->
       <url-pattern>/*</url-pattern>
    </filter-mapping>

 

4.創建Struts核心xml文件

5.創建action類繼承與ActionSupport

6.配置struts.xml

<!--詳細配置及介紹見:http://www.cnblogs.com/kundeg/p/7188699.html-->

2.2流程

1、客戶端瀏覽器發出HTTP請求

2、該請求被StrutsPrepareAndExecuteFilter接收

3、根據struts.xml配置,找到需要調用的Action類和方法, 並通過IoC方式,將值注入給Aciton

4、Action調用業務邏輯組件處理業務邏輯

5、Action執行完畢,根據struts.xml中的配置找到對應的返回結果result,並跳轉到相應頁面

6、返回HTTP響應到客戶端瀏覽器

2.3原理

 

 注意:在struts2.1.2后FilterDispatcher被替換為了StrutsPrepareAndExecuteFilter

1、 客戶端初始化一個指向Servlet容器(例如Tomcat)的請求

2、 這個請求經過一系列的過濾器(Filter)(這些過濾器中有一個叫做ActionContextCleanUp的可選過濾器,這個過濾器對於Struts2和其他框架的集成很有幫助,例如:SiteMesh Plugin)

3、 接着被StrutsPrepareAndExecuteFilter(能夠攔截請求對象ServletRequest和ServletResponse結合Struts.xml構建獨立於servlet的ActionContxt)調用,StrutsPrepareAndExecuteFilter詢問ActionMapper(含有struts.xml中Action配置的name,namespce,result等的HashMap)來決定這個請是否需要調用某個Action

4、 如果ActionMapper決定需要調用某個Action,StrutsPrepareAndExecuteFilter把請求的處理交給ActionProxy

5、 ActionProxy通過Configuration Manager詢問框架的配置文件struts.xml,找到需要調用的Action類

6、 ActionProxy創建一個ActionInvocation的實例。

7、 ActionInvocation實例使用命名模式來調用,在調用Action的過程前后,涉及到相關攔截器(Intercepter)的調用。

8、 一旦Action執行完畢,ActionInvocation負責根據struts.xml中的配置找到對應的返回結果。返回結果通常是(但不總是,也可 能是另外的一個Action鏈)一個需要被表示的JSP或者FreeMarker的模版。在表示的過程中可以使用Struts2 框架中繼承的標簽。在這個過程中需要涉及到ActionMapper

3.攔截器介紹

3.1Interceptor基礎介紹

攔截器基礎介紹以及與過濾器的對比見StrutsPreparedAndExcuteFilter與Interceptor

3.2 計時攔截器實例

 TimerAction.java

public class TimerAction extends ActionSupport{
  public String excute(){
      //下面為耗時代碼段
      int sum = 0;
      for(int i =0;i<10000;i++){
          sum+=i;
      }
      return SUCCESS;
  }
}

TimerInterceptor.java

public class TimerInterceptor extends AbstractInterceptor{
public String intercept(ActionInvocation invocation) throws Exception {
     //1.執行action之前
    long start = System.currentTimeMillis();
    //2.執行下一個攔截器,如果已經是最后一個攔截器,則執行目標Aciton
    String result = invocation.invoke();
    //3.執行Action之后
    long end = System.currentTimeMillis();
    System.out.println("執行Action花費時間:"+(end-start+"ms"));
    return result;
}
}

struts.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">

<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="true" />  
    <package name="/" extends="struts-default" strict-method-invocation="false">
             <!--注冊攔截器-->
     <interceptors>
     <interceptor name="myTimer" class="Interceptor.TimerInterceptor"> </interceptor>
     </interceptors>
        <action name="TimerAction" method="excute" class="action.TimerAction"> 
            <result name="success">/success.jsp</result>
            <!-- 引用攔截器 -->
            <interceptor-ref name="myTimer"></interceptor-ref>
        </action>
    </package>
</struts>

項目路徑(maven管理):

4.深入struts

4.1 Action搜索順序

http://localhost:8080/struts2/path1/path2/path3/student.action

第一步:判斷package是否存在,如:path1/path2/path3/

第二步:如果package存在,則判斷該package中action是否存在,如果不存在則去默認namespace的package里面尋找action

第三步:如果package不存在,檢查上一級路徑的package是否存在(直到默認namespace),重復第一步 第三步:如果沒有則報錯

4.2 動態方法調用

目的:一個action對應多個請求的處理,避免action過多

舉例:下述為類為action.helloworld的action,該action可以處理請求../add.action和../update.action,下面介紹動態調用的幾種常見方法

public class helloworld extends ActionSupport{
public String add(){
    /*  */
    return SUCCESS;
}
public String update(){
    /*  */
    return SUCCESS;
}
}

4.2.1 method方法

在struts.xml中的配置如下:

<struts>
   <package name="defalut" extends="struts-default">
        <action name="addAction" class="action.helloworld" method="add"> 
            <result name="success">/add.jsp</result>
        </action>
        <action name="updateAction" class="action.helloworld" method="update">
            <result name="success">/update.jsp</result>
        </action>
    </package>
</struts>

   訪問方式:http://localhost:8080/工程名/addAction.action(addAction可以換成updateAction)

   缺點:當一個action中方法過多的時候哦,配置過於冗余

4.4.2 感嘆號方式

修改entity為:   

public class helloworld extends ActionSupport{
public String add(){
    /*  */
    return "add";
}
public String update(){
    /*  */
    return "update";
}
}

 在struts.xml中配置如下

<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="true" />  
    <package name="default" extends="struts-default" strict-method-invocation="false">
        <action name="helloworldAction" class="action.helloworld"> 
<!--result的name屬性值和action.helloworld類中方法處理的返回值相同-->
            <result name="add">/add.jsp</result>
            <result name="update">/update.jsp</result>
        </action>
    </package>
</struts>

  訪問方式:http://localhost:8080/工程名/helloworldAction!add.action(!后面的add表示方法,可以換成update)

4.4.3 通配符方式(推薦使用)

在struts.xml中配置如下

<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="true" />  
    <package name="default" extends="struts-default" strict-method-invocation="false">
<!--{1}表示*的內容-->
        <action name="helloworld_*" method="{1}" class="action.helloworld"> 
            <result name="success">/{1}.jsp</result>
        </action>
    </package>
</struts>

  或者如下:

<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="true" />  
    <package name="default" extends="struts-default" strict-method-invocation="false">
<!--{1}代表第一個*的內容,{2}代表第二個*的內容-->
        <action name="*_*" method="{2}" class="action.{1}"> 
            <result name="success">/{2}.jsp</result>
        </action>
    </package>
</struts>

  訪問方式:http://localhost:8080/工程名/helloworld_add.action(add表示方法)

4.3 指定多個配置文件

目的:為了解決在struts.xml中配置過多,或者為了在不同的xml中配置實現更好的分類

要求:多個xml配置都必須遵守struts的dtd規范,同時要注意編碼方式要相同

舉例:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
    <constant name="struts.devMode" value="true" />
   <package name="/" extends="struts-default">
        <action name="index">
            <result>/index.jsp</result>
        </action>
        <action name="hello" class="action.hello" method="execute">
            <result name="success">/HelloWorld.jsp</result>
        </action>
    </package>
</struts>

 可以用下述兩個xml文件來表示:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
    <constant name="struts.devMode" value="true" />
    <include file="helloworld.xml"></include>
</struts>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
    <package name="/" extends="struts-default">
        <action name="index">
            <result>/index.jsp</result>
        </action>
        <action name="hello" class="action.hello" method="execute">
            <result name="success">/HelloWorld.jsp</result>
        </action>
    </package>
   </struts>

4.4 默認Action(主要討論通配符配置方式)

目的:為了改進用戶體驗,解決http404和500錯誤(不能完全解決)

舉例 :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">

<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="true" />  
    <package name="/" extends="struts-default" strict-method-invocation="false">
    <default-action-ref name="index"></default-action-ref>
       <action name="index">
       <result>/error.jsp</result>
    </action>
        <action name="helloworld_*" method="{1}" class="action.helloworld"> 
            <result name="success">/{1}.jsp</result>
        </action>
    </package>
</struts>

注意:非默認action的name屬性值一定不要以*為開頭進行通配。否則錯誤的action地址不能由默認action進行響應處理,會進入以*開頭的action。

缺點:但即使是不以*開頭的action也存在與它匹配的但工程中不存在的action地址,例如在上述配置的基礎上訪問http://localhost:8080/工程名/helloworld_ad.action還是會出現異常界面(下圖所示)。

 

解決:通過method配置可以完全解決404或500錯誤,感嘆號方式不行(不再詳述)

4.4 struts后綴 

目的:為了看起來xx,比如訪問xx.html很容易以為靜態頁面,掩蓋了本質:經過action處理跳轉后的jsp頁面

配置方式(三種):

1.在struts.xml中加上

<constant name="struts.action.extension" value="action,do,struts2"></constan

2.在struts.properties中加上

struts.action.extension=action,do,struts2

3.在web.xml中加上

  <filter>
       <filter-name>struts2</filter-name>
       <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
<!--添加內容-->
  <init-param>
  <param-name>struts.action.extension</param-name>
  <param-value>do,action,strtus2</param-value>
</init-param>
    </filter>
    <filter-mapping>
       <filter-name>struts2</filter-name>
       <url-pattern>/*</url-pattern>
    </filter-mapping>

4.5 struts傳參

4.5.1 直接用Action屬性

下列代碼依次為:前端jsp,后台action(省略struts.xml配置)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="./login.action" method="post">
用戶名:<input name="username" type="text"><br>
密碼:   <input name="password" type="password"><br>
<input type="submit" value="登陸">
</form>
</body>
</html>
View Code
public class User extends ActionSupport{
 private String username;

 public String excute(){
     System.out.println(username);
     return SUCCESS;
 }
 
public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
    
}
}
View Code

4.5.2 DomainModel

下列代碼依次為:前端jsp,后台Action,實體類model

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="./login.action" method="post">
<!-- 要指明那個對象的object.xxx -->
用戶名:<input name="user.username" type="text"><br>
密碼:   <input name="user.password" type="password"><br>
<input type="submit" value="登陸">
</form>
</body>
</html>
View Code
public class loginAction extends ActionSupport{
private User user;
public String excute(){
    System.out.println(user.getUsername());
    return SUCCESS;
}
public User getUser() {
    return user;
}
public void setUser(User user) {
    this.user = user;
}
 
}
View Code
public class User extends ActionSupport{
 private String username;
 private String password;
public String getUsername() {
    return username;
}
public void setUsername(String username) {
    this.username = username;
}
public String getPassword() {
    return password;
}
public void setPassword(String password) {
    this.password = password;
}
}
View Code

4.5.3 ModelDriven

同上

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="./login.action" method="post">
用戶名:<input name="username" type="text"><br>
密碼:   <input name="password" type="password"><br>
<!-- 為后台list傳參 -->
愛好 1:  <input name="hobby[0]" type="text"><br>
愛好 2:   <input name="hobby[1]" type="text"><br>
<input type="submit" value="登陸">
</form>
</body>
</html>
View Code
public class loginAction extends ActionSupport implements ModelDriven<User>{
private User user = new User();
public String excute(){
    System.out.println(user.getUsername());
    System.out.println(user.getHobby().get(0));
    System.out.println(user.getHobby().get(1));
    return SUCCESS;
}
 public User getModel() {
        // TODO Auto-generated method stub
        return user;
    }
}
View Code
public class User extends ActionSupport{
 private String username;
 private String password;
 private List<String> hobby;
public List<String> getHobby() {
    return hobby;
}
public void setHobby(List<String> hobby) {
    this.hobby = hobby;
}
public String getUsername() {
    return username;
}
public void setUsername(String username) {
    this.username = username;
}
public String getPassword() {
    return password;
}
public void setPassword(String password) {
    this.password = password;
}
}
View Code

4.6 result

4.6.1Action中五種內置屬性(com.opensymphony.xwork2.Action)

1. SUCCESS Action正確的執行完成,返回相應的視圖,success是name屬性的默認值。

2. NONE 表示Action正確的執行完成,但並不返回任何事視圖。

3. ERROR 表示Action執行失效,返回錯誤處理視圖。

4. LOGIN Action因為用戶沒有登錄的原因沒有正確執行,將返回該登錄視圖,要求用戶進行登錄驗證

5. INPUT Action的執行,需要從前端界面獲取參數,INPUT就是代表這個參數輸入界面,一般在應用中,會對這些 參數進行驗證,如果驗證沒有通過,將自動返回該視圖。

注意:內置屬性的意思是說可以直接return,不需要加上引號,內置屬性可以方便標識與說明,除此之外action在執行過程中可能內部return內置屬性進行跳轉,下述Input實例說明了這點。

4.6.2 Input實例

代碼(依次為前端jsp,后台action,實體類entity,struts.xml):

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="./login.action" method="post">
用戶名:<input name="username" type="text"><br>
密碼:   <input name="password" type="password"><br>
<!-- 為后台list傳參 -->
愛好 1:  <input name="hobby[0]" type="text"><br>
愛好 2:   <input name="hobby[1]" type="text"><br>
年齡:<input name="age" type="text"><br>
<input type="submit" value="登陸">
</form>
</body>
</html>
View Code
public class loginAction extends ActionSupport implements ModelDriven<User> {
    private User user = new User();

    public String excute() {
        System.out.println(user.getUsername());
        System.out.println(user.getHobby().get(0));
        System.out.println(user.getHobby().get(1));
        System.out.println(user.getAge());
        return SUCCESS;
    }

    public User getModel() {
        return user;
    }

    public void validate() {
//如果不顯式添加return INPUT,下述代碼段必須放在validat函數內
       if(user.getUsername()==null||"".equals(user.getUsername())){
            this.addFieldError("username", "用戶名不能為空");
       }
    }
}
View Code
public class User extends ActionSupport{
 private String username;
 private String password;
 private int age;
 private List<String> hobby;
public List<String> getHobby() {
    return hobby;
}
public void setHobby(List<String> hobby) {
    this.hobby = hobby;
}
public int getAge() {
    return age;
}
public void setAge(int age) {
    this.age = age;
}
public String getUsername() {
    return username;
}
public void setUsername(String username) {
    this.username = username;
}
public String getPassword() {
    return password;
}
public void setPassword(String password) {
    this.password = password;
}
}
View Code
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
    <package name="/" extends="struts-default" strict-method-invocation="false">
        <action name="login" method="excute" class="action.loginAction"> 
            <result name="success">/success.jsp</result>
            <result name="input">/login.jsp</result>
        </action>
    </package>
</struts>
View Code

測試:

                   

                      圖一                                                               圖二                                                       圖三

1.圖一可以通過action驗證返回success,跳轉到success.jsp頁面

2.圖二不可以通過action驗證,返回login.jsp頁面,因為前端傳入的age屬性為String類型與后台age的int類型不符,雖然沒有顯示判斷,但系統會自動檢查並return Input

3.圖三不可以通過action驗證,返回login.jsp頁面,因為前端的username為空后,台有關於username的判斷。

本質:

Action類的父類ActionSupport中有一個收集錯誤信息的容器Map,錯誤信息是名稱fieldName和描述信息errorMessage的鍵值對,只要該Map中有值表示校驗不通過,返回INPUT,系統可以自動addFileError("",""),也可以手動添加

4.6.3 result-type屬性(chain,redirect,dispatcher)

   type的默認值為dispatcher(請求轉發),其他常用見的有三個:chain,redirect,plaintext。

1、chain:將action和另外一個action鏈接起來,result屬性取action名字但是不要action后綴

 <package name="students" namespace="/students" extends="struts-default" strict-method-invocation="false">
        <action name="*_*" method="{2}" class="action.{1}Action">
        <result name="Students_query_success">/students/Students_query_success.jsp</result>
        <!-- chain相當於內部轉發,下述實例去執行action.StudentsAction的query方法 -->
        <result name="delete_success" type="chain">Students_query</result>
        </action>
    </package>

2、redirect:重定向(重新發起一次請求,原來的請求數據會丟失)

3、plaintext:返回網頁源代碼

4、stream:返回inputstream用於文件下載

注意:chain和dispatcher都屬於服務器內部轉發,這些轉發默認不經過filter(即轉發的action請求將無法響應)

原因:filter默認過濾來自客戶端的符合url-pattern的請求而內部轉發不在此范疇內

解決:因此使用這些type需要在web.xml中增加配置(如下)。

 <filter-mapping>
       <filter-name>struts2</filter-name>
       <!-- 所有的url都會被url過濾器解析 -->
       <url-pattern>/*</url-pattern>
<!--forward表示只過濾內部轉發的請求-->
       <dispatcher>FORWARD</dispatcher>
<!--request表示只過濾客戶端的請求-->
       <dispatcher>REQUEST</dispatcher>
    </filter-mapping>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM