天天看點

第一章 搭建Struts2開發環境

Struts2概述

       在Struts的官方網站上,寫着下面兩段話:

Apache Struts 2 is an elegant, extensible framework for creatingenterprise-ready Java web applications. The framework is designed to streamlinethe full development cycle, from building, to deploying, to maintainingapplications over time.

Apache Struts 2 was originally known as WebWork 2. After workingindependently for several years, the WebWork and Struts communities joinedforces to create Struts2. This new version of Struts is simpler to use andcloser to how Struts was always meant to be.

其大意為:Apache Struts2是一個為企業級應用打造的優秀的、可擴充的WEB架構,該架構旨在充分精簡應用程式的開發周期,進而減少建立、釋出直到應用所花費的時間。

Apache Struts2原本就是舉世聞名的Webwork2,在各自經曆幾年的發展之後,Struts和WebWork社群決定合二為一,也就是今天的Struts2。

Struts是一個基于Model2的MVC架構,為應用程式的WEB層提供了良好的結構嚴謹的實作。Struts發展較早,早期的Struts1.X已被很多J2EE程式員熟悉,經過多年來的發展,這支隊伍變得越來越大,很多企業級應用程式都是基于Struts開發的。

Struts2與Struts1.X已經不能再放到一起比較,雖然都是對MVC架構模式的實作,本質卻完全不同。Struts2的前身是WebWork,其實作方式和功能都要優于Struts1.X,但是,Struts先入為主,很多應用程式都基于Struts,其生命力和普及度使得WebWork落于下風。随着新思想和新架構的不斷湧入,特别是WEB2.0被大量提及,Struts1.x顯然無法跟上日新月異的變化,在很多應用上顯得力不從心,最終催生了Struts2.0。可以說Struts2.0是為變而變。

很大程度上,Struts2.0無法避開投機取巧的嫌疑。不過,借助Struts的名聲,加上WebWork建構良好的架構,二者取長補短,确實不失為一種黃金組合和一種絕佳的宣傳方式。

筆者杜撰此文時,可以下載下傳到的最新版本為2.1.0,但他的魅力已初露尖角,應該會有很好的前途。

Struts2的新特征

如果讀者熟悉Struts1.X,會發現Struts2比Struts1.X有了巨大的變化:

Action 類:

• Struts1要求Action類繼承一個抽象基類。Struts1的一個普遍問題是使用抽象類程式設計而不是接口。

• Struts 2 Action類可以實作一個Action接口,也可實作其他接口,使可選和定制的服務成為可能。Struts2提供一個ActionSupport基類去實作常用的接口。Action接口不是必須的,任何有execute辨別的POJO對象都可以用作Struts2的Action對象。

線程模式:

• Struts1 Action是單例模式并且必須是線程安全的,因為僅有Action的一個執行個體來處理所有的請求。單例政策限制了Struts1 Action能作的事,并且要在開發時特别小心。Action資源必須是線程安全的或同步的。

• Struts2 Action對象為每一個請求産生一個執行個體,是以沒有線程安全問題。(實際上,servlet容器給每個請求産生許多可丢棄的對象,并且不會導緻性能和垃圾回收問題)

Servlet 依賴:  

• Struts1 Action 依賴于Servlet API ,因為當一個Action被調用時HttpServletRequest和HttpServletResponse 被傳遞給execute方法。

• Struts 2 Action不依賴于容器,允許Action脫離容器單獨被測試。如果需要,Struts2 Action仍然可以通路初始的request和response。但是,其他的元素減少或者消除了直接通路HttpServetRequest 和 HttpServletResponse的必要性。

可測性:

•測試Struts1 Action的一個主要問題是execute方法暴露了servlet API(這使得測試要依賴于容器)。一個第三方擴充--StrutsTestCase--提供了一套Struts1的模拟對象(來進行測試)。

• Struts 2 Action可以通過初始化、設定屬性、調用方法來測試,“依賴注入”支援也使測試更容易。

捕獲輸入:

• Struts1 使用ActionForm對象捕獲輸入。所有的ActionForm必須繼承一個基類。因為其他JavaBean不能用作ActionForm,開發者經常建立多餘的類捕獲輸入。動态Bean(DynaBeans)可以作為建立傳統ActionForm的選擇,但是,開發者可能是在重新描述(建立)已經存在的JavaBean(仍然會導緻有備援的javabean)。

• Struts 2直接使用Action屬性作為輸入屬性,消除了對第二個輸入對象的需求。輸入屬性可能是有自己(子)屬性的rich對象類型。Action屬性能夠通過web頁面上的taglibs通路。Struts2也支援ActionForm模式。rich對象類型,包括業務對象,能夠用作輸入/輸出對象。這種ModelDriven 特性簡化了taglib對POJO輸入對象的引用。

表達式語言:

• Struts1 整合了JSTL,是以使用JSTL EL。這種EL有基本對象圖周遊,但是對集合和索引屬性的支援很弱。

• Struts2可以使用JSTL,但是也支援一個更強大和靈活的表達式語言--"Object Graph Notation Language" (OGNL). 

綁定值到頁面(view):

• Struts 1使用标準JSP機制把對象綁定到頁面中來通路。

• Struts 2 使用 "ValueStack"技術,使taglib能夠通路值而不需要把你的頁面(view)和對象綁定起來。ValueStack政策允許通過一系列名稱相同但類型不同的屬性重用頁面(view)。

類型轉換:

• Struts 1 ActionForm 屬性通常都是String類型。Struts1使用Commons-Beanutils進行類型轉換。每個類一個轉換器,對每一個執行個體來說是不可配置的。

• Struts2 使用OGNL進行類型轉換。提供基本和常用對象的轉換器。

校驗:  

• Struts 1支援在ActionForm的validate方法中手動校驗,或者通過Commons Validator的擴充來校驗。同一個類可以有不同的校驗内容,但不能校驗子對象。

• Struts2支援通過validate方法和XWork校驗架構來進行校驗。XWork校驗架構使用為屬性類類型定義的校驗和内容校驗,來支援chain校驗子屬性 

Action執行的控制:

• Struts1支援每一個子產品有單獨的Request Processors(生命周期),但是子產品中的所有Action必須共享相同的生命周期。

• Struts2支援通過攔截器堆棧(Interceptor Stacks)為每一個Action建立不同的生命周期。堆棧能夠根據需要和不同的Action一起使用。

注:以上資料從網上搜集,來源:Struts開發組,翻譯:tianxinet(胖猴)。

Struts2的環境要求

       ApacheStruts2的環境需求如下:

              Servlet API 2.4

JSP API 2.0

Java 5

需要提醒的是,在Struts中會用到Annotation,是以請将JDK版本更新到1.5.

Struts2環境搭建

4.1Struts的下載下傳

       從遊覽器輸入http://people.apache.org/builds/struts/,即可看到Struts的各個版本清單。從下圖中可以發現,現在Struts2.0的最新版是2.1.0,釋出于2007年10月29。           

第一章 搭建Struts2開發環境

(圖1)

第一章 搭建Struts2開發環境

       (圖2)

從圖2中可以看出,即可以分開下載下傳,又可以一次全部下載下傳。全部下載下傳的大小為83M,

       下表注明了各個壓縮包的作用。

壓縮包名稱 作用
struts-2.1.0-docs.zip  文檔,包含了Struts2API
struts-2.1.0-lib.zip  建構Struts2工程所需要的包
struts-2.1.0-src.zip  Struts2的所有源代碼
struts2-blank-2.1.0.war 空白工程
struts-2.1.0-all.zip 大內建,包括上面所有的内容

4.2 開發工具介紹

       目前J2EE開發工具主要分為Eclipse和NetBeans兩大陣營,Eclipse的最高版本為3.3,NetBeans的最高版本為6.0.今天剛剛從新聞上看到,NetBeans6.0的英文正式版正式釋出了,真是可喜可賀。

       筆者在開發時以Eclipse為主,但Eclipse并不支援WEB開發,需要安裝相應插件。MyEclipse是一個功能強大且架構支援非常廣泛的WEB開發插件,該産品是收費項目。目前MyEclipse的最高版本為6.0,即便如此,尚不支援Struts2.0,我們隻能手工配置Struts2.0的開發環境。

4.3 庫檔案

       從網站上下載下傳的Struts2包含了二三十個庫檔案,但大多數是可選的,有些庫是插件,用于和其他架構的整合。

       讀者可自行下載下傳struts2-blank-2.1.0.war壓縮包,展開後是一個非常簡單的項目,從WEB-INF/lib目錄中可以看到5個庫檔案,解釋如下:

包名 說明
commons-logging-1.0.4.jar 日志管理
freemarker-2.3.8.jar 表現層架構,定義了struts2的可視元件主題(theme)
ognl-2.6.11.jar OGNL表達式語言,struts2支援該EL
struts2-core-2.0.10.jar struts2的核心庫
xwork-2.0.4.jar webwork的核心庫,自然需要它的支援
第一章 搭建Struts2開發環境

(圖3)

4.3 使用Eclipse搭建Struts2的開發環境

4.3.1建立使用者庫

       将Struts2所需的包建成使用者庫,可以更加友善地進行管理和使用,這是一個好的習慣——程式設計從習慣開始。

       1.選擇菜單Window->Preferences->Java->BuildPath->User Libraries。如圖4:

第一章 搭建Struts2開發環境

       (圖4)

       2.點選右側的New…按鈕,建立一個新的使用者庫,彈出如圖5所示對話框:

第一章 搭建Struts2開發環境

       (圖5)

       3.輸入使用者庫的名稱,如:Struts2,點選OK按鈕,該對話框自動關閉。結果如圖6所示:

第一章 搭建Struts2開發環境

       (圖6)

       此時,右側的按鈕被點亮。

       4.點選“Add JARS…”按鈕,添加使用者庫所需的庫檔案,在Struts2中,至少要包含上文中提到的5個庫檔案。添加後效果如圖7所示:

第一章 搭建Struts2開發環境

       (圖7)

       5.點選“OK”完成。

4.3.2開發第一個Struts2應用程式——世界,你好

       開發WEB應用程式,本文使用了MyEclipse插件。該插件為收費軟體,目前提供英文版和日文版,不同的版本可以運作在Windows、Linux等作業系統上。為了友善使用者,MyEclipse有一個Full版,連同Eclipse一起安裝,對于初學者而言,可以減少很多麻煩和困擾。

       讀者可自行去http://www.myeclipseide.com/網站下載下傳該軟體的共享版本。建議讀者下載下傳MyEclipse5.5(這也是筆者使用的版本),這個版本相對比較穩定,MyEclipse6.0還處于測試之中。

       入門教程總是以HelloWorld作為學習的第一步,自然筆者也不例外。本示例從遊覽器輸入網址,送出請求後在頁面中顯示“世界,你好”的資訊。

       1.建立WEB工程,如圖8所示:

第一章 搭建Struts2開發環境

       (圖8)

       2.點選“Next”,輸入工程名,如圖9所示:

第一章 搭建Struts2開發環境

       (圖9)

       3.點選“Finish”完成。

       4.現在将Struts2的庫導入到工程中,右擊工程名稱彈出快捷菜單,選擇BuildPath->Add Libraries…,如圖10所示。

第一章 搭建Struts2開發環境

       (圖10)

       5.從彈出的對話框中選擇“User Libraries”,如圖11所示。

第一章 搭建Struts2開發環境

       (圖11)

       6.單擊下一步,我們看到,上文中建立的使用者庫出現在清單中,在“Struts2”前的複選框上打勾,點選“Finish”完成。如圖12。

第一章 搭建Struts2開發環境

       (圖12)

       7.将Struts2所帶的過濾器org.apache.struts2.dispatcher.FilterDispatcher配置到工程的web.xml檔案中,預設情況下,該過濾器攔截請求字元串中以.action結尾的請求,并将該請求委托給指定的Action進行處理。最直覺的表現就是調用Action的execute()方法。代碼如下:

代碼清單1:web.xml

   <filter>

       <filter-name>struts2</filter-name>

       <filter-class>

           org.apache.struts2.dispatcher.FilterDispatcher

       </filter-class>

    </filter>

    <filter-mapping>

       <filter-name>struts2</filter-name>

       <url-pattern>/*</url-pattern>

    </filter-mapping>

注:在Sturts1.X中,該行為由Servlet完成。

8.建立包com.lizanhong.action,并在該包中建立HelloWorldAction類,該類繼承自com.opensymphony.xwork2.ActionSupport。理論上,Action可以不繼承任何類或實作任何接口,以增強程式的可測試性,這也是和Struts1.X不同的地方。但是,繼承自ActionSupport可以減少更多的編碼工作。

       在ActionSupport中,定義了方法execute(),當使用者向該Action發送請求時,會自動調用。程式代碼如下:

代碼清單2:HelloWorldAction.java

package com.lizanhong.action;

import com.opensymphony.xwork2.ActionSupport;

publicclass HelloWorldAction extendsActionSupport {

    @Override

    public String execute() throws Exception {

       System.out.println("Action執行了。");

       returnSUCCESS;

    }

}

注:ActionSupport是Struts2提供的類,功能類似于Struts1.x中的Action類,該類封裝了幾個有用的功能,比如:

getText():從資源檔案中擷取國際化消息。

addFieldError():驗證輸入未通過時添加錯誤消息,支援國際化。

execute():該方法一般會被重寫,當用戶端向Action發送請求時,會調用此方法。

總結起來,該類主要提供了錯誤消息的支援和國際化支援。

       在工程類路徑下建立struts.xml檔案,這是Struts2的配置檔案,類似于Struts1.x中的struts-config.xml,在struts.xml檔案中可以配置Action、Bean、Interceptor等元件。

代碼清單3:struts.xml

<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTDStruts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

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

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

       <action name="helloworld" class="com.lizanhong.action.HelloWorldAction">

           <result>/result.jsp</result>

       </action>

    </package>

</struts>

注:WEB應用程式的類路徑是指WEB-INF/classes目錄,在Eclipse中,建立在src目錄下的檔案最終釋出後會自動複制到WEB-INF/classes目錄下。

代碼清單3中涉及到很多标簽,以下是簡單的解釋:

标簽名稱 說明
include

包含其他xml檔案,在示例中,這意味着struts.xml可以通路定義在struts-default.xml檔案中的元件。

該元素可以使得Struts2定義多個配置檔案,“分而治之”。

要注意的是,任何一個struts2配置檔案都應該和struts.xml有相同的格式,包括doctype,并且可以放在類路徑下的任何地方。

package

為Action或截攔器分組。

name:名稱,必填項,名稱自定義,沒特别要求。友善别的package引用。

extends:package能繼承其他的package,即通過該屬性實作,值為另一個package的name。

在示例中,extends =”struts-default”是從struts-default.xml中繼承的。

action 定義Action,name屬性為通路時用到的名稱,class屬性是Action的類名。
result

根據Action的傳回值定義頁面導航。

Action的預定義的傳回值有:

String SUCCESS = "success";

String NONE    = "none";

String ERROR   = "error";

String INPUT   = "input";

String LOGIN   = "login";

比如,當Action傳回SUCCESS時希望轉到ok.jsp頁面,則可以這樣寫:

<result name=”success”>ok.jsp</result>

    其中,name的預設為success。

       9.result.jsp是一個非常簡單的jsp頁面,輸出“世界,你好”。

代碼清單4:result.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//DTDHTML 4.01 Transitional//EN">

<html>

 <head>

    <base href="<%=basePath%>">

    <title>My JSP'result.jsp' starting page</title>

    <meta http-equiv="pragma" content="no-cache">

    <meta http-equiv="cache-control" content="no-cache">

    <meta http-equiv="expires" content="0">   

    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">

    <meta http-equiv="description" content="This is mypage">

    <!--

    <link rel="stylesheet"type="text/css" href="styles.css" target="_blank" rel="external nofollow" >

    -->

 </head>

 <body>

    世界,你好. <br>

 </body>

</html>

9.釋出工程,在浏覽器中輸入:http://localhost:8081/Struts2Demo/helloworld.action,在控制台輸出“Action執行了。”

10.在浏覽器的結果如下圖13:

(圖13)

struts.xml的定義檔案

代碼清單5:struts-2.0.dtd

<?xml version="1.0" encoding="UTF-8"?>

<!-- START SNIPPET: strutsDtd -->

<!--

   Struts configuration DTD.

   Use the following DOCTYPE

   <!DOCTYPE struts PUBLIC

    "-//Apache Software Foundation//DTDStruts Configuration 2.0//EN"

    "http://struts.apache.org/dtds/struts-2.0.dtd">

-->

<!ELEMENT struts (package|include|bean|constant)*>

<!ELEMENT package (result-types?, interceptors?, default-interceptor-ref?,default-action-ref?,global-results?,global-exception-mappings?, action*)>

<!ATTLIST package

    name CDATA#REQUIRED

    extends CDATA#IMPLIED

    namespace CDATA#IMPLIED

    abstract CDATA#IMPLIED

    externalReferenceResolver NMTOKEN #IMPLIED

<!ELEMENT result-types (result-type+)>

<!ELEMENT result-type (param*)>

<!ATTLIST result-type

    name CDATA#REQUIRED

    class CDATA#REQUIRED

    default (true|false) "false"

<!ELEMENT interceptors (interceptor|interceptor-stack)+>

<!ELEMENT interceptor (param*)>

<!ATTLIST interceptor

    name CDATA#REQUIRED

    class CDATA#REQUIRED

<!ELEMENT interceptor-stack (interceptor-ref+)>

<!ATTLIST interceptor-stack

    name CDATA#REQUIRED

<!ELEMENT interceptor-ref (param*)>

<!ATTLIST interceptor-ref

    name CDATA#REQUIRED

<!ELEMENT default-interceptor-ref(param*)>

<!ATTLIST default-interceptor-ref

    name CDATA#REQUIRED

<!ELEMENT default-action-ref (param*)>

<!ATTLIST default-action-ref

    name CDATA#REQUIRED

<!ELEMENT global-results (result+)>

<!ELEMENT global-exception-mappings(exception-mapping+)>

<!ELEMENT action (param|result|interceptor-ref|exception-mapping)*>

<!ATTLIST action

    name CDATA#REQUIRED

    class CDATA#IMPLIED

    method CDATA#IMPLIED

    converter CDATA#IMPLIED

<!ELEMENT param (#PCDATA)>

<!ATTLIST param

    name CDATA#REQUIRED

<!ELEMENT result (#PCDATA|param)*>

<!ATTLIST result

    name CDATA#IMPLIED

    type CDATA#IMPLIED

<!ELEMENT exception-mapping (#PCDATA|param)*>

<!ATTLIST exception-mapping

    name CDATA#IMPLIED

    exception CDATA#REQUIRED

    result CDATA#REQUIRED

<!ELEMENT include (#PCDATA)>

<!ATTLIST include

    file CDATA#REQUIRED

<!ELEMENT bean (#PCDATA)>

<!ATTLIST bean

    type CDATA#IMPLIED

    name CDATA#IMPLIED

    class CDATA#REQUIRED

    scope CDATA#IMPLIED

    static CDATA#IMPLIED

    optional CDATA#IMPLIED

<!ELEMENT constant (#PCDATA)>

<!ATTLIST constant

    name CDATA#REQUIRED

    value CDATA#REQUIRED   

<!-- END SNIPPET: strutsDtd -->

總結

       Struts是一個時下非常流行并被許多企業級應用程式采用的WEB架構,Struts2在Struts1.x的基礎上進行了大量改造,和WebWork合二為一,引進了更多的新觀念、新思想和新技術,使之更符合J2EE應用程式開發的需要。

       “工欲善其事,必先利其器”,掌握一兩種開發工具,能夠大大提高程式設計效率,也能增強開發者的信心。學習一門新技術時,第一個應用程式非常重要,如果第一個最簡單的程式運作不成功,會使得學習者的積極性大打折扣,這也是筆者不願意看到的。是以,本章圖文并茂地詳細介紹了Struts2應用程式的開發過程,并盡可能少的提及陌生的概念和術語。