深入jsp:useBean
avaBean在JSP中的應用給我們帶來了很大的方便,使得我們能夠把功能較單純的代碼提取出來,增加了代碼重用率。$#@60;jsp:useBean /$#@62;這個命令大家在每個JSP文件的開頭一般都會用吧?下文將要介紹的是useBean命令的一些特殊用法,包括怎樣為多個頁面共享的bean進行初始化,以及怎樣簡便的把request的數據傳遞到bean中去。
大家都知道bean有一個scope屬性,指明bean的類型的實例建立的位置。默認的page就表示放在PageContext對象中,可以在本頁面內部使用;request表示放在ServletRequest對象中,在當前request的處理期間都能夠訪問,這個其實和page差不多;session表示放在HttpSession對象中,只要當前頁面的page.session設置為true就能夠訪問;application表示放在ServletContext對象中,當前服務器上面屬于一個application的servlet都能訪問。使用不同的scope屬性值就能在不同的范圍內共享bean內部的數據,但是當想為bean作一些初始化工作的時候,如果不能確定哪一個頁面先運行怎么辦?
解決的方法是有的。除了常見的$#@60;jsp:useBean ... /$#@62;這種創建bean的格式以外,還有下面這種方式:
$#@60;jsp:useBean ...$#@62;代碼$#@60;/jsp:useBean$#@62;中間的代碼就可以用來進行初始化工作,因為這些代碼只在一個bean創建的時候執行。新創建一個bean的條件是,在一個application的范圍內,沒有id和scope都相同的bean存在。所以,如果你有許多頁面上使用同一個bean,又想在初始化的時候設置一些bean的property,你可以把初始化代碼放在每一個申明中,然后系統運行的時候只有第一個被執行的頁面能夠執行到這些初始化代碼。
舉個例子,你有一個網站有許多的入口頁面,現在你想跟蹤一個用戶在你的網站上逗留的時間,你可以用一個scope為session的bean來記錄用戶首次訪問的時間,在他離開的時候把總時間存到用戶數據庫里面。這里只看看怎樣記錄首次訪問時間。
我們的bean中的關鍵部分是這個樣子:
/** a bean to record user browsing time
* log-in time set by the first page visited
*/
package myapp;
public class TimeRecordBean {
private long loginTime;
private long logoutTime;
...
public void setLoginTime(long time) {
this.loginTime = time;
}
...}//end of bean class然后,在所有可能的入口頁面 娑脊燦謎廡┐耄?br>$#@60;html$#@62;$#@60;body$#@62;$#@60;%@ page import=“java.util.*”%$#@62;$#@60;%@ page session=”true”%$#@62;$#@60;% ...long visitTime = Date.getTime();...
%$#@62;$#@60;jsp:useBean id=”timerec”class=”myapp.TimeRecordBean”
scope=”session”$#@62;$#@60;jsp:setProperty name=”timerec”
property=”longinTime”
value=”$#@60;%= visitTime%$#@62;”/$#@62;$#@60;/jsp:useBean$#@62;...$#@60;/body$#@62;$#@60;/html$#@62;現在,不論用戶從哪一個頁面進入你的網站,你都會得到進入的時間。再加上對用戶id的記錄和用戶退出時的檢測就能實現你的統計了。
下面要討論的問題是怎樣方便的把request中的數據存放到bean中去。在許多web應用當中,把用戶在html表單里面填寫的數據送給一個bean去處理是非常常見的,因為在bean里面能夠方便的進行各種復雜的邏輯處理,如果直接在jsp頁面中寫scriptlet就顯得太臃腫了,而且不利于調試。但是,request.getParameter()方法返回的是String類型,對數據進行轉換比較麻煩。如果你要存放數據本來就是一個String類型,那還好說:
$#@60;jsp:useBean id=”store”class=”some.class”/$#@62;$#@60;jsp:setProperty name=”store”
property=”userName”
value=”$#@60;%= request.getParameter(“UserName”)%$#@62;”/$#@62;如果是int類型,你就要寫成這樣:
$#@60;jsp:useBean id=”store”class=”some.class”/$#@62;$#@60;%
int userAge = 0;
try {
userAge =
Interger.parseInt(request.getParameter(“UserAge”));
}
catch (NumberFormatException ex) {
userAge = AGE_UNKNOWN;
}%$#@62;$#@60;jsp:setProperty name=”store”
property=”userAge”
value=”$#@60;%= userAge%$#@62;”/$#@62;要是你的表單里面有大量的int,double之類的變量,像這樣編碼就顯得非常繁瑣。好在jsp提供了專門解決這一問題的方法:屬性自動關聯。這個功能可以把一個特定的request里面的參數與bean中的屬性建立關聯,它的方便之處主要在于不需要手工進行參數類型轉換,而是由系統自動的根據bean的屬性的定義進行類型轉換。
自動關聯的使用方法也很簡單,把普通的jsp:setProperty命令的value參數改成param參數就行了,比如上面的userAge的例子就可以簡寫為:
$#@60;jsp:setProperty name=”store”
property=”userAge”
param=”UserAge”/$#@62;兩相比較,現在是不是簡便多了?
系統提供的自動類型轉換只能作用于簡單類型,下面是針對不同的屬性類型所進行的轉換的列表:
需要注意的是,這些轉換并不考慮輸入中包含有非法字符的情況,也就是說照樣有可能產生NumberFormatException。你可以加強客戶端的數據校驗,或者利用errorPage進行錯誤處理。另外一種特殊情況是request中根本沒有你指定的參數,這個時候自動關聯功能不會像getParameter方法得到null一樣把null送入bean中,而是不進行任何操作。于是無法及時將輸入不完整的信息反饋給服務器,你最好在bean里面給屬性都賦予默認值,并且在最后的數據處理階段做出判斷。總之,數據校驗的工作并不會因此變得輕松。
自動關聯的形式還有一種,全關聯。全關聯讓你能夠只用一行代碼就完成全部變量的關聯,沒有比這更簡便的了:
$#@60;jsp:setProperty name=”store”property=”*”/$#@62;現在不用指定具體的property和param也可以進行關聯,服務器自動在名稱相同的request參數和bean屬性之間建立關聯。需要注意,所有的屬性都將參加關聯,如果你的某個屬性不是簡單類型的變量,就會出現錯誤。另外,參數和屬性的名稱必須完全一樣,包括字母的大小寫形式。
最后提請大家注意,如果使用JSWDK或者JWS 2.0作為服務器,在目標參數是double類型的情況下會出現頁面編譯錯誤。
大家都知道bean有一個scope屬性,指明bean的類型的實例建立的位置。默認的page就表示放在PageContext對象中,可以在本頁面內部使用;request表示放在ServletRequest對象中,在當前request的處理期間都能夠訪問,這個其實和page差不多;session表示放在HttpSession對象中,只要當前頁面的page.session設置為true就能夠訪問;application表示放在ServletContext對象中,當前服務器上面屬于一個application的servlet都能訪問。使用不同的scope屬性值就能在不同的范圍內共享bean內部的數據,但是當想為bean作一些初始化工作的時候,如果不能確定哪一個頁面先運行怎么辦?
解決的方法是有的。除了常見的$#@60;jsp:useBean ... /$#@62;這種創建bean的格式以外,還有下面這種方式:
$#@60;jsp:useBean ...$#@62;代碼$#@60;/jsp:useBean$#@62;中間的代碼就可以用來進行初始化工作,因為這些代碼只在一個bean創建的時候執行。新創建一個bean的條件是,在一個application的范圍內,沒有id和scope都相同的bean存在。所以,如果你有許多頁面上使用同一個bean,又想在初始化的時候設置一些bean的property,你可以把初始化代碼放在每一個申明中,然后系統運行的時候只有第一個被執行的頁面能夠執行到這些初始化代碼。
舉個例子,你有一個網站有許多的入口頁面,現在你想跟蹤一個用戶在你的網站上逗留的時間,你可以用一個scope為session的bean來記錄用戶首次訪問的時間,在他離開的時候把總時間存到用戶數據庫里面。這里只看看怎樣記錄首次訪問時間。
我們的bean中的關鍵部分是這個樣子:
/** a bean to record user browsing time
* log-in time set by the first page visited
*/
package myapp;
public class TimeRecordBean {
private long loginTime;
private long logoutTime;
...
public void setLoginTime(long time) {
this.loginTime = time;
}
...}//end of bean class然后,在所有可能的入口頁面 娑脊燦謎廡┐耄?br>$#@60;html$#@62;$#@60;body$#@62;$#@60;%@ page import=“java.util.*”%$#@62;$#@60;%@ page session=”true”%$#@62;$#@60;% ...long visitTime = Date.getTime();...
%$#@62;$#@60;jsp:useBean id=”timerec”class=”myapp.TimeRecordBean”
scope=”session”$#@62;$#@60;jsp:setProperty name=”timerec”
property=”longinTime”
value=”$#@60;%= visitTime%$#@62;”/$#@62;$#@60;/jsp:useBean$#@62;...$#@60;/body$#@62;$#@60;/html$#@62;現在,不論用戶從哪一個頁面進入你的網站,你都會得到進入的時間。再加上對用戶id的記錄和用戶退出時的檢測就能實現你的統計了。
下面要討論的問題是怎樣方便的把request中的數據存放到bean中去。在許多web應用當中,把用戶在html表單里面填寫的數據送給一個bean去處理是非常常見的,因為在bean里面能夠方便的進行各種復雜的邏輯處理,如果直接在jsp頁面中寫scriptlet就顯得太臃腫了,而且不利于調試。但是,request.getParameter()方法返回的是String類型,對數據進行轉換比較麻煩。如果你要存放數據本來就是一個String類型,那還好說:
$#@60;jsp:useBean id=”store”class=”some.class”/$#@62;$#@60;jsp:setProperty name=”store”
property=”userName”
value=”$#@60;%= request.getParameter(“UserName”)%$#@62;”/$#@62;如果是int類型,你就要寫成這樣:
$#@60;jsp:useBean id=”store”class=”some.class”/$#@62;$#@60;%
int userAge = 0;
try {
userAge =
Interger.parseInt(request.getParameter(“UserAge”));
}
catch (NumberFormatException ex) {
userAge = AGE_UNKNOWN;
}%$#@62;$#@60;jsp:setProperty name=”store”
property=”userAge”
value=”$#@60;%= userAge%$#@62;”/$#@62;要是你的表單里面有大量的int,double之類的變量,像這樣編碼就顯得非常繁瑣。好在jsp提供了專門解決這一問題的方法:屬性自動關聯。這個功能可以把一個特定的request里面的參數與bean中的屬性建立關聯,它的方便之處主要在于不需要手工進行參數類型轉換,而是由系統自動的根據bean的屬性的定義進行類型轉換。
自動關聯的使用方法也很簡單,把普通的jsp:setProperty命令的value參數改成param參數就行了,比如上面的userAge的例子就可以簡寫為:
$#@60;jsp:setProperty name=”store”
property=”userAge”
param=”UserAge”/$#@62;兩相比較,現在是不是簡便多了?
系統提供的自動類型轉換只能作用于簡單類型,下面是針對不同的屬性類型所進行的轉換的列表:
屬性類型 | 轉換方法 |
boolean | Boolean.valueOf(param).booleanValue() |
Boolean | Boolean.valueOf(param) |
byte | Byte.valueOf(param).byteValue() |
Byte | Byte.valueOf(param) |
char | Chatacter.valueOf(param).charValue() |
Character | Chatacter.valueOf(param) |
double | Double.valueOf(param).doubleValue() |
Double | Double.valueOf(param) |
int | Integer.valueOf(param).intValue() |
Integer | Integer.valueOf(param) |
float | Float.valueOf(param).floatValue() |
Float | Float.valueOf(param) |
long | Long.valueOf(param).longValue() |
Long | Long.valueOf(param) |
需要注意的是,這些轉換并不考慮輸入中包含有非法字符的情況,也就是說照樣有可能產生NumberFormatException。你可以加強客戶端的數據校驗,或者利用errorPage進行錯誤處理。另外一種特殊情況是request中根本沒有你指定的參數,這個時候自動關聯功能不會像getParameter方法得到null一樣把null送入bean中,而是不進行任何操作。于是無法及時將輸入不完整的信息反饋給服務器,你最好在bean里面給屬性都賦予默認值,并且在最后的數據處理階段做出判斷。總之,數據校驗的工作并不會因此變得輕松。
自動關聯的形式還有一種,全關聯。全關聯讓你能夠只用一行代碼就完成全部變量的關聯,沒有比這更簡便的了:
$#@60;jsp:setProperty name=”store”property=”*”/$#@62;現在不用指定具體的property和param也可以進行關聯,服務器自動在名稱相同的request參數和bean屬性之間建立關聯。需要注意,所有的屬性都將參加關聯,如果你的某個屬性不是簡單類型的變量,就會出現錯誤。另外,參數和屬性的名稱必須完全一樣,包括字母的大小寫形式。
最后提請大家注意,如果使用JSWDK或者JWS 2.0作為服務器,在目標參數是double類型的情況下會出現頁面編譯錯誤。