1. 程式人生 > >如何實現asp三層架構

如何實現asp三層架構

三、如何開發三層結構的ASP應用程式  
ASP具有良好的擴充性,我們訪問資料庫時,採用的時ADO物件,訪問檔案時,採用的是檔案系統物件(FSO),其實這時程式已經是三層結構的應用程式了,只不過由於是利用內建的物件而為意識到罷了。這些物件都遵循COM/ActiveX介面,因此我們自己開發的物件也要遵循這個介面。下面,我們就以上文提到的"合格"標準為例,演示如何建立自己的三層結構的ASP應用。  
1、在資料庫系統中建立如下資料庫表:  
    Employee: EMPLID char (5) not null,  
             Name  char (10) not null,  
             Gender char (1) not null,  
             Score   int not null  
此表儲存員工資訊和考試成績,為簡單起見,這裡只包含工號,姓名和性別三項,並且只有一門考試,EMPLID為主鍵。  

2、建立動態連結庫  

啟動VB(這裡以VB為例,你可以用你喜歡的任何支援ActiveX介面的開發工具開發),新建一工程,工程型別為ActiveX DLL。在工程中新建一個類,取名為Employee。你可以Class Builder視覺化的向類中填加屬性和方法,也可以直接手工編輯。首先填加EMPLID屬性如下:  
  Private msEMPLID as string  
  Property Let EMPLID(sEMPLID as string)  
   msEMPLID=sEMPLID  
  End Property  
  Property Get EMPLID() as string  
   EMPLID=msEMPLID  
  End Property  
一般地講,每一個屬性都應該有Property Let和Property Get兩個方法,它們分別當向屬性賦值和讀取屬性值時被呼叫。如果某個屬性只被賦值而從不被讀取(這種情況多發生在對應資料庫表的主鍵的屬性上),則Property Get方法可以省略。Property Let方法不能省略。你可以仿照上面的程式再建立Name,Gender和Score三個屬性。然後建立如下方法:  
  Public Sub Create(EMPLID as string)  
  dim conn as new Connection  
  dim rs as new Recordset  
  dim sql as string  
  'Suppose that you create a DSN in the control panel, the connectionstring property  
  'can also be dsn-less string  
  conn.ConnectionString="dsn=dsnname;uid=username;password=pwd"  
  conn.open  
  sql="select * from Employee where EMPLID='" & EMPLID & "'"  
  with rs  
   .open sql,conn,1,3  
   if .eof and .bof then  
     exit sub  
   else  
     msEMPLID=trim(.Fields("EMPLID"))  
     msName=trim(.Fields("Name"))  
     msGender=trim(.Fields("Gender"))  
     msScore=.Fields("Score")  
   end if  
   .close  
  end with  
  set rs=nothing  
  conn.close  
  set conn=nothing  
  End Sub  
這裡根據EMPLID建立Employee物件,注意資料庫中的值是賦給三個私有變數,而不是直接賦值給屬性,如果你單步除錯就會發現,給msEMPLID賦值會呼叫Property Let EMPLID,也就是給屬性賦值。  
  下面我們再建立一個類Employees,並填加如下方法:  
  private colQualifiedList as new Collection  
  private mnCurrentIndex as integer  
  Public Sub GetQualifiedList()  
  dim conn as new Connection  
  dim rs as new Recordset  
  dim sql as string  
  'Suppose that you create a DSN in the control panel, the connectionstring property  
  'can also be dsn-less string  
  conn.ConnectionString="dsn=dsnname;uid=username;password=pwd"  
  conn.open  
  sql="select EMPLID from Employee where Score>=60 order by Score desc"  
  with rs  
   .open sql,conn,1,3  
   if .eof and .bof then  
     exit sub  
   else  
     do while not .eof  
       dim oEmployee as new Employee  
       oEmployee.Create trim(.Fields("EMPLID"))  
       colQualifiedList.Add oEmployee  
       set oEmployee=nothing  
     loop  
   end if  
   .close  
  end with  
  set rs=nothing  
  conn.close  
  set conn=nothing  
  End Sub  
首先請注意VB中建立類例項的語法dim oEmployee as new Employee,後面會看到,在ASP中建立類例項的語法是不同的。這個方法檢索成績大於等於60的員工工號,並據此建立一個Employee物件,再將此物件加入私有的集合物件中。下面兩個函式遍歷集合中的元素:  
  Public Function GetFirst() as Employee  
   if colQualifiedList.count>0 then  
    mnCurrentIndex=1  
     set GetFirst=colQualifiedList.Item(1)  
   else  
     set GetFirst=nothing  
   end if  
  End Function  
  Public Function GetNext() as Employee  
   mnCurrentIndex=mnCurrentIndex+1  
   if mnCurrentIndex>colQualifiedList.count then  
     set GetNext=nothing  
   else  
     set GetNext=colQualifiedList.Item(mnCurrentIndex)  
   End if  
  End Function  
也許你會說,為何不把集合宣告Public,這樣在ASP中不是可以直接引用嗎?確實,這樣也行得通,程式設計實現起來也更簡單些,但是,這樣做破壞了封裝性原則。因為資料以何格式儲存完全是商業邏輯層的事,與使用者介面層無關,假設有一天你因為每種原因放棄了用集合來儲存資料的設計,而改用陣列或記錄集(Recordset)來儲存,那你只需要修改GetFirst和GetNext兩個函式,使用者介面層完全無需修改。  
至此類檔案建立完畢,將工程檔案存為 test.vbp,選File選單下的Make test.dll選項將其編譯。  

3、註冊動態連結庫  

啟動Web Server 上的Microsoft Transaction Server (Start--Windows NT Optionpack4--Internet Information Server--Internet Service Manager),展開Microsoft Transaction Server--Computer--My Computer--Package Installed,點滑鼠右鍵選New--Package--Create Empty Package,輸入包名Test(這裡Test是任選的名字,不一定要與DLL同名),OK-Interactive User-the current Logon user--Finish。雙擊Test--Component,右鍵選Component-New-Component-Install New component(s)-- Add File,選擇你剛編譯好的DLL檔案,MTS會發現DLL中有兩個類Employee和Employees。至此DLL註冊完畢。  

4、編寫ASP程式  
  <HTML><Body>  
  <p>Qualified Employee List</p>  
  <table border=1 cellspacing=0 cellpadding=0>  
  <tr>  
   <td>Employee ID</td>  
   <td>Name</td>  
   <td>Gender</td>  
   <td>Score</td>  
  </tr>  
  <%  
   set oEmployees=server.createobject("Test.Employees")  
   oEmployees.GetQualifiedList  
   set oEmployee=oEmployees.GetFirst()  
   do while not oEmployee is nothing  
  %>  
  <tr>  
   <td><%=oEmployee.EMPLID%></td>  
   <td><%=oEmployee.Name%></td>  
   <td><%=oEmployee.Gender%></td>  
   <td><%=oEmployee.Score%></td>  
  </tr>  
  <%  
     set oEmployee=oEmployees.GetNext()  
   loop  
  %>  
  </table>  
  </body></html>  
注意在ASP中建立類例項的語法set oEmployees=server.createobject("Test.Employees"),其中Test是DLL的名字,Employees是類的名字; 當然,如果一個函式的返回值是一個物件,類似set oEmployee=oEmployees.GetFirst()這樣的語法也是可以的。  

至此,一個完整的三層結構的應用程式已經完成了,讓我們看以下,如果把"合格"的定義改為:只有成績進入前100名才算合格,程式需要做那些修改。事實上,如果你的資料庫系統是SQL Server,你只需把SQL語句改為:  

sql="select top 100 EMPLID from Employee order by Score desc" 就已經可以了,即使為了跨資料庫系統的相容性,我們也只需要對GetQualifiedList做如下修改:  
  sql="select EMPLID from Employee order by Score desc"  
  with rs  
   .open sql,conn,1,3  
   if .eof and .bof then  
     exit sub  
   else  
     i=1  
     do while (not .eof) and (i<=100)  
       dim oEmployee as new Employee  
       oEmployee.Create trim(.Fields("EMPLID"))  
       colQualifiedList.Add oEmployee  
       set oEmployee=nothing  
       i=i+1  
     loop  
   end if  
   .close  
  end with  
  ...  
然後把DLL重新編譯,註冊就可以了,ASP程式完全不必修改。
四、一些說明和注意事項  
1、 由於這個例子比較簡單,在Employee類中可以沒有Create方法,而在Employees類中將員工的所有資訊(工號,姓名,性別,成績)都讀出來並將其賦給Employee物件對應的屬性。但在實際應用中,當Employee物件的屬性增多,或表的數量增多,表之間關係變複雜時,還是本文所示的方法更有效,程式碼重用的機會更大。  
2、當DLL被修改後,在MTS中只能將其刪除後重新註冊,因為每次重新編譯後在登錄檔中物件的ID值都將重新生成。  
3、從ASP中呼叫帶引數的類方法和函式時,所有的變數引數一定要用相應的型別轉換函式轉換後再傳入,否則會引起型別不匹配錯誤,因為VBScript中只有Variant型別,它不能自動轉換成其它型別。例如,有如下的函式定義:  
  Public Function Fun1(p1 as string,p2 as integer) as integer  
  End Function  
  在ASP程式中應如下呼叫:  
  <%  
   p1=obj.property1 ' Property1 is a string property  
   p2=obj.property2 'Property2 is an integer property  
   a=obj.Fun1(cstr(p1),cint(p2))  
   a=obj.Fun1("aaa",10) ' constant parameter need not be changed  
  %>  
  而下面的兩種寫法是錯誤的:  
  <%  
   p1=obj.property1 ' Property1 is a string property  
   p2=obj.property2 'Property2 is an integer property  
   a=obj.Fun1(p1,p2) ' incorrect,p1 and p2 are variant variables  
   p1=cstr(p1)  
   p2=cint(p2)  
   a=obj.Fun1(p1,p2) ' still incorrect  
  %>  
這裡第二種寫法仍然是錯誤的,即使經過了型別轉換,p1和p2仍然是Variant變數。在VBScript中,資料型別和型別轉換函式只在表示式運算中起作用,變數只有Variant一種型別。  

結束語  
以上對多層結構的理論和實踐進行了一番探討,希望能對您的開發有所幫助。這裡還有一個問題,即類和類的成員該如何設計。這既涉及面向物件程式設計的理論,也需要一定的實踐經驗。請參考相關的OOP理論書籍並在實踐中不斷總結,相信您一定能設計出自己的完美的多層結構的應用程式。