|
在本系列教程中我們將學(xué)習(xí)到Struts2的各種技術(shù)。在本教程中使用的工具和程序庫的版本如下: 開發(fā)工具:MyEclipse6 Web服務(wù)器:Tomcat6 Struts版本:Struts2.0.11.1 JDK版本:JDK1.5.0_12 J2EE版本:Java EE5.0 在本系列教程中Web工程的上下文路徑都是struts2,如果在Web根目錄有一個(gè)index.jsp文件,則訪問路徑如下: 由于MyEclipse6目前并不支持Struts2,所以我們需要到struts.去下載Struts2安裝包。要想正常使用Struts2,至少需要如下五個(gè)包(可能會因?yàn)?/span>Struts2的版本不同,包名略有差異,但包名的前半部是一樣的)。 struts2-core-2.0.11.1.jar xwork-2.0.4.jar commons-logging-1.0.4.jar freemarker-2.3.8.jar ognl-2.6.11.jar Struts2雖然在大版本號上是第二個(gè)版本,但基本上在配置和使用上已經(jīng)完全顛覆了Struts1.x的方式(當(dāng)然,Struts2仍然是基于MVC模式的,也是動(dòng)作驅(qū)動(dòng)的,可能這是唯一沒變的東西)。Struts2實(shí)際上是在Webwork基礎(chǔ)上構(gòu)建起來的MVC框架。我們從Struts2的源代碼中可以看到,有很多都是直接使用的xwork(Webwork的核心技術(shù))的包。既然從技術(shù)上來說Struts2是全新的框架,那么就讓我們來學(xué)習(xí)一下這個(gè)新的框架的使用方法。 如果大家使用過Struts1.x,應(yīng)該對建立基于Struts1.x的Web程序的基本步驟非常清楚。讓我們先來回顧一下建立基于Struts1.x的Web程序的基本步驟。 1. 安裝Struts。由于Struts的入口點(diǎn)是ActionServlet,所以得在web.xml中配置一下這個(gè)Servlet。 2. 編寫Action類(一般從org.apache.struts.action.Action類繼承)。 3. 編寫ActionForm類(一般從org.apache.struts.action.ActionForm類繼承),這一步不是必須的,如果要接收客戶端提交的數(shù)據(jù),需要執(zhí)行這一步。 4. 在struts-config.xml文件中配置Action和ActionForm。 5. 如果要采集用戶錄入的數(shù)據(jù),一般需要編寫若干JSP頁面,并通過這些JSP頁面中的form將數(shù)據(jù)提交給Action。 下面我們就按著編寫struts1.x程序的這五步和struts2.x程序的編寫過程一一對應(yīng),看看它們誰更“酷”。下面我們來編寫一個(gè)基于Struts2的Web程序。這個(gè)程序的功能是讓用戶錄入兩個(gè)整數(shù),并提交給一個(gè)Struts Action,并計(jì)算這兩個(gè)數(shù)的代數(shù)和,如果代碼和為非負(fù)數(shù),則跳轉(zhuǎn)到positive.jsp頁面,否則跳轉(zhuǎn)到negative.jsp頁面。 【第1步】 安裝Struts2 這一步對于Struts1.x和Struts2都是必須的,只是安裝的方法不同。Struts1的入口點(diǎn)是一個(gè)Servlet,而Struts2的入口點(diǎn)是一個(gè)過濾器(Filter)。因此,Struts2要按過濾器的方式配置。下面是在web.xml中配置Struts2的代碼: <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> 【第2步】 編寫Action類 這一步和Struts1.x也必須進(jìn)行。只是Struts1.x中的動(dòng)作類必須從Action類中繼承,而Struts2.x的動(dòng)作類需要從com.opensymphony.xwork2.ActionSupport類繼承。下面是計(jì)算兩個(gè)整數(shù)代碼和的Action類,代碼如下:package action;
import com.opensymphony.xwork2.ActionSupport; public class FirstAction extends ActionSupport { private int operand1; private int operand2; public String execute() throws Exception { if (getSum() >= 0) // 如果代碼數(shù)和是非負(fù)整數(shù),跳到positive.jsp頁面 { return "positive"; } else // 如果代碼數(shù)和是負(fù)整數(shù),跳到negative.jsp頁面 { return "negative"; } } public int getOperand1() { return operand1; } public void setOperand1(int operand1) { System.out.println(operand1); this.operand1 = operand1; } public int getOperand2() { return operand2; } public void setOperand2(int operand2) { System.out.println(operand2); this.operand2 = operand2; } public int getSum() { return operand1 + operand2; // 計(jì)算兩個(gè)整數(shù)的代碼數(shù)和 } } 從上面的代碼可以看出,動(dòng)作類的一個(gè)特征就是要覆蓋execute方法,只是Struts2的execute方法沒有參數(shù)了,而Struts1.x的execute方法有四個(gè)參數(shù)。而且execute方法的返回值也不同的。Struts2只返回一個(gè)String,用于表述執(zhí)行結(jié)果(就是一個(gè)標(biāo)志)。上面代碼的其他部分將在下面講解。 【第3步】 編寫ActionForm類 在本例中當(dāng)然需要使用ActionForm了。在Struts1.x中,必須要單獨(dú)建立一個(gè)ActionForm類(或是定義一個(gè)動(dòng)作Form),而在Struts2中ActionForm和Action已經(jīng)二合一了。從第二步的代碼可以看出,后面的部分就是應(yīng)該寫在ActionForm類中的內(nèi)容。所以在第2步,本例的ActionForm類已經(jīng)編寫完成(就是Action類的后半部分)。 【第4步】 配置Action類 這一步struts1.x和struts2.x都是必須的,只是在struts1.x中的配置文件一般叫struts-config.xml(當(dāng)然也可以是其他的文件名),而且一般放到WEB-INF目錄中。而在struts2.x中的配置文件一般為struts.xml,放到WEB-INF"classes目錄中。下面是在struts.xml中配置動(dòng)作類的代碼:<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts./dtds/struts-2.0.dtd"> <struts> <package name="struts2" namespace="/mystruts" extends="struts-default"> <action name="sum" class="action.FirstAction"> <result name="positive">/positive.jsp</result> <result name="negative">/negative.jsp</result> </action> </package> </struts> 在<struts>標(biāo)簽中可以有多個(gè)<package>,第一個(gè)<package>可以指定一個(gè)Servlet訪問路徑(不包括動(dòng)作名),如“/mystruts”。extends屬性繼承一個(gè)默認(rèn)的配置文件“struts-default”,一般都繼承于它,大家可以先不去管它。<action>標(biāo)簽中的name屬性表示動(dòng)作名,class表示動(dòng)作類名。 <result>標(biāo)簽的name實(shí)際上就是execute方法返回的字符串,如果返回的是“positive”,就跳轉(zhuǎn)到positive.jsp頁面,如果是“negative”,就跳轉(zhuǎn)到negative.jsp頁面。在<struts>中可以有多個(gè)<package>,在<package>中可以有多個(gè)<action>。我們可以用如下的URL來訪問這個(gè)動(dòng)作: 注:Struts1.x的動(dòng)作一般都以.do結(jié)尾,而Struts2是以.action結(jié)尾。 【第5步】 編寫用戶錄入接口(JSP頁面) 1. 主界面(sum.jsp) 在Web根目錄建立一個(gè)sum.jsp,代碼如下: <%@ page language="java" import="java.util.*" pageEncoding="GBK" %>
<%@ taglib prefix="s" uri="/struts-tags"%> <html> <head> <title>輸入操作數(shù)</title> </head> <body> 求代數(shù)和 <br/> <s:form action="mystruts/sum.action" > <s:textfield name="operand1" label=" 操作數(shù)1"/> <s:textfield name="operand2" label=" 操作數(shù)2" /> <s:submit value="代數(shù)和" /> </s:form> </body> </html> 在sum.jsp中使用了Struts2帶的tag。在Struts2中已經(jīng)將Struts1.x的好幾個(gè)標(biāo)簽庫都統(tǒng)一了,在Struts2中只有一個(gè)標(biāo)簽庫/struts-tags。這里面包含了所有的Struts2標(biāo)簽。但使用Struts2的標(biāo)簽大家要注意一下。在<s:form>中最好都使用Struts2標(biāo)簽,盡量不要用HTML或普通文本,大家可以將sum.jsp的代碼改為如下的形式,看看會出現(xiàn)什么效果: ... ... 求代數(shù)和 <br/> <s:form action="mystruts/sum.action" > 操作數(shù)1:<s:textfield name="operand1" /><br/> 操作數(shù)2:<s:textfield name="operand1" /><br/> <s:submit value="代數(shù)和" /> </s:form> ... ... 提示一下,在<s:form>中Struts2使用<table>定位。 2. positive.jsp <%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>顯示代數(shù)和</title> </head> <body> 代數(shù)和為非負(fù)整數(shù)<h1><s:property value="sum" /></h1> </body> </html> 3. negative.jsp <%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>顯示代數(shù)和</title> </head> <body> 代數(shù)和為負(fù)整數(shù)<h1><s:property value="sum" /></h1> </body> </html> 這兩個(gè)jsp頁面的實(shí)現(xiàn)代碼基本一樣,只使用了一個(gè)<s:property>標(biāo)簽來顯示Action類中的sum屬性值。<s:property>標(biāo)簽是從request對象中獲得了一個(gè)對象中得到的sum屬性,如我們可以使用如下的代碼來代替<s:property value=”sum”/>: <% com.opensymphony.xwork2.util.OgnlValueStack ovs = (com.opensymphony.xwork2.util.OgnlValueStack)request.getAttribute("struts.valueStack"); out.println(ovs.findString("sum")); %> 啟動(dòng)Tomcat后,在IE中輸入如下的URL來測試這個(gè)例子:
Struts2教程2:處理一個(gè)form多個(gè)submit 在很多Web應(yīng)用中,為了完成不同的工作,一個(gè)HTML form標(biāo)簽中可能有兩個(gè)或多個(gè)submit按鈕,如下面的代碼所示: <html action="
" method="post"> ![]() <input type="submit" value="保存" /> <input type="submit" value="打印" /> </html>
由于在<form>中的多個(gè)提交按鈕都向一個(gè)action提交,使用Struts2 Action的execute方法就無法判斷用戶點(diǎn)擊了哪一個(gè)提交按鈕。如果大家使用過Struts1.x就會知道在Struts1.2.9之前的版本需要使用一個(gè)LookupDispatchAction動(dòng)作來處理含有多個(gè)submit的form。但使用LookupDispatchAction動(dòng)作需要訪問屬性文件,還需要映射,比較麻煩。從Struts1.2.9開始,加入了一個(gè)EventDispatchAction動(dòng)作。這個(gè)類可以通過java反射來調(diào)用通過request參數(shù)指定的動(dòng)作(實(shí)際上只是判斷某個(gè)請求參數(shù)是不存在,如果存在,就調(diào)用在action類中和這個(gè)參數(shù)同名的方法)。使用EventDispatchAction必須將submit的name屬性指定不同的值以區(qū)分每個(gè)submit。而在Struts2中將更容易實(shí)現(xiàn)這個(gè)功能。 當(dāng)然,我們也可以模擬EventDispatchAction的方法通過request獲得和處理參數(shù)信息。但這樣比較麻煩。在Struts2中提供了另外一種方法,使得無需要配置可以在同一個(gè)action類中執(zhí)行不同的方法(默認(rèn)執(zhí)行的是execute方法)。使用這種方式也需要通過請求參來來指定要執(zhí)行的動(dòng)作。請求參數(shù)名的格式為 action!method.action 注:由于Struts2只需要參數(shù)名,因此,參數(shù)值是什么都可以。 下面我就給出一個(gè)實(shí)例程序來演示如何處理有多個(gè)submit的form: 【第1步】實(shí)現(xiàn)主頁面(more_submit.jsp)
<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>My JSP 'hello.jsp' starting page</title> </head> <body> <s:form action="submit.action" > <s:textfield name="msg" label="輸入內(nèi)容"/> <s:submit name="save" value="保存" align="left" method="save"/> <s:submit name="print" value="打印" align="left" method="print" /> </s:form> </body> </html> 在more_submit.jsp中有兩個(gè)submit:保存和打印。其中分別通過method屬性指定了要調(diào)用的方法:save和print。因此,在Action類中必須要有save和print方法。 【第2步】實(shí)現(xiàn)Action類(MoreSubmitAction)
package action;
import javax.servlet.http.*; import com.opensymphony.xwork2.ActionSupport; import org.apache.struts2.interceptor.*; public class MoreSubmitAction extends ActionSupport implements ServletRequestAware { private String msg; private javax.servlet.http.HttpServletRequest request; // 獲得HttpServletRequest對象 public void setServletRequest(HttpServletRequest request) { this.request = request; } // 處理save submit按鈕的動(dòng)作 public String save() throws Exception { request.setAttribute("result", "成功保存[" + msg + "]"); return "save"; } // 處理print submit按鈕的動(dòng)作 public String print() throws Exception { request.setAttribute("result", "成功打印[" + msg + "]"); return "print"; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } } 上面的代碼需要注意如下兩點(diǎn): save和print方法必須存在,否則會拋出java.lang.NoSuchMethodException異常。 Struts2 Action動(dòng)作中的方法和Struts1.x Action的execute不同,只使用Struts2 Action動(dòng)作的execute方法無法訪問request對象,因此,Struts2 Action類需要實(shí)現(xiàn)一個(gè)Struts2自帶的攔截器來獲得request對象,攔截器如下: 【第3步】配置Struts2 Action struts.xml的代碼如下: <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts./dtds/struts-2.0.dtd"> <struts> <package name="demo" extends="struts-default" > <action name="submit" class="action.MoreSubmitAction"> <result name="save" > /result.jsp </result> <result name="print"> /result.jsp </result> </action> </package> </struts> 【第4步】編寫結(jié)果頁(result.jsp)
<%@ page pageEncoding="GBK"%>
<html> <head> <title>提交結(jié)果</title> </head> <body> <h1>${result}</h1> </body> </html> 在result.jsp中將在save和print方法中寫到request屬性中的執(zhí)行結(jié)果信息取出來,并輸出到客戶端。 啟動(dòng)Tomcat后,在IE中執(zhí)行如下的URL來測試程序: 大家也可以直接使用如下的URL來調(diào)用save和print方法: 調(diào)用print方法:http://localhost:8080/moresubmit/submit!print.action 在本文中將詳細(xì)講述struts.xml文件的常用配置及注意事項(xiàng)。 1. 使用<include>標(biāo)簽重用配置文件 在Struts2中提供了一個(gè)默認(rèn)的struts.xml文件,但如果package、action、interceptors等配置比較多時(shí),都放到一個(gè)struts.xml文件不太容易維護(hù)。因此,就需要將struts.xml文件分成多個(gè)配置文件,然后在struts.xml文件中使用<include>標(biāo)簽引用這些配置文件。這樣做的優(yōu)點(diǎn)如下: 結(jié)構(gòu)更清晰,更容易維護(hù)配置信息。 配置文件可以復(fù)用。如果在多個(gè)Web程序中都使用類似或相同的配置文件,那么可以使用<include>標(biāo)簽來引用這些配置文件,這樣可以減少工作量。 假設(shè)有一個(gè)配置文件,文件名為newstruts.xml,代碼如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts./dtds/struts-2.0.dtd"> <struts> <package name="demo" extends="struts-default" > <action name="submit" class="action.MoreSubmitAction"> <result name="save" > /result.jsp </result> <result name="print"> /result.jsp </result> </action> </package> </struts>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts./dtds/struts-2.0.dtd"> <struts> <include file="newstruts.xml"/> <package name="test" extends="struts-default"> ![]() </package> </struts>
大家要注意一下,用<include>引用的xml文件也必須是完成的struts2的配置。實(shí)際上<include>在引用時(shí)是單獨(dú)解析的xml文件,而不是將被引用的文件插入到struts.xml文件中。 2. action的別名
在默認(rèn)情況下,Struts2會調(diào)用動(dòng)作類的execute方法。但有些時(shí)候,我們需要在一個(gè)動(dòng)作類中處理不同的動(dòng)作。也就是用戶請求不同的動(dòng)作時(shí),執(zhí)行動(dòng)作類中的不同的方法。為了達(dá)到這個(gè)目的,可以在<action>標(biāo)簽中通過method方法指定要指行的動(dòng)作類的方法名,并且需要為不同的動(dòng)作起不同的名子(也稱為別名)。如下面代碼所示: <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts./dtds/struts-2.0.dtd"> <struts> <package name="demo" extends="struts-default" > <action name="test" class="action.MyAction"> ![]() </action> <action name="my" class="action. MyAction" method="my"> ![]() </action> </package> </struts> 上面代碼的兩個(gè)動(dòng)作的class屬性都指向同一個(gè)類,name為這個(gè)類起了兩個(gè)動(dòng)作別名:test和my。在動(dòng)作my中,使用了method屬性指定要要運(yùn)行的方法名為my。 在MyAction類中必須要有my方法,代碼如下: package action;
import com.opensymphony.xwork2.ActionSupport; public class MyAction extends ActionSupport { ![]() public String execute() throws Exception { // 處理test動(dòng)作的代碼 } public String my() throws Exception { // 處理my動(dòng)作的代碼 } ![]() }
除了在struts.xml中配置別名,還可以通過請求參數(shù)來描述指定動(dòng)作(并不需要在struts.xml中配置)。請求參數(shù)的格式如下: http://localhost:8080/contextPath/actionName!method.action 關(guān)于通過請求指定動(dòng)作的詳細(xì)內(nèi)容,請參閱筆者寫的《Struts2教程2:處理一個(gè)form多個(gè)submit》。 3. 為action指定參數(shù) 在struts2中還可以為action指定一個(gè)或多個(gè)參數(shù)。大家還記著struts1.x是如何設(shè)置的action參數(shù)不? 在struts1.x中可以使用<action>標(biāo)簽的parameter屬性為其指定一個(gè)action參數(shù),如果要指定多個(gè),就只能通過逗號(,)或其他的分隔符將不同的參數(shù)隔開。而在struts2中可以通過<param>標(biāo)簽指定任意多個(gè)參數(shù)。代碼如下: <action name="submit" class="action.MyAction">
<param name="param1">value1</param> <param name="param2">value2</param> <result name="save" > /result.jsp </result> ![]() </action>
package action;
import com.opensymphony.xwork2.ActionSupport; public class MyAction extends ActionSupport { private String param1; private String param2; public String execute() throws Exception { System.out.println(param1 + param2); } public void setParam1(String param1) { this.param1 = param1; } public void setParam2(String param2) { this.param2 = param2; } ![]() }
當(dāng)struts2在調(diào)用execute之前,param1和param2的值就已經(jīng)是相應(yīng)參數(shù)的值了,因此,在execute方法中可以直接使用param1和param2。 4. 選擇result類型
在默認(rèn)時(shí),<result>標(biāo)簽的type屬性值是“dispatcher”(實(shí)際上就是轉(zhuǎn)發(fā),forward)。開發(fā)人員可以根據(jù)自己的需要指定不同的類型,如redirect、stream等。如下面代碼所示: <result name="save" type="redirect"> /result.jsp </result> 這此result-type可以在struts2-core-2.0.11.1.jar包或struts2源代碼中的struts-default.xml文件中找到,在這個(gè)文件中找到<result-types>標(biāo)簽,所有的result-type都在里面定義了。代碼如下: <result-types>
<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/> <result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/> <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/> <result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/> <result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/> <result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/> <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/> <result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/> <result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/> <result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" /> <!-- Deprecated name form scheduled for removal in Struts 2.1.0. The camelCase versions are preferred. See ww-1707 --> <result-type name="redirect-action" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/> <result-type name="plaintext" class="org.apache.struts2.dispatcher.PlainTextResult" /> </result-types> 5. 全局result 有很多時(shí)候一個(gè)<result>初很多<action>使用,這時(shí)可以使用<global-results>標(biāo)簽來定義全局的<result>,代碼如下:
<struts>
<package name="demo" extends="struts-default"> <global-results> <result name="print">/result.jsp</result> </global-results> <action name="submit" class="action.MoreSubmitAction"> ![]() </action> <action name="my" class="action.MoreSubmitAction" method="my"> ![]() </action> </package> </struts>
在本文中將詳細(xì)講述struts.xml文件的常用配置及注意事項(xiàng)。 1. 使用<include>標(biāo)簽重用配置文件 在Struts2中提供了一個(gè)默認(rèn)的struts.xml文件,但如果package、action、interceptors等配置比較多時(shí),都放到一個(gè)struts.xml文件不太容易維護(hù)。因此,就需要將struts.xml文件分成多個(gè)配置文件,然后在struts.xml文件中使用<include>標(biāo)簽引用這些配置文件。這樣做的優(yōu)點(diǎn)如下: 結(jié)構(gòu)更清晰,更容易維護(hù)配置信息。 配置文件可以復(fù)用。如果在多個(gè)Web程序中都使用類似或相同的配置文件,那么可以使用<include>標(biāo)簽來引用這些配置文件,這樣可以減少工作量。 假設(shè)有一個(gè)配置文件,文件名為newstruts.xml,代碼如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts./dtds/struts-2.0.dtd"> <struts> <package name="demo" extends="struts-default" > <action name="submit" class="action.MoreSubmitAction"> <result name="save" > /result.jsp </result> <result name="print"> /result.jsp </result> </action> </package> </struts>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts./dtds/struts-2.0.dtd"> <struts> <include file="newstruts.xml"/> <package name="test" extends="struts-default"> ![]() </package> </struts>
大家要注意一下,用<include>引用的xml文件也必須是完成的struts2的配置。實(shí)際上<include>在引用時(shí)是單獨(dú)解析的xml文件,而不是將被引用的文件插入到struts.xml文件中。 2. action的別名
在默認(rèn)情況下,Struts2會調(diào)用動(dòng)作類的execute方法。但有些時(shí)候,我們需要在一個(gè)動(dòng)作類中處理不同的動(dòng)作。也就是用戶請求不同的動(dòng)作時(shí),執(zhí)行動(dòng)作類中的不同的方法。為了達(dá)到這個(gè)目的,可以在<action>標(biāo)簽中通過method方法指定要指行的動(dòng)作類的方法名,并且需要為不同的動(dòng)作起不同的名子(也稱為別名)。如下面代碼所示: <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts./dtds/struts-2.0.dtd"> <struts> <package name="demo" extends="struts-default" > <action name="test" class="action.MyAction"> ![]() </action> <action name="my" class="action. MyAction" method="my"> ![]() </action> </package> </struts> 上面代碼的兩個(gè)動(dòng)作的class屬性都指向同一個(gè)類,name為這個(gè)類起了兩個(gè)動(dòng)作別名:test和my。在動(dòng)作my中,使用了method屬性指定要要運(yùn)行的方法名為my。 在MyAction類中必須要有my方法,代碼如下: package action;
import com.opensymphony.xwork2.ActionSupport; public class MyAction extends ActionSupport { ![]() public String execute() throws Exception { // 處理test動(dòng)作的代碼 } public String my() throws Exception { // 處理my動(dòng)作的代碼 } ![]() }
除了在struts.xml中配置別名,還可以通過請求參數(shù)來描述指定動(dòng)作(并不需要在struts.xml中配置)。請求參數(shù)的格式如下: http://localhost:8080/contextPath/actionName!method.action 關(guān)于通過請求指定動(dòng)作的詳細(xì)內(nèi)容,請參閱筆者寫的《Struts2教程2:處理一個(gè)form多個(gè)submit》。 3. 為action指定參數(shù) 在struts2中還可以為action指定一個(gè)或多個(gè)參數(shù)。大家還記著struts1.x是如何設(shè)置的action參數(shù)不? 在struts1.x中可以使用<action>標(biāo)簽的parameter屬性為其指定一個(gè)action參數(shù),如果要指定多個(gè),就只能通過逗號(,)或其他的分隔符將不同的參數(shù)隔開。而在struts2中可以通過<param>標(biāo)簽指定任意多個(gè)參數(shù)。代碼如下: <action name="submit" class="action.MyAction">
<param name="param1">value1</param> <param name="param2">value2</param> <result name="save" > /result.jsp </result> ![]() </action>
package action;
import com.opensymphony.xwork2.ActionSupport; public class MyAction extends ActionSupport { private String param1; private String param2; public String execute() throws Exception { System.out.println(param1 + param2); } public void setParam1(String param1) { this.param1 = param1; } public void setParam2(String param2) { this.param2 = param2; } ![]() }
當(dāng)struts2在調(diào)用execute之前,param1和param2的值就已經(jīng)是相應(yīng)參數(shù)的值了,因此,在execute方法中可以直接使用param1和param2。 4. 選擇result類型
在默認(rèn)時(shí),<result>標(biāo)簽的type屬性值是“dispatcher”(實(shí)際上就是轉(zhuǎn)發(fā),forward)。開發(fā)人員可以根據(jù)自己的需要指定不同的類型,如redirect、stream等。如下面代碼所示: <result name="save" type="redirect"> /result.jsp </result> 這此result-type可以在struts2-core-2.0.11.1.jar包或struts2源代碼中的struts-default.xml文件中找到,在這個(gè)文件中找到<result-types>標(biāo)簽,所有的result-type都在里面定義了。代碼如下: <result-types>
<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/> <result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/> <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/> <result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/> <result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/> <result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/> <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/> <result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/> <result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/> <result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" /> <!-- Deprecated name form scheduled for removal in Struts 2.1.0. The camelCase versions are preferred. See ww-1707 --> <result-type name="redirect-action" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/> <result-type name="plaintext" class="org.apache.struts2.dispatcher.PlainTextResult" /> </result-types> 5. 全局result 有很多時(shí)候一個(gè)<result>初很多<action>使用,這時(shí)可以使用<global-results>標(biāo)簽來定義全局的<result>,代碼如下:
<struts>
<package name="demo" extends="struts-default"> <global-results> <result name="print">/result.jsp</result> </global-results> <action name="submit" class="action.MoreSubmitAction"> ![]() </action> <action name="my" class="action.MoreSubmitAction" method="my"> ![]() </action> </package> </struts>
Struts2教程4:使用validate方法驗(yàn)證數(shù)據(jù) 在Struts2中最簡單的驗(yàn)證數(shù)據(jù)的方法是使用validate。我們從ActionSupport類的源代碼中可以看到,ActionSupport類實(shí)現(xiàn)了一個(gè)Validateable接口。這個(gè)接口只有一個(gè)validate方法。如果Action類實(shí)現(xiàn)了這個(gè)接口,Struts2在調(diào)用execute方法之前首先會調(diào)用這個(gè)方法,我們可以在validate方法中驗(yàn)證,如果發(fā)生錯(cuò)誤,可以根據(jù)錯(cuò)誤的level選擇字段級錯(cuò)誤,還是動(dòng)作級錯(cuò)誤。并且可使用addFieldError或addActionError加入相應(yīng)的錯(cuò)誤信息,如果存在Action或Field錯(cuò)誤,Struts2會返回“input”(這個(gè)并不用開發(fā)人員寫,由Struts2自動(dòng)返回),如果返回了“input”,Struts2就不會再調(diào)用execute方法了。如果不存在錯(cuò)誤信息,Struts2在最后會調(diào)用execute方法。 這兩個(gè)add方法和ActionErrors類中的add方法類似,只是add方法的錯(cuò)誤信息需要一個(gè)ActionMessage對象,比較麻煩。除了加入錯(cuò)誤信息外,還可以使用addActionMessage方法加入成功提交后的信息。當(dāng)提交成功后,可以顯示這些信息。
以上三個(gè)add方法都在ValidationAware接口中定義,并且在ActionSupport類中有一個(gè)默認(rèn)的實(shí)現(xiàn)。其實(shí),在ActionSupport類中的實(shí)現(xiàn)實(shí)際上是調(diào)用了ValidationAwareSupport中的相應(yīng)的方法,也就是這三個(gè)add方法是在ValidationAwareSupport類中實(shí)現(xiàn)的,代碼如下: private final ValidationAwareSupport validationAware = new ValidationAwareSupport();
public void addActionError(String anErrorMessage) { validationAware.addActionError(anErrorMessage); } public void addActionMessage(String aMessage) { validationAware.addActionMessage(aMessage); } public void addFieldError(String fieldName, String errorMessage) { validationAware.addFieldError(fieldName, errorMessage); } 下面我們來實(shí)現(xiàn)一個(gè)簡單的驗(yàn)證程序,來體驗(yàn)一個(gè)validate方法的使用。 先來在Web根目錄建立一個(gè)主頁面(validate.jsp),代碼如下:
<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>驗(yàn)證數(shù)據(jù)</title> </head> <body> <s:actionerror/> <s:actionmessage/> <s:form action="validate.action" theme="simple"> 輸入內(nèi)容:<s:textfield name="msg"/> <s:fielderror key="msg.hello" /> <br/> <s:submit/> </s:form> </body> </html> 在上面的代碼中,使用了Struts2的tag:<s:actionerror>、<s:fielderror>和<s:actionmessage>,分別用來顯示動(dòng)作錯(cuò)誤信息,字段錯(cuò)誤信息,和動(dòng)作信息。如果信息為空,則不顯示。 現(xiàn)在我們來實(shí)現(xiàn)一個(gè)動(dòng)作類,代碼如下:
package action;
import javax.servlet.http.*; import com.opensymphony.xwork2.ActionSupport; import org.apache.struts2.interceptor.*; public class ValidateAction extends ActionSupport { private String msg; public String execute() { System.out.println(SUCCESS); return SUCCESS; } public void validate() { if(!msg.equalsIgnoreCase("hello")) { System.out.println(INPUT); this.addFieldError("msg.hello", "必須輸入hello!"); this.addActionError("處理動(dòng)作失敗!"); } else { this.addActionMessage("提交成功"); } } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
大家從上面的代碼可以看出,Field錯(cuò)誤需要一個(gè)key(一般用來表示是哪一個(gè)屬性出的錯(cuò)誤),而Action錯(cuò)誤和Action消息只要提供一個(gè)信息字符串就可以了。 最后來配置一下這個(gè)Action,代碼如下: <package name="demo" extends="struts-default">
<action name="validate" class="action.ValidateAction"> <result name="success">/error/validate.jsp</result> <result name="input">/error/validate.jsp</result> </action> </package>
假設(shè)應(yīng)用程序的上下文路徑為demo,則可通過如下的URL來測試程序: http://localhost:8080/demo/validate.jsp 我們還可以使用ValidationAware接口的其他方法(由ValidationAwareSupport類實(shí)現(xiàn))獲得或設(shè)置字段錯(cuò)誤信息、動(dòng)作錯(cuò)誤信息以及動(dòng)作消息。如hasActionErrors方法判斷是否存在動(dòng)作層的錯(cuò)誤,getFieldErrors獲得字段錯(cuò)誤信息(一個(gè)Map對象)。下面是ValidationAware接口提供的所有的方法:
package com.opensymphony.xwork2;
import java.util.Collection; import java.util.Map; public interface ValidationAware { void setActionErrors(Collection errorMessages); Collection getActionErrors(); void setActionMessages(Collection messages); Collection getActionMessages(); void setFieldErrors(Map errorMap); Map getFieldErrors(); void addActionError(String anErrorMessage); void addActionMessage(String aMessage); void addFieldError(String fieldName, String errorMessage); boolean hasActionErrors(); boolean hasActionMessages(); boolean hasErrors(); boolean hasFieldErrors(); }
在《Struts2教程4:使用validate方法驗(yàn)證數(shù)據(jù)》中曾講到使用validate方法來驗(yàn)證客戶端提交的數(shù)據(jù),但如果使用validate方法就會將驗(yàn)證代碼和正常的邏輯代碼混在一起,但這樣做并不利于代碼維護(hù),而且也很難將過些代碼用于其他程序的驗(yàn)證。在Struts2中為我們提供了一個(gè)Validation框架,這個(gè)框架和Struts1.x提供的Validation框架類似,也是通過XML文件進(jìn)行配置。 一、服務(wù)端驗(yàn)證 下面將給出一個(gè)例子來演示如何使用Struts2的validation框架來進(jìn)行服務(wù)端驗(yàn)證。我們可以按著如下四步來編寫這個(gè)程序: 【第1步】建立Action類(NewValidateAction.java) package action;
import com.opensymphony.xwork2.ActionSupport; public class NewValidateAction extends ActionSupport { private String msg; // 必須輸入 private int age; // 在13和20之間 public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
下面我們來驗(yàn)證msg和age屬性。 【第2步】配置Action類,struts.xml的代碼如下: <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts./dtds/struts-2.0.dtd"> <struts> <package name="demo" extends="struts-default" namespace="/test"> <action name="new_validate" class="action.NewValidateAction"> <result name="input">/validate_form.jsp</result> <result name="success">/validate_form.jsp</result> </action> </package> </struts> 【第3步】編寫驗(yàn)證規(guī)則配置文件
<ActionClassName>-validation.xml <ActionClassName>-<ActionAliasName>-validation.xml 其中<ActionAliasName>就是struts.xml中<ation>的name屬性值。在本例中我們使用第一種命名規(guī)則,所以文件名是NewValidateAction-validation.xml。文件的內(nèi)容如下: <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" "http://www./xwork/xwork-validator-1.0.2.dtd"> <validators> <field name="msg"> <field-validator type="requiredstring"> <message>請輸入信息</message> </field-validator> </field> <field name="age"> <field-validator type="int"> <param name="min">13</param> <param name="max">20</param> <message> 必須在 13至20之間 </message> </field-validator> </field> </validators> 這個(gè)文件使用了兩個(gè)規(guī)則:requiredstring(必須輸入)和int(確定整型范圍)。關(guān)于其他更詳細(xì)的驗(yàn)證規(guī)則,請讀者訪問http://struts./2.0.11.1/docs/validation.html來查看。 【第4步】編寫數(shù)據(jù)錄入JSP頁。 在Web根目錄中建立一個(gè)validate_form.jsp文件,代碼如下: <%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%@ taglib prefix="s" uri="/struts-tags" %> <link rel="stylesheet" type="text/css" href="<s:url value="/styles/styles.css"/>"> <html> <head> <title>驗(yàn)證數(shù)據(jù)</title> </head> <body> <s:form action="new_validate" namespace="/test" > <s:textfield name="msg" label="姓名" /> <s:textfield name="age" label="年齡"/> <s:submit/> </s:form> </body> </html> 大家要注意一下,如果在struts.xml的<package>標(biāo)簽中指定namespace屬性,需要在<s:form>中也將namespace和action分開寫,如上面代碼所示。不能將其連在一起,Struts2需要分開的action和namespace。如下面的代碼是錯(cuò)誤的: ... ... </s:form> 在上面的程序中還使用了一個(gè)styles.css來定制錯(cuò)誤信息的風(fēng)格。代碼如下: .label {font-style:italic; } .errorLabel {font-style:italic; color:red; } .errorMessage {font-weight:bold; color:red; } 需要在Web根目錄中建立一個(gè)styles目錄,并將styles.css 假設(shè)Web工程的上下文路徑是validation,可以使用如下的URL來測試這個(gè)程序: ![]() 圖1 二、客戶端驗(yàn)證
在Struts2中實(shí)現(xiàn)客戶端驗(yàn)證非常簡單,只需要在<s:form>中加入一個(gè)validate屬性,值為true。如<s:form validate="true" ... > ... </form>即可。 三、驗(yàn)證嵌套屬性有一類特殊的屬性,即這個(gè)屬性的類型是另外一個(gè)JavaBean,如有一個(gè)User類,代碼如下: package data;
public class User { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } 在NewValidateAction類中加一個(gè)user屬性,代碼如下: package action;
import com.opensymphony.xwork2.ActionSupport; import data.User; public class NewValidateAction extends ActionSupport { private String msg; private int age; private User user; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } } 如果要驗(yàn)證NewValidateAction中的user屬性,可以使用visitor驗(yàn)證器。操作過程如下: 首先在NewValidateAction-validation.xml中加入一個(gè)<field>標(biāo)簽,代碼如下: <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" "http://www./xwork/xwork-validator-1.0.2.dtd"> <validators> ![]() <field name="user"> <field-validator type="visitor"> <param name="context">abc</param> <param name="appendPrefix">true</param> <message>User:</message> </field-validator> </field> </validators> 其中context參數(shù)將作為驗(yàn)證User類屬性的文件名的一部分,如user屬性返回一個(gè)User對象,那么用于驗(yàn)證User對象屬性的文件名為User-abc-validation.xml。這個(gè)文件要和User.class文件在同一個(gè)目錄中。appendPrefix表示是否在字段里加user,如果為true,Struts2就會使用user.name在form提交的數(shù)據(jù)中查找要驗(yàn)證的數(shù)據(jù)。這個(gè)屬性的默認(rèn)值是true。如果出錯(cuò),Struts2會將<message>標(biāo)簽中的信息加到User-abc-validation.xml文件中的相應(yīng)錯(cuò)誤信息前面。 User-abc-validation.xml文件的內(nèi)容如下:<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" "http://www./xwork/xwork-validator-1.0.2.dtd"> <validators> <field name="name"> <field-validator type="requiredstring"> <message>請輸入name</message> </field-validator> </field> <field name="age"> <field-validator type="int"> <param name="min">5</param> <param name="max">20</param> <message> 必須在 5至20之間 </message> </field-validator> </field> </validators> 下面修改validate_form.jsp,代碼如下: <s:form validate="true" action="new_validate" namespace="/test" >
<s:textfield name="msg" label="姓名" /> <s:textfield name="age" label="年齡"/> <s:textfield name="user.name" label="姓名1" /> <s:textfield name="user.age" label="年齡1"/> <s:submit/> </s:form>
大家可以看到,最后兩個(gè)<s:textfield>的name屬性是user.name和user.age,正好是加了前綴的。
圖2 經(jīng)筆者測試,使用visitor無法以客戶端驗(yàn)證的方式來驗(yàn)證user屬性,但NewValidateAction中其他的屬性可以使用客戶端測試。
Struts2教程6:在Action類中獲得HttpServletResponse對象的四種方法
在struts1.x Action類的execute方法中,有四個(gè)參數(shù),其中兩個(gè)就是response和request。而在Struts2中,并沒有任何參數(shù),因此,就不能簡單地從execute方法獲得HttpServletResponse或HttpServletRequest對象了。 但在Struts2 Action類中仍然有很多方法可以獲得這些對象。下面就列出四種獲得這些對象的方法。 【方法1】使用Struts2 Aware攔截器
這種方法需要Action類實(shí)現(xiàn)相應(yīng)的攔截器接口。如我們要獲得HttpServletResponse對象,需要實(shí)現(xiàn)org.apache.struts2.interceptor.ServletResponseAware接口,代碼如下: package action;
import com.opensymphony.xwork2.ActionSupport; import javax.servlet.http.*; import org.apache.struts2.interceptor.*; public class MyAction extends ActionSupport implements ServletResponseAware { private javax.servlet.http.HttpServletResponse response; // 獲得HttpServletResponse對象 public void setServletResponse(HttpServletResponse response) { this.response = response; } public String execute() throws Exception { response.getWriter().write("實(shí)現(xiàn)ServletResponseAware接口"); } }
在上面的代碼中,MyAction實(shí)現(xiàn)了一個(gè)ServletResponseAware接口,并且實(shí)現(xiàn)了setServletResponse方法。如果一個(gè)動(dòng)作類實(shí)現(xiàn)了ServletResponseAware接口,Struts2在調(diào)用execute方法之前,就會先調(diào)用setServletResponse方法,并將response參數(shù)傳入這個(gè)方法。如果想獲得HttpServletRequest、HttpSession和Cookie等對象,動(dòng)作類可以分別實(shí)現(xiàn)ServletRequestAware、SessionAware和CookiesAware等接口。這些接口都在org.apache.struts2.interceptor包中。 如果要獲得請求參數(shù),動(dòng)作類可以實(shí)現(xiàn)org.apache.struts2.interceptor. ParameterAware接口,但如果只想判斷某個(gè)參數(shù)是否存在,也可以實(shí)現(xiàn)com.opensymphony.xwork2.interceptor. ParameterNameAware接口。這個(gè)接口有一個(gè)acceptableParameterName方法,當(dāng)Struts2獲得一個(gè)請求參數(shù)時(shí),就會調(diào)用一次。讀者可以在這個(gè)方法中將所有的請求參數(shù)記錄下來,以便以后使用。這個(gè)方法的定義如下: boolean acceptableParameterName(String parameterName); 【方法2】使用RequestAware攔截器 這種方法和第1種方法類似。動(dòng)作類需要實(shí)現(xiàn)一個(gè)org.apache.struts2.interceptor.RequestAware接口。所不同的是RequestAware將獲得一個(gè)com.opensymphony.xwork2.util.OgnlValueStack對象,這個(gè)對象可以獲得response、request及其他的一些信息。代碼如下所示:
package action;
import java.util.Map; import org.apache.struts2.*; import com.opensymphony.xwork2.ActionSupport; import javax.servlet.http.*; import com.opensymphony.xwork2.util.*; import org.apache.struts2.interceptor.*; public class FirstAction extends ActionSupport implements RequestAware { private Map request; private HttpServletResponse response; public void setRequest(Map request) { this.request = request; } public String execute() throws Exception { java.util.Set<String> keys = request.keySet(); // 枚舉所有的key值。實(shí)際上只有一個(gè)key:struts.valueStack for(String key: keys) System.out.println(key); // 獲得OgnlValueStack 對象 OgnlValueStack stack = (OgnlValueStack)myRequest.get("struts.valueStack"); // 獲得HttpServletResponse對象 response = (HttpServletResponse)stack.getContext().get(StrutsStatics.HTTP_RESPONSE); response.getWriter().write("實(shí)現(xiàn)RequestAware 接口"); } }
我們也可以使用StrutsStatics.HTTP_REQUEST、StrutsStatics.PAGE_CONTEXT來獲得HttpServletRequest和PageContext對象。這種方法有些麻煩,一般很少用,讀者可以作為一個(gè)參考。 【方法3】使用ActionContext類
這種方法比較簡單,我們可以通過org.apache.struts2.ActionContext類的get方法獲得相應(yīng)的對象。代碼如下: HttpServletResponse response(HttpServletResponse) = ActionContext.getContext().get(org.apache.struts2.StrutsStatics.HTTP_RESPONSE); HttpServletRequest request(HttpServletRequest) = ActionContext.getContext().get(org.apache.struts2.StrutsStatics.HTTP_REQUEST); 【方法4】使用ServletActionContext類 Struts2為我們提供了一種最簡單的方法獲得HttpServletResponse及其他對象。這就是org.apache.struts2.ServletActionContext類。我們可以直接使用ServletActionContext類的getRequest、getResponse方法來獲得HttpServletRequest、HttpServletResponse對象。代碼如下: response.getWriter().write("hello world"); 從這四種方法來看,最后一種是最簡單的,讀者可以根據(jù)自己的需要和要求來選擇使用哪一種方法來獲得這些對象。 |
|
|