孫宏偉
為了保證教學(xué)質(zhì)量,也為了督促學(xué)生積極參加教學(xué)活動(dòng),上課點(diǎn)名成了大學(xué)校園內(nèi)的一道獨(dú)特的風(fēng)景線,任課的老師通常承擔(dān)了義務(wù)點(diǎn)名的責(zé)任。但這項(xiàng)工作既費(fèi)時(shí)又費(fèi)力,分散了老師的教學(xué)精力,逃課現(xiàn)象也依舊存在,效果并不如人意。
面對(duì)這一兩難的窘境,無(wú)疑可以用非人工的方式完成這項(xiàng)工作。校園卡如今已經(jīng)成為了最普遍的標(biāo)示學(xué)生身份的證件,大部分的校園卡還具備了借閱圖書(shū)、吃飯、洗浴等功能。
由此,本文將從原理上探討一個(gè)可以完成從考勤、記錄保存、記錄查詢(xún),分析一系列步驟的校園卡考勤查詢(xún)管理系統(tǒng)。
基于校園卡現(xiàn)有的RFID無(wú)線射頻技術(shù),校園卡考勤,需要得到校園卡的一個(gè)唯一標(biāo)識(shí)號(hào)即可完成考勤記錄。該考勤系統(tǒng)的基本工作流程如下:
課前學(xué)生憑各自的校園卡(基于RFID無(wú)線射頻技術(shù))刷卡后進(jìn)入教室。刷卡成功后 RFID模塊通過(guò) Wiegand-26標(biāo)準(zhǔn)協(xié)議,將數(shù)據(jù)發(fā)送給嵌入式終端設(shè)備,設(shè)備端應(yīng)用程序,是運(yùn)行于嵌入式Linux下的后臺(tái)應(yīng)用程序,該程序讀取RFID模塊的傳入信號(hào),并將其解析后,得到一個(gè)校園卡的 PID號(hào)。
接著,嵌入式設(shè)備通過(guò)與服務(wù)器的 Socket連接,將所有從RFID模塊讀取到的數(shù)據(jù)連同時(shí)間戳以及教室編號(hào),發(fā)送至服務(wù)器接收程序。
服務(wù)器接收程序與嵌入式設(shè)備上的發(fā)送程序緊密配合,負(fù)責(zé)將接收到的數(shù)據(jù)再存儲(chǔ)值入整個(gè)系統(tǒng)的“數(shù)據(jù)中心”——MySQL數(shù)據(jù)庫(kù)中。
最后,應(yīng)用的中心便建立在這個(gè)集中的數(shù)據(jù)庫(kù)中,基于考勤記錄數(shù)據(jù),可以進(jìn)行多方面的應(yīng)用,本考勤管理查詢(xún)系統(tǒng)實(shí)現(xiàn)的一個(gè) JSP網(wǎng)站應(yīng)用,可以通過(guò)瀏覽器登錄考勤網(wǎng)站,進(jìn)行考勤記錄的多功能查詢(xún)。
考勤系統(tǒng)中最前端的部分,便是嵌入式設(shè)備,校園卡普遍采用的是RFID(電子標(biāo)簽、射頻識(shí)別)技術(shù),因此,嵌入式設(shè)備端,安裝有一個(gè)RFID射頻識(shí)別模塊,專(zhuān)門(mén)負(fù)責(zé)讀取校園卡中的ID標(biāo)志。
RFID射頻識(shí)別,是一種非接觸式的自動(dòng)識(shí)別技術(shù),通過(guò)射頻信號(hào)自動(dòng)識(shí)別目標(biāo)對(duì)象并獲取相關(guān)數(shù)據(jù),可工作于各種惡劣環(huán)境。在校園卡考勤這一應(yīng)用中, RFID系統(tǒng)可以簡(jiǎn)單地概括為兩個(gè)部分:校園卡和識(shí)別校園卡編號(hào)的RFID模塊。
在本系統(tǒng)中,唯一需要記錄的是學(xué)生持校園卡進(jìn)行刷卡的校園卡編號(hào)和刷卡時(shí)間,一旦記錄下這些數(shù)據(jù),就可以結(jié)合更復(fù)雜的后臺(tái)數(shù)據(jù),支撐起一個(gè)比較完整的查詢(xún)系統(tǒng)。
RFID模塊使用了標(biāo)準(zhǔn)的 Wiegand-26接口傳輸信號(hào)。Wiegand接口通常由3根線組成,分別是:數(shù)據(jù)0(Data0),數(shù)據(jù)1(Data1)和Data return。這3條線負(fù)責(zé)傳輸Wiegand信號(hào)。D0,D1在沒(méi)有數(shù)據(jù)輸出時(shí)都保持+5V高電平。若輸出為0,則D0拉低一段時(shí)間,若輸出為1,則D1拉低一段時(shí)間。
考勤系統(tǒng)使用的校園卡識(shí)別設(shè)備,就是采用Wiegand-26標(biāo)準(zhǔn)協(xié)議的,Data0和Data1兩根發(fā)送數(shù)據(jù)信號(hào)的線,分別連接到嵌入式設(shè)備的兩個(gè)IO端口上,在嵌入式Linux操作系統(tǒng)中,通過(guò)加載自定義驅(qū)動(dòng)程序來(lái)訪問(wèn)Data0和Data1。
在加載了RFID驅(qū)動(dòng)模塊之后,嵌入式Linux中使用簡(jiǎn)單的代碼,就可以對(duì)RFID讀卡數(shù)據(jù)信號(hào)進(jìn)行讀取了。
而在考勤系統(tǒng)中需要使用到的校園卡 PID值,則如前文所述,是wiregen變量中第10位至25位總共16位值。取得校園卡PID值之后,便可將該P(yáng)ID值發(fā)送給服務(wù)器數(shù)據(jù)接收程序了。
取得了能夠區(qū)分不同校園卡的 PID值之后,接下來(lái)需要將校園卡 PID數(shù)據(jù)、刷卡所在教室的考勤設(shè)備編號(hào)、時(shí)間發(fā)送給遠(yuǎn)程服務(wù)器。
數(shù)據(jù)的發(fā)送和接收使用的是Socket套接口連接。Socket接口是TCP/IP網(wǎng)絡(luò)的API,Socket接口定義了許多函數(shù)和例程。
嵌入式終端客戶(hù)端采用 C語(yǔ)言編寫(xiě),通過(guò) Linux下的Socket與服務(wù)器主機(jī)上的Java程序建立的服務(wù)器Socket相連接。
首先,每一個(gè) Socket連接都有一個(gè)整數(shù)描述字來(lái)唯一地進(jìn)行標(biāo)識(shí)。另外,客戶(hù)端程序需要一個(gè)sockaddr_in結(jié)構(gòu)體來(lái)指定連接到服務(wù)器的地址和端口等信息,接下來(lái),先簡(jiǎn)單敘述建立設(shè)備端Socket程序的基本流程。
2.2.1 創(chuàng)建TCP套接口
Socket函數(shù)創(chuàng)建AF_INET字節(jié)流(SOCK_STREAM)套接口。該函數(shù)返回了一個(gè)整數(shù)描述字,在以后的函數(shù)調(diào)用中,都是用這個(gè)整數(shù)值來(lái)標(biāo)識(shí)這個(gè)套接口。
2.2.2 指定服務(wù)器IP地址和端口
首先將server結(jié)構(gòu)體清零,服務(wù)器的IP地址來(lái)自程序執(zhí)行參數(shù)arg[1],端口號(hào)定義為12313,填入sockaddr_in結(jié)構(gòu)體server中。置地址簇為AF_INET。Htons函數(shù)意為“從主機(jī)到網(wǎng)絡(luò)短整數(shù)”,將端口地址值轉(zhuǎn)換成主機(jī)無(wú)關(guān)的網(wǎng)絡(luò)字節(jié)序。gethostbyname把ASCII字符串參數(shù)變換到合適的地址格式。
2.2.3 與服務(wù)器鏈接
在對(duì)Socket進(jìn)行上述簡(jiǎn)單配置后,即可嘗試用connect函數(shù)與服務(wù)器進(jìn)行連接:
嘗試在fd套接口上建立一個(gè)到server服務(wù)器的連接。其中connect函數(shù)的參數(shù)fd就是前面建立socket時(shí)返回的套接口描述字,而server是描述服務(wù)器連接參數(shù)的結(jié)構(gòu)體。如果連接成功,該函數(shù)返回0,錯(cuò)誤則返回-1,在終端上會(huì)顯示提示連接失敗,并直接退出應(yīng)用程序,終止數(shù)據(jù)發(fā)送。
2.2.4 與服務(wù)器間的通訊
在與服務(wù)器成功連接后,就可以使用 send()和recv()函數(shù)進(jìn)行服務(wù)器/客戶(hù)端之間的信息收發(fā)了??记谙到y(tǒng)設(shè)備端代碼實(shí)現(xiàn)如下:
通過(guò)send函數(shù),將data所指向的數(shù)據(jù)緩沖區(qū)中的數(shù)據(jù)發(fā)送的套接口描述字fd所指代的socket連接。發(fā)送后執(zhí)行一次接收函數(shù)recv(),該函數(shù)的作用旨在發(fā)送數(shù)據(jù)之后總應(yīng)當(dāng)要求服務(wù)器端作出一個(gè)回應(yīng)。更多的應(yīng)用甚至可以通過(guò)該回應(yīng)消息來(lái)判斷服務(wù)器的狀態(tài)。
2.2.5 關(guān)閉鏈接
當(dāng)客戶(hù)端完成數(shù)據(jù)的發(fā)送,并且得到服務(wù)器的適當(dāng)回應(yīng)之后,就應(yīng)該關(guān)閉Socket鏈接,以讓操作系統(tǒng)回收該Socket鏈接。
關(guān)閉套接口和關(guān)閉文件是一樣的,調(diào)用close(fd)即可關(guān)閉Socket描述字對(duì)應(yīng)的Socket套接口。
考勤設(shè)備數(shù)據(jù)發(fā)送程序持有 PID數(shù)據(jù),但是,為了能夠讓服務(wù)器知道客戶(hù)端發(fā)送來(lái)的數(shù)據(jù)具體是什么內(nèi)容,在客戶(hù)端和服務(wù)器之間需要共同遵守一個(gè)固定數(shù)據(jù)序列協(xié)議,數(shù)據(jù)流中的前4個(gè)字節(jié)表示終端所對(duì)應(yīng)的教室編號(hào)(或者可以簡(jiǎn)單地看作設(shè)備編號(hào)),接下來(lái)4個(gè)字節(jié)表示后面緊接著的數(shù)據(jù)流包含的記錄數(shù)量,每條記錄含有10個(gè)字節(jié)的數(shù)據(jù),每條記錄的前2個(gè)字節(jié)代表刷卡PID值(16位),后8個(gè)字節(jié)代表產(chǎn)生本條記錄的時(shí)間(即刷卡時(shí)間)的 64位Timestamp表示法。當(dāng)所有的數(shù)據(jù)發(fā)送完畢后,是任何情況下都固定不變的3個(gè)字節(jié)“END”,如果服務(wù)器接收時(shí),沒(méi)有在結(jié)尾處遇到這3個(gè)字節(jié)的結(jié)尾符,那么服務(wù)器控制臺(tái)將會(huì)發(fā)出一個(gè)警告消息。
在目前的客戶(hù)端代碼中,只是簡(jiǎn)單地對(duì)每一條數(shù)據(jù)進(jìn)行一次打包發(fā)送(即count=1),當(dāng)然,如果網(wǎng)絡(luò)或其他限制比較嚴(yán)重的情況下,完全可以采用更好的算法進(jìn)行多條數(shù)據(jù)的打包。
客戶(hù)端代碼通過(guò)dataPacker()函數(shù)對(duì)PID進(jìn)行打包,將教室ID、PID、時(shí)間、結(jié)尾符填入數(shù)據(jù)緩沖區(qū)后,直接交由Socket函數(shù)send()發(fā)送給服務(wù)器端。
服務(wù)器端采用Java程序作為服務(wù)器程序,在java.net.*類(lèi)庫(kù)中通過(guò)構(gòu)造一個(gè)ServerSocket類(lèi)的實(shí)例就可以使服務(wù)器檢測(cè)到指定端口的數(shù)據(jù)。
服務(wù)器端 Java程序是 JTeaching Affair Server,JTeaching Affair Server的主類(lèi)是org.sun.ts.ui.System Controller,這個(gè)類(lèi)就包含有一個(gè)私有的java.net.Server Socket對(duì)象,在程序初始化時(shí)創(chuàng)建,監(jiān)聽(tīng)端口12313上的Socket連接請(qǐng)求,然后程序就進(jìn)入一個(gè)無(wú)限循環(huán),每當(dāng) server.accept()返回時(shí)就建立一個(gè)Receiver線程來(lái)進(jìn)行數(shù)據(jù)接收,主線程進(jìn)入下一次循環(huán),等待下一個(gè) Socket連接請(qǐng)求,因此,無(wú)論客戶(hù)端同時(shí)發(fā)起多少個(gè) Socket連接請(qǐng)求,都不會(huì)被阻塞,而是直接得到服務(wù)器的響應(yīng)。
Receiver是自定義的一個(gè)System Controller類(lèi)的靜態(tài)內(nèi)部類(lèi),繼承自Thread類(lèi):在這個(gè)專(zhuān)門(mén)用來(lái)接收數(shù)據(jù)的類(lèi)中,由線程主體run()函數(shù)來(lái)完成處理邏輯。在Receiver類(lèi)的構(gòu)造函數(shù)中,會(huì)將參數(shù)提供的socket連接引用保存的自己的私有成員變量中供 run()使用,在 run()函數(shù)中,按照客戶(hù)端/服務(wù)器共同遵守的打包/解包協(xié)議進(jìn)行數(shù)據(jù)傳輸處理,分別接收教室 ID,記錄數(shù)量,各條記錄以及結(jié)尾字符串。Java中對(duì)socket連接數(shù)據(jù)的讀取和發(fā)送,已經(jīng)被抽象成為最普通的緩沖區(qū)讀寫(xiě)操作,
首先獲得socket連接上的輸入流對(duì)象,然后將其作為構(gòu)造參數(shù)構(gòu)造一個(gè) java.io.Input Stream Reader對(duì)象,專(zhuān)門(mén)用于進(jìn)行流讀取操作,但 Input Stream Reader類(lèi)依然是一個(gè)相對(duì)底層的IO操作類(lèi),因此,這里再一次將其作為構(gòu)造參數(shù),將實(shí)際是對(duì) socket數(shù)據(jù)流的操作,最終委托給高度抽象的Buffered Reader對(duì)象。
按照之前定好的通訊協(xié)議,數(shù)據(jù)流中的前4個(gè)字節(jié)代表的是考勤設(shè)備編號(hào)(或者可以等價(jià)地說(shuō)是教室編號(hào)):
int room = in.read()*1000 + in.read()*100 + in.read()*10+in.read();
設(shè)備編號(hào)讀取完,接下來(lái)的連續(xù)四個(gè)字節(jié)代表的是本數(shù)據(jù)包所包含的記錄條數(shù),利用同樣的方法進(jìn)行解析:
有了上述數(shù)據(jù),便可推算出整個(gè)數(shù)據(jù)包剩余的字節(jié)數(shù)量,進(jìn)而對(duì)其中包含的數(shù)據(jù)記錄逐一進(jìn)行解析??偟乃枷肴缦拢?/p>
讀取記錄PID值,占兩字節(jié);
讀取記錄時(shí)間戳,占8個(gè)字節(jié);
將 PID、時(shí)間戳、連同教室編號(hào)信息數(shù)據(jù)存入考勤記錄數(shù)據(jù)庫(kù)中;
}
接下來(lái)逐步解決上述思想中的各個(gè)步驟。
首先,取得PID值,即數(shù)據(jù)條目的前兩個(gè)字節(jié):
接著連續(xù)8個(gè)字節(jié)表示時(shí)間,這里8個(gè)字節(jié)實(shí)際表示的是一個(gè)64位整數(shù),是標(biāo)準(zhǔn)的Timestamp表示法,即從1970年1月1日0時(shí)0分0秒起至今的毫秒數(shù),數(shù)據(jù)取法同取PID值類(lèi)似,每取一個(gè)字節(jié)進(jìn)行一次移位即可。
然后,Timestame對(duì)象有一個(gè)構(gòu)造函數(shù)可以直接接受一個(gè)64位的long值參數(shù)作為時(shí)間戳數(shù)據(jù)。
這樣一來(lái),考勤數(shù)據(jù)庫(kù)記錄所需要的校園卡 PID值、刷卡時(shí)間值、刷卡教室編號(hào)都已經(jīng)成功獲取,利用MySQL數(shù)據(jù)庫(kù)Java Connector接口,將上述數(shù)據(jù)逐條插入到數(shù)據(jù)庫(kù)表中記錄。每取到一條記錄,就使用INSERT語(yǔ)句將其插入到數(shù)據(jù)庫(kù)的primitive表中:
當(dāng)處理完所有的數(shù)據(jù),檢查好結(jié)尾符后,就要關(guān)閉數(shù)據(jù)庫(kù)連接,方法是類(lèi)似的,只要對(duì)所創(chuàng)建的java.sql.Connection類(lèi)對(duì)象實(shí)例調(diào)用其close方法即可。接著向客戶(hù)端發(fā)送一條提示消息,以表示正常接收了,Java中字符串是UTF-8編碼的,而這條消息此處只包含了英文,因此嵌入式Linux終端可以正常顯示。
這樣,服務(wù)器端一個(gè)線程的數(shù)據(jù)接收就基本結(jié)束了,最后調(diào)用Socket對(duì)象的close()方法關(guān)閉這個(gè)Socket連接,釋放系統(tǒng)資源,就完成了從客戶(hù)端到服務(wù)器數(shù)據(jù)傳輸?shù)恼麄€(gè)過(guò)程。
存儲(chǔ)考勤記錄的數(shù)據(jù)庫(kù),采用開(kāi)放源代碼的MySQL數(shù)據(jù)庫(kù),作為考勤管理查詢(xún)網(wǎng)站的后臺(tái)數(shù)據(jù)庫(kù)。MySQL是一個(gè)開(kāi)放源碼的小型關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),具有體積小、速度快、總體擁有成本低等特點(diǎn)。
考勤記錄數(shù)據(jù)庫(kù)涉及的所有數(shù)據(jù)庫(kù)表編碼,都采用utf-8格式編碼,即MySQL默認(rèn)編碼就設(shè)定成utf-8。也可以在數(shù)據(jù)表定義時(shí)加上后綴DEFAULT CHARSET=utf8來(lái)特別設(shè)定編碼。
接下來(lái),是整個(gè)查詢(xún)系統(tǒng)所涉及到的所有考勤記錄相關(guān)數(shù)據(jù)庫(kù)表。
teachingaffiar數(shù)據(jù)庫(kù)共有9個(gè)表格,如圖1所示:
圖1 teachingaffair數(shù)據(jù)庫(kù)
建立好上述數(shù)據(jù)庫(kù)環(huán)境后,即可在服務(wù)器程序和JSP網(wǎng)站中對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作了。要在 Java程序中使用 MySQL數(shù)據(jù)庫(kù),需要使用MySQL connector for Java,對(duì)于一般的Java應(yīng)用程序在 CLASS PATH 中加入對(duì)mysql-connector-java-5.1.6-bin.jar的引用即可,對(duì)于Web網(wǎng)站,需要在網(wǎng)站根目錄/WEB-INF/lib中有 mysql-connectorjava-5.1.6-bin.jar這個(gè)文件。
在完成對(duì)本次鏈接的操作后需要用 conn.close()關(guān)閉此次數(shù)據(jù)庫(kù)鏈接,釋放相關(guān)資源。
JSP頁(yè)面由HTML代碼和嵌入其中的Java代碼所組成??记诠芾聿樵?xún)系統(tǒng)的JSP考勤查詢(xún)網(wǎng)站中,頁(yè)面內(nèi)容在很大程度上,僅僅依靠XHTML配合Javascript呈現(xiàn)動(dòng)態(tài)頁(yè)面,JSP指令在頁(yè)面中,承擔(dān)的主要責(zé)任是一些動(dòng)態(tài)的地址賦值和身份驗(yàn)證賦值運(yùn)算。而Java Servlet則負(fù)責(zé)對(duì)HTTP請(qǐng)求產(chǎn)生動(dòng)態(tài)的 XML文檔輸出。XML文檔在考勤管理查詢(xún)網(wǎng)站中,承擔(dān)著極其重要的中間人角色,在服務(wù)器——網(wǎng)站頁(yè)面——用戶(hù)之間建立了一座簡(jiǎn)單通用的數(shù)據(jù)呈現(xiàn)的橋梁。
JSP頁(yè)面按各種功能分類(lèi)進(jìn)行頁(yè)面組織,首先在 Web根目錄下有一個(gè) index.jsp表示系統(tǒng)首頁(yè),用作用戶(hù)驗(yàn)證登錄界面。所有頁(yè)面必須要用戶(hù)登錄之后才可見(jiàn),本系統(tǒng)使用session設(shè)置用戶(hù)身份驗(yàn)證來(lái)阻止未登錄用戶(hù)訪問(wèn)受限制頁(yè)面。
主要頁(yè)面分:以學(xué)生、課程、教師為主要條件的查詢(xún)頁(yè)面;分別添加學(xué)生、班級(jí)、教師的添加操作頁(yè)面;一些輔助頁(yè)面,如導(dǎo)航側(cè)邊欄、標(biāo)題欄、腳注欄等,都以?xún)?nèi)嵌頁(yè)面的方式嵌入在上述主要頁(yè)面中。
在眾多頁(yè)面中,pageTitle.jsp是secure目錄下,所有主要頁(yè)面都包含的子頁(yè)面,是代表頁(yè)面標(biāo)題的內(nèi)嵌頁(yè)。pageFoot.jsp則是secure目錄下,所有主要頁(yè)面都包含的代表頁(yè)面頁(yè)腳的內(nèi)嵌頁(yè)。
Navigator.jsp是大部分主頁(yè)面共有的一個(gè)位于頁(yè)面左側(cè)的導(dǎo)航欄內(nèi)嵌頁(yè)面。如果用戶(hù)是按照正常的流程登錄到secure下的頁(yè)面的,注意到實(shí)際“登錄”按鈕執(zhí)行的是Javascript腳本函數(shù) jsActionLogon(),該腳本函數(shù)完成一個(gè)很簡(jiǎn)單的登錄流程。
一旦登錄成功,用戶(hù)的信息將被保存在相應(yīng)session的userSig屬性中,無(wú)論用戶(hù)定位到secure目錄下的哪個(gè)頁(yè)面中,都可以正常訪問(wèn)了。
queryStudent.jsp是一個(gè)查詢(xún)特定學(xué)生某一門(mén)課的考勤記錄的頁(yè)面。打開(kāi)該頁(yè)面的初始情況,如圖2所示:
圖2 學(xué)生查詢(xún)
在姓名一欄中輸入學(xué)生姓名,在時(shí)間過(guò)濾中選擇要查詢(xún)的課程年份,點(diǎn)擊“繼續(xù)”按鈕后會(huì)出現(xiàn)一個(gè)列表框,顯示所有符合過(guò)濾條件的學(xué)生學(xué)號(hào),隨后選擇需要查詢(xún)的學(xué)號(hào),點(diǎn)擊“繼續(xù)”按鈕,系統(tǒng)會(huì)在列表中顯示該學(xué)生在該學(xué)年中參與的所有課程,選擇要查詢(xún)的課程,再點(diǎn)擊“繼續(xù)”按鈕,表格即顯示該學(xué)生的所選課程的考勤記錄,內(nèi)容包含4個(gè)主要字段:“上課時(shí)間”、“刷卡時(shí)間”、“教室”和“狀態(tài)”。此外,當(dāng)鼠標(biāo)移動(dòng)到“上課時(shí)間”的數(shù)據(jù)上時(shí),同時(shí)顯示出下課時(shí)間(預(yù)設(shè)每堂課課時(shí)為40分鐘)。
整個(gè)實(shí)現(xiàn)通用的流程如下:
1) 建立XMLHttpRequest請(qǐng)求,向服務(wù)器發(fā)出HTTP POST請(qǐng)求。
2) 在成功得到服務(wù)器正確響應(yīng)的情況下,利用 Mootools提供的腳本功能,迭代XML文檔中的item元素,并為每一個(gè)item元素的子項(xiàng)構(gòu)造單元格。
3) 對(duì)XML文檔中的相對(duì)原始數(shù)據(jù)進(jìn)行一定的計(jì)算處理,并在相應(yīng)的單元格中,顯示相對(duì)應(yīng)的計(jì)算結(jié)果,比如是否遲到的判定,是通過(guò)Javascript腳本中計(jì)算XML文檔中,提供的數(shù)據(jù)得到的,而不是服務(wù)器直接判定好的狀態(tài)結(jié)果。
4) 每處理一個(gè)item元素,就表示表格中的一行數(shù)據(jù),切換當(dāng)前行的背景顏色。
5) 完成表格的創(chuàng)建。如果可選的“下載Excel表格”或者“發(fā)送Email”被選擇了,那么在服務(wù)器上,會(huì)另外產(chǎn)生一個(gè)URL地址,可以形成一份當(dāng)前記錄表格的Excel表格文檔,和一封HTML表格方式組織的自動(dòng)EMail發(fā)送到指定的郵箱地址中。
[1]Richard Stevens W、Bill Fenner、Andrew M.Rudoff,UNIX Network Programming(Volume 1):The Sockets Networking API,Third Edition,The People's Posts and Telecommunications Press,2010.7.1
[2]Paul DuBois,MySQL [M]Cookbook(2th Edition),O’Reilly,2006.11
[3]張洪偉,Tomcat Web開(kāi)發(fā)及整合應(yīng)用,[R]清華大學(xué),2006.2.1
[4]劉曉華、張健、周慧貞,JSP應(yīng)用開(kāi)發(fā)詳解,[j]電子工業(yè),2007.1
[5]David Flanagan,JavaScript權(quán)威指南,[C]O’Reilly,2007.5
[6]夏慧軍、魏雪輝,深入淺出Ajax,[j]電子工業(yè),2007.4