表單中用戶名和密碼兩組件的數(shù)據(jù)將通過HTTP請(qǐng)求傳給服務(wù)器的switch.jsp,服務(wù)器將這些信息封裝在request對(duì)象中傳給switch.jsp,所以switch.jsp可通過request.getParameter(String paraName)來獲取這兩個(gè)值。
復(fù)制代碼 代碼如下:
String userId = request.getParameter("userId");
String password = request.getParameter("password");
試想如果login.jsp的表單有10個(gè)以上的數(shù)據(jù)組件,則在switch.jsp中必須通過相應(yīng)數(shù)目的request.getParameter()方法獲取其值。此外,如果這些數(shù)據(jù)不是字段串類型,而是整數(shù)或浮點(diǎn)數(shù),由于request.getParameter()方法返回的值都是String,還必須進(jìn)行類型的轉(zhuǎn)換,這種工作不但單調(diào)乏味,還容易出錯(cuò)。
JSP允許你通過Bean以映射的方式接收網(wǎng)頁(yè)表單的數(shù)據(jù),Bean以這個(gè)規(guī)則映射表單的數(shù)據(jù):Bean屬性名=表單數(shù)據(jù)組件名,也即所有和Bean屬性名相同的表單數(shù)據(jù)域被自動(dòng)填充到Bean中,并且完成數(shù)據(jù)類型的轉(zhuǎn)換。如login.jsp的表單中有兩個(gè)數(shù)據(jù)組件,一個(gè)名為userId,另一個(gè)是password,定義一個(gè)擁有相同名的userId和password屬性的User.java Bean,這個(gè)Bean將可以自動(dòng)接收表單中的兩個(gè)數(shù)據(jù)組件值。
編寫User.java
我們先來編寫這個(gè)User.java的Bean,在工程中創(chuàng)建User.java,其代碼如下所示:
代碼清單 7 User.java
復(fù)制代碼 代碼如下:
package bookstore;
public class User
{
private String userId;//用戶Id
private String password;//密碼
private String userName;//用戶名
public String getPassword() {
return password;
}
public String getUserId() {
return userId;
}
public String getUserName() {
return userName;
}
public void setPassword(String password) {
this.password = password;
}
public void setUserId(String userId) {
this.userId = userId;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
除userId和password兩屬性名,還有一個(gè)用戶名屬性u(píng)serName,這個(gè)屬性的值不是從login.jsp的表單接收的,當(dāng)用戶名密碼驗(yàn)證正確后,從數(shù)據(jù)表T_USER表中獲取用戶名保存在這個(gè)屬性中,以便其他地方引用,保存并編譯這個(gè)類。
提示:
你可以通過JBuilder的Bean Express工具快速創(chuàng)建User.java的代碼,在一般情況下,你應(yīng)該通過Bean Express來創(chuàng)建Bean的屬性,這樣不但自動(dòng)產(chǎn)生get/set的屬性訪問方法,還保證了Bean命名規(guī)范。
編寫頁(yè)面程序
在創(chuàng)建User.java 的Bean后,我們著手創(chuàng)建switch.jsp,在switch.jsp中引用這個(gè)Bean。
通過File->New..->W(wǎng)eb->雙擊JSP圖標(biāo)啟動(dòng)創(chuàng)建JSP向?qū)А?
1.指定swith.jsp名字
圖 10 指定switch.jsp的名字
一直按Next到向?qū)У牡?步。
2.引用User.java Bean
圖 11 指定JSP中引用Bean
點(diǎn)擊Add Bean...按鈕,彈出Select a Class對(duì)話框,在對(duì)話框中選擇bookstore.User類,如下圖所示:
圖 12 選擇類作為Bean
按OK后,返回到向?qū)У?步的對(duì)話框,此時(shí)對(duì)話框的Bean列表中多了一行記錄,可以在ID欄中為Bean指定一個(gè)名字,在Scope中指定Bean的作用域,如下圖所示:
圖 13 引用一個(gè)Bean
我們?yōu)閁ser的Bean取名為userBean,將其作用域設(shè)置為page域。page域即為頁(yè)面作用域,在當(dāng)前頁(yè)面范圍作用域內(nèi)可用,當(dāng)JSP返回響應(yīng),或請(qǐng)求轉(zhuǎn)到其他的JSP頁(yè)面中時(shí),都不可用了,其他3個(gè)作用域說明如下:
·request作用域:當(dāng)一個(gè)請(qǐng)求產(chǎn)生直到返回響應(yīng)的范圍內(nèi)都是有效的,如a.jsp中聲明為request作用域的Bean,當(dāng)a.jsp通過<jsp:forward>轉(zhuǎn)移請(qǐng)求到b .jsp頁(yè)面中時(shí)還是可用的。
·session作用域:在用戶會(huì)話的周期內(nèi)都是可用的,會(huì)話周期為用戶登錄系統(tǒng)直到其退出系統(tǒng)為此。
·application作用域:這個(gè)作用域最長(zhǎng),表示W(wǎng)eb容器啟動(dòng)直到關(guān)閉都是有效的。
按Next到下一步。
3.設(shè)置運(yùn)行配置項(xiàng)
在向?qū)У淖詈笠徊?,你可以為?chuàng)建的JSP產(chǎn)生一個(gè)運(yùn)行配置項(xiàng),雖然向?qū)?chuàng)建一個(gè)運(yùn)行配置項(xiàng)設(shè)置為默認(rèn)選項(xiàng),但筆者認(rèn)為這并不是一個(gè)合理的默認(rèn)值,建議取消create a runtime configuration設(shè)置項(xiàng),不要?jiǎng)?chuàng)建JSP的運(yùn)行配置項(xiàng),如下圖所示:
按Finish按鈕創(chuàng)建switch.jsp文件,其代碼如下所示:
代碼清單 8 向?qū)?chuàng)建的switch.jsp
復(fù)制代碼 代碼如下:
%@ page contentType="text/html; charset=GBK" %>
html>
head>
title>
switch
/title>
/head>
jsp:useBean id="userBean" scope="page" class="bookstore.User" />
jsp:setProperty name="userBean" property="*" />
body bgcolor="#ffffff">
h1>
JBuilder Generated JSP
/h1>
/body>
/html>
第8行是引用Bean的JSP標(biāo)簽,第9行用表單的數(shù)據(jù)填充Bean的屬性值,即以名字匹配的方式將request的參數(shù)填充到Bean的屬性中,同時(shí)完成類型轉(zhuǎn)換(只有基本數(shù)據(jù)類型或構(gòu)造函數(shù)支持的才可以完成轉(zhuǎn)換)。在執(zhí)行完第9行后,userBean中的userId和password屬性將被設(shè)置為login.jsp頁(yè)面中所發(fā)送過來的用戶名和密碼的值。
因?yàn)閟witch.jsp只是用于控制,并不需要顯示內(nèi)容到客戶端,所以我們?nèi)コ齭witch.jsp中的HTML代碼,將switch.jsp調(diào)整為:
代碼清單 9 去除靜態(tài)HTML代碼后的switch.jsp
復(fù)制代碼 代碼如下:
%@ page contentType="text/html; charset=GBK" %>
jsp:useBean id="userBean" scope="page" class="bookstore.User" />
jsp:setProperty name="userBean" property="*" />
在switch.jsp中提供一段Scriptlet,將userId和password發(fā)送到數(shù)據(jù)庫(kù)和T_USER表中的用戶比較看是否是合法的用戶,根據(jù)驗(yàn)證的結(jié)果轉(zhuǎn)向不同的頁(yè)面。switch.jsp的最終代碼如下所示:
代碼清單 10 最終的switch.jsp
復(fù)制代碼 代碼如下:
%@page contentType="text/html; charset=GBK"%>
%@page import="bookstore.*"%>
%@page import="java.sql.*"%>
jsp:useBean id="userBean" scope="session" class="bookstore.User"/>
jsp:setProperty name="userBean" property="*"/>
%
Connection conn = null;
try {
conn = DBConnection.getConnection();
PreparedStatement pStat = conn.prepareStatement(
"select USER_NAME from T_USER where USER_ID=? and password = ?");
pStat.setString(1, userBean.getUserId());
pStat.setString(2, userBean.getPassword());
ResultSet rs = pStat.executeQuery();
if (rs.next()) { //密碼正確
userBean.setUserName(rs.getString(1));//設(shè)置用戶名
session.setAttribute("ses_userBean", userBean);//將userBean放入Session對(duì)象中
%>jsp:forward page=" welcome.jsp ">/jsp:forward>
%} else { //密碼錯(cuò)誤%>
jsp:forward page="fail.jsp">/jsp:forward>
%
}} finally {
if(conn != null) conn.close();
}
%>
·在第2~3行中引入Scriptlet代碼中需要的類。
·第7~14行代碼向數(shù)據(jù)庫(kù)發(fā)送查詢SQL語(yǔ)句并返回結(jié)果。
·第15行通過檢查結(jié)果集的記錄數(shù)間接判斷用戶密碼是否正確。
·第16~18行是用戶密碼正確的響應(yīng)代碼,首先用結(jié)果集的USER_NAME屬性填充userBean的userName屬性值,然后將userBean對(duì)象放入Session中,最后轉(zhuǎn)向welcome.jsp頁(yè)面。
·當(dāng)用戶輸入密碼不正確時(shí),結(jié)果集中將沒有記錄,此時(shí)rs.next()返回false,程序轉(zhuǎn)向第20行,第20行的代碼將頁(yè)面轉(zhuǎn)向到密碼輸入錯(cuò)誤的處理頁(yè)面fail.jsp。
·第22~24行的代碼用于關(guān)閉數(shù)據(jù)庫(kù)的連接。
也許大家已經(jīng)發(fā)現(xiàn)雖然第9~21行會(huì)拋出SQLException異常,但我們并沒有相應(yīng)的異常捕獲塊,在標(biāo)準(zhǔn)的Java程序中將導(dǎo)致一個(gè)編譯期的錯(cuò)誤,但在JSP中卻可以順序通過編譯,這是因?yàn)镴SP頁(yè)面本身會(huì)捕獲頁(yè)面中拋出的所有異常。
假設(shè)第11行的SQL查詢語(yǔ)句發(fā)生有錯(cuò)誤,如將用戶表名誤寫為User(正確為T_USER),當(dāng)switch.jsp被調(diào)用后,第14行將拋出SQLException異常,此時(shí)switch.jsp將顯示出異常堆棧跡的跟蹤信息頁(yè)面,如下圖如示:
圖 14 可怕的錯(cuò)誤處理頁(yè)面
上圖所示的錯(cuò)誤處理頁(yè)面可謂青面獠牙,面目猙獰,非常不友好,對(duì)于開發(fā)人員來說這種報(bào)錯(cuò)頁(yè)面也許是適合的,因?yàn)樗峁┝嗽S多錯(cuò)誤跟蹤信息,但最終用戶是不可能接受這種粗野的出錯(cuò)頁(yè)面的。JSP允許你通過<%@ page errorPage%>為頁(yè)面指定一個(gè)專門處理錯(cuò)誤的JSP頁(yè)面,以便用一種友好、直觀的形式展現(xiàn)錯(cuò)誤。在下一節(jié)里,我們將創(chuàng)建一個(gè)用于處理錯(cuò)誤的JSP頁(yè)面,在創(chuàng)建之后,我們?cè)賮頌閟witch.jsp指定錯(cuò)誤處理JSP頁(yè)面。