管理結果集
其中,得到數據庫的連接本例中是在Action類中完成的,代碼如下:
dataSource = getDataSource(request,"A");
cnn = dataSource.getConnection();
Action在調用業務對象時將連接作為一個參數傳給業務對象,再由業務對象傳給數據庫訪問對象。
要說明一點的是,要將struts-legacy.jar文件放在/webapps/mystruts/WEB-INF/lib目錄下。
我們要在/webapps/mystruts/WEB-INF/classes目錄下再建一個名叫db的子目錄,將數據訪問類以UserInfoDao.java文件名保存在該子目錄中。按照上篇文章介紹的方法,編譯各個包中的.java文件。就可以啟動Tomcat重新運行您的程序了。
細心一點的讀者可能都注意到了,到目前為止,我們程序中的各種消息都不是用中文表示的,在下一篇文章中,我們將討論Struts的國際化編程即所謂的i18n編程,對我們在編程中經常遇到的亂碼問題也一同作些分析。
參考文獻:
《JSP Web 編程指南》---電子工業出版社 Jayson Falkner等著 司光亞 牛紅等譯
《Java數據庫編程寶典》John O'Donahue等著 甑廣啟 于耀等譯
《Struts in Action》Ted Husted Cedric Dumoulin George Franciscus David Winterfeldt著
《Programming Jakarta Struts》Chuck Cavaness著
《Mastering Jakarta Struts》James Goodwill著
《Struts Kick Start》James Turner Kevin Bedell著
(第4部分)
本篇我們來討論一下struts的國際化編程問題,即所謂的i18n編程問題,這一篇我們討論其基礎部分。與這個問題緊密相關的是在各java論壇中被頻繁提及的中文亂碼問題,因為,英、美編程人員較少涉及到中文亂碼問題,因此,這方面的英文資料也是非常奇缺的,同時也很少找到這方面比較完整的中文資料,本文也嘗試對中文亂碼問題做一些探討。要解決上述問題,需要有一定的字符集方面的知識,下面,我們就先介紹字符集的有關情況:
一、從ASCII到Unicode(UTF-8)
電子計算機技術是從美國開始發展起來的,因為美國使用的文字為英文,美國規定的計算機信息交換用的字符編碼集是人們熟知的擴展ASCII碼,它以8bit字節為單位存儲,ASCII的0-31及127為控制符,32-126為可見字符,包括所有的英文字母,阿拉伯數字和其他一些常見符號,128-255的ASCII碼則沒有定義。
ASCII對英語國家是夠用了,但對其他西歐國家卻不夠用,因此,人們將ASCII擴展到0-255的范圍,形成了ISO-8859-1字符集。值得一提的是,因為考慮到程序中處理的信息大多是西文信息,因此有些WEB容器(如:Tomcat4.x)在處理所接收到的request字符串時,如果您沒指定request的編碼方式則系統就缺省地采用ISO-8859-1,明白這一點對理解后面的問題會有幫助。
相比西方的拼音文字,東方的文字(如中文)的字符數要大得多,根本不可能在一個字節內將它們表示出來,因此,它們以兩個字節為單位存儲,以中文國標字符集GB2312為例,它的第一個字節為128-255。系統可以據此判斷,若第一個字節大于127,則把與該字節后緊接著的一個字節結合起來共兩個字節組成一個中文字符。這種由多個字節存儲一個字符的字符集叫多字節字符集(MultiByte Charsets),對應的象ASCII這種用一個字節存儲一個字符的字符集叫單字節字符集(SingleByte Charsets)。在GB2312字符集中,ASCII字符仍然用一個字節存儲,換句話說該ASCII是該字符集的子集。
GB2312只包含數千個常用漢字,往往不能滿足實際需要,因此,人們對它進行擴展,這就有了我們現在廣泛使用的GBK字符集,GBK是現階段Windows及其他一些中文操作系統的缺省字符集。它包含2萬多個字符,除了保持和GB2312兼容外,還包含繁體中文字,日文字符和朝鮮字符。值得注意的是GBK只是一個規范而不是國家標準,新的國家標準是GB18030-2000,它是比GBK包含字符更多的字符集。
我國的臺灣地區使用的文字是繁體字,其字符集是BIG5,而日本采用的字符集則是SJIS。它們的編碼方法與GB2312類似,它們的ASCII字符部分是兼容的,但擴展部分的編碼則是不兼容的,比如這幾種字符集中都有"中文"這兩個字符,但他們在各自的字符集中的編碼并不相同,這就是用GB2312寫成的網頁用BIG5瀏覽時,看到的是亂糟糟的信息的原因。
可見,在字符集的世界里,呈現給我們的是一個群雄割據的局面,各字符集擁有一塊自己的地盤。這給各國和各地區交換信息帶來了很大的困難,同時,也給國際化(本地化)編程造成了很大的麻煩。
常言道:"分久必合",隨著國際標準ISO10646定義的通用字符集(Universal Character Set即UCS)的出現,使這種局面發生了徹底的改觀。UCS 是所有其他字符集標準的一個超集. 它保證與其他字符集是雙向兼容的. 就是說, 如果你將任何文本字符串翻譯到 UCS格式, 然后再翻譯回原編碼, 你不會丟失任何信息。UCS 包含了用于表達所有已知語言的字符。不僅包括拉丁語、希臘語、 斯拉夫語、希伯來語、阿拉伯語、亞美尼亞語和喬治亞語的描述、還包括中文、 日文和韓文這樣的象形文字、 以及平假名、片假名、 孟加拉語、 旁遮普語果魯穆奇字符(Gurmukhi)、 泰米爾語、印.埃納德語(Kannada)、Malayalam、泰國語、 老撾語、 漢語拼音(Bopomofo)、Hangul、 Devangari、Gujarati、Oriya、Telugu 以及其他數也數不清的語。對于還沒有加入的語言, 由于正在研究怎樣在計算機中最好地編碼它們, 因而最終它們都將被加入。
ISO 10646 定義了一個 31 位的字符集。 然而, 在這巨大的編碼空間中, 迄今為止只分配了前 65534 個碼位 (0x0000 到 0xFFFD)。 這個 UCS 的 16位子集稱為 基本多語言面 (Basic Multilingual Plane, BMP)。 將被編碼在 16 位 BMP 以外的字符都屬于非常特殊的字符(比如象形文字), 且只有專家在歷史和科學領域里才會用到它們。
UCS 不僅給每個字符分配一個代碼, 而且賦予了一個正式的名字。 表示一個 UCS 值的十六進制數, 通常在前面加上 "U+", 就象 U+0041 代表字符"拉丁大寫字母A"。 UCS 字符 U+0000 到 U+007F 與 US-ASCII(ISO 646) 是一致的, U+0000 到 U+00FF 與 ISO 8859-1(Latin-1) 也是一致的。這里要注意的是它是以16bit為單位存儲,即便對字母"A"也是用16bit,這是與前面介紹的所有字符集不同的地方。
歷史上,在國際標準化組織研究ISO10646標準的同時,另一個由多語言軟件制造商組成的協會也在從事創立單一字符集的工作,這就是現在人們熟知的Unicode。幸運的是,1991年前后ISO10646和Unicode的參與者都認識到,世界上不需要兩個不同的單一字符集。他們合并雙方的工作成果,并為創立單一編碼表而協同工作。兩個項目仍都存在并獨立地公布各自的標準,都同意保持ISO10646和Unicode的碼表兼容,并緊密地共同調整任何未來的擴展。這與當年在PC機上的操作系統MS-dos與PC-dos的情形有些相象。后面,我們將視ISO10646和Unicode為同一個東西。
有了Unicode,字符集問題接近了完美的解決,但不要高興得過早。由于歷史的原因:一些操作系統如:Unix、Linux等都是基于ASCII設計的。此外,還有一些數據庫管理系統軟件如:Oracle等也是圍繞ASCII來設計的(從其8i的白皮書上介紹的設置系統字符集和字段的字符集中可以間接地看到這一點)。在這些系統中直接用Unicode會導致嚴重的問題。用這些編碼的字符串會包含一些特殊的字符, 比如 '\0' 或 '/', 它們在 文件名和其他 C 庫函數參數里都有特別的含義。 另外, 大多數使用 ASCII 文件的 UNIX 下的工具, 如果不進行重大修改是無法讀取 16 位的字符的。 基于這些原因, 在文件名, 文本文件, 環境變量等地方,直接使用Unicode是不合適的。
在 ISO 10646-1 Annex R 和 RFC 2279 里定義的 UTF-8 (Unicode Transformation Form 8-bit form)編碼沒有這些問題。
UTF-8 有以下一些特性:
UCS 字符 U+0000 到 U+007F (ASCII) 被編碼為字節 0x00 到 0x7F (ASCII 兼容)。 這意味著只包含 7 位 ASCII 字符的文件在 ASCII 和 UTF-8 兩種編碼方式下是一樣的。
所有 >U+007F 的 UCS 字符被編碼為一個多個字節的串, 每個字節都有標記位集。 因此,ASCII 字節 (0x00-0x7F) 不可能作為任何其他字符的一部分。
表示非 ASCII 字符的多字節串的第一個字節總是在 0xC0 到 0xFD 的范圍里, 并指出這個字符包含多少個字節。 多字節串的其余字節都在 0x80 到 0xBF 范圍里。 這使得重新同步非常容易, 并使編碼無國界,且很少受丟失字節的影響。
UTF-8 編碼字符理論上可以最多到 6 個字節長, 然而 16 位 BMP 字符最多只用到 3 字節長。
字節 0xFE 和 0xFF 在 UTF-8 編碼中從未用到。
通過,UTF-8這種形式,Unicode終于可以廣泛的在各種情況下使用了。在討論struts的國際化編程之前,我們先來看看我們以前在jsp編程中是怎樣處理中文問題以及我們經常遇到的:
二、中文字符亂碼的原因及解決辦法
java的內核是Unicode的,也就是說,在程序處理字符時是用Unicode來表示字符的,但是文件和流的保存方式是使用字節流的。在java的基本數據類型中,char是Unicode的,而byte是字節,因此,在不同的環節java要對字節流和char進行轉換。這種轉換發生時如果字符集的編碼選擇不當,就會出現亂碼問題。
我們常見的亂碼大致有如下幾種情形:
1、漢字變成了問號"?"
2、有的漢字顯示正確,有的則顯示錯誤
3、顯示亂碼(有些是漢字但并不是你預期的)
4、讀寫數據庫出現亂碼
下面我們逐一對它們出現的原因做一些解釋:
首先,我們討論漢字變成問號的問題。
Java中byte與char相互轉換的方法在sun.io包中。其中,byte到char的常用轉換方法是:
public static ByteToCharConverter getConverter(String encoding);
為了便于大家理解,我們先來做一個小實驗:比如,漢字"你"的GBK編碼為0xc4e3,其Unicode編碼是\u4f60。我們的實驗是這樣的,先有一個頁面比如名為a_gbk.jsp輸入漢字"你",提交給頁面b_gbk.jsp。在b_gbk.jsp文件中以某種編碼方式得到"你"的字節數組,再將該數組以某種編碼方式轉換成char,如果得到的char值是0x4f60則轉換是正確的。
a_gbk.jsp的代碼如下:
<%@ page contentType="text/html; charset=GBK" language="java" import="java.sql.*" errorPage="" %>
<table width="611" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td> </td>
<td class="bigword"> </td>
<td> </td>
</tr>
<tr>
<td width="100"> </td>
<td class="bigword">Input</td>
<td width="100"> </td>
</tr>
<tr>
<td> </td>
<td class="bigword"> </td>
<td> </td>
</tr>
</table>
<table width="611" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td><form method="post" action="b_gbk.jsp">
<table width="611" border="0" cellpadding="0" cellspacing="0">
<tr>
<td width="100" align="right"></td>
<td><input name="ClsID" type="text" class="word" id="ClsID" maxlength="2" >
*</td>
</tr>
<tr>
<td width="100" align="right"> </td>
<td><input name="btn" type="submit" value="OK">
</td>
</tr>
</table>
</form></td>
</tr>
</table> |
b_gbk.jsp的代碼如下:
<%@ page contentType="text/html; charset=GBK" import="sun.io.*,java.util.*" %>
<%
String a=(String)request.getParameter("ClsID");
byte b[]=a.getBytes("ISO8859-1");
for(int j=0;j<b.length;j++){
out.println(Integer.toHexString(b[j])+"<br>");
}
ByteToCharConverter convertor=ByteToCharConverter.getConverter("GBK");
char[] c=convertor.convertAll(b);
out.println("b length:"+b.length+"<br>");
out.println("c length:"+c.length+"<br>");
for(int i=0;i<c.length;i++){
out.println(Integer.toHexString(c[i])+"<br>");
}
String a1=new String(a.getBytes("ISO8859-1"),"GBK");
%>
<%="a是:"+a%><br>
<%="a1是:"+a1%> |
在瀏覽器中打開a_gbk.jsp并輸入一個"你"字,點擊OK按鈕提交表單,則會出現如圖1所示的結果:
圖1
從圖1可以看出,在b_gbk.jsp中這樣將byte轉換為char是正確的,即得到的char是\u4f60。這里要注意的是:byte b[]=a.getBytes("ISO8859-1");中的編碼是ISO8859-1,這就是我們前面提到的有些web容器在您沒有指定request的字符集時它就采用缺省的ISO8859-1。
從圖1中我們還看到表達式<%="a是:"+a%>中的a并沒有正確地顯示"你"而是變成"??"這是什么原因呢?這里的a是作為一個String被顯示的,我們來看看我們常用的String構造函數:
String(byte[] bytes,String encoding);
在國標平臺上,該函數會認為bytes是按GBK編碼的,如果后一個參數省略,它也會認為是encoding是GBK。
對前一個參數就相當于將b_gbk.jsp文件的這句byte b[]=a.getBytes("ISO8859-1");中的ISO8859-1改為GBK,這樣顯然在GBK字符集中找不到相應的目的編碼,它給出的結果是0x3f、0x3f。因此,就會顯示為"??",這也就是造成亂碼的第一種現象的原因。我們的例子是演示的從byte到char的轉換過程,相反的過程也會造成同樣的問題,限于篇幅,就不在此討論了,大家自己可以做類似的實驗來驗證。
解決該問題的方法就是象例子中a1那樣,在獲取byte數組時,指定編碼為ISO8859-1。
接下來,我們討論有些漢字能正常顯示,有些不能正常顯示的問題。
如果我們將String a1=new String(a.getBytes("ISO8859-1"),"GBK");中的GBK改為GB2312則象朱镕基的"镕"字就不能正常顯示,這是因為該字是GBK中的字符而在GB2312中不存在。
解決上述兩種問題的方法就是象a1那樣構造String,也就是人們常說的同時也是常用的轉碼的方法。采用這種方法會在程序中到處出現這種語句,特別是在Struts中,Struts有一個回寫表單的功能,在回寫時也要做這種轉換,這樣的語句差不多要多一倍。因此,這是個比較笨拙的方法,有沒有簡捷一些的方法呢?其實是有的,只要在取得request的字符串前加上request.setCharacterEncoding("GBK");這句,指定request的字符集。則<%="a是:"+a%>中的a就能正常顯示,a1反而不能正常顯示。此時要將byte b[]=a.getBytes("ISO8859-1");中的ISO8859-1變成GBK,從byte到char的轉換才是正確的,這就是此時a能正常顯示而a1反而不能正常顯示的原因。如果此時要a1正常顯示則必須將String a1=new String(a.getBytes("ISO8859-1"),"GBK");中的ISO8859-1改為GBK。
很顯然,使用request.setCharacterEncoding("GBK");只能解決GBK字符問題,要解決i18n問題則要使用UTF-8來取代GBK。我們接著做上述實驗,將a_gbk.jsp和b_gbk.jsp分別另存為a.jsp和b.jsp將文件中的GBK改為UTF-8,更改后的代碼分別如下:
a.jsp代碼:
<%@ page contentType="text/html; charset=UTF-8" language="java" import="java.sql.*" errorPage="" %>
<table width="611" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td> </td>
<td class="bigword"> </td>
<td> </td>
</tr>
<tr>
<td width="100"> </td>
<td class="bigword">Input</td>
<td width="100"> </td>
</tr>
<tr>
<td> </td>
<td class="bigword"> </td>
<td> </td>
</tr>
</table>
<table width="611" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td><form method="post" action="b.jsp">
<table width="611" border="0" cellpadding="0" cellspacing="0">
<tr>
<td width="100" align="right"></td>
<td><input name="ClsID" type="text" class="word" id="ClsID" maxlength="2" >
*</td>
</tr>
<tr>
<td width="100" align="right"> </td>
<td><input name="btn" type="submit" value="OK">
</td>
</tr>
</table>
</form></td>
</tr>
</table>
b.jsp代碼:
<ccid_nobr>
<table width="400" border="1" cellspacing="0" cellpadding="2"
bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center">
<tr>
<td bgcolor="e6e6e6" class="code" style="font-size:9pt">
<pre><ccid_code> <%@ page contentType="text/html; charset=UTF-8" import="sun.io.*,java.util.*" %>
<%
request.setCharacterEncoding("UTF-8");
String a=(String)request.getParameter("ClsID");
byte b[]=a.getBytes("UTF-8");
for(int j=0;j<b.length;j++){
out.println(Integer.toHexString(b[j])+"<br>");
}
ByteToCharConverter convertor=ByteToCharConverter.getConverter("UTF-8");
char[] c=convertor.convertAll(b);
out.println("b length:"+b.length+"<br>");
out.println("c length:"+c.length+"<br>");
for(int i=0;i<c.length;i++){
out.println(Integer.toHexString(c[i])+"<br>");
}
String a1=new String(a.getBytes("UTF-8"),"UTF-8");
%>
<%="a是:"+a%><br>
<%="a1是:"+a1%> |
再在a.jsp中輸入"你"字,你會發現顯示結果中,一個漢字是用三個byte表示的,它們的值分別是0xe4、0xbd、0xa0,也就是說用UTF-8來表示漢字,每個漢字要比GBK多占用一個byte,這也是使用UTF-8要多付出的一點代價吧。
現在,我們討論一下第三個問題,即顯示亂碼,有些莫名其妙的漢字并不是你預期的結果。
在上例中將String a1=new String(a.getBytes("UTF-8"),"UTF-8");改為String a1=new String(a.getBytes("UTF-8"),"GBK");再輸入"你"字,則a1會顯示成"浣?",您只要看一看"浣"的UTF-8碼和GBK碼就會知道其中的奧秘了。
下面,我們討論一下最后一個問題,就是讀寫數據庫時出現亂碼。
現在一些常用的數據庫都支持數據庫encoding,也就是說在創建數據庫時可以指定它自己的字符集設置,數據庫數據以指定的編碼形式存儲。當應用程序訪問數據庫時,在入口和出口處都會有encoding轉換。如果,在應用程序中字符本來已變成了亂碼,當然也就無法正確地轉換為數據庫的字符集了。數據庫的encoding可根據需要來設置,比如要支持簡、繁體中文、日、韓、英語選GBK,如果還要支持其他語言最好選UTF-8。
本篇文章對字符集及中文亂碼問題做了一下探討,為實現國際化編程的實踐打下一個基礎。下一篇文章,我們將介紹struts中實現國際化編程的具體步驟,并將我們前面介紹的登錄例子進行國際化。
參考文獻:
UTF-8 and Unicode FAQ
《JSP動態網站技術入門與提高》太陽工作室 孫曉龍 趙莉編著
第5部分
一個支持i18n的應用程序應該有如下一些特征:
1增加支持的語言時要求不更改程序代碼
2字符元素、消息、和圖象保存在原代碼之外
3依賴于不同文化的數據如:日期時間、小數、及現金符號等數據對用戶的語言和地理位置應該有正確的格式
4應用程序能迅速地適應新語言和/或新地區
Struts主要采用兩個i18n組件來實現國際化編程:
第一個組件是一個被應用程序控制器管理的消息類,它引用包含地區相關信息串的資源包。第二個組件是一個JSP定制標簽,,它用于在View層呈現被控制器管理的實際的字符串。在我們前面的登錄例子中這兩方面的內容都出現過。
用Struts實現國際化編程的標準做法是:生成一個java屬性文件集。每個文件包含您的應用程序要顯示的所有消息的鍵/值對。
這些文件的命名要遵守如下規則,代表英文消息的文件可作為缺省的文件,它的名稱是ApplicationResources.properties;其他語種的文件在文件名中都要帶上相應的地區和語言編碼串,如代表中文的文件名應為ApplicationResources_zh_CN.properties。并且其他語種的文件與ApplicationResources.properties文件要放在同一目錄中。
ApplicationResources.properties文件的鍵/值都是英文的,而其他語種文件的鍵是英文的,值則是對應的語言。如在我們前面的登錄例子中的鍵/值對:logon.jsp.prompt.username=Username:在中文文件中就是:logon.jsp.prompt.username=用戶名:當然,在實際應用時要把中文轉換為AscII碼。
有了上一篇文章和以上介紹的一些基礎知識后。我們就可以將我們的登錄程序進行國際化編程了。
首先,我們所有jsp頁面文件的字符集都設置為UTF-8。即在頁面文件的開始寫如下指令行:
<%@ page contentType="text/html; charset=UTF-8" %>,在我們的登錄例子中已經這樣做了,這里不需要再改動。
其次,將所有的request的字符集也設置為UTF-8。雖然,我們可以在每個文件中加入這樣的句子:request.setCharacterEncoding("UTF-8");來解決,但這樣顯得很麻煩。一種更簡單的解決方法是使用filter。具體步驟如下:
在mystruts\WEB-INF\classes目錄下再新建一個名為filters的目錄,新建一個名為:SetCharacterEncodingFilter的類,并保存在該目錄下。其實,這個類并不要您親自來寫,可以借用tomcat中的例子。現將該例子的程序節選如下:
package filters;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.UnavailableException;
/**
* <p>Example filter that sets the character encoding to be used in parsing the
* incoming request, either unconditionally or only if the client did not
* specify a character encoding. Configuration of this filter is based on
* the following initialization parameters:</p>
* <ul>
* <li><strong>encoding</strong> - The character encoding to be configured
* for this request, either conditionally or unconditionally based on
* the <code>ignore</code> initialization parameter. This parameter
* is required, so there is no default.</li>
* <li><strong>ignore</strong> - If set to "true", any character encoding
* specified by the client is ignored, and the value returned by the
* <code>selectEncoding()</code> method is set. If set to "false,
* <code>selectEncoding()</code> is called <strong>only</strong> if the
* client has not already specified an encoding. By default, this
* parameter is set to "true".</li>
* </ul>
*
* <p>Although this filter can be used unchanged, it is also easy to
* subclass it and make the <code>selectEncoding()</code> method more
* intelligent about what encoding to choose, based on characteristics of
* the incoming request (such as the values of the <code>Accept-Language</code>
* and <code>User-Agent</code> headers, or a value stashed in the current
* user's session.</p>
*
* @author Craig McClanahan
* @version $Revision: 1.2 $ $Date: 2001/10/17 22:53:19 $
*/
public class SetCharacterEncodingFilter implements Filter {
// ----------------------------------------------------- Instance Variables
/**
* The default character encoding to set for requests that pass through
* this filter.
*/
protected String encoding = null;
/**
* The filter configuration object we are associated with. If this value
* is null, this filter instance is not currently configured.
*/
protected FilterConfig filterConfig = null;
/**
* Should a character encoding specified by the client be ignored?
*/
protected boolean ignore = true;
// --------------------------------------------------------- Public Methods
/**
* Take this filter out of service.
*/
public void destroy() {
this.encoding = null;
this.filterConfig = null;
}
/**
* Select and set (if specified) the character encoding to be used to
* interpret request parameters for this request.
*
* @param request The servlet request we are processing
* @param result The servlet response we are creating
* @param chain The filter chain we are processing
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet error occurs
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
// Conditionally select and set the character encoding to be used
if (ignore || (request.getCharacterEncoding() == null)) {
String encoding = selectEncoding(request);
if (encoding != null)
request.setCharacterEncoding(encoding);
}
// Pass control on to the next filter
chain.doFilter(request, response);
}
/**
* Place this filter into service.
*
* @param filterConfig The filter configuration object
*/
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
this.encoding = filterConfig.getInitParameter("encoding");
String value = filterConfig.getInitParameter("ignore");
if (value == null)
this.ignore = true;
else if (value.equalsIgnoreCase("true"))
this.ignore = true;
else if (value.equalsIgnoreCase("yes"))
this.ignore = true;
else
this.ignore = false;
}
// ------------------------------------------------------ Protected Methods
/**
* Select an appropriate character encoding to be used, based on the
* characteristics of the current request and/or filter initialization
* parameters. If no character encoding should be set, return
* <code>null</code>.
* <p>
* The default implementation unconditionally returns the value configured
* by the <strong>encoding</strong> initialization parameter for this
* filter.
*
* @param request The servlet request we are processing
*/
protected String selectEncoding(ServletRequest request) {
return (this.encoding);
}
} |
其中,request.setCharacterEncoding(encoding);是一個關鍵句子。
為了讓該類工作,我們還要在web.xml文件中對它進行配置,配置代碼如下:
<filter>
<filter-name>Set Character Encoding</filter-name>
<filter-class>filters.SetCharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Set Character Encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> |
最后,就是準備資源包文件,我們以創建一個中文文件為例:
將ApplicationResources.properties文件打開,另存為ApplicationResources_zh.properties,這只是一個過渡性質的文件。將文件中鍵/值對的值都用中文表示。更改完后的代碼如下:
#Application Resource for the logon.jsp
logon.jsp.title=登錄頁
logon.jsp.page.heading=歡迎 世界!
logon.jsp.prompt.username=用戶名:
logon.jsp.prompt.password=口令:
logon.jsp.prompt.submit=提交
logon.jsp.prompt.reset=復位
#Application Resource for the main.jsp
main.jsp.title=主頁
main.jsp.welcome=歡迎:
#Application Resource for the LogonAction.java
error.missing.username=<li><font color="red">沒有輸入用戶名</font></li>
error.missing.password=<li><font color="red">沒有輸入口令</font></li>
#Application Resource for the UserInfoBo.java
error.noMatch=<li><font color="red">沒有匹配的用戶</font></li>
#Application Resource for the UserInfoBo.java
error.logon.invalid=<li><font color="red">用戶名/口令是無效的</font></li>
error.removed.user=<li><font color="red">找不到該用戶</font></li>
error.unexpected=<li><font color="red">不可預期的錯誤</font></li> |
使用native2ascii工具將上面文件中的中文字符轉換為ascii碼,并生成一個最終使用的資源文件ApplicationResources_zh_CN.properties。
具體做法是打開一個dos窗口,到mystruts\WEB-INF\classes目錄下,運行如下語句:
native2ascii -encoding GBK ApplicationResources_zh.properties ApplicationResources_zh_CN.properties
生成的文件ApplicationResources_zh_CN.properties的內容如下:
#Application Resource for the logon.jsp
logon.jsp.title=\u767b\u5f55\u9875
logon.jsp.page.heading=\u6b22\u8fce \u4e16\u754c!
logon.jsp.prompt.username=\u7528\u6237\u540d:
logon.jsp.prompt.password=\u53e3\u4ee4:
logon.jsp.prompt.submit=\u63d0\u4ea4
logon.jsp.prompt.reset=\u590d\u4f4d
#Application Resource for the main.jsp
main.jsp.title=\u4e3b\u9875
main.jsp.welcome=\u6b22\u8fce:
#Application Resource for the LogonAction.java
error.missing.username=<li><font color="red">\u6ca1\u6709\u8f93\u5165\u7528\u6237\u540d</font></li>
error.missing.password=<li><font color="red">\u6ca1\u6709\u8f93\u5165\u53e3\u4ee4</font></li>
#Application Resource for the UserInfoBo.java
error.noMatch=<li><font color="red">\u6ca1\u6709\u5339\u914d\u7684\u7528\u6237</font></li>
#Application Resource for the UserInfoBo.java
error.logon.invalid=<li><font color="red">\u7528\u6237\u540d/\u53e3\u4ee4\u662f\u65e0\u6548\u7684</font></li>
error.removed.user=<li><font color="red">\u627e\u4e0d\u5230\u8be5\u7528\u6237</font></li>
error.unexpected=<li><font color="red">\u4e0d\u53ef\u9884\u671f\u7684\u9519\u8bef</font></li> |
從這里可以看出,所有的中文字都轉換成了對應的Unicode碼。
現在,再運行登錄例子程序,您會發現它已經是顯示的中文了。在瀏覽器的"工具"--"Internet選項"的"語言首選項"對話框中,去掉"中文(中國)"加上英文,再試登錄程序,此時,又會顯示英文。這就是說不同國家(地區)的客戶都可以看到自己語言的內容,這就實現了國際化編程的基本要求。如果還要顯示其他語言,可采用類似處理中文的方法進行,這里就不細講了。
本文中的例子程序所采用的數據庫仍然是MS SQLServer2000,數據庫字符集為gbk。實驗表明,對簡、繁體中文,英文及日文字符都能支持。
參考文獻:
《Programming Jakarta Struts》Chuck Cavaness著
《Mastering Jakarta Struts》James Goodwill著
第6部分
本文我們來討論一下Struts中的輸入校驗問題。我們知道,信息系統有垃圾進垃圾出的特點,為了避免垃圾數據的輸入,對輸入進行校驗是任何信息系統都要面對的問題。在傳統的編程實踐中,我們往往在需要進行校驗的地方分別對它們進行校驗,而實際上需要校驗的東西大多都很類似,如必需的字段、日期、范圍等等。因此,應用程序中往往到處充斥著這樣一些顯得冗余的代碼。而與此形成鮮明對照的是Struts采用Validator框架(Validator框架現在是Jakarta Commons項目的一部分)來解決校驗問題,它將校驗規則代碼集中到外部的且對具體的應用程序中立的.xml文件中,這樣,就將那些到處出現的校驗邏輯從應用程序中分離出來,任何一個Struts應用都可以使用這個文件,同時還為校驗規則的擴展提供了便利。更難能可貴的是由于Validator框架將校驗中要用到的一些消息等信息與資源綁定有機結合在一起,使得校驗部分的國際化編程變得十分的便捷和自然。
Validator框架大致有如下幾個主要組件:
Validators:是Validator框架調用的一個Java類,它處理那些基本的通用的校驗,包括required、mask(匹配正則表達式)、最小長度、最大長度、范圍、日期等
.xml配置文件:主要包括兩個配置文件,一個是validator-rules.xml,另一個是validation.xml。前者的內容主要包含一些校驗規則,后者則包含需要校驗的一些form及其組件的集合。
資源綁定:提供(本地化)標簽和消息,缺省地共享struts的資源綁定。即校驗所用到的一些標簽與消息都寫在ApplicationResources.properity文件中。
Jsp tag:為給定的form或者action path生成JavaScript validations。
ValidatorForm:它是ActionForm的一個子類。
為了對Validator框架有一個比較直觀的認識,我們還是以前面的登陸例子的輸入來示范一下Validator框架的使用過程:
首先,找一個validator-rules.xml文件放在mystruts\WEB-INF目錄下,下面是該文件中涉及到的required驗證部分代碼的清單:
<validator name="required"
<!--①-->
classname="org.apache.struts.validator.FieldChecks"
method="validateRequired"
methodParams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionErrors,
javax.servlet.http.HttpServletRequest"
<!--②-->
msg="errors.required">
<!--③-->
<javascript><![CDATA[
function validateRequired(form) {
var isValid = true;
var focusField = null;
var i = 0;
var fields = new Array();
oRequired = new required();
for (x in oRequired) {
var field = form[oRequired[x][0]];
if (field.type == 'text' ||
field.type == 'textarea' ||
field.type == 'file' ||
field.type == 'select-one' ||
field.type == 'radio' ||
field.type == 'password') {
var value = '';
// get field's value
if (field.type == "select-one") {
var si = field.selectedIndex;
if (si >= 0) {
value = field.options[si].value;
}
} else {
value = field.value;
}
if (trim(value).length == 0) {
if (i == 0) {
focusField = field;
}
fields[i++] = oRequired[x][1];
isValid = false;
}
}
}
if (fields.length > 0) {
focusField.focus();
alert(fields.join('\n'));
}
return isValid;
}
// Trim whitespace from left and right sides of s.
function trim(s) {
return s.replace( /^\s*/, "" ).replace( /\s*$/, "" );
}
]]>
</javascript>
</validator> |
① 節的代碼是引用一個服務器邊的驗證器,其對應的代碼清單如下:
public static boolean validateRequired(Object bean,
ValidatorAction va, Field field,
ActionErrors errors,
HttpServletRequest request) {
String value = null;
if (isString(bean)) {
value = (String) bean;
} else {
value = ValidatorUtil.getValueAsString(bean, field.getProperty());
}
if (GenericValidator.isBlankOrNull(value)) {
errors.add(field.getKey(), Resources.getActionError(request, va, field));
return false;
} else {
return true;
}
} |
② 節是驗證失敗后的出錯信息,要將對應這些鍵值的信息寫入到ApplicationResources.properity文件中,常見的錯誤信息如下:
# Standard error messages for validator framework checks
errors.required={0} is required.
errors.minlength={0} can not be less than {1} characters.
errors.maxlength={0} can not be greater than {1} characters.
errors.invalid={0} is invalid.
errors.byte={0} must be a byte.
errors.short={0} must be a short.
errors.integer={0} must be an integer.
errors.long={0} must be a long.
errors.float={0} must be a float.
errors.double={0} must be a double.
errors.date={0} is not a date.
errors.range={0} is not in the range {1} through {2}.
errors.creditcard={0} is an invalid credit card number.
errors.email={0} is an invalid e-mail address. |
③ 節的代碼用于客戶邊的JavaScript驗證
其次,在validation.xml文件中配置要驗證的form極其相應的字段,下面是該文件中的代碼:
<?xml version="1.0" encoding="UTF-8"?>
<!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">
<form-validation>
<formset>
<form name="userInfoForm">
<field property="username"
depends="required,mask,minlength,maxlength">
<arg0 key="logon.jsp.prompt.username" resource="true"/>
<arg1 name="minlength" key="${var:minlength}" resource="false"/>
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var>
<var-name>mask</var-name>
<var-value>^\w</var-value>
</var>
<var>
<var-name>minlength</var-name>
<var-value>2</var-value>
</var>
<var>
<var-name>maxlength</var-name>
<var-value>16</var-value>
</var>
</field>
<field property="password"
depends="required,minlength,maxlength">
<arg0 key="logon.jsp.prompt.password" resource="true"/>
<arg1 name="minlength" key="${var:minlength}" resource="false"/>
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var>
<var-name>minlength</var-name>
<var-value>2</var-value>
</var>
<var>
<var-name>maxlength</var-name>
<var-value>16</var-value>
</var>
</field>
</form>
</formset>
</form-validation> |
這里要注意的是:該文中的和中的鍵值都是取自資源綁定中的。前面還講到了出錯信息也是寫入ApplicationResources.properity文件中,因此,這就為國際化提供了一個很好的基礎。
再次,為了使服務器邊的驗證能夠進行,將用到的formBean從ActionForm的子類改為ValidatorForm的子類,即:
將public class UserInfoForm extends ActionForm改為:public class UserInfoForm extends ValidatorForm
到此,進行服務器邊的驗證工作已經一切準備得差不多了,此時,只要完成最后步驟就可以實驗服務器邊的驗證了。但大多數情況下,人們總希望把這些基本的簡單驗證放在客戶邊進行。
為了能進行客戶邊的驗證,我們還要對logon.jsp文件做適當的修改。
將
<html:form action="/logonAction.do" focus="username"> |
改為
<html:form action="/logonAction.do" focus="username" onsubmit="return validateUserInfoForm(this)"> |
在標簽后加上:
<html:javascript dynamicJavascript="true" staticJavascript="true" formName="userInfoForm"/> |
最后,對struts的配置文件struts-config.xml作適當的修改:
1、將
<action input="/logon.jsp" name="userInfoForm"
path="/logonAction" scope="session" type="action.LogonAction" validate="false" > |
改為
<action input="/logon.jsp" name="userInfoForm"
path="/logonAction" scope="session" type="action.LogonAction" validate="true" > |
其作用是要求進行校驗
2、將下列代碼放在struts-config.xml文件中的標簽前。其作用是將用于校驗的各個組件結合在一起。
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml" />
</plug-in> |
到此為止,我們的一切工作準備就緒,您可以享受自己的勞動成果了,試著輸入各種組合的用戶名和口令,看看它們的驗證效果。仔細體會你會發現,服務器邊的驗證要更全面一些,比如對password的字符長度的驗證。
參考文獻:
《Struts in Action》Ted Husted Cedric Dumoulin George Franciscus David Winterfeldt著
《Programming Jakarta Struts》Chuck Cavaness著
第7部分
上一篇文章中介紹校驗時提到客戶邊的校驗用到了JavaScript,實際上用Struts配合JavaScript還可以實現許多有用的功能,比如,級聯下拉菜單的實現就是一個典型的例子:
本例假設要實現的是一個文章發布系統,我們要發布的文章分為新聞類和技術類,其中新聞類又分為時事新聞和行業動態;技術類又分為操作系統、數據庫、和編程語言等,為了便于添加新的條目,所有這些都保存在數據庫表中。
為此,我們建立一個名為articleClass的表和一個名為articleSubClass的表。
articleClass表的結構如下:
articleClassID字段:char類型,長度為2,主鍵
articleClassName字段:varchar類型,長度為20
articleSubClass表的結構如下:
articleClassID字段:char類型,長度為2
articleSubClassID字段:char類型,長度為2與articleClassID一起構成主鍵
articleSubClassName字段:varchar類型,長度為20 |
表建好后,在articleClass表中錄入如下數據:如,01、新聞類;02、技術類
在articleSubClass表中錄入:01、01、時事新聞;01、02、行業動態;02、01、操作系統等記錄。到這里,數據庫方面的準備工作就已做好。
有了前面做登錄例子的基礎,理解下面要進行的工作就沒有什么難點了,我們現在的工作也在原來mystruts項目中進行。首先,建立需要用到的formbean即ArticleClassForm,其代碼如下:
package entity;
import org.apache.struts.action.*;
import javax.servlet.http.*;
import java.util.Collection;
public class ArticleClassForm extends ActionForm {
//為select的option做準備
private Collection beanCollection;
private String singleSelect = "";
private String[] beanCollectionSelect = { "" };
private String articleClassID;
private String articleClassName;
private String subI;//子類所在行數
private String subJ;//子類所在列數
private String articleSubClassID;
private String articleSubClassName;
public Collection getBeanCollection(){
return beanCollection;
}
public void setBeanCollection(Collection beanCollection){
this.beanCollection=beanCollection;
}
public String getSingleSelect() {
return (this.singleSelect);
}
public void setSingleSelect(String singleSelect) {
this.singleSelect = singleSelect;
}
public String[] getBeanCollectionSelect() {
return (this.beanCollectionSelect);
}
public void setBeanCollectionSelect(String beanCollectionSelect[]) {
this.beanCollectionSelect = beanCollectionSelect;
}
public String getArticleClassID() {
return articleClassID;
}
public void setArticleClassID(String articleClassID) {
this.articleClassID = articleClassID;
}
public String getArticleClassName() {
return articleClassName;
}
public void setArticleClassName(String articleClassName) {
this.articleClassName = articleClassName;
}
public String getSubI() {
return subI;
}
public void setSubI(String subI) {
this.subI = subI;
}
public String getSubJ() {
return subJ;
}
public void setSubJ(String subJ) {
this.subJ = subJ;
}
public String getArticleSubClassID() {
return articleSubClassID;
}
public void setArticleSubClassID(String articleSubClassID) {
this.articleSubClassID = articleSubClassID;
}
public String getArticleSubClassName() {
return articleSubClassName;
}
public void setArticleSubClassName(String articleSubClassName) {
this.articleSubClassName = articleSubClassName;
}
} |
將它放在包entity中。其次,我們的系統要訪問數據庫,因此也要建立相應的數據庫訪問對象ArticleClassDao,其代碼如下:
package db;
import entity.ArticleClassForm;
import db.*;
import java.sql.*;
import java.util.Collection;
import java.util.ArrayList;
import org.apache.struts.util.LabelValueBean;
public class ArticleClassDao {
private Connection con;
public ArticleClassDao(Connection con) {
this.con=con;
}
public Collection findInUseForSelect(){
PreparedStatement ps=null;
ResultSet rs=null;
ArrayList list=new ArrayList();
String sql="select * from articleClass order by articleClassID";
try{
if(con.isClosed()){
throw new IllegalStateException("error.unexpected");
}
ps=con.prepareStatement(sql);
rs=ps.executeQuery();
while(rs.next()){
String value=rs.getString("articleClassID");
String label=rs.getString("articleClassName");
list.add(new LabelValueBean(label,value));
}
return list;
}
catch(SQLException e){
e.printStackTrace();
throw new RuntimeException("error.unexpected");
}
finally{
try{
if(ps!=null)
ps.close();
if(rs!=null)
rs.close();
}
catch(SQLException e){
e.printStackTrace();
throw new RuntimeException("error.unexpected");
}
}
}
public Collection findInUseForSubSelect(){
PreparedStatement ps=null;
ResultSet rs=null;
PreparedStatement psSub=null;
ResultSet rsSub=null;
int i=0;//大類記數器
int j=0;//小類記數器
String classID="";
String subClassID="";
String subClassName="";
ArrayList list=new ArrayList();
ArticleClassForm articleClassForm;
String sql="select * from articleClass order by articleClassID";
try{
if(con.isClosed()){
throw new IllegalStateException("error.unexpected");
}
ps=con.prepareStatement(sql);
rs=ps.executeQuery();
while(rs.next()){
i++;
classID=rs.getString("articleClassID");
String sqlSub="select * from articleSubClass where articleClassID=?
order by articleSubClassID";
psSub=con.prepareStatement(sqlSub);
psSub.setString(1,classID);
rsSub=psSub.executeQuery();
articleClassForm=new ArticleClassForm();
articleClassForm.setSubI(""+i);
articleClassForm.setSubJ(""+j);
articleClassForm.setArticleSubClassID("請輸入一個小類");
articleClassForm.setArticleSubClassName("請輸入一個小類");
list.add(articleClassForm);
while(rsSub.next()){
subClassID=rsSub.getString("articleSubClassID");
subClassName=rsSub.getString("articleSubClassName");
j++;
//optionStr="articleSubClassGroup[" + i + "][" + j + "]=
new Option('"+ subClassName +"','"+ subClassID+ "')";
articleClassForm=new ArticleClassForm();
articleClassForm.setSubI(""+i);
articleClassForm.setSubJ(""+j);
articleClassForm.setArticleSubClassID(subClassID);
articleClassForm.setArticleSubClassName(subClassName);
list.add(articleClassForm);
}
j=0;
}
return list;
}
catch(SQLException e){
e.printStackTrace();
throw new RuntimeException("error.unexpected");
}
finally{
try{
if(ps!=null)
ps.close();
if(rs!=null)
rs.close();
}
catch(SQLException e){
e.printStackTrace();
throw new RuntimeException("error.unexpected");
}
}
}
} |
將它保存在db目錄中。它們的目的是將文章的類和子類信息從數據庫表中讀出,以一定的格式保存在集合對象中以供頁面顯示。
再次,我們要建立相應的jsp文件,文件名為selectArticleClass.jsp,代碼如下:
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<html>
<head>
<title>
選擇文件類別
</title>
</head>
<body bgcolor="#ffffff">
<h3>
選擇文件所屬類型
</h3>
<html:errors/>
<table width="500" border="0" cellspacing="0" cellpadding="0">
<tr>
<td><html:form name="articleClassForm" type="entity.ArticleClassForm"
action="selectArticleClassAction.do">
<table width="500" border="0" cellspacing="0" cellpadding="0">
<tr>
<td align="right">文章大類*</td>
<td>
<html:select property="articleClassID" styleClass="word"
onchange="articleClassFormredirect(this.options.selectedIndex)">
<html:option value="">請選擇一個大類</html:option>
<html:optionsCollection name="articleClassForm" property="beanCollection" styleClass="word"/>
</html:select>
</td>
</tr>
<tr>
<td align="right">文章小類*</td>
<td>
<select name="articleSubClassID" Class="word" >
<option value="">請選擇一個小類</option>
</select>
<SCRIPT language=JavaScript>
<!--
var articleSubClassGroups=document.articleClassForm.articleClassID.
options.length
var articleSubClassGroup=new Array(articleSubClassGroups)
for (i=0; i<articleSubClassGroups; i++)
articleSubClassGroup[i]=new Array()
<logic:iterate name="articleSubClassList" id="articleClassForm"
scope="request" type="entity.ArticleClassForm">
articleSubClassGroup[<bean:write name="articleClassForm"
property="subI"/>][<bean:write name="articleClassForm"
property="subJ"/>]=new Option("<bean:write name="articleClassForm"
property="articleSubClassName"/>","<bean:write name="articleClassForm"
property="articleSubClassID"/>")
</logic:iterate>
var articleSubClassTemp=document.articleClassForm.articleSubClassID
function articleClassFormredirect(x){
for (m=articleSubClassTemp.options.length-1;m>0;m--)
articleSubClassTemp.options[m]=null
for (i=0;i<articleSubClassGroup[x].length;i++){
articleSubClassTemp.options[i]=new
Option(articleSubClassGroup[x][i].text,
articleSubClassGroup[x][i].value)
}
articleSubClassTemp.options[0].selected=true
}
//-->
</SCRIPT>
</td>
</tr>
</table>
</html:form>
</td>
</tr>
</table>
</body>
</html> |
這里值得重點關注的是其中的JavaScript代碼,有興趣的可以仔細分析一下它們是怎樣配合集合中的元素來實現級聯選擇的。
最后,為了例子的完整。我們將涉及到action代碼和必要的配置代碼在下面列出:其中,action的文件名為SelectArticleClassAction.java,代碼如下:
package action;
import entity.*;
import org.apache.struts.action.*;
import javax.servlet.http.*;
import javax.sql.DataSource;
import java.sql.Connection;
import db.ArticleClassDao;
import java.util.Collection;
import java.sql.SQLException;
public class SelectArticleClassAction extends Action {
public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm,
HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
/**@todo: complete the business logic here, this is just a skeleton.*/
ArticleClassForm articleClassForm = (ArticleClassForm) actionForm;
DataSource dataSource;
Connection cnn=null;
ActionErrors errors=new ActionErrors();
try{
dataSource = getDataSource(httpServletRequest,"A");
cnn = dataSource.getConnection();
ArticleClassDao articleClassDao=new ArticleClassDao(cnn);
Collection col=articleClassDao.findInUseForSelect();
articleClassForm.setBeanCollection(col);
httpServletRequest.setAttribute("articleClassList",col);
//處理子類選項
Collection subCol=articleClassDao.findInUseForSubSelect();
httpServletRequest.setAttribute("articleSubClassList",subCol);
return actionMapping.findForward("success");
}
catch(Throwable e){
e.printStackTrace();
//throw new RuntimeException("未能與數據庫連接");
ActionError error=new ActionError(e.getMessage());
errors.add(ActionErrors.GLOBAL_ERROR,error);
}
finally{
try{
if(cnn!=null)
cnn.close();
}
catch(SQLException e){
throw new RuntimeException(e.getMessage());
}
}
saveErrors(httpServletRequest,errors);
return actionMapping.findForward("fail");
}
} |
將其保存在action目錄中。
在struts-config.xml文件中做如下配置:
在
中加入
<form-bean name="articleClassForm" type="entity.ArticleClassForm" /> |
在
中加入:
<action name="articleClassForm" path="/selectArticleClassAction" scope="session"
type="action.SelectArticleClassAction" validate="false">
<forward name="success" path="/selectArticleClass.jsp" />
<forward name="fail" path="/genericError.jsp" />
</action> |
為了對應配置中的
<forward name="fail" path="/genericError.jsp" /> |
,我們還要提供一個顯示錯誤信息的jsp頁面,其代碼如下:
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html>
<head>
<title>
genericError
</title>
<link href="css/mycss.css" rel="stylesheet" type="text/css">
</head>
<body bgcolor="#ffffff">
<html:errors/>
</body>
</html> |
現在一切就緒,可以編譯執行了。在瀏覽器中輸入:http://127.0.0.1:8080/mystruts/selectArticleClassAction.do就可以看到該例子的運行結果了
posted on 2005-10-24 22:15
Sung 閱讀(1108)
評論(0) 編輯 收藏 所屬分類:
Struts