struts2總結

jopen 11年前發布 | 76K 次閱讀 Struts2 Web框架 Struts

1.為什么學習Struts框架

   a.Struts框架好處

struts2是主流的開發技術,大多數公司在使用,struts把相關的servlet組件的各種操作都進行了相應的封裝,這樣就可以輕松地完成復雜的操作。Struts2是基于MVC模式開發的,MVC結構是一個優秀的設計思想,可以提高程序結構的靈活性,便于日后的維護和擴展。

 --簡化開發工作量,提高開發效率

     --采用了優秀的設計思想(MVC)

  b.Struts框架作用

struts充當控制器,接收請求,分發處理,

  c.如何學習Struts框架

     先重點掌握框架使用,原理性有余力可以多了解些。

 

注:我們目前使用的Struts版本為struts2 2.1.8。(2.1.6版本bug較多)

  d.學校struts要掌握的重點:

valuestack

action

result

攔截器

標記庫

2.MVC模式在JavaWeb中的應用

   *a.什么是MVC

     是一種軟件架構的思想,將一個軟件的組成部分劃分成三種不同類型的 模塊,分別是:

模型(用于封裝業務邏輯,包括業務數據和業務處理邏輯,由JavaBean組件   (比如實體類,DAO,Service)實現),

視圖(負責顯示界面與用戶交互,處理表示邏輯,一種是展示數據,另一種      是接受數據,由jsp組件實現),

控制器(用于控制流程,協調模型與視圖,由Servlet、Filter組件(比如之 前的ActionServlet)實現)。

使用mvc的最主要的原因是為了實現模型的復用:即模型只需要開發 一次, 模型不關心處理的結果如何展現,模型將結果交給不同的視 圖,由視圖來展 現這些數據;另外,可以利用不同的視圖來訪問 同一個模型。  

 

MVC:基于面向對象的一種常見的體系架構

Model:

封裝數據以及對數據操作的方法(相當于飯店中做菜的材料(數據)和做菜的廚師(方法)

一個流程用一個方法

View:

封裝的是用戶界面,接收用戶請求,負責輸入和輸出(和用戶打交道)(相當于服務員)

Controller:

封裝的是業務流程,控制業務流程(相當于飯店中的管理者)(如果程序比較簡單,可以把Controller寫在Model里面)

 

   b.為什么使用MVC

     企業程序更強調結構靈活,易于擴展和升級。所以廣泛選用MVC模式開發。

   *c.JavaWeb中如何實現MVC結構

    JavaWeb技術主要有:Servlet,JSP,JavaBean,Filter,Listener等

    V部分:JSP組件 (cart.jsp)

    M部分:JavaBean組件(entity,dao)

    C部分:Servlet,Filter組件 (ShoppingCartServlet)

 *d.MVC處理流程

   --首先瀏覽器發出請求

   --請求進入C控制器

   --C控制器調用M模型組件處理

   --M模型組件處理后返回處理結果

   -- C控制器調用V視圖組件生成響應信息

 

 *e.Struts框架的MVC實現

    原有ShoppingCart程序,雖然符合MVC結構,但不適合大型項目開發,因為請求一多,ShoppingCartServlet會出現大量的if..else... ,可以進行以下方式的改造:

為ShoppingCartServlet配置一個XML文件,該文件定義不同請求和不同Action組件的對應關系,將原有if..else..分支處理用Action組件封裝。   

  **f.Struts框架的處理流程

    --瀏覽器發出struts請求

    --請求進入struts控制器

    --struts控制器解析xml配置文件(xml定義了請求和Action對應關系)

    --控制器根據不同請求,調用不同的Action

    --Action調用DAO處理請求,之后返回結果

    --控制器根據結果調用視圖組件為用戶響應

 struts總結

 

3.了解Struts歷史

   Struts框架分成Struts1和Struts2.Struts2和Struts1沒有必然聯系。Struts2是以WebWork框架核心(xwork)為基礎構建起來

最早出現的 Struts1是一個非常著名的框架,它實現了MVC模式。Struts1簡單小巧,其中最成熟的版本是Struts1.2。之后出現了WebWork框架,其實現技術比Struts1先進,但影響力不如Struts1。在框架技術不斷發展過程中,有人在WebWork核心XWork的基礎上包裝了 Struts1(算是兩種框架的整合),由此,結合了Struts1的影響力和WebWork的先進技術,Struts 2誕生了。所以說,Struts2不是Struts1的升級,它更像是WebWork的升級版本。

*4.Struts基本使用

   a.引入struts2核心開發包(5個) 

(1).struts2-core-2.1.8.1.jar

Struts2核心包,是Struts框架的“外衣。

(2).xwork-core-2.1.6.jar

Struts2核心包,是WebWork內核。

(3).ognl-2.7.3.jar

用來支持ognl表達式的,類似于EL表達式,功能比EL表達式強大的

多。

(4).freemarker-2.3.15.jar

freemarker是比jsp更簡單好用,功能更加強大的表現層技術,用來 替代jsp的。在Struts2中提倡使用freemarker模板,但實際項目中使 用jsp也很多。

(5).commons-fileupload-1.2.1.jar

用于實現文件上傳功能的jar包。

b.在web.xml中配置下struts控制器

   c.根據請求編寫Action,JSP

   d.在struts.xml定義Action和請求對應關系

5.HelloWord入門實例

welcome.action-->Struts控制器-->struts.xml-->WelcomeAction

-->welcome.jsp

(Action請求可以是/welcome.action或者/welcome兩種寫法)

7、struts.xml基本配置

struts.xml放在src根目錄下。

a) <struts>

根元素,可以包含多個<package>元素

b)<package>

<package name="***" namespace="/默認" extends="struts-default">

元素主要用于將Action分組定義。name屬性用于指定包名;extends一般指 定為struts-default。struts-default這個包在struts-default.xml中定義,其中 包含了struts2運行所需的必要組件。

添加namespace屬性的主要作用是避免在大項目中出現的命名沖突問題。

注意:

http://localhost:8080/struts01/netctoss/welcome

<package name="demo1" namespace="/netctosss" 

extends="struts-default">

<action name="welcome" class="action.WelcomeAction">

     <result name="success">/WEB-INF/jsp/Welcome.jsp</result>

 </action>

namespace屬性默認為“/”(即從應用名后的第一個"/"開始到最后一個“/”結束)。

eg:對于http://localhost:8080/struts01/netctoss/cost/showList.action

其中的namespace屬性值應為”/netctoss/cost”。

eg:

如果不加namespace="/netctoss"那么

http://localhost:8080/struts01/netctoss/list.action便不會得到正確的匹配

一個<package>元素可以包含多個<action>..</action>主要用于定義請求

和Action組件的對應關系。name屬性指定請求名;class屬性指定Action的包

名.類名

c)<action>

<action name="***" method="execute默認" class="***">

一個<action>元素可以包含多個<result>...<result>主要用于定義視圖響 應。name屬性與Action.execute()返回值一致。

其中

(1).method屬性可以省略,如果省略則默認調用Action中的execute()方法

(2.)如果不指定class屬性,Struts會默認調用框架底層的ActionSupport

      類處理(見下面:)。框架會默認為該<action>添加一個class,作用是

      轉發到對應

      的<result  name="success">中指定的頁面。當有nameform請求發

      來時,struts不會調 用action(找不到)而是直接調用result中name屬

      性為success對應的頁面。

注:name=”success”可以省略

<action name="nameform">

  <!--<result name=”success”>/WEB-INF/jsp/Welcome.jsp</result>-->

       <result>/WEB-INF/jsp/Welcome.jsp</result>

</action>

  struts總結

--------ActionSupport類:---------

 public String execute(){

     return “success”;

}

  

d)<result>

<result name="success默認" type="dispatcher默認">

e:注意:

1.對于package、action、result,如果使用默認屬性值,則可以省略屬性名。

eg:<result name=”sucess” type=”dispatcher”>****</sesult>

  如果使用默認屬性值:則可以寫成:

  <result >****</sesult>

 

對于重復使用的result可以寫成全局的result

<!-- 定義全局result -->

<global-results>

<!-- 錯誤處理 -->

<result name="error">/WEB-INF/jsp/error.html</result>

<!-- 攔截器登錄處理 -->

<result name="login" type="redirectAction">showLogin</result>

</global-results>

 

2.page包中的各組件的放置順序:

具體見struts-2.1.7dtd

package (result-types——> interceptors——>default-interceptor-ref——> 

default-action-ref——> default-class-ref——> global-results——> 

global-exception-mappings——> action*)>

攔截器配置放在global-results之前

 

3.當項目業務處理較多時如果將所有的配置都寫在struts.xml一個文件中將很不方便,所以可以將不同的處理模塊分別寫在不同的xml文件中,最后在struts.xml中加載和模塊配置文件,過程如下:

struts.xml:

<struts>

<!-- 加載各模塊配置文件 -->

<include file="struts-cost.xml"/>

<include file="struts-account.xml"/>

...........

<package name="netctoss-default" extends="json-default">

<!-- 追加共通的Action,Interceptor組件 -->

攔截器、全局results....

</package>

</struts>

struts-cost.xml:

<!-- 資費模塊配置文件 -->

<struts>

<package name="cost" extends="netctoss-default">

........

</package>

</struts>

struts-account.xml:

<!-- 資費模塊配置文件 -->

<struts>

<package name="account" extends="netctoss-default">

........

</package>

</struts>

.............................

瀏覽器訪問地址:

http://localhost:8080/應用名/namespace/action

http://localhost:8080/struts03_2/list/costList.action?page=4

以上的namespace默認為’’/’,本例為list

8、如何解決用戶繞過ActionServlet,直接訪問jsp文件的問題。

將所有jsp文件拷貝到WEB-INF目錄下。因為WEB-INF目錄中的內容不能直接訪問,但能轉發過來。

當然也可以用之前的session技術(太麻煩)。

對于struts中WebRoot文件夾下的.jsp頁面仍可以直接輸入地址訪問。

9、Struts2提供的方便之處:

a.數據的自動的封裝

根據頁面組件的name屬性,自動封裝到Action中對應的name屬性中。

在Jsp頁面<input name=”name” type=”text”/>

在action中會自動給屬性private String name 賦值。但是注意要有name對應的getter和setter方法。

b.數據的自動的傳遞

Action中的屬性在jsp頁面可以直接用EL表達式拿到

eg:

Action中屬性private String name;

在jsp頁面上可以直接${name}的到對應的值

按理說,EL表達式取數據的對象只有pageContext,request,session,application四類,不應該從Action對象中取name屬性值,但 struts框架重新包裝了request,getAttribute()方法被改寫(request的其他方法沒被改寫),如果從request對象中調用getAttribute()方法沒獲取到值(null),那么會自動從action中取,這樣,struts中EL表達式就可以直接獲取到 Action屬性中的值了。

上面介紹的采用了包裝模式:(相當于手機加殼案例和線程池案例(其中的close方法特殊)。參考如下:

public class StrutsRequestWrapper extends HttpServletRequestWrapper{

     //重寫

     public Object getAttribute(String key){

           //尋找原request信息

           Object obj = super.getAttribute(key);

           if(obj == null){

              //尋找valuestack信息

               obj = valuestack.findValue(key);

              //Ognl.getValue(key,context,root);

           } struts總結

           return obj;

     }

}

${name} -->request.getAttribute("name")

-->Ognl.getValue("name",context,root)

 

10.項目示例(資費列表顯示)

a.顯示默認主頁面

 index.action-->struts控制器-->index.html

b.資費列表顯示

feeList.action-->struts控制器

-->FeeListAction-->FeeDAO-->COST

-->fee_list.jsp

  1)編寫COST對應的Entity實體類

  2)編寫DAO,DBUtil

     --引入oracle驅動包

  3)編寫Action

  4)配置Action

  5)編寫JSP

    --引入jstl.jar,standard.jar

11.OGNL技術的使用

  1)什么是OGNL

OGNL是Object-Graphic Navigation Language(對象圖導航語言)的縮寫,

是一種功能強大的表達式語言(與EL表達式類似)。OGNL可以讓我們用非常

簡單的表達式訪問對象層(訪問對象的數據和方法),它用一個獨立的lib形

式出現(封裝于ognl.jar工具包中),方便我們使用或者構建自己的框架。 

 

OGNL區別于EL表達式,OGNL可以在.java文件中通過getValue()方法訪問對

象,而EL表達式不可以在.java文件中使用;EL表達式在.jsp文件中可以直接

輸出數據,而OGNL不可以,OGNL在.jsp文件中只能當做struts標簽中的屬性

值,通過struts標簽訪問數據。

  2)OGNL基本原理

    OGNL工具主要由3部分構成,具體如下

    a.OGNL引擎

        負責解析ONGL表達式,定位數據

    b.Root根存儲區(Object類型)

        負責存儲要訪問的目標對象(一個)。

    c.Context變量存儲區(Map類型)

        負責存放多個要訪問的目標對象。


  *3)OGNL基本語法

    a.訪問Root區域對象基本語法

       Ognl.getValue("OGNL表達式""Map存儲器內容","根存儲器內容");

Ognl.getValue("OGNL表達式""根存儲器內容");

--訪問簡單數據:"屬性" 例如"name"

int id = (Integer)Ognl.getValue("id", foo);

String name = (String)Ognl.getValue("name", foo);

       --訪問數組或List集合:"屬性[0]" 

           例如"arr[1]"

String arrVal = (String)Ognl.getValue("arr[1]", foo);

String  listVal = (String)Ognl.getValue("list[2]", foo);

       --訪問map集合元素:"屬性['key']"或"屬性.key"

     例如"map.c"或"map[‘two’]"  

          注:”map[‘a’]”不可用(‘a’結果為整數)

String mapVal = (String)Ognl.getValue("map.b", foo);

String mapval2 = (String)Ognl.getValue("map['user.name']",foo);

 --訪問方法:"屬性值.方法()",

    例如"list.size()"

System.out.println(Ognl.getValue("map['two'].toUpperCase()", foo));

System.out.println(Ognl.getValue("list.size()", foo));

 --訪問構造方法:"new 包名.構造方法"

    例如"new java.util.Date()"

Object obj = 

Ognl.getValue("new org.tarena.entity.Foo('TOM')", foo);

 --訪問靜態成員:"@包名.類名@成員"

    例如"@java.lang.Math@PI"

Ognl.getValue("@java.lang.Math@abs(-1)", foo);

Ognl.getValue("@java.lang.Math@PI", foo);

 --創建List對象:"{元素1,元素2}"

Object obj1 = Ognl.getValue("{'struts','hibernate','spring'}",foo);

 --創建Map對象

    "#{key1:value1,key2:value2}"

Object obj2 = Ognl.getValue("#{1:'tom',2:'jack',3:'rose'}", foo);

 

public static void main(String[] args) throws Exception {

Foo foo = new Foo();

foo.setId(100);

foo.setName("張三");

foo.setArr(new String[] { "A""B""C" });

foo.setList(Arrays.asList("芙蓉""鳳姐""春哥"));

Map<String, String> map = new HashMap<String, String>();

map.put("one""Java");

map.put("two""JavaWeb");

map.put("three""Struts2");

map.put("user.name""Scott");

foo.setMap(map);

//測試OGNL訪問foo目標對象

//Ognl.getValue("OGNL表達式", "Map存儲器內容","根存儲器內容");

//Ognl.getValue(expression, root);

Map context = new HashMap();

//訪問root基本的屬性值

int id = (Integer)Ognl.getValue("id", foo);

System.out.println(id);

String name = (String)Ognl.getValue("name", foo);

System.out.println(name);

System.out.println(Ognl.getValue("user.name", foo));

//訪問root數組和集合元素

String arrVal = (String)Ognl.getValue("arr[1]", foo);

System.out.println(arrVal);

String  listVal = (String)Ognl.getValue("list[2]", foo);

System.out.println(listVal);

//訪問root對象的map集合元素

String mapVal = (String)Ognl.getValue("map.b", foo);

System.out.println(mapVal);

String mapval2 = (String)Ognl.getValue("map['user.name']",foo);

System.out.println(mapval2);

//支持運算符

System.out.println(Ognl.getValue("id+1",foo));

//System.out.println((Integer)Ognl.getValue("id",foo)+1);

System.out.println(Ognl.getValue("\"姓名:\"+name", foo));

System.out.println(Ognl.getValue("id > 200",foo));

//方法調用

System.out.println(Ognl.getValue("map['two'].toUpperCase()", foo));

System.out.println(Ognl.getValue("list.size()", foo));

//構造方法的調用

Object obj = Ognl.getValue("new org.tarena.entity.Foo('TOM')", foo);

System.out.println(obj);

System.out.println(Ognl.getValue("name", obj));

//靜態方法和常量的調用

System.out.println(Ognl.getValue("@java.lang.Math@abs(-1)", foo));

System.out.println(Ognl.getValue("@java.lang.Math@PI", foo));

//創建一個list集合

Object obj1 = Ognl.getValue("{'struts','hibernate','spring'}",foo);

System.out.println(obj1.getClass().getName());

//創建一個map集合

Object obj2 = Ognl.getValue("#{1:'tom',2:'jack',3:'rose'}", foo);

System.out.println(obj2.getClass().getName());

}

12、OGNL技術在Struts的使用

在Struts2中有一個ValueStack(本質就是存放數據的集合)數據對象,該對象存儲了請求相關的所有數據信息。例如request,session,application,action等.

  Struts2采用OGNL工具對ValueStack進行操作。

  1)xwork對OGNL進行了部分改造

    在xwork中將原來OGNL標準結構中的Root存儲區改造成了一個棧結構

    (CompoundRoot)以前只能存放一個對象,現在進行了擴容,可以存放

    多個對象

    當利用"屬性"表達式訪問時,優先去棧頂對象尋找,沒有再去次棧頂尋找。

2)ValueStack結構(OgnlValueStack)

    ValueStack就是一個容器(Map集合)(存放東西的不是Tomcat容器)

 

3)Struts2標簽的使用

  在JSP中,利用Struts2標簽顯示數據,需要為標簽指定OGNL表達式,標簽利用表達式定位ValueStack中的數據,進行相應操作。

  a) debug標簽:顯示valuestack狀態

<s:debug></s:debug>

  b) iterator標簽:循環集合元素

    value屬性:指定ognl

    var屬性:指定循環變量,會被存放到ValueStack的context區域。

    status屬性:指定循環狀態變量,會被存放到ValueStack的context區域.該

                 變量有count屬性表示一共循環了多少個元素。

    index屬性表示當前循環元素的索引。

<s:iterator value="new int[totalPages]" status="i">

       <s:if test="#i.count==page">

          <a class="current_page"href="costList.action?page=${i.count }">

              <s:property value="#i.count"/>

           </a>

        </s:if>

         <s:else>

          <a href="costList.action?page=${i.count }">

           <s:property value="#i.count"/>

          </a>

        </s:else>

 </s:iterator>          

  c) if...else...標簽:判斷分支

       test屬性:指定ognl判斷表達式

<s:if test="page < totalPages>                  

          <a href="costList?page=${page+1 }">下一頁</a>

        </s:if>

        <s:else>

           下一頁 

 </s:else>

  d) property標簽:顯示數據

       value屬性:指定ognl表達式

<s:iterator value="costList" var="cost">

  <tr><td><s:property value="#cost.id"/></td></tr>

</s:iterator>

  e) date標簽:將date數據格式化輸出

       name屬性:指定ognl表達式

       format屬性:指定日期模板

<td>

<s:date name="#cost.createTime" format="yyyy-MM-dd HH:mm:ss"/>

</td> 

13、Action組件的相關使用

   1)Action組件的原理

       --客戶發出action請求給struts控制器

--前端控制器截獲請求并根據配置信息調用對應的action

       --struts控制器會創建valuestack對象

       --struts控制器根據請求創建Action對象并將Action壓入valuestack的root

         棧頂(Action線性安全,不用考慮并發問題,struts會為每一個請求 創

         建一個Action對象,區別于Servlet)

       --struts控制器調用一系列攔截器做一些輔助性的工作(一般都是

         valuestack的操作),如通過parmaeterInterceptor將表單中的數據賦值

          給action中的對象;還有將請求相關request,session對象放入到

          valuestack的context區域,同時將ValueStack對象存入到request中。

          存儲的key為”struts.valueStack”。(這樣,當一次請求結束后,容器

          會銷毀request,request銷毀了,其中的valuestack對象也就銷毀了)

       --控制器調用Action,執行業務方法處理(根據輸入算輸出并返回結果)

       --控制器根據Action返回值調用result視圖組件處理。

       --請求處理完畢,銷毀valuestack和Action對象。

       一次請求,一個valuestack和action對象

 2Struts中寫Action過程

定輸入、定輸出、根據輸入算輸出、返回結果

   *3)Action中如何使用session,request

        (1).利用ActionContext和ServletActionContext工具類(不推薦)

         a.ActionContext返回是Struts框架封裝成Map之后的

  request,session,application.

eg:

//將用戶信息寫入Session

ActionContext ac = ActionContext.getContext();

Map<String,Object> session = ac.getSession();

session.put("user", adminCode);

Map<String,Object> application = ac.getApplication();

Map<String,Object> request = (Map)ac.get("request");

         b.ServletActionContext返回的是Servlet中使用的request, session,

           application原有類型。

        (使用建議:存值取值建議用Map結構API,如果有特殊需求再采用

          Servlet原有類型(如獲取客戶端IP))

eg:

HttpServletRequest request = ServletActionContext.getRequest();

HttpSession session = httpRequest.getSession();

HttpServletResponse response = ServletActionContext.getResponse();

ServletContext application = ServletActionContext.getServletContext()

 

ActionContext工具類中的方法getSession()如何將HttpSession對

象封裝成Map對象的說明:

      Map----impements--->AbstructMap---extends-->SessionMap(重

                                            寫了Map中的put和get方法)

----如何將原有HttpSession封裝成Map------

public class SessionMap extends AbstractMap{

    private HttpSession session;   

     public SessionMap(HttpSession session){

          this.session = session;

    }

      public void put(Object key,Object val){

          session.setAttribute(key,val);

     }

     public Object get(Object key){

         session.getAttribute(key);

     }

}

不推薦使用 ActionContext訪問Session的方式,因為這種方式的“侵入性”較強。ActionContext是Struts2的API, 如果使用其他框架代替目前的Struts2框架,而我們實際項目中的Action的數量非常龐大,每個類都修改的話,會非常麻煩。

   (2).利用Aware接口方式注入(推薦)

將Action實現Aware接口,由框架底層將對象注入給Action中相應的變量

當action實例化時候,struts框架就會自動將session對象(在valuestack中)賦值給實現了SessionAware接口的類中的變量(就是注入)。

(即session,ruquest,response,application) 

RequestAware 對應的是Map結構的Request

  SessionAware 對應的是Map結構的Session

  ApplicationAware 對應的是Map結構的Application

           ServletRequestAware對應的HttpServletRequest

ServletResponseAware對應的HttpServeltResponse

ServletContextAware對應的ServletContext

eg:

public class LoginAction implements SessionAware{

protected Map<String,Object> session;

    ...............

public void setSession(Map<String, Object> session) {

this.session = session;

}

public String execute(){

if(("admin".equals(adminCode)) && ("1234".equals(passWord))){

session.put("user"adminCode);

return "success";

}else{

return "error";

}

}

}

(3)、使用工具類(ActionContext、ServletActionContext)還是

Aware接口?

Action組件內部用Aware接口、Action組件之外(比如后面的攔截器)用ActionContext、ServletActionContext

   4)Action屬性注入

  作用:在創建Action對象時指定屬性值

  在<action>配置中為Action組件的屬性指定一個初始值,該值在創建

       Action對象時注入。可以將一些變化的參數值,利用該方法指定。例如

       pageSize,管理員用戶名,dir存儲路徑等。

在<action>配置中,為Action對象的屬性指定初始值。使用格式如下:

<action name="feeList" class="org.action.FeeListAction">

        <!--創建Action對象時給屬性指定一個值-->

        <param name="屬性名">屬性值</param>

        <result></result>

      </action>

eg:

public class ListAction{

    private Stirng param1;

    private String param2;

    .....

public String getParam1(){

return param1;

}

..... struts總結

public setParam1(Stirng param1){

this.param1 = param1;

}

.......

 }

       struts.xml:

       <action name="feeList" class="org.action.FeeListAction">

        <param name="param1">admin</param>

        <param name="param2">1234</param>

        <result>........</result>

      </action>

   5)Action通配符配置

       Action通配符可以將多個具有相同屬性的Action整合為一個Action。

在<action>配置時,name請求名可以使用若干個*符號。然后再其他屬

       性中通過使用{1},{2}引用第一個*號,第二個*號所代表的字符串。

<!-- 通配符配置 -->

<action name="*_*" method="{2}"class="com.tarena.action.{1}">

    <result name="success">/index.jsp</result>

    </action>

 

  eg:

           CostAction.java:

public class CostAction {

//屬性定義--省略

public String add(){

System.out.println("資費添加操作");

return "success";

}

public String update(){

System.out.println("資費更新操作");

return "success";

}

}

struts.xml:

<action name="cost_*" method="{1}"

class="com.tarena.action.CostAction">

  <result name="success">/index.jsp</result>

</action>

 

14、Result組件的相關使用

  1)Result組件原理

    a.Result組件的作用

     Result組件負責生成響應視圖內容。將ValueStack中的數據做不同形式

     的輸出。

     Struts2框架提供了多種不同的Result組件類型,用于做不同形式響應。

      例如json數據響應,流數據響應,jsp響應等。

    b.Result組件相關配置

       --Result聲明定義

         <package>

              <result-types>

                <result-type name="result類型" class="Result組件實現類"/>

              </result-types>

         </package>

        --Result使用定義

        <action>

          <result name="標示符" type="result類型"></result>

        </action>

c.編寫一個轉發功能的Result組件

定義的類類必須實現Result接口(Result組件),并且將約定的execute方法實現在該方法中編寫了生成響應輸出的邏輯代碼。

public class MyDispatcherResult implements Result{

     private String location;

     //setter和getter方法

................

     //約定方法

  public void execute(){

            HttpServletRequest request = ServletActionContext.getRequest();

         HttpServletResponse response =ServletActionContext.getResponse();

          RequestDispatcher rd = request.getRequestDispatcher(location);

             rd.forward(request,response);

      }

}

  *2)掌握經常使用的Result組件

      a. JSP視圖

       --dispatcher(默認):以轉發方式調用JSP

       --redirect:以重定向方式調用JSP

        <result name="" type="dispatcher(默認)/redirect">

          jsp頁面

       </result>

      b.Action視圖

       --chain:以轉發方式調用下一個Action

       --redirectAction:以重定向方式調用下一個Action

    c:

stream:以字節流方式響應,Action中的InputStream類型的屬性以

         字節流方式輸出。

eg:由服務器端生成驗證碼圖片并以流的方式發送給瀏覽器。

 

在struts.xml端的配置如下:

 <!--驗證碼處理 -->

    <action name="image" class="org.tarena.netctoss.action.ImageAction">

       <result type="stream"  name="success">

       <param name="inputName">imageStream</param>

       </result>

       <result name="fail">/WEB-INF/jsp/login.jsp</result>

   </action>

注:其中的<param name="inputName">imageStream</param>區別于Action

    屬性注入,其作用為:給result對象指定參數值

     d:

json:以json字符串響應,將Action中指定的屬性拼成一個json字符串輸

出。

     注:

其中,a、b、c中的result組件在’struts-defaulg”包下,d中的result組件

     在”json-default”,struts-core.jar中的默認包

<package name="struts-default" abstract="true">如下:

 

<package name="struts-default" abstract="true">

<result-types>

            <result-type name="chain" class="*****"/>

            <result-type name="dispatcher" class="*****"/>

            <result-type name="freemarker" class="*****"/>

            <result-type name="httpheader" class="*****"/>

            <result-type name="redirect" class="*****"/>

            <result-type name="redirectAction" class="*****"/>

            <result-type name="stream" class="class="*****"/>

            <result-type name="velocity" class="class="*****"/>

            <result-type name="xslt" class="*****"/>

            <result-type name="plainText" class="*****"/>

        </result-types>

</package>

    相同命名空間調用:

  <result type="redirectAction">

      請求名

  </result>

    跨命名空間調用

  <result type="redirectAction">

      <param name="actionName">請求名</param>

      <param name="namespace">/</param>

  </result>

    ======資費刪除流程=====

fee_delete.action-->FeeDeleteAction-->FeeDAO

-->FeeListAction-->fee_list.jsp

============練習=============

完成課上項目任務。

擴展任務:完成資費的添加,更新處理,查看,啟用等。

 

16、json Result組件

   主要負責將Action的屬性以json字符串格式輸出。

   json Result的使用步驟:

   a.引入struts2-json-plugin.jar

   b.將<package>元素的extends屬性改為繼承"json-default"(json-default包

     的范圍比原struts-default包大,所以更改后仍可以使用以前包中的組件)

   c.<result>使用配置

     //只返回Action中一個屬性值

  <result type="json">

       <param name="root">屬性名</param>

  </result>

    //返回Action中多個屬性值

  <result type="json">

       <param name="includeProperties">

       屬性名1,屬性名2,屬性名3

      </param>

  </result>

   //返回Action中所有屬性值

  <result type="json">

  </result>

 

   因為使用name屬性默認值,所以name=”success”可以省略。

 

17、Struts2表單標簽

  1.什么是標簽

struts標簽封裝了界面顯示邏輯,用于簡化JSP。

jstl標簽用來代替jsp頁面中的java代碼,struts標簽不但可以代替jsp頁面中的

java代碼,還可以代替jsp頁面中html標記

  2.struts常用標簽:

textfield,password,hidden,textarea

radio,checkboxlist,select

checkbox,form

a) textfield 

   以輸入框方式顯示屬性值.

   name屬性指定ognl表達式,表示輸入框中的值

<input type="text" class="readonly" name=cost.id value=${cost.id

 readonly />

相當于:

  <s:textfield name="cost.id" cssClass="readonly" readonly="true">

</s:textfield>

規定輸入字段為只讀(內容不可被更改)。在html中input標簽readonly屬性

     直接寫,在struts標簽中要寫成:readonly=”true”。類似的的還有disabled要寫成

     disabled=”true”

b) textarea 

   以文本域方式顯示屬性值.

   name屬性指定ognl表達式,表示文本域中的值

 <textarea class="width300 height70">${cost.descr}</textarea>

<s:textarea name="cost.descr" cssClass="width300 height70"></s:textarea>

c)password:

 以文本框方式顯示密碼

 name屬性指定ognl表達式,,表示輸入框中的值

注:默認情況下,文本框內不會顯示密碼,如果要顯示密碼則需要設置showPassword屬性。

密碼:<s:password name="password" showPassword="true"></s:password>

d) radio: 

    以一組單選框方式顯示,并可以根據屬性值決定哪個選項選中。

 list屬性指定集合ognl,用于生成若干radio選項。

 name屬性指定ognl,用于決定哪個raido選中。

<s:radio name="cost.costType" list="#{'1':'包月','2':'套餐','3':'計時'}">

</s:radio>

e)checkbox:

以單選框方式顯示選中狀態

name屬性指定ognl表達式,name屬性值為true時,單選框默認會被選中

eg:

婚姻狀況:<s:checkbox name="marry""></s:checkbox>已婚

f)checkboxlist:

以復選框方式顯示選中狀態

name屬性指定ognl表達式,用來決定哪些復選框默認被選中。

list屬性為map<key,value>集合

listKey屬性為map集合中的key

listValue屬性為map集合中的value,為在界面顯示的內容

參考struts05_1中的form.jsp

eg1:

愛好:<s:checkboxlist name="chk" list="#session.favors" listKey="id" 

       listValue="name"></s:checkboxlist>

eg2:

    <s:checkboxlist name=”” list=”costList’” listKey="id" 

       listValue="name"></s:checkboxlist>

 

g)select:

 以下拉列表的方式顯示數據:

     name屬性指定ognl表達式,用來決定哪個option默認被選中。

eg1:

<s:select name="status" cssClass="select_search"

         list="#{0:暫停,'1':'開通','2':'暫停','3':'刪除'}">

          </s:select>

相當于

 <select class="select_search" >

                     <option value="2">全部</option>

                     <option value="1">開通</option>

                     <option value="0">暫停</option>

                     <option value="-1">刪除</option>

     </select>

   eg2:

   <s:select list=costList name=”” listKey=id listValue=name></s:select>

注:對于上面的struts標簽中的name屬性,不但可以指定ognl表達式獲取相關的數據,還可以將action中的屬性名設置為name的屬性值,這樣就可以實現表單數據的自動提交。

h)form:

theme屬性:表示主題,可選項有xhtml和simple;如果不寫,默認為xhtml 。

  theme屬性如果為默認值(xhtml),那么在使用struts表單標

    簽時候會自動添加樣式(自動添加tr、tr,讓顯示更美觀),

    這樣就會破壞當前頁面的布局和樣式。

    如果在用struts表單標簽時,沒有用struts中的form標簽而是

    使用html中的form標簽,那么在使用struts表單標簽時候也

    會自動添加樣式

<s:form action="update" namespace="/" theme="simple">

   .............

</s:form>

 通用屬性(所有標記都具備的屬性):

label

labelpostion

required

tooltip

tooltipIconPath

cssClass(html中的class)

cssStyle(html中的style)

name

value

 

18、攔截器組件

2)什么是攔截器:

  一般利用攔截器封裝一些通用性處理功能,便于重復利用。例如請求參

    數給action屬性賦值、日志記錄、權限檢查、文件上傳、事務處理等。攔截

    器通過配置方式調用,因此使用方法比較靈活,便于維護或擴展。

Struts2框架提供了大量的攔截器組件,如果不能滿足開發者需要,可以

 進行自定義。

eg:

<interceptor name="params" 

class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>

其中ParametersInterceptor類用于在創建Action對象時將表單中的參數

賦值給Action中的相關屬性。

具體見:

ReferencedLibraries/struts2-core-2.1.8.jar/struts-default.xml

 /<interceptors>標記

 

2)攔截器完整工作流程:

 

a.客戶發送一個Action請求,請求交給控制器

b.控制器創建一個ValueStack、Action對象,并將Action壓入ValueStack棧頂

c.控制器調用ActionInvocation組件執行請求處理

d.ActionInvocation組件調用請求相關的攔截器組件--前部分處理.

e.然后再調用Action組件業務方法

f.然后再調用Result組件處理方法

g.最后執行攔截器組件--后部分處理.

h.將響應信息輸出,為客戶端響應

 3)攔截器作用

    攔截器可以在Action和Result組件調用之前執行,也可以在Action和Result

    組件之后執行。

 4)自定義攔截器

    a.編寫攔截器組件實現類(兩種方法):

     1.編寫攔截器組件實現類實現Interceptor接口的interceptor方法。

   public class MyInterceptor implements Interceptor{

      public String intercept (ActionInvocation in){

           //攔截器的前期處理邏輯

           in.invoke();//執行Action和Result

          //in.invokeActionOnly();//僅執行Action

           //攔截器的后期處理邏輯

       }

}

eg:

public class CheckLoginInterceptor implements Interceptor{

public void destroy() {

// TODO Auto-generated method stub

}

public void init() {

// TODO Auto-generated method stub

}

public String intercept(ActionInvocation in) throws Exception {

System.out.println("(前期處理)自定義攔截器被調用。。。");

ActionContext ac = ActionContext.getContext();

//ActionContext ac = in.getInvocationContext();

Map<String,Object> session = ac.getSession();

//登錄檢查

if(session.get("user") == null){

//為登錄

return "login";//進入登錄頁面

}

in.invoke();//執行ActionDAO和Result--->jsp

    System.out.println("(后期處理)自定義攔截器被調用。。。");

return null;//invoke()方法執行之后,后面的返回值都無效即不會返回),因為執行in.invoke(),也即執行Action和Result調用Jsp后,返回的值沒有任何意義。

}

           }

  2.所有攔截器組件實現類也可以通過繼承AbstractInterceptor類并實現

   inteceptor方法。

eg:

public class Interceptor2 extends AbstractInterceptor {

public String intercept(ActionInvocation in) throws Exception {

System.out.println("(前期處理)自定義攔截器被調用。。。");

// ActionContext ac = ActionContext.getContext();

ActionContext ac = in.getInvocationContext();

Map<String, Object> session = ac.getSession();

// 登錄檢查

if (session.get("user") == null) {

// 未登錄

return "login";// 進入登錄頁面

}

in.invoke();// 執行Action和Result

              System.out.println("(后期處理)自定義攔截器被調用。。。");

return null;//invoke()方法執行之后,后面的返回值都無效(即不會返回),寫著只是好看一點

}

       }

   注意:當執行了invoke()方法后,invoke()方法后面的返回值無效(即不會返回),寫著只是好看一點。如果沒有執行invoke(),返回值有效。控制器會根據該返回值調用一個Result生成響應信息

 b.注冊攔截器(將攔截器注冊給struts2框架)

(1).方法一:

<package>

   <interceptors>

       <interceptor name="攔截器名"class="攔截器實現類"/>

       <interceptor name="" class=""/>

   </interceptors>

</package>

eg:

 <!-- 定義攔截器 -->

<interceptors>

  <interceptor name="checklogin" 

        class="org.tarena.netctoss.interceptor.CheckLoginInterceptor2"/>

 </interceptors>

 <!-- 使用攔截器 -->

<action name="costDelete" class=org.tarena.netctos.CostDeleteAction>

      <interceptor-ref name="checklogin"/>

    <interceptor-ref name="defaultStack"/>//調用默認攔截器棧中的攔截器

  <result name=cuccess>/WEB-INF/jsp/cost/cost_delete.jsp</result>

</action>

  struts總結

(1).方法二

創建攔截器棧(<interceptor-stack name="loginStack">),將多個攔截器放在攔截器棧中,這樣就可以在需要的地方直接引入攔截器棧就行了(<interceptor-ref name="loginStack"/>

eg:

<!-- 定義攔截器 -->

<interceptors>

  <interceptor name="checklogin" 

        class="org.tarena.netctoss.interceptor.CheckLoginInterceptor2"/>

<interceptor-stack name="loginStack">

<interceptor-ref name="checklogin"/>

<interceptor-ref name="defaultStack"/>

 </interceptor-stack>

</interceptors>

    <!-- 使用攔截器 -->

<action name="costDelete" class=org.tarena.netctos.CostDeleteAction>  

<interceptor-ref name="loginStack"/>   

<result name=cuccess>/WEB-INF/jsp/cost/cost_delete.jsp</result>

</action>

方法二中的定義攔截器的方法實際上是先定義一個checklogin攔截器,然后定義一個攔截器棧(用于存放多個攔截器),把定義的checklogin攔截器和struts默認的攔截器放在攔截器棧里面。在使用攔截器時候,直接引入攔截器棧就可以了(相當于引入了checklogin攔截器和struts默認攔截器)。

 

  c.使用攔截器組件

    (1).為所有Action指定默認使用配置,這樣,攔截器便對該包中的所有Action

       起攔截作用

   <package ******>

        <default-interceptor-ref  name="攔截器名"/>

   </package>

   --(2).為某一個Action指定使用配置

   <action>

      <interceptor-ref name="攔截器名"/>

   </action>

eg:

<action name="showAddCost">

       <interceptor-ref name="loginStack"/>

<interceptor-ref name="defaultStack"/>

<result>/WEB-INF/jsp/cost/cost_add.jsp</result>

</action>

   注意:如果為某個Action指定了攔截器配置,不會再調用指定的默認攔截器.所以一般會加上<interceptor-ref name="defaultStack"/>

 

5)fileUpload內置攔截器的使用

   a)fileUpload攔截器功能

       用于實現文件上傳功能。

fileUpload攔截器處理流程:

  客戶端發送上傳文件請求

首先,struts控制器收到請求后調用fileUpload攔截器,fileUpload攔截器調用commons-file-upload.jar上傳組件對請求提交

的表單信息進行解析。

然后將解析后的文件保存到服務器臨時目錄下,并將臨時目錄下的文件

   對象賦值給Action的File屬性。

執行Action,在Actin業務中,需要做文件復制,將臨時文件轉移到目標

   目錄中。

當Action和Result調用完畢后,清除臨時目錄下的文件,因此在Actin業務中,需要做文件復制,將臨時文件轉移到目標目錄中。

   b)上傳示例

     注意事項:

      --需要引入commons-io.jar)

      --form表單method必須為post;enctype必須為multipart/form-data

      --Action組件按下面規則接收表單信息

          <input type="file" name="xxx">

        Action屬性如下:

          private File xxx;// 臨時目錄下的文件

          private String xxxFileName;// 源文件名

          private String xxxContentType;// 源文件類型

     ---struts默認允許上傳的文件所占最大內存為2097152字節(不同計算機可

        能略有不同)。如果要更改默認設置,可以參考如下“更改struts中的默

        認設置”

更改struts中的默認設置(即修改如下配置文件):

ReferencedLibraries/struts2-core-2.1.8.jar/org-apache.struts2/default.properties

 

18、更改strts中的默認配置:

1.更改對客服端發送過來的參數進行解碼的方式:

<constant name="struts.i18n.encoding" value="gbk"/>(默認為utf-8)

2.更該允許客戶端上傳的最大文件大小值:

<constant name=struts.multipart.maxSize value=100000000/>

(默認大小為:2097152字節,約2M)

 

19、全局異常處理:

<!--全局的異常處理,當異常從Action中拋出時,會自動進入全局異常處理模塊-->

   <global-results>

      <!-- 錯誤處理 -->

    <result name="error">/WEB-INF/jsp/error.html</result>

     </global-results>

 

 <global-exception-mappings>

<exception-mapping exception="java.lang.Exception" result="error">

       </exception-mapping>

 </global-exception-mappings>

 

20、用戶輸入不存在請求資源路徑(及action不存在)處理:

<!-- 指定一個默認響應的Action,當遇到例外的action請求,該項配置啟作用 -->

<default-action-ref name="defaultAction"/>

<!-- 采用重定向方式調用toLogin -->

<action name="defaultAction">

<result type="redirectAction">

<param name="namespace">/</param>

<param name="actionName">toLogin</param>

</result>

</action>

    <!-- 顯示登錄頁面 -->

    <action name="toLogin">

<result>/WEB-INF/jsp/login.jsp</result>

 </action>

通過此配置后,用戶輸入非法請求資源路徑時便不會出現“404”錯誤提示了,而是友好地跳轉到登錄頁面。

======NETCTOSS項目========

1)項目描述(一期工程)

  實現電信計費系統的賬號管理,業務管理,資費管理,管理員和角色管理的功能。

2)項目技術架構

  主要采用Struts2,JDBC,Ajax,jQuery技術。

   采用MVC結構分層思想開發。

   表現層(V):JSP,Ajax,jQuery

   控制層(C):Struts2控制器Filter+Action

   業務層(M):JavaBean,Bean組件

   數據訪問層(M):DAO+JDBC

3)項目工程結構

  a.開發包引入

    --Struts2開發包(5個核心+1個json響應包)

    --Oracle驅動包

  b.src源碼

    org.tarena.netctoss.action

    org.tarena.netctoss.action.fee

    org.tarena.netctoss.action.account

    org.tarena.netctoss.service

    org.tarena.netctoss.dao

    org.tarena.netctoss.pojo

    org.tarena.netctoss.util

    org.tarena.netctoss.test

  c.配置文件

    web.xml : 配置struts2控制器

    struts.xml:struts2框架主配置

     --struts-fee.xml : 資費模塊配置

     --struts-account.xml:賬號模塊配置

  d.WebRoot

     WebRoot/WEB-INFO/jsp/fee/資費頁面

     WebRoot/styles/樣式文件

     WebRoot/js/腳本文件

     WebRoot/images/頁面圖片

  

=========記錄檢索=========

search.action-->SearchAction-->DAO

 

 

 

1.項目評審

  1)自我簡介,項目需求描述,功能演示

  2)典型功能實現講解

2.共通問題處理

  1)表單校驗處理(參考“jQuery表單校驗插件”目錄的資料)

     可以利用jQuery編寫校驗函數,

     也可以基于現有的jQuery擴展插件來實現

     例如validate和formvalidate等插件都可以

   2)Struts2全局異常處理

       當異常拋出Action的業務方法時,可以利用全局異常處理方式解決(在struts.xml追加配置)。

   3)將頁眉導航部分提取成一個head.jsp,

 通過include方式引入各個頁面。

   4)設置一個默認響應Action。

  遇到不能識別的Action請求,或找不到請求對應的Action時,調用該默認Action做響應

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!