
網名:hoojo
E-mail:hoojo_@126.com
專注于Java,現從事電警卡口、智能交通、電子警察、數字城市等應用開發,擅長JavaEE、Flex、ActionScript及Web前端HTML、CSS、JavaScript、ExtJS、jQuery、Mootools等開發。對常用開源框架有一定的認識和見解。
我們都知道普通的文件上傳是通過表單進行文件上傳的,還不能達到異步上傳的目的。通過使用某些技術手段,比如jquery form.js可以達到異步上傳的目的,但最重要的問題在于,它不能夠進行多個文件的上傳。如果你要上傳多個文件,必須一個一個地上傳,同時還要在界面上處理當上傳完一個文件之后,下一個文件上傳框的問題。
現在我們有了一個更多的運行,即使用swfupload進行多文件異步上傳。顧名思義,它是一個flash的上傳工具,但在界面上的表現形式使它和普通的html元素一樣,沒有復雜的展現,就一個普通的上傳框,即可達到想要目的。
關于swfupload的使用這里自不必多,這里主要介紹的是解決在java web開發過程中經常碰到的驗證失敗的問題。這是因為flash在上傳的時候使用的是和瀏覽器不同的會話,flash的SWFUpload上傳利用socket套接字進行通信,所以導致session和原來上一次的會話不同,導致session丟失。這樣就導致服務器在驗證時自然被認為是新會話,從而驗證不能通過,導致上傳不能成功了。
解決問題的方法,就是讓flash在上傳文件的時候帶上同在一個界面的session標識,這通常是修改其中的upload_url來達到我們的目的,修改如下所示:
upload_url: "/admin/infobuild/image/upload.action;jsessionid=${pageContext.session.id }"
<!-- 這句要房子jsp頁面中的script腳本中,或是放在servlet的response.getWriter()流中的script腳本中;總之要在swfupload 的js引入之前執行 -->
window["sessionId"]="${pageContext.session.id}";
<!-- 這句話就可以在引入的js中使用 -->
upload_url: Gtip.util.addContextPath("/admin/infobuild/image/upload.action;jsessionId" + "=" + window["sessionId"]),
以上方案是解決在jsp頁面中解決的取值java的變量值;
如上代碼的第一句放到jsp文件中,如jsp的公共include文件中。下面一句就放到js文件中,如引入的upload.js文件當中。
但以上代碼還存在一個問題,就是默認的sessionName問題。在tomcat或者其它j2ee容器,默認的sessionName也是 jsessionId。如果我們修改了sessionName如通過tomcat的server.xml修改session_cookie_name,這樣默認的sessionName就是我們修改之后的了。解決此問題,需要再加一個參數設置才可,如下所示:
<!-- 這三行放在include 導入的那個jsp的頁面中 -->
window["contextPath"] = "${pageContext.request.contextPath}";
window["sessionId"] = "${pageContext.session.id}";
window["sessionName"] = "jsessionId";
// js中使用jsp中設置的window的變量值
upload_url: addContextPath("/admin/infobuild/image/upload.action;" + window["sessionName"] + "=" + window["sessionId"])
以上代碼的前三行放到公共的include.jsp中,最后一行放到公共的upload.js中。這樣即可滿足最終要求了。
不過有一點不好的即是,在部署環境中時,如果部署環境修改了sessionName,則必須在此include.jsp中修改一個具體的sessionName才可。
轉載請標明出處:i flym
本文地址:http://www.iflym.com/index.php/code/201108190001.html
做手機Web開發做瀏覽器兼容用到了,所以在網上找了些匯總下。
alert($(window).height()); //瀏覽器當前窗口可視區域高度
alert($(document).height()); //瀏覽器當前窗口文檔的高度
alert($(document.body).height());//瀏覽器當前窗口文檔body的高度
alert($(document.body).outerHeight(true));//瀏覽器當前窗口文檔body的總高度 包括border padding margin
alert($(window).width()); //瀏覽器當前窗口可視區域寬度
alert($(document).width());//瀏覽器當前窗口文檔對象寬度
alert($(document.body).width());//瀏覽器當前窗口文檔body的高度
alert($(document.body).outerWidth(true));//瀏覽器當前窗口文檔body的總寬度 包括border padding margin
// 獲取頁面的高度、寬度
function getPageSize() {
var xScroll, yScroll;
if (window.innerHeight && window.scrollMaxY) {
xScroll = window.innerWidth + window.scrollMaxX;
yScroll = window.innerHeight + window.scrollMaxY;
} else {
if (document.body.scrollHeight > document.body.offsetHeight) { // all but Explorer Mac
xScroll = document.body.scrollWidth;
yScroll = document.body.scrollHeight;
} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
xScroll = document.body.offsetWidth;
yScroll = document.body.offsetHeight;
}
}
var windowWidth, windowHeight;
if (self.innerHeight) { // all except Explorer
if (document.documentElement.clientWidth) {
windowWidth = document.documentElement.clientWidth;
} else {
windowWidth = self.innerWidth;
}
windowHeight = self.innerHeight;
} else {
if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
windowWidth = document.documentElement.clientWidth;
windowHeight = document.documentElement.clientHeight;
} else {
if (document.body) { // other Explorers
windowWidth = document.body.clientWidth;
windowHeight = document.body.clientHeight;
}
}
}
// for small pages with total height less then height of the viewport
if (yScroll < windowHeight) {
pageHeight = windowHeight;
} else {
pageHeight = yScroll;
}
// for small pages with total width less then width of the viewport
if (xScroll < windowWidth) {
pageWidth = xScroll;
} else {
pageWidth = windowWidth;
}
arrayPageSize = new Array(pageWidth, pageHeight, windowWidth, windowHeight);
return arrayPageSize;
}
// 滾動條
document.body.scrollTop;
$(document).scrollTop();
有問題可以留言、私信、發郵件: Blog:http://blog.csdn.net/IBM_hoojo 方法一:
Email:hoojo_@126.com
1、安裝Rational Rose2003時,在需選擇安裝項的時候,只選擇Rational Rose EnterPrise Edition即可,不需選擇其他項,之后選擇“DeskTop Installation from CD Image“,一路下一步。出現Mem_pointer_Bad錯誤,點擊確定繼續;
2、安裝finish后將彈出的Rational License Key Administrator向導等窗口關閉。若有連接FLEXlm License Server的出錯提示框出現,也關閉它們。
安裝會出現 Mem_pointer_Bad 錯誤,原因應該是某個函數因為安全等級問題而無法運行,只要下載一個SHW32.dll把 ../Rational/Rose/SHW32.dll替換即可。(注:此方法可以避免報錯,但是亦可能會造成Rose新建工程報Automation錯誤,所以此方法基本無效。。。任他報錯吧!囧)
下載地址: http://www.oyksoft.com/soft/1880.html
3、安裝好Rational Rose Enterprise Editon后,打開rose2003crack.rar壓縮包,里面有四個文件,分別為flexlm.cpl、license.dat、lmgrd.exe、rational.exe。
4、用記事本打開license.dat文件,大約在文件的中間位置有:
SERVER MICROSOFT ANY
DAEMON rational "C:\Program Files\Rational\common\rational.exe"
將其修改為:SERVER 計算機名 ANY DAEMON rational "自己安裝的目錄\rational.exe"后,保存。
5、將license.dat、 lmgrd.exe 、rational.exe三個文件一起拷貝到:安裝目錄\rational\common\ 下面。
如:若為默認則為:C:\Program Files\Rational\common\目錄。
6、將flexlm.cpl拷貝到C:\Windows\system32目錄下。
7、進入控制面板,則在控制面板的上方會增加了一個圖標,即FLEXlm License Manager,將其打開,在Setup頁中lmgrd.exe右側目錄寫為:C:\Program Files\Rational\Common\lmgrd.exe(若為默認安裝目錄)
License File右側目錄寫為:C:\Program Files\Rational\Common\license.dat 點擊“應用”。
8、回到Control頁,點擊Start,若出現"Server Started",則表示已經成功,可以點擊Status,若狀態為:計算機名:license server UP(MASTER)則成功。
9、這時可打開安裝的Rational Rose Enterprise Edition,若還是出現Error,則打開Rational License Key Administrator ,點擊工具欄中的第一個工具(Start WIzard),點擊下一步,在Server Name中的名字改為自己的計算機名,port可以不輸,能進入下一個管理窗口并且沒出錯提示,就代表license server配置成功,Rational的產品應該可以運行了。
——————————————————————————————————————————————————
更簡單方法二:
安裝完成后,下載rational_perm.dat覆蓋到Common文件夾即可完成破解,簡單吧 o(∩_∩)o...哈哈!
###########################################################################
另一版本:
FROM:http://blog.csdn.net/fenglibing/archive/2007/08/17/1747693.aspx
這么好的東西,不拿來出分享,我對不起原作者呀。但是我這里不知道作者是誰,感謝在先了。
http://www.oyksoft.com/soft/1880.html
http://files.cnblogs.com/lixianhuei/rose2003crack.rar
以上兩個網址分別是用來下載Rational Rose 2003及其破解軟件的。
1、安裝Rational Rose2003時,在需選擇安裝項的時候,只選擇Rational Rose EnterPrise Edition即可,不需選擇其他項。
2、安裝好Rational Rose Enterprise Editon后,打開rose2003crack.rar壓縮包,里面有四個文件,分別為flexlm.cpl、license.dat、lmgrd.exe、rational.exe。
3、用記事本或者是EditPlus打開license.dat文件,大約在文件的中間位置有:SERVER Microsoft ANY
DAEMON rational “C:\Program Files\Rational\common\rational.exe” 將其修改為:SERVER 計算機名 ANY DAEMON rational “自己安裝的目錄\rational.exe”后,保存
注:若是按默認目錄安裝,則只需修改計算機名即可。
4、將license.dat、 lmgrd.exe 、rational.exe三個文件一起拷貝到:安裝目錄\rational\common\ 下面。
如:若為默認則為:C:\Program Files\Rational\common\目錄。
5、將flexlm.cpl拷貝到system32目錄下。如win2000系統中為C:\WINNT\system32目錄。
6、進入控制面板,則在控制面板的上方會增加了一個圖標,即FLEXlm License Manager,將其打開,在Setup頁中lmgrd.exe右側目錄寫為:C:\Program Files\Rational\Common\lmgrd.exe(若為默認安裝目錄)
License File右側目錄寫為:C:\Program Files\Rational\Common\license.dat
7、回到Control頁,點擊Start,若出現”Server Started”,則表示已經成功,可以點擊Status,若狀態為:計算機名:license server UP(MASTER)則成功。
8、這時可打開安裝的Rational Rose Enterprise Edition,若還是出現Error,則打開Rational License Key Administrator ,點擊工具欄中的第一個工具(Start WIzard),點擊下一步,在Server Name中的名字改為自己的計算機名即可。因現在的學習需在使用Rational Rose,所以進行了安裝,但確實花了不少工夫,所以特把自己安裝的經驗來跟大家一起分享,希望能對大家有所幫助。
該文章為轉載文章,原文作者應該是163.com的blog,但找不到作者blog,只能通過圖片url找到是163.com的
Email:hoojo_@126.com
Blog:http://blog.csdn.net/IBM_hoojo
摘要: 最近在搭建一個項目,需要用到很多通用的工具類,自己也寫了幾個。現在分享一下,也方便自己以后使用。如果你覺得不錯的話,也歡迎轉載。blog http://blog.csdn.net/IBM_hoojohttp://hoojo.cnblogs.comhttp://hoojo.blogjava.netemail hoojo_@126.com 文件上傳狀態枚舉類: package com... 閱讀全文 摘要: 支持將Image的寬度、高度縮放到指定width、height,并保存在指定目錄通過目標對象的大小和標準(指定)大小計算出圖片縮小的比例可以設置圖片縮放質量,并且可以根據指定的寬高縮放圖片 源碼: package com.hoo.util; import java.awt.Image;import java.awt.image.BufferedImage;import java.io.... 閱讀全文Struts 概述
隨著MVC 模式的廣泛使用,催生了MVC 框架的產生。在所有的MVC 框架中,出現最早,應用最廣的就是Struts 框架。
Struts 的起源
Struts 是Apache 軟件基金組織Jakarta 項目的一個子項目, Struts 的前身是CraigR. McClanahan 編寫的JSP Model2 架構。
Struts 在英文中是"支架、支撐"的意思,這表明了Struts 在Web 應用開發中的巨大作用,采用Struts 可以更好地遵循MVC 模式。此外, Struts 提供了一套完備的規范,以基礎類庫,可以充分利用JSP/Servlet 的優點,減輕程序員的工作量,具有很強的可擴展性。
Struts優點
提高開發效率,減輕了程序員的工作量,降低了重復代碼(降低代碼冗余),文件不再臃腫。
可以規范軟件開發的行為。ActionForm為我們封裝請求數據
增加代碼的擴展性、移植性
提高代碼的可重用性、可讀性,無需多個Servlet多個方法
Action轉發頁面只須配置跳轉資源即可,無效全路徑、硬編碼。降低代碼的耦合性
Struts 架構的工作原理
1. Model 部分
Struts 的Model 部分由ActionForm和JavaBean 組成。其中ActionForm用于封裝用戶請求參數,所有的用戶請求參數由系統自動封裝成ActionForm 對象:該對象被ActionServlet轉發給Action; 然后Action 根據ActionForm里的請求參數處理用戶請求。JavaBean 則封裝了底層的業務邏輯,包括數據庫訪問等。在更復雜的應用中,JavaBean所代表的絕非一個簡單的JavaBean,可能是EJB 組件或者其他的業務邏輯組件。該Model 對應圖3 .4的Model 部分。
2. View 部分
Struts 的View 部分采用JSP 實現。Struts 提供了豐富的標簽庫,通過這些標簽庫可以最大限度地減少腳本的使用。這些自定義的標簽庫可以實現與Model 的有效交互,并增加了顯示功能。對應圖的JSP 部分。
整個應用由客戶端請求驅動,當客戶端請求被ActionServlet 攔截時, ActionServlet根據請求決定是否需要調用Model 處理用戶請求,當用戶請求處理完成后,其處理結果通過JSP 呈現給用戶。
3. Controller部分
Struts 的Controller 由兩個部分組成。
·系統核心控制器—攔截用戶請求ActionServlet 派發請求
·業務邏輯控制器—處理用戶請求的Action,處理業務邏輯
其中,系統核心控制器是一個ActionServlet。該控制器由Struts 框架提供,繼承HttpServlet類,因此可以配置成一個標準的Servlet。該控制器負責攔截所有Http請求,然后根據用戶請求決定是否需要調用業務邏輯控制器,如果需要調用業務邏輯控制器,則將請求轉發給Action 處理,否則直接轉向請求的JSP 頁面。業務邏輯控制器負責處理用戶請求,但業務邏輯控制器本身并不具有處理能力,而是調用Model 來完成處理。業務邏輯控制器對應圖3 .4中的Action 部分。
下面結合圖3.7 對Struts 的工作流程作詳細的講解。
Web 應用都是請求一響應的程序結構。程序是由客戶端Client 發出Http 請求開始的,客戶端請求被ActionServlet 攔截。在ActionServlet 處,有兩種情況:
·要求邏輯控制器處理的請求:
·簡單轉發的請求。
對于第一種的請求,ActionServlet 需要調用對應的Action。因此ActionServlet 將請求轉發到Action ,如果請求還配置了對應的FormBean,則ActionServlet 還負責用請求參數填充ActionForm,此時如果ActionForm還沒有創建。ActionServlet會幫我們創建一個可以用的ActionForm,如果ActionForm已經創建就直接給我們用, ActionForm 的實質就是JavaBean,專門用于封裝請求參數。并且在次期間,如果ActionForm如果有驗證方法,會去執行驗證方法,如果驗證通過會進入Action中。驗證失敗,會跳轉到Action配置的input資源頁面。
此時的Action 將無須從HTTP Request 中獲取請求參數,而是從ActionForm 中獲得請求參數。Action 獲得請求參數后,調用Model 對象由JavaBean 處理用戶請求。Action處理完用戶請求之后,將處理結果包裝成ActionForward,回送給ActionServlet。
由于ActionForward 對象封裝了JSP 資源的映射。因此, ActionServlet 知道調用合適的JSP 資源表現給客戶端。
對于第二種請求, HTTP 請求無須Action 處理,只是對普通資源的請求,作為超級鏈接的替代。因為ActionServlet 直接將該請求轉發給JSP 資源,既不會填充ActionForm,也無須調用Action 處理。
JSP 頁面在表現之前,還需要調用對應的JavaBean,此處的JavaBean 不再是包含業務邏輯的JavaBean,而是封裝了處理結果的普通vo (值對象)。JSP 頁面根據vo 的值,可能利用JSTL 或者Struts 的標簽庫來生成HTTP 響應給客戶端。總之JSP 應盡量避免使用Java 腳本。
Action配置
path是我們請求訪問的路徑,如果用struts標簽,會默認加上.do的后綴。ActionServlet攔截到*.do的請求后,就進行相應的業務處理,然后派發到path對應的Action;
name是Action對象的ActionForm,ActionForm是封裝請求的信息,如表單
attribute和name一樣,可以省略,在省略的情況下用name。都是對應ActionForm
type是Action對象對應的文件路徑,含包名
scope是ActionForm的作用域,默認request
parameter后帶方法名稱,即請求所執行的方法
forward是轉發后的資源頁面
ActionForward配置
name邏輯名稱和Action中的mapping.forward參數對應
path對應映射的JSP頁面
redirect是否重定向請求
forward有全局和局部的2種,如果當前Action配置的forward資源在當前配置的Action中沒有找到,然后回到全局的forward資源中查找。局部優先全局
ActonForm配置
name是form的名稱
type是form的包名+文件名
ActionForm還有動態ActionForm、驗證ActionForm
國際化I18N(Internationalization)
目的:是適應更多的、更好的用戶界面
Java 程序的國際化主要通過如下三個類完成。
java.util. ResourceBundle: 對應用于加載一個資源包。
java.util.Locale: 對應一個特定的國家/區域及語言環境。
java.text.MessageFormat: 用于將消息格式化。
為了實現程序的國際化,必須先提供程序所需要的資源文件。資源文件的內容是和很多key-value 對。其中key 是程序使用的部分,而value 則是程序界面的顯示。
資源文件的命名可以有如下三種形式。
baseName _language_country.properties。
baseName _language.properties。
baseNarne.properties 。
其中baseName 是資源文件的基本名,用戶可以自由定義。而language 和count可都不可隨意變化,必須是Java 所支持的語言和國家。
1.國際化支持的語言和國家
事實上, Java 也不可能支持所有國家和語言,如需要獲取Java 所支持的語言和國家,可調用Locale 類的getAvailableLocale 方法來獲取。該方法返回一個Locale 數組,該數組里包含了Java 所支持的語言和國家。
2. 編寫國際化所需的資源
國際化所需的資源文件內容是key-value 對,下面提供了兩個資源文件,這兩個資源文件很簡單,只包含一個key-value 對。
下面是MyResource.properties 的文件的內容:
資源文件的內容: key-value 對。
msg=Hello , {O} Today is {1}.
下面是MyResource_zh_CN.properties 文件的內容:
資源文件的內容: key-value 對
msg=你好. {O} 今天是{l}。
所有資源文件的key 都是相同的,只是value 會隨國家和語言的不同而變化。
3.程序從哪里獲取資源呢?
在ResourceBundle 加載資源時按如下順序搜索。
搜索所有國家和語言都匹配的資源文件,例如,對于簡體中文的環境,先搜索如下文件:
MyResource_zh_CN.properties
如果沒有找到國家和語言都匹配的資源文件,則再搜索語言匹配的文件,即搜索如下文件:
MyResource_zh.properties
如果上面的文件依然無法搜索到,則搜索baseNarne 匹配的文件,即搜索如下文件:
MyResource.properties
4. 使用類文件代替資源文件
Java 也允許使用類文件代替資源文件,即將所有的key-value對存入class 文件,而不是屬性文件。
用來代替資源文件的Java 文件必須滿足如下條件。
·類的名字必須為baseNarne_language_country,這與屬性文件的命名相似。
·該類必須繼承ListResourceBundle,并重寫getContents 方法,該方法返回Object數組,該數組的每一個項都是key=value 對。
eg:下面的類文件可以代替上面的屬性文件:
public class MyResource_zh_CN extends ListResourceBundle {
// 定義資源
private final Object myData[][] = { "msg" , " {0}您好!今天是{l} "};
//重寫方法getContents()
public Object[] [] getContents() {
//該方法返回資源的key-value對
return myData;
}
}
如果系統同時存在資源文件及類文件,則系統將以類文件為主,而不會調用資源文件。對于簡體中文的Locale, ResourceBundle 搜索資源的順序是:
(1) baseName zh CN.class 。
(2) baseNarne_zh_CN.properties。
(3) baseNarne zh.class 。
(4) baseNarne_zh.properties。
(5) baseNarne.class。
(6) baseNarne.properties。
當系統按上面的順序搜索資源文件時,如果前面的文件不存在,則會使用下一個:如果一直找不到對應的文件,系統將拋出異常。
struts加載資源文件
資源文件的加載通過struts-config.xml文件來配置,加載資源文件應從Web 應用的WEB-INF/classes路徑開始加載。因此,資源文件必須放在WEB-INF/classes路徑或該路徑的子路徑下。如果直接放在WEB-INF/classes 路徑下,在配置資源文件時,直接指定資源文件的baseName 即可。但如果放在子路徑下,則必須以包的形式配置。
動態ActionForm
Why?當一個form表單的屬性、字段非常多的情況下,需要我們不斷的修改、添加ActionForm中的屬性,并提供getter、setter方法。雖然這個類比較簡單,但是大量重復的getter、setter方法也是比較繁瑣的。這個時候struts的動態ActionForm就派上用場了。使用動態ActionForm 的目的是為了減少代碼的書寫量,但是相對在配置方面要復雜些。
配置動態ActionForm
所有的動態ActionForm 的實現類都必須是org.apache.struts.action.DynaActionForm類,或者是它的子類。使用動態ActionForm 與前面不同的是:因為系統不清楚動態ActionForm 的屬性,所以必須在配置文件中配置對應的屬性。可以使用form-property 元素來配置動態ActionForm 的屬性。
<!一配置動態ActionForm,動態Aciton 必須使用烏rnaActionForm 一〉
<form-bean name="loginForm" type="org.apache.struts.action.DynaActionForm">
<!一配置ActionForm的屬性: username-->
<form-property name="username" type="java.lang.String"/>
<! 配置ActionForm的屬性: pass-->
<form-property name="pass"type="java.lang.String"/>
</form-bean>
<!-- 配置Action中的path , type , name 屬性>
<action path="/login" type="com.hoo.LoginAction" name="loginForm">
<!一配置兩個局部Forward-->
<forward name="welcome" path="/WEB-INF/jsp/welcome.jsp"/>
<forward name="input" path="/login.jsp"/>
</action>
從上面的配置文件可看出,動態ActionForm 的配置必須增加form-property 元素,每個屬性必須對應一個form-property元素。
form-property元素包含兩個屬性。
name: 屬性的名字,必須與JSP 頁面的表單域的名字相同。
type: 屬性的類型。
使用動態ActionForm
//必須重寫該核心方法,該方法actionForm 將表單的請求參數封裝成值對象
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
//將ActionForm強制類型轉換為DynaActionForm
DynaActionForm loginForm = (DynaActionForm)form;
//從ActionForm中解析出請求參數: username
String username = (String)loginForm.get("username");
//從ActionForm中解析出請求參數: password
String pass = (String)loginForm.get("pass");
//后面的處理與前一個示例的Action 相同。
…………
}
使用動態ActionForm 時,請求參數必須使用DynaActionForm的getter 方法獲取。
DynaActionForm 的getter 方法主要有如下三個。
Object get(java.lang.String name): 根據屬性名返回對應的值。
Object get(java.lang.String name, int index): 對于有多個重名表單域的情況, Struts將其當成數組處理,此處根據表面域名和索引獲取對應值。
Object get(java.lang.String name, java.lang.String key): 對于使用Map 屬性的情況,根據屬性名及對應key. 獲取對應的值。
Struts 的標簽庫
Struts 提供了大量的標簽庫,用于完成表現層的輸出。借助于Struts 的標簽庫,可避免在JSP 中嵌入大量的Java 腳本,從而提高代碼的可讀性。
Struts 主要提供了如下三個標簽庫。
A、 html: 用于生成HTML 的基本標簽。
B、 bean: 用于完成程序國際化,輸出Struts 的ActionForm 的屬性值等。
C、 logic: 用于完成循環、選擇等流程控制。
使用html 標簽庫
Struts 為htrnl 的大部分標簽提供了對應的htrnl 標簽, htrnl 所支持的標簽大致有如下。
* base: 表現成一個HTML 的<base>標簽。
* button: 表現成一個按鈕,該按鈕默認沒有任何動作。
* cancel: 表現成一個取消按鈕。
* checkbox: 表現成一個Checkbox 的輸入框。
* error: 用于輸出數據校驗的出錯提示。
* file: 表現成一個文件瀏覽輸入框。
* form: 表現成一個form 域。
* frame: 表現成一個HTML<frame>標簽。
* hidde: 表現成一個隱藏域。
* htrnl: 表現成HTML 的<htrnl>標簽。
* image: 表現成表單域的image 域。
* img: 表現成一個HTML 的img 標簽。
* javascrit: 表現成JavaScript 的校驗代碼,這些校驗代碼根據ValidatorPlugIn 生成。
* link: 表現成HTML 的超級鏈接。
* messages: 用于輸出Struts 的各種提示信息,包括校驗提示。
* multibox: 表現成一個Checkbox 輸入框。
* option: 表現成選擇框的一個選項。
* password: 表現成一個密碼輸入框。
* radio: 表現成一個單選輸入框。
* reset: 表現成一個重設按鈕。
* rewrite: 表現成一個URL 。
* select: 表現成一個列表選擇框。
* submit: 表現成一個提交按鈕。
* text: 表現成一個單行文本輸入框。
* textarea: 表現成一個多行文本框。
使用bean 標簽庫
bean 標簽庫主要用于輸出屬性值、提示消息及定義請求參數等。下面是bean 標簽庫的常用標簽。
* cookie: 將請求的cookie 的值定義成腳本可以訪問的JavaBean 實例。
* define: 將某個bean 的屬性值定義成腳本可以訪問的變量。
* header: 將請求頭的值定義成腳本可以訪問的變量。
* include: 將某個JSP 資源完整定義成一個bean 實例。
* message: 用于輸出國際化信息。
* page: 將page Context 中的特定項定義成一個bean 。
* parameter: 將請求參數定義成腳本可以訪問的變量。
* resource: 加載Web 應用的資源,并將其變成JavaB eano
* struts: 用于將某個Struts 的內部配置成一個bean 。
* write: 用于輸出某個bean 的屬性值。
使用logic 標簽庫
logic 標簽庫是使用最頻繁,相對復雜的標簽庫。logic 標簽庫主要用于完成基本的流程控制,比如循環及選擇等。
logic 標簽庫主要有如下標簽。
* empty: 如果給定的變量為空或者為空字符串,則就計算并輸出標簽體的內容。
* equal: 如果給定變量與特定的值相等,則會計算并輸出該標簽體的內容。
* forward: 將某個頁面的控制權forward 確定的ActionForward 項。
* greaterEqual: 如果給定變量大于或等于特定的值,則會計算并輸出標簽體的內容。
* greaterThan: 如果給定變量大于特定的值,則會計算井輸出標簽體的內容。
* iterate: 通過遍歷給定集合的元素,對標簽體的內容進行循環。
* lessEqual: 如果給定變量小于或等于特定的值,則會計算并輸出標簽體的內容。
* lessThan: 如果給定變量小于特定的值,則會計算并輸出標簽體的內容。
* match: 如果特定字符串是給定消息合適的子字符串,則會計算并輸出標簽體的內容。
* messagesNotPresent: 如果請求中不包含特定的消息內容,將計算并輸出標簽體的內容。
* messagesPresent: 如果請求中包含特定的消息內容,則計算并輸出標簽體的內容。
* notEmpty: 如果給定的變量既不為空,也不是空字符串,則計算并輸出標簽體的內容。
* notEqual: 如果給定變量不等于特定的值,則會計算并輸出標簽體的內容。
* notMatch: 如果特定宇符串不是給定消息合適的子字符串,則會計算并輸出標簽體的內容。
* notPresent: 如果特定的值沒有出現在請求中,則計算并輸出標簽體的內容。
* present: 如果特定的值出現在請求中,則計算并輸出標簽體的內容。
* redirect: 重定向頁面。
Struts 的數據校驗
數據校驗也稱為輸入校驗,指導對用戶的輸入進行基本過濾,包括必填宇段,宇段必須為數字及兩次輸入的密碼必須相匹配等。這些是每個MVC 框架都應該完成的任務,Struts 提供了基本的數據校驗,如果結合commons-validator, Struts 則擁有強大的校驗框架,包括進行客戶端的JavaScript 校驗等。
Struts 的數據校驗大致有如下幾種方式:
ActionForm 的代碼校驗。
Action 里的代碼校驗。
結合commons-validator.jar 的校驗。
ActionForm 的代碼校驗
ActionForm 的代碼校驗是最基本的校驗方式。這種校驗方式是重寫ActionForm 的validate 方法,在該方法內對所有的宇段進行基本校驗。如果出現不符合要求的輸出,則將出錯提示封裝在ActionError 對象里,最后將多個ActionError 組合成ActionErrors 對象,該對象里封裝了全部的出錯提示。并將錯誤信息用<html:error/>展現在配置的input的失敗頁面上。
Action 的代碼校驗
在Action 里通過代碼完成輸入校驗,是最基本,也最容易使用的方法。與最初的MVC 設計相似,在調用業務邏輯組件之前,先對數據進行基本校驗。這是最傳統也是最原始的方法。
這種校驗方式非常容易理解,所有的代碼都需要程序員自己控制,相當靈活。
但有如下幾個不方便之處。
·用戶需要書寫大量的校驗代碼,使程序變得煩瑣。
· 數據校驗應該在填充ActionForm里完成,最好能在客戶端完成校驗,而不是推遲到Action 里才完成數據校驗。
注意:在實際的使用中,這種校驗方式不僅程序開發復雜,且性能也不高。
結合commons-validator.jar 的校驗
借助于commons-validator.jar 的支持, Struts的校驗功能非常強大,幾乎不需書寫任何代碼。不僅可以完成服務器端校驗,同時還可完成客戶端校驗,即彈出Javascript 提示。
使用commons-validator.jar 校驗框架時,有如下幾個通用配置。
·增加校驗資源。
·利用ValidatorPlugIn 加載校驗資源。
·ActionForm 使用ValidatorForm 的于類。
下面分別通過三個示例講解這三種校驗:基本的校驗、對動態ActionForm 執行校驗及彈出JavaScript 校驗提示。
1. 繼承ValidatorForm 的校驗
如果需要使用commons-validator 框架,請按如下步驟進行。
(1) Struts 的ActionForm必須是ValidatorForm的子類,提供驗證屬性字段的getter、setter方法
(2) 編寫表單域時必須滿足校驗規則。校驗規則都由規則文件控制,規則文件有以下兩個。
* validator-rules.xml 文件
* validation.xml 文件
第一個文件可在Struts 的解壓縮后的文件夾的lib 下找到,將該文件復制到WEB-INF
2. common-validator支持的校驗規則
common-validator支持的校驗規則非常豐富,特別是mask 和validwhen 兩個規則,
極大地豐富了該校驗框架的功能。
常用的校驗規則有如下幾種。
* required: 必填。
* va1idwhen: 必須滿足某個有效條件。
* minlength: 輸入必須大于最小長度。
* maxlength: 輸入必須小于最大長度。
* mask: 輸入匹配正確的表達式。
* byte: 輸入只能是一個byte 類型變量。
* short: 輸入只能是一個short 類型變量。
* integer: 輸入只能是一個integer 變量。
* long: 輸入只能是一個long 變量。
* float: 輸入只能是一個float 變量。
* double: 輸入只能是一個double 變量。
* date: 輸入必須是一個日期。
* intRange: 輸入的數字必須在整數范圍內。
* floatRange: 輸入的數字必須在單精度浮點數范圍內。
* doubleRange: 輸入的數字必須在雙精度浮點數范圍內。
* email: 輸入必須是有效的E-mail 地址。
* uri: 輸入必須是有效的uri 地址。
3.使用DynaValidatorForm 的校驗
即使不書寫ActionForm,也可以利用cornmon-validator 校驗框架。此時使用的ActionForm 的實現類,必須既是動態Form ,也是驗證Form,DynaValidatorForm 就是滿足這兩個條件的Form。
4. 彈出客戶端JavaScript提示
如需要彈出客戶端JavaScript 校驗非常簡單,無須修改其他配置文件,只需修改登錄使用的JSP 頁面的兩個地方。
(1) 為form 元素增加onsubmit="return validateXxxForm(this);"屬性,其中的XxxForm就是需要校驗的form 名,與struts-config.xrnl中配置的form-bean 的name 屬性一致,也與validation.xrnl文件中需要校驗的form 的name 屬性一致。
(2) 增加<html:javascript formName="xxxForm"/> ,其中xxxForm 是需要校驗的form 名。
注意:即使使用了客戶端技驗規則,也不要刪除頁面的htm1 :rnessages 標簽。因為該標簽會在客戶端技驗通過,而在服務器端技驗并未通過時彈出提示。
Struts 的異常框架
Struts 1.1 版本中加入了對異常的處理,稱之為Exception Handling,標志著作為一個整體的框架, Struts 越來越趨于成熟。
在以前的Struts 開發過程中,對于異常的處理,主要是采用手動處理的方式:如通過try/catch 等捕獲異常:然后將定制個性化的,比較詳細的錯誤信息放進ActionMessage中:最后在返回頁面中把這些錯誤信息反饋給用戶。
對于異常的原始信息,不管是最終用戶還是開發員都不希望看到。
借助于Struts 的異常框架,異常處理只需通過struts-config.xm1文件定義即可。根據異常定義的位置不同,異常可分為局部異常和全局異常兩種。
·局部異常作為action 的子元素中定義。
·全局異常在globa1-excetpions 元素中定義。
異常定義的格式如下:
<exception key="keyNarne" type="ExceptionNarne" scope="scope" path="uri"/>: 當Struts 出現ExceptionNarne 的異常時,頁面自動轉向uri 指向的資源,并在該頁面輸出keyName 對應的國際化中的出錯提示。
幾種常用的Action
除了基本的Action 之外, Struts 還提供了幾個其他類型的Action ,這些Action 大大豐富了Struts 的功能。下面介紹如下兒個常用的Action 。
* DispatchAction: 能同時完成多個Action 功能的Action 。
* ForwardActon: 該類用來整合Struts 和其他業務邏輯組件,通常只對請求作有效性檢查。
* IncludeAction: 用于引入其他的資源和頁面。
* LookupDispatchAction: DispatchAction 的子類,根據按鈕的key ,控制轉發給action的方法。
* MappingDispatchAction: DispatchAction 的子類,一個action 可映射出多個Action地址。
* SwitchAction: 用于從一個模塊轉換至另一個模塊,如果應用分成多個模塊時,就可以使用SwitchAction 完成模塊之間的切換。
DispatchAction
在該action 的配置中,增加了parameter屬性,該屬性用于指定參數名,即Struts 將根據該參數的值調用對應的方法。為了讓請求增加method 的參數,method參數對應的是要請求執行的方法。
<action path="/login" type="com.hoo.LoginAction" name="loginForm" scope="request" validate="true" input="login.jsp" parameter="method">
<forward name="success" path="/welcome.jsp"/>
</action>
Login.do?method=login
MappingDispatchAction
可將同一個Action 的不同方法映射成多個Action URI ,這種Action 的寫法與DispatchAction 非常相似,同樣不需要重寫execute 方法,而是將書寫多個自定義的方法。這些方法除了方法名與execute 方法不同外,其他的參數列表及異常處理完全一樣。
<!-- 配置第一個Action. 實現類是com.hoo.LoginAction , parameter 為add-->
<action path="/add" type="com.hoo.LoginAction" name="loginForm" scope="request" validate="true" input="login.jsp" parameter="add">
<forward name="success" path="/welcome.jsp"/>
</action>
<! 配置第二個Action. 實現類是com.hoo.LoginAction , parameter 為modify-->
<action path="/modify" type="com.hoo.LoginAction" name="loginForm" scope="request" validate="true" input="login.jsp" parameter="modify">
<forward name="success" path="/welcome.jsp"/>
</action>
其中,path對應的是請求的地址uri,而parameter是對于當前請求所執行的方法;
注意:使用MappingDispatchAction 并沒有帶來太大的優勢,系統完全可以書寫兩個Action,分別定義兩個不同的action 映射,而其他部分沒有區別。
LookupDispatchAction
LookupDispatchAction也是DispatchAction 的一種,但它的處理更加簡單。該Action也可包含多個處理方法,它可讓處理方法與按鈕直接關聯,無須使用任何的JavaScript腳本。因此可通過重寫getKeyMethodMap方法完成按鈕與Action 中方法的關聯。
//用于關聯按鈕和方法
protected Map getKeyMethodMap() {
Map map = new HashMap();
//如果按鈕標題的key 為button.add. 則提交該按鈕時對應add 方法
map .put ("button. add" , "add");
//如果按鈕標題的key 為button.modify. 則提交該按鈕時對應modify 方法
map.put ("button.modify" , "modify") ;
return map;
}
ForwardAction
如果需要從一個頁面或資源轉換到另一個資源時,直接使用頁面或資源路徑的超級鏈接定位并不是好的做法,這使得控制器沒有機會處理相關的請求事直。
使用ForwardAction可以完成請求的轉發,當控制器調用ForwardAction的perform()方法時,它會使用屬性parameter 所設定的路徑進行forward 的動作。下面是一個設定ForwardAction的例子:
<actlon-mapplngs>
<action path="/welcome" type="org.apache.struts.actions.ForwardAction" parameter="/welcome.jsp"/>
</action-mappings>
該action 僅僅完成轉發,并沒有執行其他的額外動作。頁面控制轉發的代碼如下:
<a href="welcome.do">轉入</a>
當單擊轉入超級鏈接時,將可以轉向ForwardAction中parameter指向的資源。
IncludeAction
IncludeAction的用法與ForwardAction的用法比較相似,區別在于ForwardAction將跳轉到action 定義的資源,而IncludeAction用于引入該action 對應的資源。
下面是IncludeAction定義的源代碼:
<action-mapplngs>
<action path="/welcome" type="org.apache. struts.actions.IncludeAction" parameter="/welcome.jsp"/>
</action-mappings>
該action 用于經welcome.jsp 作為資源導入。
頁面中負責加載該action 所導入資源的代碼如下:
<jsp:include page="welcome.do"/><br>
上面的代碼將會把welcome action 定義的資源導入該頁面。
SwitchAction
SwitchAction 主要用于模塊之間的切換。當一個應用之中存在多個模塊時,使用SwitchAction在不同模塊之間的action 之間切換還是相當方便的。
Struts 的常見擴展方法
Struts 的強大吸引力還來自于它的可擴展性,其擴展性通常有如下三種方式。
·實現PlugIn: 如果需要在應用啟動或關閉時完成某些操作,可以創建自己的PlugIn類。
·繼承RequestProcessor: 如果想在請求被處理中的某個時刻做一些業務邏輯時,可以考慮實現自己的RequestProcessor 類。
·繼承ActionServlet: 如果需要在每次開始處理請求之前,或者處理請求結束之后完成某些操作,可以實現自己的ActionServlet 來完成擴展。
下面分別從三個方面來介紹Struts 的擴展。
實現PlugIn 接口
Struts 已經演示了PlugIn 的擴展方法:與common- validation 的整合。后面還將介紹Spring 與Struts 的整合,也利用了PlugIn 的擴展。
在下面的應用中,系統使用Hibernate 作為持久層,在啟動時創建SessionFactory 實例,并將該SessionFactory 存入application ,在應用關閉時銷毀SessionFactory 。只需如下兩步即可完成此功能。
(1) 實現自己的PlugIn 類。實現PlugIn 接口必須實現如下兩個方法。
1 void destroy()。
2 void init(ActionServlet serlet, ModuleConfig config) 。
應用啟動時調用init 方法,而應用關閉時則調用destroy 方法。
下面是SessionFactoryLoaderPlugIn 的實現類:
public class SessionFactoryLoaderPlugin implements PlugIn {
//Hibernate 的配置文件
private String configFile;
//應用關閉時,銷毀資源
public void destroy()
System.out.println("系統銷毀SessionFactory");
}
//應用啟動時,完成SessionFactory 的初始化
public void init(ActionServlet actionServlet , ModuleConfig config) throws ServletException
System.out.println("系統以" + getConfigFile() + "為配置文件初始化SessionFactory") ;
//獲取Plugln 配置文件的方法
public String getConfigFile() {
return configFile;
}
// 負責加載Plugln 配置屬性的方法
public void setConfigFile(String configFile) {
this.configFile = configFile;
}
}
在上面的PlugIn 中,并沒有真正初始化SessionFactory ,僅在控制臺打印出字符串來標識創建動作。另外,還提供了configFile 屬性的setter 和getter 方法,這兩個方法負責訪問plugin 元素的configFile 屬性。
( 2 ) 將SessionFactoryLoaderPlugIn 配置在struts-config.xml 文件中。方法與ValidatorPlugIn 的配置并沒有區別,下面是配置SessionFactoryLoaderPlugIn 的代碼:<plug-in className="hoo.SessionFactoryLoaderPluging">
<set-property property="conf工gFile" value=" WEB-INF/hibernate.cfg.xml"I>
</plug-in>
在配置SessionFactoryLoaderPlugIn 時,配置了configFile 屬性,該屬性用于確定Hibernate 配置文件的文件名。
繼承RequestProcessor
RequestProcessor 是Struts 的核心類,而Struts 的核心控制器是ActionServlet 。但ActionServlet 并未完成真正的處理,只是調用RequestProcessor , RequestProcessor 才是Struts 的核心類。
擴展RequestProcessor 的實例在Spring 中有個示范, Spring 提供的Delegating RequestProcessor 是一個很好的示例。下面示例對RequestProcessor 進行簡單的擴展。
RequestProcessor 包含了如下常見的方法。
* ActionForm processActionForm: RequestProcessor填充ActionForm 時執行該方法。
* Action processActionCreate: RequestProcessor 調用Action 時調用該方法。
* boolean processPreprocess: 預處理用戶請求時執行該方法。
* boolean processValidate: 處理輸入校驗時調用該方法。
擴展RequestProcessor 只需兩步即可。
(2)在struts-config.xml 文件中配置MyRequestProcessor。用戶重寫了RequestProcessor,但Struts 并不知道,必須在struts-config且nl 中配置才可以。
下面是配置MyRequestProcessor 的代碼:
<controller processorClass="lee.MyRequestProcessor" />
該屬性的配置應該放在action-mappings元素之后。
注意:重寫RequestProccessor的方法時,別忘了使用super 來調用父類的動作。如果沒有調用該方法,意味著開發者必須完成Struts 框架所完成的動作。這是不應該的,因為程序員只是在框架中加入額外的處理,并不是要替代Struts。
繼承ActionServlet如果需要在開始處理請求,或者處理結束之后加入自己的處理時,可對ActionServlet進行擴展。例如解決中文的編碼問題。
ActionServlet 接收處理請求參數時,并不是按GBK 的解碼方式處理請求,因此容易形成亂碼。為了解決該問題,可以強制指定ActionServlet 使用GBK 的解碼方式。
繼承ActionServlet重寫process方法,設置request、response編碼為gbk,然后配置在web.xml中。
Servlet 是一種比JSP 更早的動態網頁編程技術。在沒有JSP 之前, Servlet 也是同時充當視圖層、業務邏輯層及持久層角色。
Servlet 的開發效率非常低,特別是當使用Servlet 生成表現層頁面時,頁面中所有的HTML 標簽,都需采用Servlet 的輸出流來輸出,因此極其煩瑣。由于Servlet 是個標準的Java 類,因此必須由程序員開發,其修改難度大,美工人員根本無法參與Servlet 頁面的開發。這一系列的問題,都阻礙了Servlet 作為表現層的使用。
自MVC 規范出現后, Servlet 的責任開始明確下來,僅僅作為控制器使用,不再需要生成頁面標簽,也不再作為視圖層角色使用。
Servlet ,通常稱為服務器端小程序,是運行在服務器端的程序,用于處理及響應客戶端請求。
Servlet 是個特殊的Java 類,這個Java 類必須繼承HttpServlet 。每個Servlet 可以響應戶端的請求。Servlet 提供不同的方法用于響應客戶端請求。
doGet: 用于響應客戶端的get 請求。
doPost: 用于響應客戶端的post 請求。
doPut: 用于響應客戶端的put 請求。
doDelete: 用于響應客戶端的delete 請求。
事實上,客戶端的請求通常只有get 和post 兩種; Servlet 為了響應這兩種請求,必須重寫doGet 和doPost 兩個方法。如果Servlet 為了響應四個方法,則需要同時重寫上面的四個方法。
大部分時候, Servlet 對于所有請求的響應都是完全一樣的。此時,可以采用重寫一個方法來代替上面的幾個方法, Servlet 只需重寫service 方法即可響應客戶端的所有請求。另外, HttpServlet 還包含兩個方法。
init(ServletConfig config): 創建Servlet 實例時,調用的初始化方法。
destroy: 銷毀Servlet 實例時,自動調用的資源回收方法。
通常無須重寫init和destroy兩個方法,除非需要在初始化Servlet 時,完成某些資源初始化的方法,才考慮重寫init 方法。如果需要在銷毀Servlet 之前,先完成某些資源的回收,比如關閉數據庫連接等,才需要重寫destroy 方法。
注意:如果重寫了init(ServletConfig config)方法,則應在重寫該方法的第一行調用super.init(config) 。該方法將調用HttpServlet 的init 方法。
Servlet 和JSP 的區別在于:
Servlet 中沒有內置對象,原來JSP 中的內置對象都必須通過HttpServletRequest對象,或由HttpServletResponse 對象生成:
對于靜態的HTML 標簽, Servlet 都必須使用頁面輸出流逐行輸出。
這也正是筆者在前面介紹的: JSP 是Servlet 的一種簡化,使用JSP 只需要完成程序員需要輸出到客戶端的內容,至于JSP 中的Java 腳本如何鑲嵌到一個類中,由JSP 容器完成。而Servlet 則是個完整的Java 類,這個類的service 方法用于生成對客戶端的響應。
Servlet 的配置
編輯好的Servlet 源文件并不能響應用戶請求,還必須將其編譯成class 文件。將編譯后的HelloServlet. class 文件放在WEB-INF/classes 路徑下,如果Servlet 有包,則還應該將class 文件放在對應的包路徑下。
為了讓Servlet 能響應用戶請求,還必須將Servlet 配置在Web 應用中。配置Servlet時,需要修改web.xrnl 文件。
配置Servlet 需要配置兩個部分。<servlet>/<servlet-mapping>
Servlet的生命周期
Servlet 在容器中運行,其實例的創建及銷毀等都不是由程序員決定的,而是由容器進行控制。
Servlet 的創建有兩個選擇。
客戶端請求對應的Servlet 時,創建Servlet 實例:大部分的Servlet 都是這種Servlet。 Web 應用啟動時,立即創建Servlet 實例:即load-on-startup Servlet。
每個Servlet 的運行都遵循如下生命周期。
(1)創建Servlet 實例。
(2) Web 容器調用Servlet 的init 方法,對Servlet 進行初始化。
(3) Servlet 初始化后,將一直存在于容器中,用于響應客戶端請求。如果客戶端有get 請求,容器調用Servlet 的doGet 方法處理并響應請求。對于不同的請求,有不同的處理方法,或者統一使用service 方法處理來響應用戶請求。
(4) Web 容器角色銷毀Servlet 時,調用Servlet 的destroy 方法,通常在關閉Web容器之時銷毀Servlet。
使用Servlet創作為控制器
正如前面見到,使用Servlet 作為表現層的工作量太大,所有的HTML 標簽都需要使用頁面輸出流生成。因此,使用Servlet 作為表現層有如下三個劣勢。
開發效率低,所有的HTML 標簽都需使用頁面輸出流完成。
不利于團隊協作開發,美工人員無法參與Servlet 界面的開發。
程序可維護性差,即使修改一個按鈕的標題,都必須重新編輯Java 代碼,并重新編譯。
整個結構非常清晰,下面是MVC 中各個角色的對應組件。
M: Model,即模型,對應JavaBean 。
V: View ,即視圖,對應JSP 頁面。
C: Controller,即控制器,對應Servlet。
load-on-startup Servlet
Servlet 的實例化有兩個時機:用戶請求之時,或應用啟動之時。應用啟動時就啟動的Servlet 通常是用于某些后臺服務的Servlet ,或者攔截很多請求的Servlet; 這種Servlet 通常作為應用的基礎Servlet 使用,提供重要的后臺服務。如果需要Web 應用啟動時,可使用load-on-startup 元素完成Servlet 的初始化。load-on-startup 元素只接收一個整型值,這個整型值越小, Servlet 就越優先初始化。
訪問Servlet 的配置參數
配置Servlet 時,還可以增加附加的配置參數。通過使用配置參數,可以實現更好地解耦,避免將所有的參數以硬編碼方式寫在程序中。
訪問Servlet 配置參數要通過ServletConfig 類的實例完成, ServletConfig提供如下方法。
java.lang.String getInitParameter(java.lang.String name): 用于獲取初始化參數。
注意: JSP 的內直對象config 就是此處的ServletConfig
自定義標簽類
使用標簽類,可以使用簡單的標簽來封裝復雜的功能,從而使團隊更好地協作開發(能讓美工人員更好地參與JSP 頁面的開發)。
自定義標簽類都必須繼承一個父類: java.Servlet.jsp.tagext.TagSupport 。除此之外,自定義標簽類還有如下要求。
·如果標簽類包含屬性,每個屬性都有對應的getter 和setter 方法。
·重寫doStartTag或doEndTag方法,這兩個方法生成頁面內容。
·如果需要在銷毀標簽之前完成資源回收,則重寫re1ease方法。
TLD 文件
TLD 是Tag Library Definition 的縮寫,即標簽庫定義,文件的后綴是tld ,每個TLD文件對應一個標簽庫,一個標簽庫中可包含多個標簽。TLD 文件也稱為標簽庫定義文件。標簽庫定義文件的根元素是taglib,它可以有多個tag 子元素,每個tag 子元素都對應一個標簽。
編輯了標簽庫定義文件還不夠, Web 容器還無法加載標簽庫定義文件。還必須在web.xml 文件中增加標簽庫的定義。在web.xml 文件中定義標簽庫時使用taglib 元素,該元素包含兩個子元素: taglib-uri和taglib-location,前者確定標簽庫的URI; 后者確定標簽庫定義文件的位置。
使用標簽庫
使用標簽庫分成以下兩步。
(1) 導入標簽庫:使用taglib 編譯指令導入標簽。
(2) 使用標簽:在JSP 頁面中使用自定義標簽。
taglib 的語法格式如下:
〈%@ taglib uri="tagliburi" prefix="tagPrefix" %〉
其中uri 屬性確定標簽庫定義文件的URI,這個URI 就是在web.xml 文件中為標簽
庫定義的URI。而prefix 屬性確定的是標簽前綴,即在JSP 頁面中使用標簽時,該標簽
庫負責處理的標簽前綴。
使用標簽的語法格式如下:
<tagPrefix : tagName tagAttribute=ntagValue n ...>
<tagBody/>
</tagPrefix>
如果該標簽沒有標簽體,則可以使用如下語法格式:
<tagPrefix : tagName tagAttribute=ntagValue n …/>
帶標簽體的標簽
帶標簽體的標簽,就是允許在標簽內嵌套標簽,通常可用于完成一些邏輯運算例如判斷和循環等。
帶標簽體的標簽需要繼承BodyTagSupport,該類包含一個bodyContent 屬性,該屬性代表標簽體。
BodyTagSupport 還包含兩個方法。
doAfterBody: 每次處理完標簽體后調用該方法。
void doInitBody: 開始調用標簽體時調用該方法。
如果有必要,可以重寫這兩個方法。
在處理標簽類的各個方法中,不同的返回值對應不同的含義,常用的返回值有如下幾個。
SKIP_BODY: 不處理標簽體,直接調用doEndTag方法。
SKIP_PAGE: 忽略標簽后面的JSP 頁面。
EVAL_PAGE: 處理標簽結束,直接處理頁面內容。
EVAL_BODY_BUFFERED: 處理標簽體。
EVAL_BODY_INCLUDE: 處理標簽體,但忽略setBodyContent和doInitBody方法。
EVAL_BODY_AGAIN: 對標簽體循環處理。
Filter
Filter 并不是一個標準的Servlet ,它不能處理用戶請求,也不能對客戶端生成響應。主要用于對HttpServletRequest 進行預處理,也可以對HttpServletResponse 進行后處理,是個典型的處理鏈。
Filter 有如下幾個用處。
·在HttpServletRequest 到達Servlet 之前,攔截客戶的HttpServletRequest 。
·根據需要檢查HttpServletRequest ,也可以修改HttpServletRequest 頭和數據。
·在HttpServletResponse 到達客戶端之前,攔截HttpServletResponse 。
·根據需要檢查HttpServletResponse ,也可以修改HttpServletResponse 頭和數據。
Filter 有如下幾個種類。
·用戶授權的Filter: Filter 負責檢查用戶請求,根據請求過濾用戶非法請求。
·日志Filter: 詳細記錄某些特殊的用戶請求。
·負責解碼的Filter: 包括對非標準編碼的請求解碼。
.能改變XML 內容的XSLTFilter 等。
一個Filter 可負責攔截多個請求或響應:一個請求或響應也可被多個請求攔截。
創建一個Filter 只需兩個步驟:
(1)創建Filter 處理類:
(2) 在web.xml 文件中配置Filter。
創建Filter 類
創建Filter 必須實現javax.servle t. Filter 接口,在該接口中定義了三個方法。
void init(FilterConfig config): 用于完成Filter 的初始化。
void destroy: 用于Filter 銷毀前,完成某些資源的回收。
void doFilter(ServletRequest request, ServletResponse response,FilterChain chain): 實現過濾功能,該方法就是對每個請求及響應增加的額外處理。
執行chain.doFilter(request,reponse)方法,當Filter 對請求過濾后,依然將請求發送到目的地址。如果檢查權限,可以在Filter 中根據用戶請求的HttpSession,判斷用戶權限是否足夠。
如果權限不夠,則調用重定向即可,無須調用chain.doFilter(request,reponse)方法。
配置Filter
Filter 的配置和Servlet 的配置非常相似,都需要配置兩個部分:
·配置Filter 名。
·配置Filter 攔截URL 模式。
區別在于, Servlet 通常只配置一個URL ,而Filter 可以同時攔截多個請求的URL。
因此,可以配置多個Filter 攔截模式。
Listener
摘要: UML的組成Listener 的作用非常類似于load-on-startup Servlet。用于在Web 應用啟動時,啟動某些后臺程序,這些后臺程序負責為系統運行提供支持。
Listener 與load-on-startup Servlet 的區別在于: Listener 的啟動時機比load-on-startup Servlet 早,只是Listener 是Servlet 2.3 規范之后才出現的。
使用Listener 只需要兩個步驟:
(1) 創建Listener 實現類。
(2) 在web.xml 文件中配置Listener。
創建Listener 類
創建Li stener 類必須實現ServletContex tListener 接口,該接口包含兩個方法。
eontextInitialized(ServletContextEvent see): 啟動Web 應用時,系統調用該Filter的方法。
eontextDestroyed(ServletContextEvent see): 關閉Web 應用時候,系統調用Filter
的方法。
配置Listener
正如load-an-startup Servlet 一樣, Listener 用于啟動Web 應用的后臺服務程序,但不負責處理及響應用戶請求,因此無須配置URL。
若將Listener 配置在Web 容器中(如果Web 容器支持Listener),則Listener 將隨Web 應用的啟動而啟動。
配置Listener 時使用<listener/>元素,下面是配置Listener 的片段:
<!-- 配置Listener-->
<listener>
<!- 指定Listener 的實現類→
<listener-class>lee.ScheduleListener</listener-class>
</listener>
在上面的配置中,既無須配置Listener 的名字,也無須配置Listener 的URL 只需配置它的實現類即可。此時容器將自動檢測部署在容器中的Listener,并在應用啟動時,自動加載所有的Listener。
開發環境:
System:Windows
WebBrowser:IE6+、Firefox3+
JavaEE Server:tomcat5.0.2.8、tomcat6
IDE:eclipse、MyEclipse 8
Flex IDE:Flash Builder 4
BlazeDS:4.5
開發依賴庫:
JavaEE5、blazeDS 4.5
Email:hoojo_@126.com
Blog:http://blog.csdn.net/IBM_hoojo
1、 首先要提供相關的jar包
Java服務器端需要提供BlazeDS相關的配置和jar包
下載地址:http://opensource.adobe.com/wiki/display/blazeds/download+blazeds+trunk
下載后,解壓你可以看到這樣的一個目錄
Docs就是文檔
Resource是源碼
SampleDB是示例用的數據庫,可以運行startdb.bat來啟動數據庫
Tomcat是內置的tomcat,如果你沒有tomcat的話可以使用它,在tomcat的webapps目錄中有samples示例
blazeds.war就是blazeDS的核心文件、庫,你可以把這個war放到tomcat的webapps目錄下,就會自動解壓。當然你也可以自己手動解壓。
Blazeds-spring.war是和spring整合的配置
Ds-console.war是blazeDS的控制臺程序
Samples.war是官方提供的示例
Samples-spring.war是spring和blazeDS的整合示例
1、新建一個JavaWeb Project工程,然后在WEB-INF/lib目錄中添加如下jar包
這些jar包可以在blazeds.war包中的lib目錄中可以找到
2、 然后你需要將blazeds.war包中的WEB-INF目錄下的flex目錄復制到當前工程的WEB-INF下
3、 將blazeds.war包中的WEB-INF目錄下的web.xml的配置,添加到當前工程的web.xml文件中
4、 最后基本的樣式如下
5、 最后你發布當前工程,如果沒有錯誤就表明你服務器端部署成功了。
6、 編寫一個HelloWorld的java程序。代碼如下
package com.hoo.flex;
/**
* <b>function:</b> HelloWorld Example
* @author hoojo
* @createDate 2011-8-31 下午06:11:27
* @file HelloWorld.java
* @package com.hoo.flex
* @project BlazeDSServer
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public class HelloWorld {
public HelloWorld() {
}
public String sayHello(String name) {
return "[" + name + "] say hello!";
}
}
就一個sayHello方法,接收一個參數。
1、創建一個Flex工程,在選擇服務器技術的時候,你需要選擇J2EE。然后勾上使用J2EE技術,然后選擇BlazeDS。點擊Next下一步
2、配置根文件夾,也就是JavaEE服務器端發布程序在tomcat中的位置。我這里是在tomcat的webapps的BlazeDSServer中,BlazeDSServer是我的服務器端程序。根URL是訪問服務器端程序的url;上下文目錄對應工程名稱;最后就是輸出文件夾目錄,這個是Flex的文件最后在tomcat中保存的目錄。
3、最后你需要設置服務器端的services-config.xml的路徑到編譯參數中,這個很重要!如果你不設置的話,那么你在后面用RemoteObject調用BlazeDS的時候,就需要設置endpoint。設置如下:
-services是參數鍵,后面的字符串是值。我這里是設置BlazeDSServer發布到tomcat目錄中的services-config.xml的路徑。
4、編譯Flex前端代碼,代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" viewSourceURL="BlazeDSHelloWorld.mxml" layout="absolute" minWidth="955" minHeight="600">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.rpc.AsyncToken;
import mx.rpc.events.ResultEvent;
private function faultHandler(event: Event): void {
Alert.show(event.toString(), event.type);
}
private function resultHandler(event: ResultEvent): void {
//event.result是服務器端返回對象
result.text = "Message:" + event.result.toString();
}
private function sendHandler(): void {
helloRemoteObject.sayHello(userName.text);
}
]]>
</mx:Script>
<!-- 當工程沒有設置編譯器-service參數 或是-context-root等參數,就需要手動設置endpoint參數 -->
<mx:RemoteObject
id="helloRemoteObject"
destination="helloWorld"
fault="faultHandler(event)"
result="resultHandler(event)"
showBusyCursor="true"/>
<mx:Panel x="10" y="10" width="272" height="148" layout="absolute" title="BlazeDS Remote HelloWorld Sample">
<mx:Label x="10" y="22" text="請輸入名稱"/>
<mx:TextInput x="70" y="19" id="userName"/>
<mx:Button x="184" y="45" label="發送" click="sendHandler()"/>
<mx:Text x="10" y="79" id="result"/>
</mx:Panel>
</mx:Application>
首先你需要將Java服務器端的HelloWorld程序配置在flex的remoting-config.xml中,配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<service id="remoting-service"
class="flex.messaging.services.RemotingService">
<adapters>
<adapter-definition id="java-object" class="flex.messaging.services.remoting.adapters.JavaAdapter" default="true"/>
</adapters>
<default-channels>
<channel ref="my-amf"/>
</default-channels>
<destination id="helloWorld">
<properties>
<source>com.hoo.flex.HelloWorld</source>
</properties>
</destination>
</service>
上面mxml代碼中的RemoteObject的destination對應的就是remoting-config.xml配置文件中的destination的id。這個是一一對應的,然后在sendHandler方法中,helloRemoteObject對應的就是RemoteObject的id,而sayHello方法對應的就是配置在remoting-config.xml中的destination的source的Java服務器端代碼的公有方法。添加完配置后,需要重啟tomcat。
運行上面的flex程序后,如果輸入參數后,點擊發送,可以看到服務器端返回的消息就說明BlazeDS整合Flex成功了。
摘要: Dom4j也可以很方便完成XML文檔的創建、元素的修改、文檔的查詢遍歷等,但dom4j稍比jdom復雜一點,不過在大片文檔的情況下dom4j的性能要不jdom好。 # 準備 首先,提供相關的jar包 Dom4j jar包下載: http://sourceforge.net/projects/dom4j/files/dom4j-2.0.0-ALPHA-2/ jaxen jar下載: http://... 閱讀全文 摘要: 可擴展標記語言——eXtensible Markup Language 用戶可以自己定義語言標記,只要有開始和閉合標簽即可。 xsl裝飾、修飾xml的顯示結果。 dtd約束xml文件中的標記。 ? XML的優點: 1、xml可以讓數據和標記分離。 2、異質信息互通 3、機... 閱讀全文 一、數據庫設計的必要性
二、什么是數據庫設計
三、數據庫設計的重要
四、數據模型
實體-關系(E-R)數據模型
實體(Entity)
屬性(Attribute)
關系(Relationship)
五、數據庫設計步驟
1、 需求分析階段
2、 概要設計階段
3、 詳細設計階段
六、數據庫設計規范化
數據庫設計中經常出現的問題
規范設計
規范化和性能關系
Go批處理語句
使用、切換數據庫
創建、刪除數據庫
基本數據類型
精確數字類型
近似數字類型
日期時間類型
字符串類型
Unicode字符串類型
二進制字符串類型
判斷表或其他對象及列是否存在
創建、刪除表
給表添加字段、修改字段、刪除字段
添加、刪除約束
插入數據
查詢、修改、刪除數據
備份數據、表
利用存儲過程查詢表信息
變量
1、 局部變量(Local Variable)
2、 全局變量(Global Variable
輸出語句
邏輯控制語句
1、 if-else判斷語句
2、 while…continue…break循環語句
3、 case
4、 其他語句
基本常用查詢
嵌套子查詢
# from (select … table)示例
# in, not in子句查詢示例
# exists和not exists子句查詢示例
# some、any、all子句查詢示例
聚合查詢
1、 distinct去掉重復數據
2、 compute和compute by匯總查詢
3、 cube匯總
排序函數
# row_number函數
# rank函數函數
# dense_rank函數
# partition by分組子句
# ntile平均排序函數
集合運算
1、 union和union all進行并集運算
2、 intersect進行交集運算
3、 except進行減集運算
公式表表達式
連接查詢
1、 簡化連接查詢
2、 left join左連接
3、 right join右連接
4、 inner join內連接
5、 cross join交叉連接
6、 自連接(同一張表進行連接查詢)
函數
1、 聚合函數
2、 日期時間函數
3、 數學函數
4、 元數據
5、 字符串函數
6、 安全函數
7、 系統函數
8、 配置函數
9、 系統統計函數
10、 用戶自定義函數
索引
1、 什么是索引
2、 索引分類
3、 創建索引
4、 適合的創建索引的列
5、 不適合創建索引的列
視圖
1、 什么是視圖
2、 創建視圖準則
3、 創建視圖
4、 修改視圖
5、 加密視圖
存儲過程的概念
1、 存儲過程的優點
A、 存儲過程允許標準組件式編程
B、 存儲過程能夠實現較快的執行速度
C、 存儲過程減輕網絡流量
D、 存儲過程可被作為一種安全機制來充分利用
系統存儲過程
用戶自定義存儲過程
1、 創建語法
2、 創建不帶參數存儲過程
3、 修改存儲過程
4、 帶參存儲過程
5、 帶通配符參數存儲過程
6、 帶輸出參數存儲過程
7、 不緩存存儲過程
8、 加密存儲過程
9、 帶游標參數存儲過程
10、 分頁存儲過程
Raiserror
事務
什么是觸發器
DML觸發器分為:
1、 after觸發器(之后觸發)
a、 insert觸發器
b、 update觸發器
c、 delete觸發器
2、 instead of 觸發器 (之前觸發)
創建觸發器
# 創建insert類型觸發器
# 創建delete類型觸發器
# 創建update類型觸發器
# update更新列級觸發器
# instead of類型觸發器
# 創建instead of觸發器
# 顯示自定義消息raiserror
# 修改觸發器
# 啟用、禁用觸發器
# 查詢創建的觸發器信息
# 示例,驗證插入數據
# 示例,操作日志