2、“Cannot find bean XXX in any scope”
在Action里一般會request.setAttribute()一些對象,然后在轉向的jsp文件里(用tag或request.getAttribute()方法)得到這些對象并顯示出來。這個異常是說jsp要得到一個對象,但前面的Action里并沒有將對象設置到request(也可以是session、servletContext)里。
可能是名字錯了,請檢查jsp里的tag的一般是name屬性,或getAttribute()方法的參數值;或者是Action邏輯有問題沒有執行setAttribute()方法就先轉向了。
還有另外一個可能,純粹是jsp文件的問題,例如會指定一個id值,然后在循環里使用這個值作為name的值,如果這兩個值不同,也會出現此異常。(都是一個道理,request里沒有對應的對象。)
3、“Missing message for key "XXX"”
缺少所需的資源,檢查ApplicationResources.properties文件里是否有jsp文件里需要的資源,例如:
這行代碼會找msg.name.prompt資源,如果AppliationResources.properties里沒有這個資源就會出現本異常。在使用多模塊時,要注意在模塊的struts-config-xxx.xml里指定要使用的資源文件名稱,否則當然什么資源也找不到,這也是一個很容易犯的錯誤。
4、“No getter method for property XXX of bean teacher”
這條異常信息說得很明白,jsp里要取一個bean的屬性出來,但這個bean并沒有這個屬性。你應該檢查jsp中某個標簽的property屬性的值。例如下面代碼中的cade應該改為code才對:
5、“Cannot find ActionMappings or ActionFormBeans collection”
待解決。
6、“Cannot retrieve mapping for action XXX”
在.jsp的
標簽里指定action='/XXX',但這個Action并未在struts-config.xml里設置過。
7、HTTP Status 404 - /xxx/xxx.jsp
Forward的path屬性指向的jsp頁面不存在,請檢查路徑和模塊,對于同一模塊中的Action轉向,path中不應包含模塊名;模塊間轉向,記住使用contextRelative="true"。
8、沒有任何異常信息,顯示空白頁面
可能是Action里使用的forward與struts-config.xml里定義的forward名稱不匹配。
9、“The element type "XXX" must be terminated by the matching end-tag "XXX".”
這個是struts-config.xml文件的格式錯誤,仔細檢查它是否是良構的xml文件,關于xml文件的格式這里就不贅述了。
10、“Servlet.init() for servlet action threw exception”
一般出現這種異常在后面會顯示一個關于ActionServlet的異常堆棧信息,其中指出了異常具體出現在代碼的哪一行。我曾經遇到的一次提示如下:
java.lang.NullPointerException
at org.apache.struts.action.ActionServlet.parseModuleConfigFile(ActionServlet.java:1003)
at org.apache.struts.action.ActionServlet.initModuleConfig(ActionServlet.java:955)
為解決問題,先下載struts的源碼包,然后在ActionServlet.java的第1003行插入斷點,并對各變量進行監視。很丟人,我竟然把struts-config.xml文件弄丟了,因此出現了上面的異常,應該是和CVS同步時不小心刪除的。
11、“Resources not defined for Validator”
這個是利用Validator插件做驗證時可能出現的異常,這時你要檢查validation.xml文件,看里面使用的資源是否確實有定義,form的名稱是否正確,等等。
一.JSP頁面部分
1. 頁面文字處理
1.1概述
由于STRUTS提供了很好的國際化的支持,因此JSP頁面可以STRUTS的這一特性做到國際化。
STRUTS允許將不同語言的文字寫在多個資源文件中,每個資源對應一種語言,而在JSP頁面上則通過STRUTS標簽< bean:message>來顯示文字,該標簽可以根據瀏覽器的當前語言設置確定從對應的語種資源文件中取出字符串,顯示在頁面上。
1.2資源文件
實現國際化,首先需要準備好資源文件,需要支持的語言各對應一個。資源文件一定要用支持多國語言文字的文本編輯器(如WORD,一定不能用NOTEPAD、UE等)編寫,其格式如下:
# Project international
index.title=XX信息系統
index.copyright=XXX有限公司 版權所有
其中以#開頭的行是注釋,其它的行都是KEY=VALUE的形式,定義了一個KEY對應當前語言下的文字。保存資源文件時,需要在文件類型選項中選擇純文本類型,編碼選擇其它>>UTF-8,注意資源文件的擴展名為.properties,文件名可以任意取。
這樣保存的資源文件還不能直接被STRUTS使用,JDK提供了一個工具native2ascii對編寫的資源文件進行轉換,該工具位于%JDK%/bin/目錄下,一般在JDK正確安裝后可以直接在命令行使用。使用native2ascii工具轉換的資源的文件的命令行格式如下:
native2ascii -encoding UTF-8 ApplicationResources.properties ApplicationResources_zh_CN.properties
其中-encoding參數指明編寫的資源文件的編碼格式,這里必須與編輯時選擇保存的編碼格式一致,后面兩個參數分別是需要轉換的資源文件名和轉換后保存的資源文件名。
轉換后的資源文件名都必須以一個特定的前輟開頭,該前輟寫在struts-config.xml配置中,后輟是對應語言的簡稱,如
英文(美國) ApplicationResources _en_US.properties
中文(簡體)ApplicationResources _zh_CN.properties
中文(繁體)ApplicationResources _tw.properties
泰語 ApplicationResources _th.properties
資源文件的存放目錄可以是/WEB-INF/classes/下的任意目錄,為了便于管理 ,建議在/WEB-INF/ classes/下建立目錄resources,將所有的資源文件都放在該目錄下。STRUTS通過配置文件struts-config.xml配置資源文件的所在位置,如:
< message-resources parameter="resources.ApplicationResources" />
其中目錄以包的方式表示。
1.3 JSP頁面顯示
為了支持國際化,JSP頁面的編碼方式需要設成UTF-8,即在頁面的頭部加入以下幾行:
< %@ page contentType="text/html; charset=UTF-8" %>
< %@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
……(STRUTS及其它標簽庫引用)
< html:html locale="true">
JSP頁面的中文字要全部寫到資源文件中,注意每種語言資源文件都要寫到,否則在使用某種語言訪問系統時可能會報錯。JSP中使用STRUTS標簽< bean:message key="index.title"/>顯示資源文件中定義的字符串。這樣當改變瀏覽器的當前語言后,頁面會自動取得與瀏覽器當前語言對應的資源文件中的字符串顯示在頁面上。
對于在ACTION的JAVA代碼中直接設置的變量,如需要在JSP頁面上進行顯示,那么在設置變量時也需要從資源文件中通過KEY取到當前語言的字符串,再使用request.setAttribute方法進行設置,這樣在JSP頁面上使用< bean:write>標簽展現設置的變量才會對應不同的語言會呈現不同的字符串。
在JAVA代碼中取資源文件的信息的方法是,首先通過Globals.MESSAGES_KEY從request或session變量中取得資源對象(MessageResources),再調用MessageResources.getMessage方法即可取得相應的字符串,該方法需的兩個參數是當前語言區域設置(Locale)和字符串的KEY,其中當前語言區域設置(Locale)保存在SESSION變量中,其變量名為Globals.LOCALE_KEY,該變量在下一節手工設置語言時也有提到。
1.4手工設置顯示語言
用瀏覽器的語言設置來決定系統采用哪種語言展現可能會出現一個問題,就是用戶的瀏覽器語言與他想要使用系統的語言不一致的情況,如某客戶瀏覽器的語言設置為英文,但他還是在使用主站系統時看到的是中文界面。該問題可以通過手工選擇語言來解決,在程序中可以通過設置名為Globals.LOCALE_KEY(Globals.LOCALE_KEY 是 struts的常量)的SESSION變量,也能改變系統中當前語言的設置,代碼類似于:
Locale newLocale = new Locale( language, country );
session.setAttribute( Globals.LOCALE_KEY, newLocale );
其中變量language, country 可以通過用戶的選擇設置相應的值,各種語言的對應值參考http://www.unicode.org/unicode/onlinedat/countries.html。
2. 帶有文字的圖片處理
2.1靜態圖片
帶有文字的圖片應該也要根據語言的不同而顯示不同的圖片,但圖片本身不是文本信息,無法直接用< bean:message>標簽來完成國際化操作。但由于頁面上顯示圖片取決于< image>標簽的src屬性,因此可以為每個圖片對應各種語言的都準備一個版本,文件名或路徑有所差異,然后將每種語言對應的圖片的路徑及文件名放在資源文件中,而在JSP頁面上< image>標簽的src屬性由< bean:message>標簽指定,這樣即可以完成圖片的國際化。
2.2 JAVA生成動態圖片
由于生成動態圖片是在服務器端進行,因此同樣需要將生成圖形字符的靜態部分放在資源文件中,如圖形名稱等,從資源文件中取字符串的方法在JSP頁面顯示部分已有說明;從數據庫中取出的部分可以不用做任何處理,直接從數據庫取出與靜態部分拼裝成圖形字符串即可,數據庫相關設置在數據庫部分有詳細說明。
3. 頁面提交參數處理
頁面上向WEB服務器提交參數有兩種方式,一是在訪問URL后面附加上request變量,這樣的變量在服務器端可以通過request.getParameter方法得到,另一種方式是在JSP頁面上用FORM表單方式提交,這種方法提交的變量在服務器端可以通過form的getXXX方法取到變量的值。
當WEB系統需要國際化時,JSP頁面的編碼方式被指定為UTF-8(前面已有說明),也就是說頁面上可以處理各國文字,在使用URL傳遞變量時需要將變量用JS方法encodeURI方法處理過,才能在服務器端得到正確的值,如
location.href="int/do/common/queryUserInfo.do?sqlcode=QUERY0001&hh="+encodeURI(document.all.hh.value)+"&hm="+encodeURI(document.all.hm.value)+"&bmbh="+encodeURI(document.all.bmbh.value);
由于這種方式需要對每個request變量調用encodeURI方法,處理起來比較麻煩,但用FORM表單提交的方式即不需要進行任何處理,因此在開發時應盡量使用FORM表單提交的方式進行數據傳遞。
如果需要JAVA代碼中生成URL,則其中傳遞的參數也需要調用URLEncoder.encode方法進行處理,并指定編碼方式為"UTF-8"。
在服務器端取得客戶端傳遞的參數時也需要對參數進行字符集的轉換后才可以下確使用,如
strString = new String(strString.getBytes("ISO-8859-1"), "GBK");
但如此對每個變量都需要這樣處理也是非常麻煩,實際上可以利用servlet的Filter機制進行統一處理。在調用servlet(包括struts)時,在到達實際的servlet類前,會首先調用指定的Filter進行處理,Filter處理完成后再決定是否交給實際請求的servlet類處理。
利用這一點,我們可以新建一個類繼承自Filter基類,重載doFilter方法,并在該方法中加入
request.setCharacterEncoding(“UTF-8”);
指定客戶端的字符集為UTF-8(默認客戶端的字符集為ISO8859),這樣在ACTION類中取得的參數就不需要進行任何的轉換處理了。
配置Filter的地方在web.xml,在web.xml文件中加入類似這樣的配置即可以使自定義的Filter生效:
< filter>
< filter-name>charsetfilter< /filter-name>
< filter-class> international.CharsetFilter< /filter-class>
< init-param>
< param-name>encoding< /param-name>
< param-value>UTF-8< /param-value>
< /init-param>
< /filter>
< filter-mapping>
< filter-name>charsetfilter< /filter-name>
< url-pattern>/*< /url-pattern>
< /filter-mapping>
二.數據庫設置
在數據庫建庫時需要將數據庫的字符集指定為unicode編碼類型,以支持多種語言。
有一點需要特別說明的是UTF-8是用3個字節表示一個漢字,這點在進行表結構設計時需要注意,適當設置字段的長度。
web應用發布描述文件可以在應用開著者,發布者和組裝者之間傳遞配置信息,Web容器在啟動的時候從該文件中讀取配置信息,根據它來裝載和配置web應用.文檔類型定義DTD對XML文檔的格式做了定義,DTD吧XML文檔劃分為元素,屬性,實體每一種XML文檔都有獨自的DTD文件.可以從網上下載.<web-app>元素是web.xml的根元素,其他元素必須嵌入在<web-app>元素之內.要注意的是子元素也是有順序的比如必須是首先<servlet>,然后<servlet-mapping>最后<taglib>.
為Struts應用配置Web.xml文件:
首先最重要的一步是配置ActionServlet,這個用<servlet>標簽的servlet-name屬性起一個名字叫action,然后用servlet-class屬性指定ActionServlet的類.
然后用<servlet-mapping>標簽的servlet-name屬性指定action,在用url-pattern指定接收范圍是*.do的請求.不管應用中包含了多少子應用,都只需要配置一個ActionServlet,類來出來應用中的不同的功能,其實者就是不必要的,因為Servlet本身就是多線程的,而且目前Struts只允許配置一個ActionServlet.聲明ActionServlet的初始化參數:<servlet>的<init-param>子元素用來配置Servlet的初始化參數.param-name設置config參數名.param-value設置struts-config.xml的路徑參數值.
配置歡迎使用清單:
如果客戶訪問Web的時候值是訪問了WEB應用的根目錄URL.沒有具體的指定文件,Web會自動調用Web的歡迎文件.<welcome-file-list>元素來配置的.通過其中的<welcome-file>歡迎頁面</welcome-file>來配置.
配置錯誤處理:
盡管Struts框架功能強大的錯誤處理機制,但是不能保證處理所有的錯誤或者異常.當錯誤發生時,如果框架不能處理這種錯誤,把錯誤拋棄給Web容器,在默認的情況下web容器會想客戶端返回錯誤信息.如果想避免讓客戶看到原始的錯誤信息,可以在Web應用發布描述文件中配置<error-page>元素.通過<error-code>404來定義錯誤的類型.然后通過<location>要處理錯誤的JSP頁面來對錯誤進行處理.還可以用<exception-type>來設置異常,然后通過<location>來處理異常的JSP頁面來處理異常.
配置Struts標簽庫:
這個就和以前學到的JSP自定義標簽類似,配置元素為<taglib>來配置.<taglib-uri>這個指定標簽庫的uri,類似起一個名稱.<taglib-location>這個是標簽庫的位置也就是實際所在的路徑.通過這樣的方法引入一個標簽庫,然后在前臺JSP頁面就可以通過自己定義的URI來調用標簽.
Struts配置文件:
struts-config.xml文件.
首先研討一下org.apache.struts.config包,在struts應用啟動的時候會把Struts配置文件信息讀取到內存中,并把它們存放在config包中相關的JavaBean類的實例中.包中的每一個類都和struts配置文件中特定的配置元素對應,ModuleConfig在Struts框架中扮演了十分重要的角色,它是整個config包的核心,在Struts運行時來存放整個應用的配置信息.如果有多個子應用都會有一個ModuleConfig對象,它和Struts文件根元素的<struts-config>對應.根元素中包含<form-bean><action><forward>等元素.
<struts-config>元素:時Struts配置文件的根元素,和它對應的配置類ModuleConfig類,<struts-config>元素有8個子元素.他們的DTD定義是data-sources?form-bean? global-exception?global-forwards?action-mapping?controller?message-resources?plug-in*在Struts配置文件中,必須按照DTD指定的先手順序來配置<struts-config>元素的各個子元素,如果顛倒了這些子元素的順序,會產生錯誤.
<data-sources>元素:用來配置應用所需要的數據源,數據源負責創建和特定的數據庫的連接.許多數據源采用連接池的機制實現.以便提高數據庫訪問的性能.JAVA語言提供了javax.sql.DataSource接口,所有的數據源都必須實現這個接口.許多應用服務器和Web服務器都提供了數據源組件.很多數據庫廠商也提供了數據源的實現.<data-sources>元素包含多個<data-source>子元素永遠配置特定的數據源.他們可以包含多個<set-property>子元素用于設置數據源的各種屬性.配置了數據源以后,就可以在Action類中訪問數據源,在Action中定義了getDataSource(HttpRequest)方法,用于獲取數據源對象的引用.然后可以利用DataSource對象調用getConnection獲取一個連接對象對數據庫進行操作.在配置文件中聲明多個數據源的時候需要為每一個數據源分配唯一的Key值,通過這個來表示特定的數據源.獲取特定的數據源的時候可以用dataSource = getDataSource(reqeust,”A”);
<form-beans>元素:用來配置多個ActionForm,包含一個或者N個<form-bean>子元素.每個<form-bean>元素都包含多個屬性.className指定和<form-bean>匹配的類.name指定該ActionForm的唯一標識符,這個屬性是必須的以后作為引用使用.type指定ActionForm類的完整類名,這個屬性也是必須的.注意包名也要加上.<form-property>是指定動態的Form的元素,以后會深入了解.
<global-exception>元素:用于配置異常處理,元素可以包含一個或者多個<exception>元素,用來設置JAVA異常和異常處理類ExceptionHandler之間的映射.className指定和元素對應的配置類,默認的不用動.handler指定異常處理類默認是ExceptionHandler.key指定在本地資源文件中異常的消息Key,path指定當前異常發生的時候轉發的路徑.scope指定ActionMessages實例存放的范圍.type指定需要處理異常類的名字,必須的.bundle指定Resource Bundle.
<global-forwards>元素:用來聲明全局轉發,元素可以有一個或者N個<forward>元素組成,用于把一個邏輯名映射到特定的URL,通過這種方法Action類或者JSP頁面無需指定URL,只要指定邏輯名稱就可以實現請求轉發或者重定向.這樣可以減少控制組件和視圖的聚合.易于維護.className對應的配置類.contextRelative如果為true表示當path屬性以/開頭的時候,給出的是對應的上下文URL默認是false.name轉發路徑的邏輯名,必須寫.path轉發或者重定向的URL,必須寫必須是以/開頭.redirect設置為true的時候表示執行重定向操作,此項為false的時候,表示執行請求轉發操作.重定向與請求轉發的區別以后就是重定向是把請求生成應答給客戶端然后在重新發送給定向的URL,瀏覽器地址欄會有顯示.而轉發就是直接把請求轉發給本應用的另一個文件,不生成應答所以客戶端IE沒顯示.
<action-mapping>元素:包含一個或者N個<action>元素,描述了從特定的請求路徑到響應的Action的映射.在<action>元素中可以包含多個<exception>和<forward>子元素,他們分別配置局部異常處理和局部轉發.attribute設置Action關聯的ActionForm在request或者session范圍內的key.就是在request或者session共享內的名稱.className對應配置元素的類.默認的是ActionMapping.forward指定轉發URL路徑include指定包含URL路徑.input指定包含表單的URL,當表單驗證失敗的時候發送的URL.name,指定和該Action關聯的Form名字.該名字必須是在form-bean中定義過的,可寫可不寫.path必須/開頭的方位Action的路徑.parameter指定Action配置參數.在Action的execute()方法中可以調用ActionMapping的getParameter()方法來讀取匹配的參數.roles指定允許調用該Action的安全角色,多個角色之間逗號格開.scope指定Form的存在范圍.默認是session.tyep指定Action的完整類名.unknown如果是true表示可以處理用戶發出的所有的無效的ActionURL默認是false.validate指定是否調用ActionForm的validate方法.
<controller>元素:用于配置ActionServlet.buffreSize指定上載文件的輸入緩沖大小.該屬性為可選默認4096.className指定元素對應的配置類,ControllerConfig.然后是contentType指定響應結果內容類型和字符編碼,該屬性為可選,默認是text/html如果在Action或者JSP網頁也設置了類型內容,會覆蓋這個.locale指定是否把Locale對象保存到當前用戶的session中默認false.tempDir指定處理文件上載的臨時工作目錄.nochache如果是true在響應結果中加入特定的頭參數.
<message-resources>元素:用來配置Resource Bundle.用于存放本地文本消息文件.className元素對應的配置類.MessageResourcesConfig.factory指定消息的工廠類.key指定文件存放的Servlet對象中采用的屬性Key.null指定如何處理未知消息.parameter指定消息的文件名.
<plug-in>元素:用于配置Struts插件.
配置多應用模塊:所有的子應用都可以共享同一個ActionServlet實例,但是每個子應用都有單獨的配置文件.把應用劃分為多個子應用模塊.首先為每個應用創建單獨的Struts配置文件,在web.xml的ActionServlet配置代碼中添加幾個子應用信息.采用<forward>元素來實現應用之間的切換.
Digester組件:是一個Apache的另一個開源代碼項目.當Struts被初始化的時候,首先會讀取并解析配置文件,框架采用Digester組件來且西配置文件.然后創建config包中的對象.者對象用于存放配置信息.
其實配置文件不難,只要都理其中的原理就OK了.真正實際的項目開發中,采用的工具例如Eclipse系列,提供了相應的插件,在創建一個Struts工程的時候配置文件的標簽都是自動生成的,而我們只需要往里面填寫屬性就OK了.