三、Global.asa
ASP的application和session對象體現了其他ASP內置對象所沒有的特征--事件。每一個訪客訪問服務器時都會觸發一個OnStart事件(第一個訪客會同時觸發Application和Session的OnStart事件,但Application先於Session),每個訪客的會話結束時都會觸發一個OnEnd事件(最後一個訪客會話結束時會同時觸發Application和Session的OnEnd事件,但Session先於Application)。
OnStart和OnEnd這兩個事件一般應用在虛擬社區中統計在線人數、修改用戶的在線離線狀態等。要具體定義這兩個事件,需要將代碼寫在Global.asa文件,並將該文件放在站點的根目錄下(缺省是\Inetpub\wwwroot\)。另外,Application和Session對象規定了在OnEnd事件裡除了Application對象外其他ASP內置對象(Response、Request、Server、Session...)一概不能使用。以下舉一個虛擬社區統計在線人數的例子來說明如何使用這兩個事件。
文件說明:
global.asa 位於d:\Inetpub\wwwroot\目錄下
default.ASP 位於d:\Inetpub\wwwroot\目錄下,虛擬社區登錄頁面
login.ASP 位於d:\Inetpub\wwwroot\目錄下,用於檢測用戶輸入的用戶名及密碼
index.ASP 位於d:\Inetpub\wwwroot\目錄下,虛擬社區首頁
bbs.mdb 位於d:\Inetpub\wwwroot\目錄下,存儲用戶信息的數據庫
數據庫(Access)結構:
===bbs表===
id 用戶ID,長整型
name 用戶名,文本型
code 密碼,文本型
online 在線狀態,是/否
===global.asa===
<script LANGUAGE="VBScript" RUNAT="Server">
Sub Application_OnStart
application("online")=0
End Sub
sub Application_OnEnd
nd Sub
Sub Session_OnStart
End Sub
Sub Session_OnEnd
if session.contents("pass") then '判斷是否為登錄用戶的Session_OnEnd
application.lock
application("online")=application("online")-1
application.unlock
end if
End Sub
</script>
==============
===login.ASP===
......'密碼驗證,連接數據庫,檢測用戶輸入的用戶名及密碼是否正確
if 密碼驗證通過 then
session("name")=rs("name")
session("id")=rs("id")
session("pass")=true
else
rs.close
conn.close
response.write "密碼錯誤!"
response.end
end if
application.lock
application("online")=application("online")+1
conn.Execute ("update bbs set online=1 where id="&session("id"))'將用戶的狀態設為在線
application.unlock
rs.close
conn.close
response.redirect "index.ASP" '初始化數據後跳轉到社區首頁
===========
在本例中,用application("online")變量記錄已經登錄社區的在線人數,因為一旦有用戶訪問服務器而不管用戶是否登錄,都會產生OnStart事件,所以不能在OnStart事件裡使Applicaiton("online")加一。因為不管是否是登錄用戶的會話結束都會產生OnEnd事件(假如有訪客訪問了服務器但並不登錄社區,他的會話結束後也會產生OnEnd事件),所以在Session_OnEnd事件裡用了句if語句來判斷是否為已登錄用戶的OnEnd事件,如果是才將在線人數減一。
這只是一個統計在線人數的簡單例子,對於一個完整的虛擬社區來說,僅僅統計有多少人在線是不夠的,在本例中數據庫裡有個online字段是用來記錄用戶的在線狀態,用戶登錄的時候,在login.ASP裡將online設為1,但用戶離線時並沒有將online設為0,要完善它,就要修改一下Session_OnEnd事件,在該事件裡將online設為0。
===global.sas===
<script LANGUAGE="VBScript" RUNAT="Server">
Sub Application_OnStart
application("online")=0
set application("conn")=Server.CreateObject("ADODB.Connection")
application("db")=Server.MapPath("\bbs.mdb") '此處最好使用絕對路徑\bbs.mdb,下文有詳細介紹
End Sub
sub Application_OnEnd
set application("conn")=nothing
End Sub
Sub Session_OnStart
End Sub
Sub Session_OnEnd
if session.contents("pass") then '判斷是否為登錄用戶的Session_OnEnd
application("con").open ="driver={Microsoft Access Driver (*.mdb)};dbq="&application("db")
application.lock
application("online")=application("online")-1
application("con").Execute ("update frIEnds set online=0 where id="&session.contents("id"))
application.unlock
application("con").close
end if
End Sub
</script>
==============
至此,完整的代碼已經完成了。因為在Application和Session的OnEnd事件裡不能使用Server對象,所以要將數據庫的連接及數據庫在服務器上的物理地址(d:\inetpub\wwwroot\bbs.mdb)存儲在application變量中,並在Application_OnStart事件中預先處理。同理,在Session_OnEnd事件中不能用session("pass")來代替session.contents("pass")(以下有詳盡說明)。
四、本文實例中值得引起注意的兩點
⒈OnEnd事件裡的session.contents
剛開始接觸global.asa的朋友經常會將上面Session_OnEnd事件裡的
if session.contents("pass") then 寫成
if session("pass") then,
這樣的話系統不會提示錯誤,但是永遠也不會執行then後面的內容,這是因為在OnEnd事件裡禁止使用Session對象,但是可以用Session對象的集合來調用session變量。因為IIS並沒提示任何錯誤信息,所以筆者曾經在這上面浪費了很多時間。在此希望大家引以為鑒!
⒉Application_OnStart事件裡用Server.MapPath獲取數據庫的物理地址時應使用絕對地址為了說明這個問題,大家可以做個實驗:將上面Application_OnStart事件裡的
application("db")=Server.MapPath("\bbs.mdb")改為:
application("db")=Server.MapPath("bbs.mdb")
然後在d:\inetpub\wwwroot\目錄下建立一個test子目錄,寫一個temp.ASP在test目錄裡。
====test.ASP====
<%response.write application("db")%>
================
再將temp.asp拷貝一份放在根目錄下(d:\inetpub\wwwroot\)。用記事本打開global.asa,再打開兩個浏覽器,浏覽器A輸入地址http://localhost/temp.ASP,按回車,將在浏覽器上輸出:
d:\inetpub\wwwroot\bbs.mdb
然後,在記事本的窗口上點"文件"菜單,選"保存"(使global.asa的修改時間改變,從而使IIS重啟動所有服務),再在浏覽器B輸入地址http://localhost/test/temp.ASP,按回車,在浏覽器上輸出的是:
d:\inetpub\wwwroot\test\bbs.mdb
global.asa文件雖然是放在站點根目錄下,但是如果在server.mappath中使用的是相對地址,而觸發Application_OnStart事件的用戶第一次訪問的頁面又不是屬於根目錄的話,得到數據庫的物理地址將不會是期望的結果,希望大家要特別小心。