Struts2學習整理

Struts2的相關配置文件

    * default.properties        -- 在org/apache/struts2/目錄下,表明的是配置的是Struts2的常量的值html

    * struts-default.xml        -- 在Struts2的核心包下,表明的是Struts2核心功能的配置(Bean、攔截器、結果類型等)前端

    * struts-plugin.xml         -- 配置插件的信息java

    * struts.xml                -- 重點中的重點配置,表明WEB應用的默認配置,能夠配置常量,基本就配置它就能夠web

    * struts.properties         -- 該文件是Struts的默認配置文件  (能夠配置常量 )正則表達式

    * web.xml                   -- 配置前端控制器(能夠配置常量)express


注意:後加載的配置文件會覆蓋掉以前加載的配置文件(在這些配置文件中能夠配置常量)apache



Struts2核心配置文件Struts2.xml的配置入門


  <package>標籤

若是要配置<Action>的標籤,那麼必需要先配置<package>標籤,表明的包的概念。數組

包含的屬性瀏覽器

name         包的名稱,要求是惟一的,管理action配置。緩存

extends      繼承,能夠繼承其餘的包,只要繼承了,那麼該包就包含了其餘包的功能,通常都是繼承struts-default

namespace  名稱空間,通常與<action>標籤中的name屬性共同決定訪問路徑,常見的配置以下:

                * namespace=""      -- 默認的名稱空間(訪問的方式和namespace="/"是同樣的)

                * namespace="/"     -- 根名稱空間

                * namespace="/aaa"  -- 帶有名稱的名稱空間

                * abstract          -- 抽象的。這個屬性基本不多使用,值若是是true,那麼編寫的包是被繼承的。     


<action>標籤

 表明配置action類,包含的屬性

name              和<package>標籤的namespace屬性一塊兒來決定訪問路徑的。

class                配置Action類的全路徑(默認值是ActionSupport類)

 method          Action類中執行的方法,若是不指定,默認值是execute


<result>標籤

action類中方法執行,返回的結果跳轉的頁面

name      結果頁面邏輯視圖名稱

type        結果類型(默認值是轉發,也能夠設置其餘的值)



默認的Action和Action默認的處理類

 默認的Action

 在地址欄上輸入一個不存在的action請求,程序會報404的異常。

 可是在<package>標籤中經過<default-action-ref name="指定action標籤name屬性"></default-action-ref>來該請求。


Action默認處理類

 在地址欄上輸入一個正確的action請求,可是<action>標籤中的class屬性沒有寫具體的Action類

 在<package>標籤中經過<default-class-ref class="指定action類的全路徑"></default-class-ref>


Struts2配置經常使用的常量

能夠在Struts2框架中的哪些配置文件中配置常量

struts.xml

 <constant name="key" value="value"></constant>

web.xml

在StrutsPrepareAndExecuteFilter配置文件中配置初始化參數


struts.i18n.encoding=UTF-8            指定默認編碼集,做用於HttpServletRequest的setCharacterEncoding方法 

struts.action.extension=action,,       該屬性指定須要Struts 2處理的請求後綴,該屬性的默認值是action,即全部匹配*.action的請求都由Struts2處理。若是用戶須要指定多個請求後綴,則多個後綴之間以英文逗號(,)隔開

 struts.serve.static.browserCache=true     設置瀏覽器是否緩存靜態內容,默認值爲true(生產環境下使用),開發階段最好關閉 

struts.configuration.xml.reload=false     當struts的配置文件修改後,系統是否自動從新加載該文件,默認值爲false(生產環境下使用),開發階段最好打開 

struts.devMode = false                    開發模式下使用,這樣能夠打印出更詳細的錯誤信息 

struts.enable.DynamicMethodInvocation = true  開啓對Action的動態方法訪問


指定多個struts的配置文件

在大部分應用裏,隨着應用規模的增長,系統中Action的數量也會大量增長,致使struts.xml配置文件變得很是臃腫。

爲了不struts.xml文件過於龐大、臃腫,提升struts.xml文件的可讀性,咱們能夠將一個struts.xml配置文件分解成多個配置文件,而後在struts.xml文件中包含其餘配置文件。

能夠在<package>標籤中,使用<include>標籤來引入其餘的struts_xx.xml的配置文件。例如:

    <struts>
<include file="struts-part1.xml"/>
<include file="struts-part2.xml"/>
    </struts>



實現Action的三種方式


Action類就是一個POJO類

POJO類:

POJO(Plain Ordinary Java Object)簡單的Java對象。簡單來講,沒有繼承某個類,沒有實現接口,就是POJO的類。


Action類能夠實現Action接口

Action接口中定義了5個常量,5個常量的值對應的是5個邏輯視圖跳轉頁面(跳轉的頁面仍是須要本身來配置),還定義了一個方法,execute方法。

你們須要掌握5個邏輯視圖的常量

SUCCESS       -- 成功.

INPUT         -- 用於數據表單校驗.若是校驗失敗,跳轉INPUT視圖.

LOGIN         -- 登陸.

ERROR         -- 錯誤.

NONE          -- 頁面不轉向.


Action類能夠去繼承ActionSupport類

對請求參數進行校驗

設置錯誤信息

讀取國際化信息



在Action中獲取Servlet相關API的三種方式


在Action類中也能夠獲取到Servlet一些經常使用的API,有以下三種方式獲取

    * 徹底解耦合的方式

    * 使用接口注入的方式

    * 使用ServletActionContext中靜態方法直接訪問Servlet的API



徹底解耦合的方式

若是使用該種方式,Struts2框架中提供了一個類,ActionContext類,該類中提供一些方法,經過方法獲取Servlet的API

 一些經常使用的方法以下:

static ActionContext getContext()        獲取ActionContext對象實例

java.util.Map<java.lang.String,java.lang.Object> getParameters()      獲取請求參數,至關request.getParameterMap();

 java.util.Map<java.lang.String,java.lang.Object> getSession()     獲取的表明session域的Map集合,就至關於操sessio域

 java.util.Map<java.lang.String,java.lang.Object> getApplication()    獲取表明application域的Map集合

  void put(java.lang.String key, java.lang.Object value)         注意:向request域中存入值。



使用接口注入的方式

Struts2框架中提供了一些接口,編寫的Action類能夠是去實現這些接口,而後實現這些接口中的方法,這些方法都是把一些Servlet的經常使用對象經過參數的方式傳遞進來。

    經常使用的接口以下:

        * ServletRequestAware       -- 注入request

        * ServletContextAware       -- 注入ServletContext

        * ServletResponseAware      -- 注入response.


使用ServletActionContext中靜態方法直接訪問Servlet的API

    Struts2框架提供了一個類,ServletActionContext,該類中提供了一些靜態的方法

     具體的方法以下

        * getPageContext();

        * getRequest()

        * getResponse();

        * getServletContext();



訪問Action的三種方式

經過<action>標籤中的method屬性,訪問到Action中的具體的方法


傳統的配置方式

    具體的實例以下:

        頁面代碼

      <a href="${pageContext.request.contextPath}/addBook.action">添加圖書</a>
            <a href="${pageContext.request.contextPath}/deleteBook.action">刪除圖書</a>


         配置文件的代碼

            <package name="demo" extends="struts-default" namespace="/">
                <action name="addBook" class="cn.zlq.demo.BookAction" method="add"></action>
                <action name="deleteBook" class="cn.zlq.demo.BookAction" method="delete"></action>
            </package>


         Action的代碼

            public String add(){
                System.out.println("添加圖書");
                return NONE;
            }
            public String delete(){
                System.out.println("刪除圖書");
                return NONE;
            }


通配符的訪問方式

使用通配符的方式能夠簡化配置文件的代碼編寫,並且擴展和維護比較容易。

具體實例以下:

  頁面代碼

  <a href="${pageContext.request.contextPath}/order_add.action">添加訂單</a>
            <a href="${pageContext.request.contextPath}/order_delete.action">刪除訂單</a>


 配置文件代碼

 <action name="order_*" class="cn.zlq.demo.OrderAction" method="{1}"></action>


  Action的代碼

    public String add(){
                System.out.println("添加訂單");
                return NONE;
            }
            public String delete(){
                System.out.println("刪除訂單");
                return NONE;
            }


 通配符更抽象的寫法

具體的實例以下:

頁面的代碼

   <a href="${pageContext.request.contextPath}/OrderAction_add.action">添加訂單</a>


配置文件代碼

 <action name="*_*" class="cn.zlq.demo.{1}" method="{2}"></action>


 Action的代碼

            public class OrderAction extends ActionSupport{
                public String add(){
                    System.out.println("添加訂單");
                    return NONE;
                }
            }


動態方法訪問的方式 

 若是想完成動態方法訪問的方式須要開啓一個常量,struts.enable.DynamicMethodInvocation = false,把值設置成true。

 注意:不一樣的Struts2框架的版本,該常量的值不必定是true或者false,須要本身來看一下。若是是false,須要本身開啓。

 在struts.xml中開啓該常量。

             

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


具體代碼以下

頁面的代碼

            <a href="${pageContext.request.contextPath}/product!add.action">添加商品</a>
            <a href="${pageContext.request.contextPath}/product!delete.action">刪除商品</a>

配置文件代碼

   

        <action name="product" class="cn.zlq.demo.ProductAction"></action>

 Action的類的代碼

         

  public class ProductAction extends ActionSupport{
                public String add(){
                    System.out.println("添加訂單");
                    return NONE;
                }
                public String delete(){
                    System.out.println("刪除訂單");
                    return NONE;
                }
            }


對結果頁面的跳轉

結果頁面存在兩種方式

 全局結果頁面

條件:

若是<package>包中的一些action都返回success,而且返回的頁面都是同一個JSP頁面,這樣就能夠配置全局的結果頁面。

 全局結果頁面針對的當前的包中的全部的Action,可是若是局部還有結果頁面,會優先局部的。

使用的標籤是

            <global-results>
                <result>/demo/suc.jsp</result>
            </global-results>


局部結果頁面

        <result>/demo/suc.jsp</result>


結果頁面的類型

結果頁面使用<result>標籤進行配置,包含兩個屬性

        name  -- 邏輯視圖的名稱

        type  -- 跳轉的類型,值一些,須要掌握一些經常使用的類型。常見的結果類型去struts-default.xml中查找。

            * dispatcher        -- 轉發.type的默認值.Action--->JSP

            * redirect          -- 重定向. Action--->JSP

            * chain             -- 多個action之間跳轉.從一個Action轉發到另外一個Action.  Action---Action

            * redirectAction    -- 多個action之間跳轉.從一個Action重定向到另外一個Action. Action---Action

            * stream            -- 文件下載時候使用的.

 注意:當使用一個Action標籤完成多個Action配置時,會出現Input結果視圖衝突的狀況,也就是說,在不一樣邏輯中跳入的input邏輯視圖是同一個,此時咱們能夠在本身的Action方法上加上 @InputConfig(resultName="邏輯視圖的名稱")的註解而後再在Result中配置便可。

    這個爲何這樣呢?你們能夠看源碼:




Struts2的Action對數據封裝的兩種方式


屬性驅動

提供對應屬性的set方法進行數據的封裝

   * 表單的哪些屬性須要封裝數據,那麼在對應的Action類中提供該屬性的set方法便可

   * 表單中的數據提交,最終找到Action類中的setXxx的方法,最後賦值給全局變量。

   * 注意:Struts2的框架採用的攔截器完成數據的封裝。

   * 注意:這種方式不是特別好:由於屬性特別多,提供特別多的set方法,並且還須要手動將數據存入到對象中.

   * 注意:這種狀況下,Action類就至關於一個JavaBean,就沒有體現出MVC的思想,Action類又封裝數據,又接收請求處理,耦合性較高。


在頁面上,使用OGNL表達式進行數據封裝

   * 在頁面中使用OGNL表達式進行數據的封裝,就能夠直接把屬性封裝到某一個JavaBean的對象中。

   * 在頁面中定義一個JavaBean,而且提供set方法:例如:private User user;

   * 頁面中的編寫發生了變化,須要使用OGNL的方式,表單中的寫法:<input type="text" name="user.username">

   * 注意:只提供一個set方法還不夠,若是沒有user實例化,必須還須要提供user屬性的get和set方法,先調用get方法,判斷一下是否有user對象的實例對象,若是沒有,調用set方法把攔截器建立的對象注入進來。


模型驅動

使用模型驅動的方式,也能夠把表單中的數據直接封裝到一個JavaBean的對象中,而且表單的寫法和以前的寫法沒有區別!

編寫的頁面不須要任何變化,正常編寫name屬性的值。

模型驅動的編寫步驟

   * 手動實例化JavaBean,即:private User user = new User();

   * 必須實現ModelDriven<T>接口,實現getModel()的方法,在getModel()方法中返回user便可!!

Struts2的Action對集合對象的封裝的兩種方式

封裝複雜類型的參數(集合類型 Collection 、Map接口等)

需求:頁面中有可能想批量添加一些數據,那麼如今就可使用上述的技術了。把數據封裝到集合中。

把數據封裝到Collection中

   * 由於Collection接口都會有下標值,全部頁面的寫法會有一些區別,注意:

 <input type="text" name="products[0].name" />

   * 在Action中的寫法,須要提供products的集合,而且提供get和set方法。

把數據封裝到Map中

   * Map集合是鍵值對的形式,頁面的寫法

<input type="text" name="map['one'].name" />

   * Action中提供map集合,而且提供get和set方法。


在Action中不推薦使用模型驅動的方式來封裝數據到集合中。


Struts2對數據的類型轉換

Struts2中自帶類型轉換攔截器

Struts2內部提供了大量轉換器,用來完成數據類型轉換的問題,有以下

   * boolean 和 Boolean

   * char和 Character

   * int 和 Integer

   * long 和 Long

   * float 和 Float

   * double 和 Double

   * Date 能夠接收 yyyy-MM-dd 格式字符串

   * 數組 能夠將多個同名參數,轉換到數組中

   * 集合 支持將數據保存到 List 或者 Map 集合

當發生類型轉換錯誤的時候,根據報錯的信息提示,跳轉input類型的結果視圖。

   * 說明若是程序出現異常,會跳轉到input結果視圖,那能夠在<action>標籤中配置input結果視圖

在跳轉的頁面中能夠經過一個固定的標籤來顯示錯誤的信息:

* 能夠先須要先引入Struts2的標籤庫,而後使用標籤顯示錯誤!

<%@ taglib prefix="s" uri="/struts-tags" %>

* <s:fielderror/>,這是Struts2提供的標籤,使用它顯示錯誤的提示信息。


若是類型轉換的攔截器中發生了錯誤,那麼會把錯誤信息放在Struts2錯誤區域中(Struts2的錯誤區域分紅兩部分,一部分是字段錯誤,一部分是Actionc錯誤)

* 等執行到最後一個攔截器(workflow)時,workflow攔截器會去Struts2的錯誤區域中找是否存在錯誤。

* 若是存在錯誤,就跳轉到input視圖。

* 若是不存在錯誤,執行目標Action類中具體的方法。


自定義類型轉換器

若是一些特殊的數據類型不能轉換,那麼須要自定義數據類型的轉換器。

開發自定義類型轉換的開發步驟

編寫類型轉換器

        實現TypeConverter接口,實現一個方法

Object convertValue(Map<String,Object> context,Object target, Member member,String propertyName,Object value,Class toType);

        繼承DefaultTypeConverter類,重寫一個方法

Object convertValue(Map<String,Object> context,Object value,Class toType)

        繼承StrutsTypeConverter類,重寫兩個方法

  Object convertFromString(Map context,String[] values,Class toClass)

                > 從字符串轉換成具體類型

                > values數組,存入的值就是用戶輸入的值

                > toClass 要轉換的數據的類型 Date.class

            * String convertToString(Map context,Object o)

                > 把具體的類型轉換成字符串

                > o 表明的要轉換的數據

注意:類型轉換自己就是一個雙向的過程:

* JSP ---> Action   String ---> 某個類型

* Action ---> JSP   某個類型 ---> String                


 * 類型轉換的代碼,以 1990/10/10 爲例,自定義日期轉換器,完成轉換,下面這段代碼是第二種方法,也就是繼承了DefaultTypeConverter類。

  public Object convertValue(Map<String, Object> context, Object value,
            Class toType) {
            // 根據toType判斷 是請求封裝 仍是 數據回顯
            DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
            if (toType == Date.class) {
                // 請求參數封裝 (value是字符串)
                String[] params = (String[]) value;
                String strVal = params[0]; // 轉換爲 日期類型
                try {
                    return dateFormat.parse(strVal);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            } else {
                // 回顯(value是 Date)
                Date date = (Date) value;
                return dateFormat.format(date);
            }
            return null;
        }


 註冊類型轉換器

局部註冊:針對某個表單中的某個字段生效的!

            * 屬性驅動的方式:使用set方法接收數據

                > 注意:在Action所在的包下建立一個文件,文件的格式是:Action類名-conversion.properties文件,該文件中配置要轉換數據的字段和對應的轉換器全路徑

                    * 例如:birthday=cn.zlq.demo3.MyDateConverter

            * 模型驅動的方式:實現ModelDriven接口的方式

                > 注意:在實體類所在的包下建立一個文件,文件的格式是:實體類名-conversion.properties文件,該文件中配置要轉換數據的字段和對應的轉換器全路徑

                    * 例如:birthday=cn.zlq.demo3.MyDateConverter


全局註冊:針對整個項目的全部的日期類型都會生效的!

            * 在src的目錄下,建立一個xwork-conversion.properties  (名稱是固定的)

                > 例如:java.util.Date=cn.zlq.demo3.MyDateConverter


Struts2對數據的校驗的兩種方式


數據校驗包含兩種方式,第一種是手動編碼完成數據校驗方式,第二種是經過配置文件完成數據校驗方式。

手動編碼校驗方式

開發的步驟

        > 步驟一: 封裝數據 

        > 步驟二: 實現校驗Action ,必須繼承ActionSupport 類 

        > 步驟三: 覆蓋validate方法,完成對Action的業務方法 數據校驗 this.addFieldError (ActionSupport提供)

        > 步驟四: 在jsp中 經過 <s:fieldError/> 顯示錯誤信息


針對的是Action中全部的方法進行校驗

 讓Action繼承ActionSupport類,重寫ActionSupport類中的validate()方法,在該方法中完成數據校驗。


 針對的是Action中某個方法完成校驗

 手動在Action中編寫一個方法,方法名稱是validate方法名稱()  例如:public void validateAdd(){  }

            * Action中有一個save的方法,只校驗save方法。

            * validateSave()    -- 使用該方法去校驗save的方法



經過XML配置文件的方式完成數據的校驗

 xml配置校驗原理 : 將不少校驗規則代碼已經寫好,只須要在xml中定義數據所使用校驗規則就能夠了 

開發的步驟

        > 步驟一 :編寫jsp

        > 步驟二 :編寫Action 繼承ActionSupport 或者 實現 Validateable 接口 

        > 步驟三 :封裝請求參數

            * 使用xml校驗 必須提供get方法

        > 步驟四 :編寫校驗規則xml文件 

            * 具體的配置文件相關標籤和屬性詳解

<field name="password">
                    <!-- 校驗器類型 -->
                    <field-validator type="requiredstring">
                        <message>密碼不能爲空</message>
                    </field-validator>
                    <!-- 規定密碼的長度 -->
                    <field-validator type="stringlength">
                        <param name="minLength">3</param>
                        <param name="maxLength">8</param>
                        <message>密碼在3-8位之間</message>
                    </field-validator>
                </field>

針對的是Action中全部的方法進行校驗

        > 在Action所在的包中建立一個XML文件,命名規則:Action類名-validation.xml。而且須要引入指定的DTD的約束:xwork-core-2.3.15.3.jar/xwork-validator-1.0.3.dtd


        > 具體的值:

<!DOCTYPE validators PUBLIC
                "-//Apache Struts//XWork Validator 1.0.3//EN"
                "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">


針對的是Action中的某個方法進行校驗

 在Action所在的包中建立一個XML文件,命名規則:Action類名-方法對應的訪問路徑-validation.xml。引入DTD文件等。

            * 例如:Reg6Action-reg6-validation.xml



Struts2框架提供的XML校驗規則

    * required (必填校驗器,要求被校驗的屬性值不能爲null),空格沒問題。

    * requiredstring (必填字符串校驗器,要求被校驗的屬性值不能爲null,而且長度大於0,默認狀況下會對字符串去先後空格)

    * stringlength (字符串長度校驗器,要求被校驗的屬性值必須在指定的範圍內,不然校驗失敗,minLength參數指定最小長度,maxLength參數指定最大長度,trim參數指定校驗field以前是否去除字符串先後的空格)

    * regex (正則表達式校驗器,檢查被校驗的屬性值是否匹配一個正則表達式,expression參數指定正則表達式,caseSensitive參數指定進行正則表達式匹配時,是否區分大小寫,默認值爲true)

    * int(整數校驗器,要求field的整數值必須在指定範圍內,min指定最小值,max指定最大值)

    * double(雙精度浮點數校驗器,要求field的雙精度浮點數必須在指定範圍內,min指定最小值,max指定最大值)

    * fieldexpression (字段OGNL表達式校驗器,要求field知足一個ognl表達式,expression參數指定ognl表達式,該邏輯表達式基於ValueStack進行求值,返回true時校驗經過,不然不經過)

    * email(郵件地址校驗器,要求若是被校驗的屬性值非空,則必須是合法的郵件地址)

    * url(網址校驗器,要求若是被校驗的屬性值非空,則必須是合法的url地址)

    * date(日期校驗器,要求field的日期值必須在指定範圍內,min指定最小值,max指定最大值)




Struts2的攔截器

原理

* 攔截器就是AOP(Aspect-Oriented Programming)的一種實現。

    * 過濾器:過濾從客服端發送到服務器端請求的.


    * 攔截器:攔截對目標Action中的某些方法進行攔截.

        * 攔截器不能攔截JSP.

        * 攔截到Action中某些方法.


攔截器和過濾器的區別

    1)攔截器是基於JAVA反射機制的,而過濾器是基於函數回調的。

    2)過濾器依賴於Servlet容器,而攔截器不依賴於Servlet容器

    3)攔截器只能對Action請求起做用,而過濾器能夠對幾乎全部的請求起做用。

    4)在Action的生命週期中,攔截器能夠屢次被調用,而過濾器只能在容器初始化時被調用一次   

    * 攔截器 採用 責任鏈 模式

        > 在責任鏈模式裏,不少對象由每個對象對其下家的引用而鏈接起來造成一條鏈。

        > 責任鏈每個節點,均可以繼續調用下一個節點,也能夠阻止流程繼續執行


    * 在struts2 中能夠定義不少個攔截器,將多個攔截器按照特定順序 組成攔截器棧 (順序調用 棧中的每個攔截器 )


Struts2的自定義攔截器

編寫攔截器

須要實現Interceptor接口,實現接口中的三個方法。

    * interceptor接口有不少的實現類,編寫最簡單的方式就是繼承AbstractInterceptor實現類。      

    * 代碼例如:

 public String intercept(ActionInvocation invocation) throws Exception {
        User user = (User) ServletActionContext.getRequest().getSession().getAttribute("existUser");
            if(user == null){
                ActionSupport as = (ActionSupport) invocation.getAction();
                as.addActionError("您沒有登錄!");
                return as.LOGIN;
            }else{
                // 放行
                return invocation.invoke();
            }
        }


須要在struts.xml中進行攔截器的配置

配置一共有兩種方式

 第一種方式

            在<package>包中定義攔截器,出如今<package>包的上方

  <interceptors>
     <interceptor name="loginInterceptor" class="cn.zlq.interceptor.LoginInterceptor"></interceptor>
   </interceptors>

             在某個action中引入攔截器

  <interceptor-ref name="loginInterceptor"></interceptor-ref>

注意:若是引入了本身定義的攔截器,那麼Struts2框架默認的攔截器就不會再執行了,因此須要引入Struts2默認的攔截器。

<interceptor-ref name="defaultStack"></interceptor-ref>

 第二種方式

                在<package>包中定義攔截器的時候,本身直接定義一個攔截器棧

<interceptors>
   <interceptor name="loginInterceptor" class="cn.zlq.interceptor.LoginInterceptor"/>
   <interceptor-stack name="myStack">
           <interceptor-ref name="loginInterceptor"/>
           <interceptor-ref name="defaultStack"/>
    </interceptor-stack>
 </interceptors>

            在Action包中引入本身定義的攔截器棧

<action name="book_*" class="cn.zlq.action.BookAction" method="{1}">
<interceptor-ref name="myStack"/>
</action>



Struts2的文件上傳

Struts2框架的使用攔截器完成了文件上傳

底層使用也是FileUpload開源的組件。

    * 提供 FileUpload 攔截器,用於解析 multipart/form-data 編碼格式請求,解析上傳文件的內容 

    * fileUpload攔截器 默認在 defaultStack 棧中, 默認會執行的 


    * 在Action中編寫文件上傳,須要定義三個屬性

        文件類型File ,屬性名與表單中file的name屬性名一致.

        字符串類型String , 屬性名:前段是name屬性名一致 +ContentType;

        字符串類型String , 屬性名:前段是name屬性名一致+FileName;


        最後須要爲上述的三個屬性提供set方法。

        能夠經過FileUtils提供 copyFile 進行文件複製,將上傳文件 保存到服務器端 


文件上傳中存在的問題

    * 先配置input邏輯視圖

    * 在頁面中顯示錯誤信息


    * 文件上傳的總大小默認值是2M,若是超過了2M,程序會報出異常。可使用<s:actionError>來查看具體信息!

        > 解決總大小的設置,找到常量:

            * struts.multipart.parser=jakarta       -- 默認文件上傳解析器,就是FileUpload組件

            * struts.multipart.saveDir=             -- 文件上傳的臨時文件存儲目錄

            * struts.multipart.maxSize=2097152      -- 文件上傳的最大值(總大小),默認是2M


        > 能夠在struts.xml中設置常量,修改文件上傳的默認總大小!!!

          <constant name="struts.multipart.maxSize" value="5000000"></constant>


經過攔截器來設置文件上傳的一些屬性

 先在<action>標籤中引入文件上傳的攔截器

     

  <interceptor-ref name="defaultStack">
            <!-- 設置單個上傳文件的大小 -->
            <param name="fileUpload.maximumSize">2097152</param>
            <!-- 設置擴展名 -->
            <param name="fileUpload.allowedExtensions">.txt</param>
        </interceptor-ref>


多文件上傳

    * 在Action中仍是編寫三個屬性

        > 屬性須要是數組或者List集合,這樣就能夠完成多文件上傳了。        

        > 注意:是數組或者List集合        

        private File [] upload;             // 表明上傳的文件

        private String [] uploadContentType;    // 表明文件的類型

        private String [] uploadFileName;       // 上傳文件的名稱


         提供屬性的set方法


Struts2的文件下載


Action類必需要有返回結果,而且返回結果中必需要依賴stream結果類型。

    * 在<action>標籤中配置stream的結果類型。

    * 能夠經過<result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>源碼發現有一些須要設置的屬性。

     

  <result name="success" type="stream">
            <param name="contentType">${contentType}</param>
            <param name="contentDisposition">attachment;filename=${downFileName}</param>
            <param name="inputName"></param>
   </result>

上面的代碼的${contentType}這種寫法須要Action類提供對應的方法,對應的方法以下

  // 獲取文件的MIME類型
        public String getContentType(){
            return ServletActionContext.getServletContext().getMimeType(filename);
        }       
        // 設置文件的輸入流
        public InputStream getInputStream(){
         return ServletActionContext.getServletContext().getResourceAsStream("/download/"+filename);
        }
        // 設置Content-Disposition屬性
        public String getDownFilename() throws IOException{
            String agent = ServletActionContext.getRequest().getHeader("User-Agent");
            return this.encodeDownloadFilename(filename, agent);
        }

解決下載文件中文亂碼的問題

 

 public String encodeDownloadFilename(String filename, String agent) throws IOException{
if(agent.contains("Firefox")){ // 火狐瀏覽器
    filename = "=?UTF-8?B?"+new BASE64Encoder().encode(filename.getBytes("utf-8"))+"?=";
}else{ // IE及其餘瀏覽器
    filename = URLEncoder.encode(filename,"utf-8");
}
return filename;
    }



OGNL表達式

OGNL是Object Graphic Navigation Language(對象圖導航語言)的縮寫,它是一個開源項目。

    * 所謂對象圖,即以任意一個對象爲根,經過OGNL能夠訪問與這個對象關聯的其它對象。

    * 經過它簡單一致的表達式語法,能夠存取對象的任意屬性,調用對象的方法,遍歷整個對象的結構圖,實現字段類型轉化等功能。它使用相同的表達式去存取對象的屬性。


Struts2框架使用OGNL做爲默認的表達式語言

    * OGNL是一種比EL強大不少倍的語言 

    * xwork 提供 OGNL表達式 


OGNL 提供五大類功能 

   * 支持對象方法調用,如xxx.doSomeSpecial(); 

   * 支持類靜態的方法調用和值訪問

   * 訪問OGNL上下文(OGNL context)和ActionContext; (重點 操做ValueStack值棧 )

   * 支持賦值操做和表達式串聯

   * 操做集合對象。




值棧

    * 值棧就至關於Struts2框架的數據的中轉站,向值棧存入一些數據。從值棧中獲取到數據。

    * ValueStack 是 struts2 提供一個接口,實現類 OgnlValueStack ---- 值棧對象 (OGNL是從值棧中獲取數據的 )

    * Action是多例的,有一塊兒請求,建立Action實例,建立一個ActionContext對象,表明的是Action的上下文對象,還會建立一個ValueStack對象。線程安全的

    * 每一個Action實例都有一個ValueStack對象 (一個請求 對應 一個ValueStack對象 )

    * 在其中保存當前Action 對象和其餘相關對象 (值棧中 是有Action 引用的 )

    * Struts 框架把 ValueStack 對象保存在名爲 「struts.valueStack」 的請求屬性中,request中 (值棧對象 是 request一個屬性)

        * ValueStack vs = (ValueStack)request.getAttribute("struts.valueStack");


值棧的內部結構 

    * 值棧由兩部分組成

        > root      -- Struts把動做和相關對象壓入 ObjectStack 中--List

        > context   -- Struts把各類各樣的映射關係(一些 Map 類型的對象) 壓入 ContextMap 中


    * Struts 會把下面這些映射壓入ContextMap中

        > parameters: 該 Map 中包含當前請求的請求參數  ?name=xxx&password=123

        > request: 該 Map 中包含當前 request 對象中的全部屬性

        > session: 該 Map 中包含當前 session 對象中的全部屬性

        > application:該 Map 中包含當前 application  對象中的全部屬性

        > attr: 該 Map 按以下順序來檢索某個屬性: request, session, application


    * ValueStack中 存在root屬性 (CompoundRoot) 、 context 屬性 (OgnlContext )

        > CompoundRoot 就是ArrayList

        > OgnlContext 就是 Map


    * context 對應Map 引入 root對象 

        > context中還存在 request、 session、application、 attr、 parameters 對象引用 

        > OGNL表達式訪問值棧中的數據

            * 訪問root中數據時 不須要 #

            * 訪問 request、 session、application、 attr、 parameters 對象數據 必須寫 # 


        > 操做值棧 默認指 操做 root 元素 


值棧對象的建立

    * 值棧對象是請求時建立的

    * ActionContext是綁定到當前的線程上,那麼在每一個攔截器或者Action中獲取到的ActionContext是同一個。

    * ActionContext中存在一個Map集合,該Map集合和ValueStack的contextMap是同一個地址。

    * ActionContext中能夠獲取到ValueStack的引用。

    



Action中獲取值棧對象的三種方法

        * ValueStack vs1 = (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack");

        * ValueStack vs2 = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);

        * ValueStack vs3 = ActionContext.getContext().getValueStack();



向值棧保存數據

    向值棧保存數據,主要針對 root

    * 兩種方式

        valueStack.push(Object obj);

            * push方法的底層調用root對象的push方法(把元素添加到0位置)

        valueStack.set(String key, Object obj);

            * 源碼獲取map集合(map有多是已經存在的,有多是新建立的),把map集合push到棧中,再把數據存入到map集合中。

        在jsp中 經過 <s:debug /> 查看值棧的內容 


    *屬性驅動方式:

當ActionContext中提供了一個JavaBean的get方法,就能不將這個JavaBean放到值棧中而取到這個值

這是由於值棧的中有ActionContext對象,能夠經過這個對象取到JavaBean


    *模型驅動方式:

當Action中經過模型驅動獲取到對象的時候,會將模型驅動中的對象壓入值棧的root棧頂,因此此時能夠獲取到經過Action模型驅動封裝的對象


EL 表達式獲取值棧中的數據

* StrutsPreparedAndExecuteFilter的doFilter代碼中 request = prepare.wrapRequest(request);    

        對Request對象進行了包裝 ,StrutsRequestWrapper 

        加強了request的 getAttribute

            Object attribute = super.getAttribute(s);

            if (attribute == null) {

               attribute = stack.findValue(s);

            }

        訪問request範圍的數據時,若是數據找不到,去值棧中找 

        request對象 具有訪問值棧數據的能力 (查找root的數據)



在JSP頁面中獲取值棧中的值

具體在Struts2中怎麼使用呢?以下步驟:

    * 須要先引入Struts2的標籤庫

         <%@ taglib prefix="s" uri="/struts-tags" %>

    * 使用Struts2提供的標籤中的標籤

         <s:property value="OGNL表達式"/>


在JSP頁面使用OGNL表達式

    * 訪問對象方法:

        <s:property value="'hello'.length()"/>

    * 訪問對象的靜態方法:

        > struts2中靜態方法訪問被禁止的.開啓一個常量.

        <constant name="struts.ognl.allowStaticMethodAccess" value="true"/>

        > 在頁面中:

        <s:property value="@java.lang.Math@random()"/>



使用OGNL表達式獲取值棧中的數據

# 符號

        <s:property value="#request.name"/>

        <s:property value="#session.name"/>

        <s:property value="#application.name"/>

        <s:property value="#attr.name"/>

        <s:property value="#parameters.id"/>

        <s:property value="#parameters.name"/>



%號

強制字符串解析成OGNL表達式。

         例如:在request域中存入值,而後在文本框(<s:textfield>)中取值,如今到value上。

         <s:textfield value="%{#request.msg}"/>


{ }中值用''引發來,此時再也不是ognl表達式,而是普通的字符串

        例如:<s:property value="%{'#request.msg'}"/> 



$號

在配置文件中可使用OGNL表達式

相關文章
相關標籤/搜索