Struts2 技術全總結 (正在更新)

背景:Struts1是一個高度成熟的框架,運行效率高,但其致命缺陷在於與JSP/Servlet的耦合很是緊密,於是致使了一些嚴重問題。其次,Struts1與Servlet API的嚴重耦合,使應用難以測試;Struts1代碼嚴重依賴Struts1 API,屬於侵入式框架。因爲其種種侷限性,纔有了Struts2的誕生。html

Struts2與1差異巨大,Struts2以WebWork爲核心,採用攔截器的機制處理用戶請求,這樣的設計使業務邏輯控制器與Servlet API徹底脫離開。java

Part 1  Struts2快速入門web

 1. 安裝與配置apache

 下載struts-2.3.15.1-all.zip,這裏採用該版本,打開後有文件夾:apps 實例代碼 ,docs 幫助文檔,lib jar包,src 源代碼文件;瀏覽器

 2.開始寫項目tomcat

1.添加jar包;(可直接複製實例項目,複製jar)安全

2.在web.xml中加入struts2的 filter ,內容以下:服務器

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9",version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www/w3/org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
     <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>

     <welcome-file-list>
            <welcome-file>index.html<welcome-file>
     </welcome-file-list>
</web-app>

 

從配置文件中,能夠看出, Struts2 其實就是一個filtersession

3.在src文件夾下添加struts.xml配置文件架構

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

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

 

4. 寫jsp頁面,或html頁面;寫java bean, action, dbutils(此實例爲簡明,省略了這些內容);

最簡單的示例,在web文件夾下寫 index.jsp

<%@page language="java" import="java.util.*" pageEncoding="UTF-8">
<%
String path=request.getContextPath();
String basePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
   <head>
        <base href="<%=basePath%>">
        <title>My JSP 'index.jsp' starting page</title>
   </head>
    <body>
            First One
     </body>
</html>

 

測試:部署tomcat或直接使用preview server,http://localhost:port/項目名/index.adtion

注意, .action 

 

Part 2  Struts2工做流程和核心概念

Struts2使用了WebWork的設計核心(XWork),在內部使用攔截器處理用戶請求,從而容許用戶業務邏輯控制器和ServletAPI分離。Struts2內部是一個MVC架構,Struts2 的核心控制器是FilterDispatcher,客戶端發送請求,而通過核心控制器FilterDispatcher處理,根據頁面發送的請求,從而肯定請求的是哪一個action,而action是MVC中的Model,最後肯定返回哪一個頁面(html或jsp)

具體工做流程:

(1)瀏覽器發送請求;

(2)核心攔截器FilterDispatcher根據請求決定調用合適的action;

(3)攔截器自動對應運用通用功能;

(4)回調用action上的execute()方法;

(5)action的execute()方法處理信息結果輸出到瀏覽器。

 

2)核心概念:當瀏覽器發送請求到Servlet容器時,會經歷一系列Filter過濾器,這些過濾器包括ActionContextCleanUp,接着FilterDispatcher被調用,經過參考ActionMapper決定一個請求和一個Action關聯。FilterDispatcher參考框架的配置文件管理,ActionProxy生成一個ActionInvocation,它負責執行命令,並負責查找適當的結果以和struts.xml中的action result相比較,調用一個在JSP或FreeMarker中繪製的模板。而Action是須要與struts.xml配置文件一塊兒結合使用的,下面將詳細講述配置文件使用:

    [1] struts.xml文件配置

       先來個實例:

login.jsp

<%@page language="java" import="java.util.*" pageEncoding="utf-8"%>

<%
String path=request.getContextPath();
String basePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
   <head>
     <base href="<%=basePath%>">
     <title></title>
   </head>
   <body>
        <form action="login" method="post"> 
         用戶名:<input type="text" name="uname"></br>
         密碼:<input type="password" name="pwd"></br>
         <input type="submit" value="登陸">
       </form>
   </body>
</heml>

LoginAction類

public class LoginAction{
   private String uname;
   private String pwd;
   public String getUname(){
      return uname;
   }
   public void setUname(String uname){
       this.uname=uname;
   }
   public String getPwd(){
      return pwd; 
   }
   public void setPwd(String pwd){
      this.pwd=pwd;
  }
  public String excute(){
      if("JokerJason".equals(uname)&&"12345".equals(pwd)){
          return "success";
      }
          return "fail";
  }
}          

注意:在上述LoginAction中,屬性uname和pwd必須和頁面保持一致,這是由於在Struts2中提供屬性參數及set/get方法經過ioc的方式將頁面參數注入到Action類裏。

寫完Action類,對其進行配置,在src目錄下建立struts.xml文件,以下

<struts>
  <package name="default" namespace="/" extends="struts-default">
      <action name="login" class="LoginAction">
           <result name="success">success.jsp</result>
           <result name="fail">fail.jsp</result>
     </action>
   </package>
</struts>

              (1)package: 包在java中是用來分類的,在Struts2中,也是用來分類的,在Struts2的配置文件中,一個文件能夠有多個包;

                                 package有不少屬性,name是包名,namespace是命名空間,若是訪問一個Action,則必定要是namespace+actionname;

                                 如本例中,要訪問LoginAction,則必須是:http://localhost:8080/項目名/login;最後的login就是namespace+action;

                                 extends指定繼承哪一個Struts的組件,一般都是繼承struts-default才能使用Struts中組件。固然若是想使用JSON,就須要繼承JSON-default;

              (2)action:action是核心控制器FilterDispatcher將要訪問的具體action,name指定的是action的名稱,class指定的是具體類名,一般是包名+類名;

              (3)result:指的是返回的結果頁面,name指定返回結果,在實際路徑頁面中必定要加"/"

   [2]Action對象詳解

  Struts2中Action無須實現任何接口和任何類型,可是爲了方便實現Action,大多數狀況下采用下面兩種方式對Action進行處理:

        (1)繼承com.opensymphony.xwork2.ActionSupport;

        (2)實現com.opensymphony.xwork.Action;

   默認狀況下,都須要重載(Override)或者覆寫(Overload)其中的String excute()throws exception方法。

下面對上面實例進行修改,兩個環節進行:

           1.將LoginAction繼承ActionSupport 

import com.opensymphony.xwork2.ActionSupport;

public class LoginAction extends ActionSupport{
  private String uname;
  private String pwd;
  public String getUname(){
     return uname;
  }
  public void setUname(String uname){
    this.uname=uname;
  }
  public String getPwd(){
    return pwd;
  }
  public void setPwd(String pwd){
    this.pwd=pwd;
  }
  public String execute(){
    if("jokerjsaon"equals(uname)&&"1234"equals(pwd)){
       return "fail";//與struts.xml中配置的result相同
    }
  }
}   

        2.在struts.xml中進行配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC 
   "-//Apache SoftWare Foundation//DTD Struts Configuration 2.3//EN "
   "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
  <package name="default" namespace="/" extends="struts-default">
      <action name="login" class="LoginAction">
           <result name="success">success.jsp</result>
           <result name="fail">fail.jsp</result>
     </action>
   </package>
</struts>

         這樣修改並未看到太大變化,反而會由於繼承一個ActionSupport類增長了累贅,但,先看一下Action接口的實現方式:

package com.opensymphony.xwork2;
  public interface Action{
     public static final String SUCCESS="success";
     public static final String NONE="none";
     public static final String ERROR="error";
     public static final String INPUT="input";
     public static final String LOGIN="login";
     public String execute()throws Exception;
  }

      表面上看實現Action接口沒有什麼好處,事實上實現改接口,有利於更好的實現Action類。Action接口中定義了五個字符串常量,由於ActionSupport是Action的實現類,因此繼承了ActionSupport也就可使用這五個常量了:以下

import com.opensymphony.xwork2.ActionSupport;

public class LoginAction extends ActionSupport{
  private String uname;
  private String pwd;
  public String getUname(){
     return uname;
  }
  public void setUname(String uname){
    this.uname=uname;
  }
  public String getPwd(){
    return pwd;
  }
  public void setPwd(String pwd){
    this.pwd=pwd;
  }
  public String execute(){
    if("jokerjsaon"equals(uname)&&"1234"equals(pwd)){
       return ERROR;//注意此處
    }
  }
}   

 

Part 3 Struts2配置文件

   1.   Struts的配置文件類型

          Struts2的配置文件分爲內部使用和供開發人員使用兩大類,內部配置文件由Struts2框架自動加載,對其自身進行配置,其餘的配置文件由開發人員使用,用於對Web應用進行配置。Struts2所需的配置文件以下表:

文件 位置 用途
web.xml /WEB-INF/ Web部署描述文件 
struts.xml /WEB-INF/classes 包含result映射,action映射,攔截器配置等
struts.properties /WEB-INF/classses 與struts.xml做用同樣,不一樣的配置文件罷了
struts-default.xml /WEB-INF/lib/struts-core.jar Struts2提供的默認配置,由框架提供
struts-plugin.xml  /WEB-INF/lib/struts-xxx-plugin.jar Struts2框架插件所提供的配置文件

               下面對核心內容進行解釋:

                [1]  struts.xml配置文件:是該框架的核心配置文件,用於配置和管理開發人員編寫的Action,在這個配置文件中,開發人員能夠配置做用於Action的攔截器,Action和result的映射等。

                [2]struts-default.xml: 基礎配置文件,爲框架提供默認設置,該文件包含在struts2-core-2.x.jar中,由框架自動加載。其會被自動包含在struts.xml中,以提供標準的配置設置而不須要複製其內容:

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

(其內容包括Servlet轉發,Servlet重定向,FreeMarker模板輸出,XSTL渲染,內置攔截器和不一樣攔截器組成的攔截器棧等等)

        2. Struts2的包配置

               Struts2中的包相似於java中的包,提供了將action,result,攔截器和攔截器棧組織爲一個邏輯單元的一種方式。Struts2中的包能夠擴展另外的包,從而繼承原有包的全部定義,並能夠添加本身包的特有配置,以及修改原有包的部分配置。在struts.xml中庸package定義包,下面爲屬性:

                 +   name:(必須) 被其餘包引用的key(鍵);

                 +   extends: (沒必要須) 指定須要擴展的包(若是須要擴展多個包,用","逗號隔開,父包必須在子包前面) ;

                 +   namespace:(沒必要須) 指定命名空間;

                 +   abstract :(沒必要須) 聲明包爲抽象(這樣包內不能再有action的定義,好比前面struts-default.xml就是抽象包,可使用抽象包進行一些默認配置,其餘包繼承以減小工做量);

                  實例:

<package name="default" extends="struts-default">
    <action name="login" class="LoginAction">
          <result name="success">/success.jsp</result>
          <result name="error">/error.jsp</result>
    </action>
</package>
<package name="test" extends="default" namespace="/my">
</package>

            當發起/my/login.action的路徑請求時,會先在test包內查找是否有合適的action,而在此時是在test包中存在LoginAction處理請求,由於test包繼承了default包,某種意義上包的extends至關於java的extends。

       3.  名稱空間配置

            package的namespace屬性能夠將包中的action配置爲不一樣的名稱空間,這樣在不一樣名稱空間中可使用同名action。Struts2框架使用action名字和它所在的名稱空間來標識一個action

            當Struts2接收到一個請求時,它會將請求URL分爲namespace和action名字兩個部分,而後Struts2從struts.xml中查詢namespace/action這個命名對,若是沒有找到,就會在默認的名稱空間搜索相應的action名。默認名稱空間用空字符串" "表示,若是在定義包時沒有使用namespace,就指定了默認名稱空間。

            此外,Struts2還支持以"/"命名的根名稱空間,若是直接請求Web應用上下文路徑下的action,那麼框架會在根名稱空間查找相應的action,若是沒有找到就在默認名稱空間查找:

<!--default包在默認名稱空間中-->
<package name="default" extends="struts-default">
   <action name="foo" class="LoginAction">
        <rfesult name="success">foo.jsp</result>
   </action>
   <action name="bar" class="LoginAction"></action>

<!--mypackage1包在根名稱空間裏-->
<package name="mypackage1" namespace="/">
     <action name="moo" class="LoginActionTwo">
           <result name="success">/moo.jsp</result>
     </action>
</package>

<!--mypackage2包在/accp名稱空間中-->
<package name="mypackage2" namespace="/accp">
     <action name="foo" class="LoginActionThree">
           <result name="success">/foo2.jsp</result>
     </action>
</package>

當發起請求/moo.action時,框架會在根空間('/')查找moo.action,若是沒有找到再在默認空間查找,此例中Mypackage中存在moo.action,所以它會被執行,結果轉向moo.jsp。

       4. Action相關配置

       struts2的核心功能是Action,對於開發人員來講,使用struts2框架主要的工做就是編寫action類Action類通常都要實現Action接口,並實現接口中的execute()方法:簽名以下:

public String execute()

    Struts2並不要求本身編寫的Action類必定實現Action接口,也能夠編寫普通java類做爲Action,只要此類提供一個返回類型爲String的無參public方法:

public String  xxx()

     實際開發中,Action類不多使用Action接口,一般都是繼承ActionSupport類

     開發好Action後,在struts.xml配置,以告訴Struts2框架,針對某個URL的請求應該交給哪一個Action處理。

     struts.xml中action元素屬性以下:

            + name  必須   Action名稱,用於匹配請求;

            + class   非必須   Action實現類的完整類名

            + method   非必須  執行Action調用的方法;

            + converter  非必需   應用於Action的類型轉換器的完整類名;

         ! 注意 : 在爲Action取名時,默認狀況下不準出現斜槓("/"),若是必須使用,例如<action name="book/manage" class="LoginAction">,就須要在struts.xml中加入: <constant name="struts.enable.SlashesInActionNames" values="true"> 

                      此外,不在取名中使用"_"和"."避免一些莫名其妙的問題!

   前面講述了在Struts2中可使用一個普通的java類做爲Action類,並且在此類中的方法沒有特殊要求,對於此點Struts2如何處理?其實Action中有一個method屬性能夠自定義方法,而不須要使用默認的excute()方法。

   例如在一個新聞發佈系統中,對新聞有四種操做,添加,修改,刪除,查詢。在具體實現中,爲了節約Action數量,一般在一個Action中編寫四個方法實現CURD操做:

public class CurdAction(){
  public String addNews(){return SUCCESS;}
  public String deleteNews(){return SUCCESS;}
  public String updateNews(){return SUCCESS;}
  public String selectNews(){return SUCCESS;}
}

  如今的問題是,如何才能讓框架在不一樣請求到達時,去調用CurdAction裏面的相應方法呢?在執行Action時,默認的調用方法是execute()方法。Action中的method屬性能夠指定不一樣的方法,以下配置:

<package name="default" extends="struts-default">
    <!--請求/list時,調用CurdAction類上的selectNews方法-->
    <action name="list" class="CurdAction" method="selectNews">
        <result>/list.jsp</result>
    </action>
    <action name="edit" class="CurdAction" method="editNews">
        <result>/edit.jsp</result>
    </action>
    <action name="delete" class="CurdAction" method="deleteNews">
        <result>/delete.jsp</result>
    </action>
    
    <action name="other" class="CurdAction">
        <result>/edit.jsp</result>
    </action>
</package>

    Struts2在根據Action元素的method屬性查找方法時有兩種途徑:

          + 查找與method屬性值徹底一致的方法;

          + 查找doMethod()形式的方法;

    在上例中,當請求/list時,Struts2首先查找selectNews()方法,若是找不到,則繼續查找名爲doCreate()的方法;

    [另一種無須配置就能夠直接調用Action中的非execute()方法的方式,就是直接使用struts2動態方法DMI,語法以下

actionName!methodName.action

例如:

<action name="list" class="action.CurdAction">
...
</action>

當發起/list!selectNews.action時,將調用CurdAction類中的selectNews方法或doSelectNews().

注意:DIM存在安全隱患,能夠在struts.xml中配置禁止使用:

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

    ]

      5.通配符簡化配置

          一般來講,應用越大,action配置數量越多,經過使用通配符,能夠將一些類似的mapping綁在一塊兒,用一個通用的mapping表示。

          優點:大大減小配置文件內容;

          劣勢:可讀性差;

          使用原則:約定高於配置;在項目中,不少命名規則是約定的,使用通配符必須有一個約定,以下

<action name="User_*" class="action.UserAction method="{1}"">
    <result>/{1}success.jsp</result>
</action>

         *表示匹配全部,在struts2中,{1}表示第一個*號。

         此時若是UserAction裏面有100個方法,只須要配置一次便可;可是若是有多種Action類,就須要以下修改:

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

       注意:在開發前,約定優先於配置,大大下降工做量。

   

    6.返回結果的配置

         一個result表明了一個可能的輸出。當Action類的方法執行完成後,返回一個字符串類型的結果碼,框架根據這個結果選擇對應的result向用戶輸出。

        result配置由兩部分組成:(位於struts.xml中)

              + result映射

              + result類型

        result的屬性以下:

屬性 必要性 說明
name 指定result的邏輯名
type 指定result的類型,不一樣類型的result表明了不一樣類型的輸出結果

       具體配置方法有三種:

               + 最複雜的配置:

<package name="default" namespace="/" extends="struts-default">
  <action name="login" class="action.LoginAction">
      <result name="success" type="dispatcher">
          <param name="location">/success.jsp</param>
      </result>
   </action>
</package> 

              + 精簡版

<package name="default" namespace="/" extends="struts-default">
  <action name="login" class="action.LoginAction">
      <result name="success">
          <param name="location">/success.jsp</param>
      </result>
   </action>
</package> 

<!--這裏沒有設定type屬性,由於默認爲dispatcher-->

               +簡化版

<package name="default" namespace="/" extends="struts-default">
  <action name="login" class="action.LoginAction">
      <result name="success">/success.jsp
      </result>
   </action>
</package> 

           上述的dispatcher是什麼?下面看struts2-core.jar包下面的struts-default.xml,發現以下配置

<result-types>
    <result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
   <result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/>
   <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
   <result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/>
   <result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/>
   <result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionResult"/>
   <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>
   <result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/>
   <result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/>
   <result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult"/>
</result-types>

          這些配置就表明了struts2中全部的result配置類型.

           Struts2框架調用Action對請求處理後,就要向用戶呈現一個結果視圖。Struts2支持多種類型的視圖,由不一樣的結果類型來管理。一個結果類型就是實現了com.opensymphony.xwork2.Result接口的類。

           Strut2中預約義了多種結果類型,以下圖:

結果類型 說明
chain 用於Action鏈式處理
dispatcher 用於web資源的集成,包括JSP的集成
freemarker 用於FreeMarker的集成
httpheader 用於控制特殊的HTTP行爲
redirect 用於重定向到另外的URL(web資源)
redirectAction 用於重定向到另外的action映射
stream 用於向瀏覽器返回一個InputStream(用於文件下載)
velocity 用於velocity集成
xslt 英語XML/XSLTWYS DN
plaintext 用於顯示某個特定頁面(如jsp,html的原始內容)
   

                              下面對常見的result配置類型詳細介紹:

                (1)dispatcher結果類型

                        最多見的結果類型主要是dispatcher類型,此結果類型也是要struts2中默認的結果類型。Struts2在後臺使用Servlet API的RequestDispatcher來轉發請求,所以在用戶的整個請求過程當中,目標Servlet API接收的request/response對象始終是同一個。Dispatcher結果類型實現類爲ServletDispatcherResult,該類有兩個屬性:location和param.這兩個屬性經過struts.xml中的result元素的param子元素設置。以下配置:

<result name="success" type="dispatcher">
    <param name="location">/success.jsp</param>
    <param name="parse">true</param>
</result>

                       location參數用於指定action執行完畢後要轉向的目標資源,location是默認的參數,能夠不用給出.

                       parse用於指定是否可以解析location參數中的OGNL表達式。若是爲false則不解析,默認爲true.以下:

                          實例:一個新聞系統,每一個新聞一個id,當用戶點擊新聞連接,一個帶id參數的請求發送到Action類裏,Action處理完後轉跳到view.jsp

<action name="view" class="ViewAction">
    <result name="success" type="dispatcher">
        <param name="location">/view.jsp?id=${id}</param>
        <param name="parse">true</param>
    </result>
</action>

                (2) redirect結果類型

                     在一次用戶交互中,存在兩次請求,一次是客戶端發送給服務器,服務器sendRedirect(),而後客戶端第二次訪問redirect後的目標資源。這就意味着在目標資源中不能訪問Action實例,解決方案以下:               +   數據保存在session裏;

                     +   經過請求參數來傳遞;

                     如:用戶登陸頁面裏,登錄成功後使用redirect結果類型將其重定向到歡迎頁面,在歡迎頁面中顯示出來。採起第二種方法:

<action name="login" class="LoginAction">
     <resulttype="redirect">x.jsp?username=${username}</result>
</action>

                     若是LoginAction裏username屬性值爲JokerJason,則重定向後瀏覽器中顯示的URL地址爲hhtp://localhost:8080/..../x.jsp?username=JokerJason

                     (注意:加密處理)

              (3) redirectAction結果類型

                   redirectAction與redirect的後臺原理是同樣的,都是利用HttpServletResponse的sendRedirect方法將請求重定向到指定的URL,那麼二者的區別呢?

 

 

 

 

    (正在更新)

相關文章
相關標籤/搜索