深入Struts 1.1

深入Struts 1.1

developerWorks
文檔選項
將此頁作爲電子郵件發送

將此頁作爲電子郵件發送


拓展 Tomcat 應用

下載 IBM 開源 J2EE 應用服務器 WAS CE 新版本 V1.1


級別: 初級

王和全 ([email protected]),

2003 年 8 月 02 日

作爲基於MVC模式的Web應用最經典框架,Struts已經正式推出了1.1版本,該版本在以往版本的基礎上,提供了許多激動人心的新功能。本文就將帶你走進Struts 1.1去深入地瞭解這些功能。

說明:希望本文的讀者能有一定的Struts使用基礎。

Model 2

 

Struts是基於Model 2之上的,而Model 2是經典的MVC(模型-視圖-控制器)模型的Web應用變體,這個改變主要是由於網絡應用的特性--HTTP協議的無狀態性引起的。Model 2的目的和MVC一樣,也是利用控制器來分離模型和視圖,達到一種層間鬆散耦合的效果,提高系統靈活性、複用性和可維護性。在多數情況下,你可以將Model 2與MVC等同起來。

下圖表示一個基於Java技術的典型網絡應用,從中可以看出Model 2中的各個部分是如何對應於Java中各種現有技術的。




在利用Model 2之前,我們是把所有的表示邏輯和業務邏輯都集中在一起(比如大雜燴似的JSP),有時也稱這種應用模式爲Model 1,Model 1的主要缺點就是緊耦合,複用性差以及維護成本高。





回頁首


Struts 1.1 和Model 2

 

既然Struts 1.1是基於Model 2之上,那它的底層機制也就是MVC,下面是Struts 1.1中的MVC實現示意圖:




圖解說明:其中不同顏色代表MVC的不同部分:紅色(控制器)、紫色(模型)和綠色(視圖)

首先,控制器(ActionServlet)進行初始化工作,讀取配置文件(struts-config.xml),爲不同的Struts模塊初始化相應的ModuleConfig對象。比如配置文件中的Action映射定義都保存在ActionConfig集合中。相應地有ControlConfig集合、FormBeanConfig集合、ForwardConfig集合和MessageResourcesConfig集合等。

提示:模塊是在Struts 1.1中新提出的概念,在稍後的內容中我們將詳細介紹,你現在可以簡單地把模塊看作是一個子系統,它們共同組成整個應用,同時又各自獨立。Struts 1.1中所有的處理都是在特定模塊環境中進行的。模塊的提出主要是爲了解決Struts 1.0中單配置文件的問題。

控制器接收HTTP請求,並從ActionConfig中找出對應於該請求的Action子類,如果沒有對應的Action,控制器直接將請求轉發給JSP或者靜態頁面。否則控制器將請求分發至具體Action類進行處理。

在控制器調用具體Action的execute方法之前,ActionForm對象將利用HTTP請求中的參數來填充自己(可選步驟,需要在配置文件中指定)。具體的ActionForm對象應該是ActionForm的子類對象,它其實就是一個JavaBean。此外,還可以在ActionForm類中調用validate方法來檢查請求參數的合法性,並且可以返回一個包含所有錯誤信息的ActionErrors對象。如果執行成功,ActionForm自動將這些參數信息以JavaBean(一般稱之爲form bean)的方式保存在Servlet Context中,這樣它們就可以被其它Action對象或者JSP調用。

Struts將這些ActionForm的配置信息都放在FormBeanConfig集合中,通過它們Struts能夠知道針對某個客戶請求是否需要創建相應的ActionForm實例。

Action很簡單,一般只包含一個execute方法,它負責執行相應的業務邏輯,如果需要,它也進行相應的數據檢查。執行完成之後,返回一個ActionForward對象,控制器通過該ActionForward對象來進行轉發工作。我們主張將獲取數據和執行業務邏輯的功能放到具體的JavaBean當中,而Action只負責完成與控制有關的功能。遵循該原則,所以在上圖中我將Action對象歸爲控制器部分。

提示:其實在Struts 1.1中,ActionMapping的作用完全可以由ActionConfig來替代,只不過由於它是公共API的一部分以及兼容性的問題得以保留。ActionMapping通過繼承ActionConfig來獲得與其一致的功能,你可以等同地看待它們。同理,其它例如ActionForward與ForwardConfig的關係也是如此。

下圖給出了客戶端從發出請求到獲得響應整個過程的圖解說明。




下面我們就來詳細地討論一下其中的每個部分,在這之前,先來了解一下模塊的概念。





回頁首


模塊

 

我們知道,在Struts 1.0中,我們只能在web.xml中爲ActionServlet指定一個配置文件,這對於我們這些網上的教學例子來說當然沒什麼問題,但是在實際的應用開發過程中,可能會有些麻煩。因爲許多開發人員都可能同時需要修改配置文件,但是配置文件只能同時被一個人修改,這樣肯定會造成一定程度上的資源爭奪,勢必會影響開發效率和引起開發人員的抱怨。

在Struts 1.1中,爲了解決這個並行開發的問題,提出了兩種解決方案:

  1. 多個配置文件的支持
  2. 模塊的支持

 

支持多個配置文件,是指你能夠爲ActionServlet同時指定多個xml配置文件,文件之間以逗號分隔,比如Struts提供的MailReader演示例子中就採用該種方法。

  <!-- Action Servlet Configuration -->
  <servlet>
	<servlet-name>action</servlet-name>
	<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
	<init-param>
		<param-name>config</param-name>
		<param-value>/WEB-INF/struts-config.xml, /WEB-INF/struts-config-registration.xml</param-value>
	</init-param> 
	<load-on-startup>1</load-on-startup>
  </servlet>

這種方法可以很好地解決修改衝突的問題,不同的開發人員可以在不同的配置文件中設置自己的Action、ActionForm等等(當然不是說每個開發人員都需要自己的配置文件,可以按照系統的功能模塊進行劃分)。但是,這裏還是存在一個潛在的問題,就是可能不同的配置文件之間會產生衝突,因爲在ActionServlet初始化的時候這幾個文件最終還是需要合併到一起的。比如,在struts-config.xml中配置了一個名爲success的<forward>,而在struts-config-registration.xml中也配置了一個同樣的<forward>,那麼執行起來就會產生衝突。

爲了徹底解決這種衝突,Struts 1.1中引進了模塊(Module)的概念。一個模塊就是一個獨立的子系統,你可以在其中進行任意所需的配置,同時又不必擔心和其它的配置文件產生衝突。因爲前面我們講過,ActionServlet是將不同的模塊信息保存在不同的ModuleConfig對象中的。要使用模塊的功能,需要進行以下的準備工作:

1、爲每個模塊準備一個配置文件

2、配置web.xml文件,通知控制器

決定採用多個模塊以後,你需要將這些信息告訴控制器,這需要在web.xml文件進行配置。下面是一個典型的多模塊配置:

<init-param>
	<param-name>config</param-name>
	<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
	<param-name>config/customer</param-name> 
	<param-value>/WEB-INF/struts-config-customer.xml</param-value>
</init-param>
<init-param> 
	<param-name>config/order</param-name>
	<param-value>/WEB-INF/struts-config-order.xml</param-value>
</init-param>

要配置多個模塊,你需要在原有的一個<init-param>(在Struts 1.1中將其對應的模塊稱爲缺省模塊)的基礎之上,增加模塊對應的<init-param>。其中<param-name>表示爲config/XXX的形式,其中XXX爲對應的模塊名,<param-value>中還是指定模塊對應的配置文件。上面這個例子說明該應用有三個模塊,分別是缺省模塊、customer和order,它們分別對應不同的配置文件。

3、準備各個模塊所需的ActionForm、Action和JSP等資源

但是要注意的是,模塊的出現也同時帶來了一個問題,即如何在不同模塊間進行轉發?有兩種方法可以實現模塊間的轉發,一種就是在<forward>(全局或者本地)中定義,另外一種就是利用org.apache.struts.actions.SwitchAction。

下面就是一個全局的例子:

    ... 
    <struts-config>
	... 
	<global-forwards>
		<forward name="toModuleB"
			contextRelative="true"  
			path="/moduleB/index.do" 
		redirect="true"/>   
	... 
	</global-forwards>  
	...   
    </struts-config>

可以看出,只需要在原有的path屬性前加上模塊名,同時將contextRelative屬性置爲true即可。此外,你也可以在<action>中定義一個類似的本地<forward>。

  <action-mappings>
	<!-- Action mapping for profile form -->
	<action path="/login" 
	type="com.ncu.test.LoginAction"  
	name="loginForm"     
	scope="request"      
	input="tile.userLogin"
	validate="true">     
	<forward name="success" contextRelative="true" path="/moduleA/login.do"/> 
	</action> 
  </action-mappings>

如果你已經處在其他模塊,需要轉回到缺省模塊,那應該類似下面這樣定義,即模塊名爲空。

<forward name="success" contextRelative="true" path="/login.do"/>

此外,你也可以使用org.apache.struts.actions.SwitchAction,例如:

    ...
    <action-mappings> 
	<action path="/toModule" 
	type="org.apache.struts.actions.SwitchAction"/>  
	...    
    </action-mappings>  
    ...





回頁首


ActionServlet

 

我們首先來了解MVC中的控制器。在Struts 1.1中缺省採用ActionServlet類來充當控制器。當然如果ActionServlet不能滿足你的需求,你也可以通過繼承它來實現自己的類。這可以在/WEB-INF/web.xml中來具體指定。

要掌握ActionServlet,就必須瞭解它所扮演的角色。首先,ActionServlet表示MVC結構中的控制器部分,它需要完成控制器所需的前端控制及轉發請求等職責。其次,ActionServlet被實現爲一個專門處理HTTP請求的Servlet,它同時具有servlet的特點。在Struts 1.1中它主要完成以下功能:

  • 接收客戶端請求
  • 根據客戶端的URI將請求映射到一個相應的Action類
  • 從請求中獲取數據填充Form Bean(如果需要)
  • 調用Action類的execute()方法獲取數據或者執行業務邏輯
  • 選擇正確的視圖響應客戶

 

此外,ActionServlet還負責初始化和清除應用配置信息的任務。ActionServlet的初始化工作在init方法中完成,它可以分爲兩個部分:初始化ActionServlet自身的一些信息以及每個模塊的配置信息。前者主要通過initInternal、initOther和initServlet三個方法來完成。

我們可以在/WEB-INF/web.xml中指定具體的控制器以及初始參數,由於版本的變化以及Struts 1.1中模塊概念的引進,一些初始參數被廢棄或者移入到/WEB-INF/struts-config.xml中定義。下面列出所有被廢棄的參數,相應地在web.xml文件中也不鼓勵再使用。

  • application
  • bufferSize
  • content
  • debug
  • factory
  • formBean
  • forward
  • locale
  • mapping
  • maxFileSize
  • multipartClass
  • nocache
  • null
  • tempDir

ActionServlet根據不同的模塊來初始化ModuleConfig類,並在其中以XXXconfig集合的方式保存該模塊的各種配置信息,比如ActionConfig,FormBeanConfig等。

初始化工作完成之後,ActionServlet準備接收客戶請求。針對每個請求,方法process(HttpServletRequest request, HttpServletResponse response)將被調用。該方法指定具體的模塊,然後調用該模塊的RequestProcessor的process方法。

protected void process(HttpServletRequest request, 
		HttpServletResponse response) 
		throws IOException, ServletException {
	RequestUtils.selectModule(request, getServletContext());        
	getRequestProcessor(getModuleConfig(request)).process(request, response);
}

RequestProcessor包含了Struts控制器的所有處理邏輯,它調用不同的processXXX方法來完成不同的處理。下表列出其中幾個主要的方法:

方法 功能
processPath 獲取客戶端的請求路徑
processMapping 利用路徑來獲得相應的ActionMapping
processActionForm 初始化ActionForm(如果需要)並存入正確的scope中
processActionCreate 初始化Action
processActionPerform 調用Action的execute方法
processForwardConfig 處理Action返回的ActionForward




回頁首


ActionForm

 

對於ActionForm你可以從以下幾個方面來理解它:

  1. ActionForm表示HTTP窗體中的數據,可以將其看作是模型和視圖的中介,它負責保存視圖中的數據供模型或者視圖使用。Struts 1.1文檔中把它比作HTTP和Action之間的防火牆,這體現了ActionForm具有的過濾保護的作用,只有通過ActionForm驗證的數據才能夠發送到Action處理。
  2. ActionForm是與一個或多個ActionConfig關聯的JavaBean,在相應的action的execute方法被調用之前,ActionForm會自動利用請求參數來填充自己(初始化屬性)。
  3. ActionForm是一個抽象類,你必須通過繼承來實現自己的類。

 

ActionForm首先利用屬性的getter和setter方法來實現初始化,初始化完畢後,ActionForm的validate方法被調用,你可以在其中來檢查請求參數的正確性和有效性,並且可以將錯誤信息以ActionErrors的形式返回到輸入窗體。否則,ActionForm將被作爲參數傳給action的execute方法以供使用。

ActionForm bean的生命週期可以設置爲session(缺省)和request,當設置爲session時,記得在reset方法中將所有的屬性重新設置爲初始值。

由於ActionForm對應於HTTP窗體,所以隨着頁面的增多,你的ActionForm將會急速增加。而且可能同一類型頁面字段將會在不同的ActionForm中出現,並且在每個ActionForm中都存在相同的驗證代碼。爲了解決這個問題,你可以爲整個應用實現一個ActionForm或者至少一個模塊對應於一個ActionForm。

但是,聚合的代價就是複用性很差,而且難維護。針對這個問題,在Struts 1.1中提出了DynaActionForm的概念。

DynaActionForm類

DynaActionForm的目的就是減少ActionForm的數目,利用它你不必創建一個個具體的ActionForm類,而是在配置文件中配置出所需的虛擬ActionForm。例如,在下表中通過指定<form-bean>的type爲"org.apache.struts.action.DynaActionForm"來創建一個動態的ActionForm--loginForm。

<form-beans>
	<form-bean name="loginForm" type="org.apache.struts.action.DynaActionForm">  
		<form-property name="actionClass" type="java.lang.String"/>
		<form-property name="username" type="java.lang.String"/>
		<form-property name="password" type="java.lang.String"/> 
	</form-bean> 
</form-beans>

動態的ActionForm的使用方法跟普通的ActionForm相同,但是要注意一點。普通的ActionForm對象需要爲每個屬性提供getter和setter方法,以上面的例子而言,我們需要提供getUsername() 和 setUsername()方法取得和設置username屬性,同樣地有一對方法用於取得和設置password屬性和actionClass屬性。

如果使用DynaActionForm,它將屬性保存在一個HashMap類對象中,同時提供相應的get(name) 和 set(name)方法,其中參數name是要訪問的屬性名。例如要訪問DynaActionForm中username的值,可以採用類似的代碼:

String username = (String)form.get("username");

由於值存放於一個HashMap對象,所以要記得對get()方法返回的Object對象做強制性類型轉換。正是由於這點區別,如果你在Action中非常頻繁地使用ActionForm對象,建議還是使用普通的ActionForm對象。

在Struts 1.1中,除了DynaActionForm以外,還提供了表單輸入自動驗證的功能,在包org.apache.struts.validator中提供了許多有用的類,其中最常見的就是DynaValidatorForm類。

DynaValidatorForm類

DynaValidatorForm是DynaActionForm的子類,它能夠提供動態ActionForm和自動錶單輸入驗證的功能。和使用DynaActionForm類似,你必須首先在配置文件中進行配置:

<form-beans>
	<form-bean name="loginForm" type="org.apache.struts.validator.DynaValidatorForm"> 
		<form-property name="actionClass" type="java.lang.String"/>     
		<form-property name="username" type="java.lang.String"/> 
		<form-property name="password" type="java.lang.String"/>  
	</form-bean>
</form-beans>

同時要定義驗證的插件:

  <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
	<set-property property="pathnames"  
	value="/WEB-INF/validator-rules.xml,  
	/WEB-INF/validation.xml"/>
  </plug-in>

其中的validator.xml和validator-rules.xml分別表示驗證定義和驗證規則的內容(可以合併在一起),比如針對上例中的DynaValidatorForm,我們有如下驗證定義(validator.xml):

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE form-validation PUBLIC  
"-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0//EN"  
"http://jakarta.apache.org/commons/dtds/validator_1_0.dtd">
<!--    Validation Rules    $Id: validation.xml-->
<form-validation>  
<!-- ========== Default Language Form Definitions ===================== -->
<formset>  
	<form name="loginForm">     
		<field property="username" depends="required, minlength,maxlength"> 
			<arg0   key="prompt.username"/>          
			<arg1   key="${var:minlength}" name="minlength" resource="false"/>       
			<arg2   key="${var:maxlength}" name="maxlength" resource="false"/>              
			<var>                
				<var-name>maxlength</var-name>    
				<var-value>16</var-value>         
			</var>          
			<var>      
				<var-name>minlength</var-name>     
				<var-value>3</var-value>         
			</var>       
		</field>     
		<field property="password" depends="required, minlength,maxlength" bundle="alternate">          
			<arg0   key="prompt.password"/>   
			<arg1   key="${var:minlength}" name="minlength" resource="false"/>          
			<arg2   key="${var:maxlength}" name="maxlength" resource="false"/>  
			<var>              
				<var-name>maxlength</var-name>     
				<var-value>16</var-value>        
			</var>          
			<var>      
				<var-name>minlength</var-name> 
				<var-value>3</var-value>       
			</var>        
		</field>    
	</form>   
</formset>
</form-validation>

從上述定義中,我們可以看到對於字段username有三項驗證:required, minlength, maxlength,意思是該字段不能爲空,而且長度在3和16之間。而validator-rules.xml文件則可以採用Struts提供的缺省文件。注意在<form-bean>中定義的form是如何與validation.xml中的form關聯起來的。最後,要啓動自動驗證功能,還需要將Action配置的validate屬性設置爲true。

<action path="/login"  
type="com.ncu.test.LoginAction"
name="loginForm"          
scope="request"         
input="tile.userLogin"validate="true">

此時,Struts將根據xml配置文件中的定義來檢驗表單輸入,並將不符合要求的錯誤信息輸出到頁面。但是你可能會想:這個功能雖然好,可是什麼檢驗都跑到服務器端執行,效率方面和用戶易用性方面是不是有些問題?你可能會懷念起那簡單的JavaScript客戶端驗證。

不用擔心,在Struts 1.1中也支持JavaScript客戶端驗證。如果你選擇了客戶端驗證,當某個表單被提交以後,Struts 1.1啓動客戶端驗證,如果瀏覽器不支持JavaScript驗證,則服務器端驗證被啓動,這種雙重驗證機制能夠最大限度地滿足各種開發者的需要。JavaScript驗證代碼也是在validator-rules.xml文件中定義的。要啓動客戶端驗證,你必須在相應的JSP文件中做如下設置:

  1. 爲<html:form>增加onsubmit屬性
  2. 設置Javascript支持

 

下表中列出了一JSP文件的示例代碼,紅字部分爲Javascript驗證所需代碼。

<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<table bgcolor="#9AFF9A" cellspacing="0" cellpadding="10" border="1" width="100%">
	<tr>
	<td> 
	<table cellspacing="0" cellpadding="0" border="0" width="100%"> 
	<tr bgcolor="#696969"> 
		<td align="center">     
		<font color="#FFFFFF">Panel 3: Profile</font>  
		</td>
		</tr> 
	<tr>  
		<td><br> 
		<html:errors/>  
		<html:form action="/login.do" focus="username"  οnsubmit="return validateLoginForm(this);">  
		<html:hidden property="actionClass"/>   
		<center>      
		<table>      
			<tr>        
			<td>UserName:</td>   
			<td><html:text property="username" size="20"/></td> 
			</tr> 
			<tr>  
			<td>Password:</td>   
			<td><html:password property="password" size="20"/></td>    
			</tr>  
			<tr>  
			<td colspan=2><html:submit property="submitProperty" value="Submit"/></td>     
		</table>   
		</center>  
		</html:form> 
		<html:javascript formName="loginForm" dynamicJavascript="true" staticJavascript="false"/>  
	
	<script language="Javascript1.1" src="staticJavascript.jsp"></script>  
	</td> 
	</tr> 
	</table>
	</td>
	</tr>
</table>

其中onsubmit的值爲"return validateLoginForm(this);",它的語法爲:

return validate + struts-config.xml中定義的form-bean名稱 + (this);

staticJavascript.jsp的內容爲:

<%@ page language="java" %>
<%-- set document type to Javascript (addresses a bug in Netscape according to a web resource --%>
<%@ page contentType="application/x-javascript" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html:javascript dynamicJavascript="false" staticJavascript="true"/>

如果validator-rules.xml中定義的基本驗證功能不能滿足你的需求,你可以自己添加所需的驗證類型。





回頁首


Action

 

我們通過繼承Action類來實現具體的執行類。具體Action類的功能一般都在execute(以前是perform方法)方法中完成,其中主要涉及到以下幾個方面:

  1. 輔助ActionForm進行一些表單數據的檢查。
  2. 執行必要的業務邏輯,比如存取數據庫,調用實體bean等。
  3. 更新服務器端的bean數據,後續對象中可能會用到這些數據,比如在JSP中利用bean:write來獲得這些數據。
  4. 根據處理結果決定程序的去處,並以ActionForward對象的形式返回給ActionServlet。

 

提示:由於在Action和ActionForm中都可以實現驗證方法,那麼如何來安排它們之間的分工呢?一般來說,我們秉着MVC分離的原則,也就是視圖級的驗證工作放在ActionForm來完成,比如輸入不能爲空,email格式是否正確,利用ValidatorForm可以很輕鬆地完成這些工作。而與具體業務相關的驗證則放入Action中,這樣就可以獲得最大ActionForm重用性的可能。

前面我們提到過,我們主張將業務邏輯執行分離到單獨的JavaBean中,而Action只負責錯誤處理和流程控制。而且考慮到重用性的原因,在執行業務邏輯的JavaBean中不要引用任何與Web應用相關的對象,比如HttpServletRequest,HttpServletResponse等對象,而應該將其轉化爲普通的Java對象。關於這一點,可以參考Petstore中WAF框架的實現思路。

此外,你可能還注意到execute與perform的一個區別:execute方法簡單地擲出Exception異常,而perform方法則擲出ServletException和IOException異常。這不是說Struts 1.1在異常處理功能方面弱化了,而是爲了配合Struts 1.1中一個很好的功能--宣稱式異常處理機制。





回頁首


宣稱式異常處理

 

和EJB中的宣稱式事務處理概念類似,宣稱式異常處理其實就是可配置的異常處理,你可以在配置文件中指定由誰來處理Action類中擲出的某種異常。你可以按照以下步驟來完成該功能:

  1. 實現org.apache.struts.action.ExceptionHandler的子類,覆蓋execute方法,在該方法中處理異常並且返回一個ActionForward對象
  2. 在配置文件中配置異常處理對象,你可以配置一個全局的處理類或者單獨爲每個Action配置處理類

 

下表就定義了一個全局的處理類CustomizedExceptionHandler,它被用來處理所有的異常。

<global-exceptions> 
<exception 
	handler="com.yourcorp.CustomizedExceptionHandler" 
	key="global.error.message" 
	path="/error.jsp"    
	scope="request"    
	type="java.lang.Exception"/>
</global-exceptions>

其中具體的參數含義,可以參考ExceptionHandler.java源文件。





回頁首


taglib

 

講完了模型和控制器,接下來我們要涉及的是視圖。視圖的角色主要是由JSP來完成,從JSP的規範中可以看出,在視圖層可以"折騰"的技術不是很多,主要的就是自定義標記庫的應用。Struts 1.1在原有的四個標記庫的基礎上新增了兩個標記庫--Tiles和Nested。

其中Tiles除了替代Template的基本模板功能外,還增加了佈局定義、虛擬頁面定義和動態頁面生成等功能。Tiles強大的模板功能能夠使頁面獲得最大的重用性和靈活性,此外可以結合Tiles配置文件中的頁面定義和Action的轉發邏輯,即你可以將一個Action轉發到一個在Tiles配置文件中定義的虛擬頁面,從而減少頁面的數量。比如,下表中的Action定義了一個轉發路徑,它的終點是tile.userMain,而後者是你在Tiles配置文件中定義的一個頁面。

<!-- ========== Action Mapping Definitions ============================== -->
<action-mappings>  
<!-- Action mapping for profile form --> 
	<action path="/login"   
		type="com.ncu.test.LoginAction"      
		name="loginForm"    
		scope="request"     
		input="tile.userLogin"
		validate="true">     
		<forward name="success" path="tile.userMain"/>   
	</action> 
</action-mappings>

Tiles配置文件:tiles-defs.xml

<!DOCTYPE tiles-definitions PUBLIC 
"-//Apache Software Foundation//DTD Tiles Configuration//EN"       "http://jakarta.apache.org/struts/dtds/tiles-config.dtd">
<tiles-definitions>  
<!-- =======================================================  --> 
<!-- Master definitions                                       -->
<!-- =======================================================  --> 
<!-- Page layout used as root for all pages. --> 
<definition name="rootLayout" path="/tiles-layouts/rootLayout.jsp"> 
	<put name="titleString" value="CHANGE-ME"/>   
	<put name="topMenu" value="/tiles-components/topMenu.jsp"/> 
	<put name="leftMenu" value="/tiles-components/panel1.jsp"/>  
	<put name="body" value="CHANGE-ME"/>   
	<put name="footer" value="/tiles-components/footer.jsp"/> 
</definition> 
<!-- =======================================================  --> 
<!-- Page definitions 					-->  
<!-- =======================================================  --> 
<!-- User Login page --> 
<definition name="tile.userLogin" extends="rootLayout"> 
	<put name="titleString" value="User Login"/>  
	<put name="body" value="/src/userLogin.jsp"/> 
</definition>  
<!-- User Main page --> 
<definition name="tile.userMain" extends="rootLayout"> 
	<put name="titleString" value="User Main"/>  
	<put name="body" value="/src/userMain.jsp"/> 
</definition>
</tiles-definitions>

而Nested標記庫的作用是讓以上這些基本標記庫能夠嵌套使用,發揮更大的作用。





回頁首


Commons Logging 接口

 

所謂的Commons Logging接口,是指將日誌功能的使用與日誌具體實現分開,通過配置文件來指定具體使用的日誌實現。這樣你就可以在Struts 1.1中通過統一的接口來使用日誌功能,而不去管具體是利用的哪種日誌實現,有點於類似JDBC的功能。Struts 1.1中支持的日誌實現包括:Log4J,JDK Logging API, LogKit,NoOpLog和SimpleLog。

你可以按照如下的方式來使用Commons Logging接口(可以參照Struts源文中的許多類實現):

package com.foo;
// ...
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
//...
	public class Foo {    
	// ...    
	private static Log log = LogFactory.getLog(Foo.class);
	// ...    
	public void setBar(Bar bar) {       
		if (log.isTraceEnabled()) {         
			log.trace("Setting bar to " + bar);   
		}      
	this.bar = bar;   
	}
// ...
}

而開啓日誌功能最簡單的辦法就是在WEB-INF/classes目錄下添加以下兩個文件:

commons-logging.properties文件:

# Note: The Tiles framework now uses the commons-logging package to output different information or debug statements. 
Please refer to this package documentation to enable it. The simplest way to enable logging is to create two files in 
WEB-INF/classes:
# commons-logging.properties
# org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
# simplelog.properties
# # Logging detail level,
# # Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
#org.apache.commons.logging.simplelog.defaultlog=trace
org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog

simplelog.properties文件:

# Logging detail level,
# Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
org.apache.commons.logging.simplelog.defaultlog=fatal

這裏我們採用的日誌實現是SimpleLog,你可以在simplelog.properties文件指定日誌明細的級別:trace,debug,info,warn,error和fatal,從trace到fatal錯誤級別越來越高,同時輸出的日誌信息也越來越少。而這些級別是和org.apache.commons.logging.log接口中的方法一一對應的。這些級別是向後包含的,也就是前面的級別包含後面級別的信息。

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章