Struts2與Struts1Struts2與Struts1對比
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(這使得測試要依賴于容器)。一個第三方
擴展--Struts TestCase--提供了一套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.action.extension
The URL extension to use to determine if the request is meant for a Struts action
用URL擴展名來確定是否這個請求是被用作Struts action,其實也就是設置 action的后綴,例如
login.do的'do'字。
struts.configuration
The org.apache.struts2.config.Configuration implementation class
org.apache.struts2.config.Configuration接口名
struts.configuration.files
A list of configuration files automatically loaded by Struts
struts自動加載的一個配置文件列表
struts.configuration.xml.reload
Whether to reload the XML configuration or not
是否加載xml配置(true,false)
struts.continuations.package
The package containing actions that use Rife continuations
含有actions的完整連續的package名稱
struts.custom.i18n.resources
Location of additional localization properties files to load
加載附加的國際化屬性文件(不包含.properties后綴)
struts.custom.properties
Location of additional configuration properties files to load
加載附加的配置文件的位置
struts.devMode
Whether Struts is in development mode or not
是否為struts開發模式
struts.dispatcher.parametersWorkaround
Whether to use a Servlet request parameter workaround necessary for some versions of WebLogic
(某些版本的weblogic專用)是否使用一個servlet請求參數工作區(PARAMETERSWORKAROUND)
struts.enable.DynamicMethodInvocation
Allows one to disable dynamic method invocation from the URL
允許動態方法調用
struts.freemarker.manager.classname
The org.apache.struts2.views.freemarker.FreemarkerManager implementation class
org.apache.struts2.views.freemarker.FreemarkerManager接口名
struts.i18n.encoding
The encoding to use for localization messages
國際化信息內碼
struts.i18n.reload
Whether the localization messages should automatically be reloaded
是否國際化信息自動加載
struts.locale
The default locale for the Struts application
默認的國際化地區信息
struts.mapper.class
The org.apache.struts2.dispatcher.mapper.ActionMapper implementation class
org.apache.struts2.dispatcher.mapper.ActionMapper接口
struts.multipart.maxSize
The maximize size of a multipart request (file upload)
multipart請求信息的最大尺寸(文件上傳用)
struts.multipart.parser
The org.apache.struts2.dispatcher.multipart.MultiPartRequest parser implementation for a
multipart request (file upload)
專為multipart請求信息使用的org.apache.struts2.dispatcher.multipart.MultiPartRequest解析器接口
(文件上傳用)
struts.multipart.saveDir
The directory to use for storing uploaded files
設置存儲上傳文件的目錄夾
struts.objectFactory
The com.opensymphony.xwork2.ObjectFactory implementation class
com.opensymphony.xwork2.ObjectFactory接口(spring)
struts.objectFactory.spring.autoWire
Whether Spring should autoWire or not
是否自動綁定Spring
struts.objectFactory.spring.useClassCache
Whether Spring should use its class cache or not
是否spring應該使用自身的cache
struts.objectTypeDeterminer
The com.opensymphony.xwork2.util.ObjectTypeDeterminer implementation class
com.opensymphony.xwork2.util.ObjectTypeDeterminer接口
struts.serve.static.browserCache
If static content served by the Struts filter should set browser caching header properties or
not
是否struts過濾器中提供的靜態內容應該被瀏覽器緩存在頭部屬性中
struts.serve.static
Whether the Struts filter should serve static content or not
是否struts過濾器應該提供靜態內容
struts.tag.altSyntax
Whether to use the alterative syntax for the tags or not
是否可以用替代的語法替代tags
struts.ui.templateDir
The directory containing UI templates
UI templates的目錄夾
struts.ui.theme
The default UI template theme
默認的UI template主題
struts.url.http.port
The HTTP port used by Struts URLs
設置http端口
struts.url.https.port
The HTTPS port used by Struts URLs
設置https端口
struts.url.includeParams
The default includeParams method to generate Struts URLs
在url中產生 默認的includeParams
struts.velocity.configfile
The Velocity configuration file path
velocity配置文件路徑
struts.velocity.contexts
List of Velocity context names
velocity的context列表
struts.velocity.manager.classname
org.apache.struts2.views.velocity.VelocityManager implementation class
org.apache.struts2.views.velocity.VelocityManager接口名
struts.velocity.toolboxlocation
The location of the Velocity toolbox
velocity工具盒的位置
struts.xslt.nocache
Whether or not XSLT templates should not be cached
是否XSLT模版應該被緩存
在Struts2中,action中的getXXX()只在服務器啟動時執行一次,一刷新頁面顯示的數據內容全都沒了,這種問題的解
決辦法是:
在web.xml中配置struts2.0時,
<filter-mapping>
<filter-name>action2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
把/*改成*.ation就OK了
一、Struts2配置文件
Struts2相關的配置文件有web.xml,struts.xml,struts.properties,
struts-default.xml,velocity.properties,struts-default.vm。其中web.xml,struts.xml是必須的,其它的配置
文件可選擇。它們在web應用中的功能如下:
web.xml:包含所有必須的框架組件的web部署描述符。
Struts.xml:配置包含result/view類型、action映射、攔截器等的Struts2的主要配置文件。
Struts.properties:配置struts2的框架屬性。
Struts-default.xml:在文件在struts-action-x.x.jar中,該文件是應該被包含在struts.xml中的缺省配置。
Welocity.properties:重寫了velocity的配置文件。
Struts-default.vm:相對于velocity的缺省配置。
二、Struts2配置元素
Struts2核心的配置文件是缺省的struts.xml。
必要的時候,缺省的配置文件可以包含其它的配置文件;struts文件可以放入jar中,并自動插入應用程序,這樣每個
模塊可以包含自己的配置文件并自動配置。在Freemarker和Velocity模塊中,模板也能從classpath中加載,所以整個
模塊可以作為一個簡單的jar文件被包含。
Struts.xml配置文件可以包含Interceptor、Action類和Results。
Struts.xml配置元素說明:
1、Packages
Packages:packages把actions、results、results types、interceptors
和interceptor-stacks組裝到一個邏輯單元中,從概念上講,packages就像一個對象,可以被其它子包從寫,而且可
以擁有自己獨立的部分。
Name屬性是packages的必填元素,它作為一個關鍵字被后邊的包引用;extends元素是可選的,它允許包擴展一個和多
個前邊定義的包。注意,
struts.xml文件是至上而下處理的,所有被擴展的包,需要在擴展包前定義。
Abstract元素是可選的,它可以申明一個不包含actions的配置文件。
2、Namespace
Namespace元素把actions細分到邏輯模塊,每一個namespace都有自己的
前綴(prefix),namespace避免了action之間的名字沖突,當前綴出現在URI中時,這些標簽都是名字空間感知的(
“namespace aware”),所以這些namespace prefix不必嵌入到表單或連接中。
Default的namespace是一個空字符串“”,如果在指定的配置文件中,沒有找到action,缺省的namespace也會被查找
。Local/global策略允許應用程序在action “extends”元素層次結構之外,有全局的action配置。缺省的namespace
也可以不在package中申明。
Namespace prefix可以注冊為java的申明式安全,以確保授權的用戶才能訪問namespace的資源。
Root namespace(“/”)也被支持,root就是當直接請求context path的時候的namespace。
[個人理解:namespace的用法就像struts1.x中的path一樣,只不過它在package中什么路徑,而在action中申明
action名子罷了]
3、Include
Include元素使得框架能應用“divide and conquer”來配置文件。被include
的每個配置文件必須和struts.xml有一樣的格式,一個大的項目可以采用這樣方式來組織程序模塊。
Include元素也可以和package交替出現,框架將按照順序加載配置文件。
4、Interceptor configuration
Interceptor允許應用程序在Action方法執行前后定義執行代碼,
Interceptor在應用程序開發中十分重要,對于Interceptor有許多用例,如validation, property population,
security, logging, 和profiling。
Interceptor被定義為一個Java類,Interceptor也可以組裝成Interceptor-stack,他們將按照定義的順序執行。
在struts-default.xml中定義了一些缺省的Interceptor-stack,以便框架能很好地運行。
5、Action
Action是框架的“工作單元”。Action可以指定一個Interceptor-stack、
一序列的return type和一序列的異常處理,但只有name屬性是必須的。
--------------------------------------------------------------------------------
struts2.0簡單的例子今天在apache網站上無意中看到了struts項目2.0.8正式發布了,懷著欣喜的心情我下載了
stuts2.0.8完整包。 Struts2.0.8是struts項目和WebWork2.2項目的合并版本,集成了兩大流行MVC框架的優點,對
struts框架來說是一個大的提升,同時也更大程度地簡化了開發人員的開發過程。我簡單地研究了一下這個新版本,
現在給大家介紹一個入門級的小例子,希望能對學習這個新版本的朋友有點幫助。
這個例子完成了一次URL調用返回結果頁面的過程。
首先,要從apache網站上下載struts2.0.8的完整包(可以從這里下載:
http://www.signal42.com/mirrors/apache/struts/binaries/struts-2.0.8-all.zip),解壓后需要找到下列幾個文
件:
commons-logging-1.0.4.jar
freemarker-2.3.8.jar
ognl-2.6.11.jar
struts2-core-2.0.8.jar
xwork-2.0.3.jar
然后,我們就開始做第一個例子,我們就使用經典的“HelloWorld”的名字吧!
1. 制作目錄結構
如下圖所示:
stuts2是web應用的根目錄。
2. 拷貝引用文件
將上面列舉的jar文件拷貝到步驟1中制作的目錄struts2\WEB-INF\lib中。
3. 制作jsp文件HelloWorld.jsp
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Hello World!</title>
</head>
<body>
<h2><s:property value="message" /></h2>
</body>
</html>
將該文件拷貝到步驟1中制作的目錄struts2\example中。
4.制作java文件HelloWorld.java
package example;
/** *//**
* <code>Set welcome message.</code>
*/
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorld extends ActionSupport ...{
public static final String MESSAGE = "Struts is up and running ...";
public String execute() throws Exception ...{
setMessage(MESSAGE);
return SUCCESS;
}
private String message;
public void setMessage(String message)...{
this.message = message;
}
public String getMessage() ...{
return message;
}
}
使用下面的命令編譯這個java文件:
set CLASSPATH=yourdirectory\xwork-2.0-beta-1.jar
javac HelloWorld.java
將編譯后的HelloWorld.class文件拷貝到步驟1中制作的目錄struts2\WEB-INF\classes\example中。
5.制作web應用的描述文件web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="
xmlns:xsi="
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-
app_2_4.xsd"
version="2.4">
<display-name>Struts Blank</display-name>
<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>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
將該文件拷貝到步驟1中制作的目錄struts2\WEB-INF中。
6.制作MANIFEST.MF文件(從其它地方隨便找一個即可)
將該文件拷貝到步驟1中制作的目錄struts2\META-INF中。
7.制作struts配置文件struts.xml和struts.properties
struts.xml文件:
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"
<struts>
<package name="abc" namespace="/example" extends="struts-default">
<action name="HelloWorld" class="example.HelloWorld">
<result>/example/HelloWorld.jsp</result>
</action>
<!-- Add your actions here -->
</package>
</struts>
struts.properties文件:
struts.devMode = true
struts.enable.DynamicMethodInvocation = false
將這兩個文件拷貝到步驟1中制作的目錄struts2\ WEB-INF\classes中。
好了整個例子的文件我們都搞定了。
最后,你可以將制作好的web應用struts2拷貝到tomcat下運行。
訪問http://localhost:8080/struts2/example/HelloWorld.action如果能夠看到頁面上的“Struts is up and
running ...”提示信息說明你的例子是正確的。
--------------------------------------------------------------------------------
Struts2.0 中文亂碼1.為了能正確顯示 jsp頁面直接寫的中文 在jsp頁面正確顯示添加下面字符設置。
<%@ page contentType="text/html;charset=GBK"%>
2.為了解決form提交到action中的中文參數亂碼問題,在src\struts.properties文件添加
struts.i18n.encoding=GBK
或
在struts2-core-2.0.8.jar 包中路徑為struts2-core-2.0.8\org\apache\struts2 有一個default.properties
文件
把struts.i18n.encoding=UTF-8改為struts.i18n.encoding=GBK 或者在struts.xml里面改
這樣在action中取到的參數不用自己手工轉碼 了。
--------------------------------------------------------------------------------
Struts 2.0的標志(Tag)介紹介紹常用標志前,我想先從總體上,對Struts 1.x與Struts 2.0的標志庫(Tag
Library)作比較。 Struts 1.x Struts 2.0
分類 將標志庫按功能分成HTML、Tiles、Logic和Bean等幾部分 嚴格上來說,沒有分類,所有標志都在URI為
“/struts-tags”命名空間下,不過,我們可以從功能上將其分為兩大類:非UI標志和UI標志
表達式語言(expression languages) 不支持嵌入語言(EL) OGNL、JSTL、Groovy和Velcity
以上表格,純屬個人總結,如有所不足或錯誤,請不吝指正
好了,我要開始介紹“常用”(這里所謂的“常用”,是指在已往工作中使用Struts里經常用到的)的標志了。
要在JSP中使用Struts 2.0標志,先要指明標志的引入。通過在JSP的代碼的頂部加入以下代碼可以做到這點。
<%@taglib prefix="s" uri="/struts-tags" %>
非UI標志
if、elseif和else
描述:
執行基本的條件流轉。
參數:
名稱 必需 默認 類型 描述 備注
test 是 Boolean 決定標志里內容是否顯示的表達式 else標志沒有這個參數
id 否 Object/String 用來標識元素的id。在UI和表單中為HTML的id屬性
例子:
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Condition Flow</title>
</head>
<body>
<h3>Condition Flow</h3>
<!--
這里有點小技巧:
本來可以用#parameters.name[0]來獲得,請求中name的值。但是,在我實現include例子時,
無論我用param標志給name賦任何值,#parameters里面不會含有任何值,所以#parameters.name也為空
值。
其原因為:
當使用include標志時,被包含的頁面(included)里#parameters拿到的是包含頁面里的請求參數。
因此,這里必須手工調用request.getParameter("name")。
-->
<s:set name="name" value="<%= "'" + request.getParameter("name") + "'" %>" />
<s:if test="#name == 'Max'">
Max's file here
</s:if>
<s:elseif test="#name == 'Scott'">
Scott's file here
</s:elseif>
<s:else>
Other's file here
</s:else>
</body>
</html>
例1 condition.jsp
iterator
描述:
用于遍歷集合(java.util.Collection)或枚舉值(java.util.Iterator)。
參數:
名稱 必需 默認 類型 描述
status 否 String 如果設置此參數,一個IteratorStatus的實例將會壓入每個遍歷的堆棧
value 否 Object/String 要遍歷的可枚舉的(iteratable)數據源,或者將放入新列表(List)的對象
id 否 Object/String 用來標識元素的id。在UI和表單中為HTML的id屬性
例子:
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
List list = new ArrayList();
list.add("Max");
list.add("Scott");
list.add("Jeffry");
list.add("Joe");
list.add("Kelvin");
request.setAttribute("names", list);
%>
<html>
<head>
<title>Iterator</title>
</head>
<body>
<h3>Names: </h3>
<!--
1、此處的空property元素用于獲得當前iterator的值
2、status被設成stuts,在iterator的里面就可以通過#stuts取得IteratorStatus的對象。
IteratorStatus類包含當前序號信息,如是否第一個或最后一個,是否為奇數序號。這些信息在我們做格式化的時候
,顯得非常有用。
-->
<ol>
<s:iterator value="#request.names" status="stuts">
<s:if test="#stuts.odd == true">
<li>White <s:property /></li>
</s:if>
<s:else>
<li style="background-color:gray"><s:property /></li>
</s:else>
</s:iterator>
</ol>
</body>
</html>
例2 iterator.jsp
i18n
描述:
加載資源包到值堆棧。它可以允許text標志訪問任何資源包的信息,而不只當前action相關聯的資源包。
參數:
名稱 必需 默認 類型 描述
value 是 Object/String 資源包的類路徑(如com.xxxx.resources.AppMsg)
id 否 Object/String 用來標識元素的id。在UI和表單中為HTML的id屬性
例子:
HelloWorld=Hello Wrold!
例3 classes\ ApplicationMessages.properties
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Internationization</title>
</head>
<body>
<h3>
<s:i18n name="ApplicationMessages">
<s:text name="HelloWorld" />
</s:i18n>
</h3>
</body>
</html>
例3 i18n.jsp
include
描述:
包含一個servlet的輸出(servlet或jsp的頁面)。
參數:
名稱 必需 默認 類型 描述
value 是 String 要包含的jsp或servlet
id 否 Object/String 用來標識元素的id。在UI和表單中為HTML的id屬性
例子:
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Iterator</title>
</head>
<body>
<h3>Interator Page</h3>
<s:include value="/condition.jsp">
<s:param name="name">Max</s:param>
</s:include>
<h3>i18n</h3>
<s:include value="/i18n.jsp" />
</body>
</html>
例4 include.jsp
param
描述:
為其他標簽提供參數,比如include標簽和bean標簽. 參數的name屬性是可選的,如果提供,會調用Component的方法
addParameter(String, Object), 如果不提供,則外層嵌套標簽必須實現UnnamedParametric接口(如TextTag)。
value的提供有兩種方式,通過value屬性或者標簽中間的text,不同之處我們看一下例子:
<param name="color">blue</param><!-- (A) -->
<param name="color" value="blue"/><!-- (B) -->
(A)參數值會以String的格式放入statck.
(B)該值會以java.lang.Object的格式放入statck.
參數:
名稱 必需 默認 類型 描述
name 否 String 參數名
value 否 String value表達式
id 否 Object/String 用來標識元素的id。在UI和表單中為HTML的id屬性
例子:
請參考例4。
set
描述:
set標簽賦予變量一個特定范圍內的值。當希望給一個變量賦一個復雜的表達式,每次訪問該變量而不是復雜的表達式
時用到。其在兩種情況下非常有用: 復雜的表達式很耗時 (性能提升) 或者很難理解 (代碼可讀性提高)。
參數:
名稱 必需 默認 類型 描述
name 是 String 變量名字
scope 否 String 變量作用域,可以為application, session, request, page, 或action.
value 否 Object/String 將會賦給變量的值
id 否 Object/String 用來標識元素的id。在UI和表單中為HTML的id屬性
例子:
請參考例1。
text
描述:
支持國際化信息的標簽。國際化信息必須放在一個和當前action同名的resource bundle中,如果沒有找到相應
message,tag body將被當作默認message,如果沒有tag body,message的name會被作為默認message。
參數:
名稱 必需 默認 類型 描述
name 是 String 資源屬性的名字
id 否 Object/String 用來標識元素的id。在UI和表單中為HTML的id屬性
例子:
請參考例3。
url
描述:
該標簽用于創建url,可以通過"param"標簽提供request參數。
當includeParams的值時'all'或者'get', param標簽中定義的參數將有優先權,也就是說其會覆蓋其他同名參數的值
。
參數: 略
例子:
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>URL</title>
</head>
<body>
<h3>URL</h3>
<a href='<s:url value="/i18n.jsp" />'>i18n</a><br />
<s:url id="url" value="/condition.jsp">
<s:param name="name">Max</s:param>
</s:url>
<s:a href="%{url}">if\elseif\else</s:a>
</body>
</html>
例5 url.jsp
property
描述:
得到'value'的屬性,如果value沒提供,默認為堆棧頂端的元素。
參數:
名稱 必需 默認 類型 描述
default 否 String 如果屬性是null則顯示的default值
escape 否 true Booelean 是否escape HTML
value 否 棧頂 Object 要顯示的值
id 否 Object/String 用來標識元素的id。在UI和表單中為HTML的id屬性
例子:
請參考例2。
--------------------------------------------------------------------------------
UI標志UI標志又可以分為表單UI和非表單UI兩部分。表單UI部分基本與Struts 1.x相同,都是對HTML表單元素的包裝
。不過,Struts 2.0加了幾個我們經常在項目中用到的控件如:datepicker、doubleselect、timepicker、
optiontransferselect等。因為這些標志很多都經常用到,而且參數也很多,要在一篇文章詳細說明并非易事。
需要深入了解這些標志的朋友,可以到以下查看以下網址:
http://wiki.javascud.org/display/ww2cndoc/Tags WebWork2文檔中文化計劃(中文)
http://cwiki.apache.org/WW/tag-reference.html Tag Developers Guide(英文)
本文有相當的內容也來自這兩處。
--------------------------------------------------------------------------------
Struts 2.0的Action講解http://www.tkk7.com/max/archive/2006/10/25/77157.html
當請求HelloWorld.action發生時,Struts運行時(Runtime)根據struts.xml里的Action映射集(Mapping),實例化
tutoiral.HelloWorld類,并調用其execute方法。當然,我們可以通過以下兩種方法改變這種默認調用。這個功能
(Feature)有點類似Struts 1.x中的LookupDispathAction。
在classes/sturts.xml中新建Action,并指明其調用的方法;
訪問Action時,在Action名后加上“!xxx”(xxx為方法名)。
現方法一,在classes/sturts.xml中加入下面代碼:
<action name="AliasHelloWorld" class="tutorial.HelloWorld" method="aliasAction">
<result>/HelloWorld.jsp</result>
</action>例2 classes/struts.xml中AlaisHelloWorld Action的配置
通過上面的兩個例子,細心的朋友應該可能會發現classes/tutorial/HelloWorld.java中Action方法(execute和
aliasAction)返回都是SUCCESS。這個屬性變量我并沒有定義,所以大家應該會猜到它在ActionSupport或其父類中定
義。沒錯,SUCCESS在接口com.opensymphony.xwork2.Action中定義,另外同時定義的還有ERROR, INPUT, LOGIN,
NONE。
此外,我在配置Action時都沒有為result定義名字(name),所以它們默認都為success。值得一提的是Struts 2.0中
的result不僅僅是Struts 1.x中forward的別名,它可以實現除forward外的很激動人心的功能,如將Action輸出到
FreeMaker模板、Velocity模板、JasperReports和使用XSL轉換等。這些都過result里的type(類型)屬性
(Attribute)定義的。另外,您還可以自定義result類型。
下面讓我們來做一個Velocity模板輸出的例子,首先在classes/struts.xml中新建一個Action映射(Mapping),將其
result類型設為velocity,如以下代碼所示:
<action name="VMHelloWorld" class="tutorial.HelloWorld">
<result type="velocity">/HelloWorld.vm</result>
</action>例3 classes/struts.xml中VMHelloWorld Action的配置
新建HelloWorld.vm,內容如下所示:
<html>
<head>
<title>Velocity</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<h2>Message rendered in Velocity: $message</h2>
</body>
</html>例3 HelloWorld.vm
很多時候我的同事會問我:“如果我要取得Servlet API中的一些對象,如request、response或session等,應該怎么
做?這里的execute不像Struts 1.x的那樣在參數中引入。”開發Web應用程序當然免不了跟這些對象打交道。在
Strutx 2.0你可以有兩種方式獲得這些對象:非IoC(控制反轉Inversion of Control)方式和IoC方式。
非IoC方式
要獲得上述對象,關鍵Struts 2.0中com.opensymphony.xwork2.ActionContext類。我們可以通過它的靜態方法
getContext()獲取當前Action的上下文對象。 另外,org.apache.struts2.ServletActionContext作為輔助類
(Helper Class),可以幫助您快捷地獲得這幾個對象。
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
HttpSession session = request.getSession();
如果你只是想訪問session的屬性(Attribute),你也可以通過ActionContext.getContext().getSession()獲取或添
加session范圍(Scoped)的對象。
IoC方式
要使用IoC方式,我們首先要告訴IoC容器(Container)想取得某個對象的意愿,通過實現相應的接口做到這點。具體
實現,請參考例6 IocServlet.java。
package tutorial;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
publicclass NonIoCServlet extends ActionSupport {
private String message;
public String getMessage() {
return message;
}
@Override
public String execute() {
ActionContext.getContext().getSession().put("msg", "Hello World from Session!");
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
HttpSession session = request.getSession();
StringBuffer sb =new StringBuffer("Message from request: ");
sb.append(request.getParameter("msg"));
sb.append("<br>Response Buffer Size: ");
sb.append(response.getBufferSize());
sb.append("<br>Session ID: ");
sb.append(session.getId());
message = sb.toString();
return SUCCESS;
}
}例6 classes/tutorial/NonIoCServlet.java
package tutorial;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import org.apache.struts2.interceptor.SessionAware;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
publicclass IoCServlet extends ActionSupport implements SessionAware, ServletRequestAware,
ServletResponseAware {
private String message;
private Map att;
private HttpServletRequest request;
private HttpServletResponse response;
public String getMessage() {
return message;
}
publicvoid setSession(Map att) {
this.att = att;
}
publicvoid setServletRequest(HttpServletRequest request) {
this.request = request;
}
publicvoid setServletResponse(HttpServletResponse response) {
this.response = response;
}
@Override
public String execute() {
att.put("msg", "Hello World from Session!");
HttpSession session = request.getSession();
StringBuffer sb =new StringBuffer("Message from request: ");
sb.append(request.getParameter("msg"));
sb.append("<br>Response Buffer Size: ");
sb.append(response.getBufferSize());
sb.append("<br>Session ID: ");
sb.append(session.getId());
message = sb.toString();
return SUCCESS;
}
}例6 classes/tutorial/IoCServlet.java
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>Hello World!</title>
</head>
<body>
<h2>
<s:property value="message" escape="false"/>
<br>Message from session: <s:property value="#session.msg"/>
</h2>
</body>
</html>例6 Servlet.jsp
<action name="NonIoCServlet" class="tutorial.NonIoCServlet">
<result>/Servlet.jsp</result>
</action>
<action name="IoCServlet" class="tutorial.IoCServlet">
<result>/Servlet.jsp</result>
</action>
--------------------------------------------------------------------------------
在src文件夾中加入struts.properties文件,內容如下:
struts.custom.i18n.resources=globalMessages
Struts 2.0有兩個配置文件,struts.xml和struts.properties都是放在WEB-INF/classes/下。
struts.xml用于應用程序相關的配置
struts.properties用于Struts 2.0的運行時(Runtime)的配置
在src文件夾中加入globalMessages_en_US.properties文件,內容如下:
HelloWorld=Hello World!
在src文件夾中加入globalMessages_zh_CN.properties文件,內容如下:
HelloWorld=你好,世界!
在WebContent文件夾下加入HelloWorl.jsp文件,內容如下:
<%@ page contentType="text/html; charset=UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h2><s:text name="HelloWorld"/></h2>
<h2><s:property value="%{getText('HelloWorld')}"/></h2>
</body>
</html>
資源文件查找順序
之所以說Struts 2.0的國際化更靈活是因為它可以能根據不同需要配置和獲取資源(properties)文件。在Struts
2.0中有下面幾種方法:
使用全局的資源文件,方法如上例所示。這適用于遍布于整個應用程序的國際化字符串,它們在不同的包(package)
中被引用,如一些比較共用的出錯提示;
使用包范圍內的資源文件。做法是在包的根目錄下新建名的package.properties和package_xx_XX.properties文件。
這就適用于在包中不同類訪問的資源;
使用Action范圍的資源文件。做法為Action的包下新建文件名(除文件擴展名外)與Action類名同樣的資源文件。它
只能在該Action中訪問。如此一來,我們就可以在不同的Action里使用相同的properties名表示不同的值。例如,在
ActonOne中title為“動作一”,而同樣用title在ActionTwo表示“動作二”,節省一些命名工夫;
使用<s:i18n>標志訪問特定路徑的properties文件。使用方法請參考我早前的文章《常用的Struts 2.0的標志(Tag)
介紹》。在您使用這一方法時,請注意<s:i18n>標志的范圍。在<s:i18n name="xxxxx">到</s:i18n>之間,所有的國
際化字符串都會在名為xxxxx資源文件查找,如果找不到,Struts 2.0就會輸出默認值(國際化字符串的名字)。
上面我列舉了四種配置和訪問資源的方法,它們的范圍分別是從大到小,而Struts 2.0在查找國際化字符串所遵循的
是特定的順序,如圖3所示:
圖3 資源文件查找順序圖
假設我們在某個ChildAction中調用了getText("user.title"),Struts 2.0的將會執行以下的操作:
查找ChildAction_xx_XX.properties文件或ChildAction.properties;
查找ChildAction實現的接口,查找與接口同名的資源文件MyInterface.properties;
查找ChildAction的父類ParentAction的properties文件,文件名為ParentAction.properties;
判斷當前ChildAction是否實現接口ModelDriven。如果是,調用getModel()獲得對象,查找與其同名的資源文件;
查找當前包下的package.properties文件;
查找當前包的父包,直到最頂層包;
在值棧(Value Stack)中,查找名為user的屬性,轉到user類型同名的資源文件,查找鍵為title的資源;
查找在struts.properties配置的默認的資源文件,參考例1;
輸出user.title。
參數化國際化字符串
許多情況下,我們都需要在動行時(runtime)為國際化字符插入一些參數,例如在輸入驗證提示信息的時候。在
Struts 2.0中,我們通過以下兩種方法做到這點:
在資源文件的國際化字符串中使用OGNL,格式為${表達式},例如:
validation.require=${getText(fileName)} is required
使用java.text.MessageFormat中的字符串格式,格式為{ 參數序號(從0開始), 格式類形(number | date | time
| choice), 格式樣式},例如:
validation.between=Date must between {0, date, short} and {1, date, short}
在顯示這些國際化字符時,同樣有兩種方法設置參數的值:
使用標志的value0、value1...valueN的屬性,如:
<s:text name="validation.required" value0="User Name"/>
使用param子元素,這些param將按先后順序,代入到國際化字符串的參數中,例如:
<s:text name="validation.required">
<s:param value="User Name"/>
</s:text>
讓用戶方便地選擇語言
開發國際化的應用程序時,有一個功能是必不可少的——讓用戶快捷地選擇或切換語言。在Struts 2.0中,通過
ActionContext.getContext().setLocale(Locale arg)可以設置用戶的默認語言。不過,由于這是一個比較普遍的應
用場景(Scenario),所以Struts 2.0為您提供了一個名i18n的攔截器(Interceptor),并在默認情況下將其注冊到
攔截器鏈(Interceptor chain)中。它的原理為在執行Action方法前,i18n攔截器查找請求中的一個名
為"request_locale"的參數。如果其存在,攔截器就將其作為參數實例化Locale對象,并將其設為用戶默認的區域
(Locale),最后,將此Locale對象保存在session的名為“WW_TRANS_I18N_LOCALE”的屬性中。
下面,我將提供一完整示例演示它的使用方法。
package tutorial;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Map;
publicclass Locales {
public Map<String, Locale> getLocales() {
Map<String, Locale> locales =new Hashtable<String, Locale>(2);
locales.put("American English", Locale.US);
locales.put("Simplified Chinese", Locale.CHINA);
return locales;
}
}tutorial/Locales.java
<%@taglib prefix="s" uri="/struts-tags"%>
<script type="text/javascript">
<!--
function langSelecter_onChanged() {
document.langForm.submit();
}
//-->
</script>
<s:set name="SESSION_LOCALE" value="#session['WW_TRANS_I18N_LOCALE']"/>
<s:bean id="locales" name="tutorial.Locales"/>
<form action="<s:url includeParams="get" encode="true"/>" name="langForm"
style="background-color: powderblue; padding-top: 4px; padding-bottom: 4px;">
Language: <s:select label="Language"
list="#locales.locales" listKey="value" listValue="key"
value="#SESSION_LOCALE == null ? locale : #SESSION_LOCALE"
name="request_locale" id="langSelecter"
onchange="langSelecter_onChanged()" theme="simple"/>
</form>LangSelector.jsp
上述代碼的原理為,LangSelector.jsp先實例化一個Locales對象,并把對象的Map類型的屬性locales賦予下拉列表(
select) 。如此一來,下拉列表就獲得可用語言的列表。大家看到LangSelector有<s:form>標志和一段Javascript腳
本,它們的作用就是在用戶在下拉列表中選擇了后,提交包含“reqeust_locale”變量的表單到Action。在打開頁面
時,為了下拉列表的選中的當前區域,我們需要到session取得當前區域(鍵為“WW_TRANS_I18N_LOCALE”的屬性),
而該屬性在沒有設置語言前是為空的,所以通過值棧中locale屬性來取得當前區域(用戶瀏覽器所設置的語言)。
你可以把LangSelector.jsp作為一個控件使用,方法是在JSP頁面中把它包含進來,代碼如下所示: <s:include
value="/LangSelector.jsp"/>
在例1中的HellloWorld.jsp中<body>后加入上述代碼,并在struts.xml中新建Action,代碼如下:
<action name="HelloWorld">
<result>/HelloWorld.jsp</result>
</action>
或者,如果你多個JSP需要實現上述功能,你可以使用下面的通用配置,而不是為每一個JSP頁面都新建一個Action。
<action name="*">
<result>/{1}.jsp</result>
</action>
分布運行程序,在瀏覽器的地址欄中輸入http://localhost:8080/Struts2_i18n/HelloWorld.action,出現圖4所示頁
面:
圖3 HelloWorld.action
在下拉列表中,選擇“American English”,出現圖5所示頁面:
圖4 HelloWorld.action
可能大家會問為什么一定要通過Action來訪問頁面呢?
你可以試一下不用Action而直接用JSP的地址來訪問頁面,結果會是無論你在下拉列表中選擇什么,語言都不會改變。
這表示不能正常運行的。其原因為如果直接使用JSP訪問頁面,Struts 2.0在web.xml的配置的過濾器(Filter)就不
會工作,所以攔截器鏈也不會工作。