統(tǒng)計和顯示頁面的訪問次數(shù)是一個常見的 WEB 應(yīng)用,因為在網(wǎng)頁每次被訪問時,頁面的訪問次數(shù)都要發(fā)生改變,所以這個功能必須通過服務(wù)器端的程序來實現(xiàn)。頁面訪問計數(shù)器在服務(wù)器端的基本執(zhí)行過程為:首先從數(shù)據(jù)庫或其他存儲系統(tǒng)中取出頁面原來的訪問次數(shù),然后將原來的訪問次數(shù)加 1 后再作為當前訪問次數(shù)送給瀏覽器顯示,同時將當前訪問次數(shù)存儲回數(shù)據(jù)庫或其他存儲系統(tǒng)中,以便下次訪問該頁面時使用。但是,一些 WEB 站點只能輸出靜態(tài)頁面內(nèi)容,沒有開放運行服務(wù)器端程序的功能。例如,一些提供免費網(wǎng)頁空間的站點,在客戶端訪問任何類型的文件時,服務(wù)器都會原封不動地輸出給瀏覽器去處理,顯然無法直接在這些只支持靜態(tài)內(nèi)容的 WEB 站點上編寫服務(wù)器端程序來實現(xiàn)頁面訪問次數(shù)的統(tǒng)計和顯示功能。于是,一些具有執(zhí)行服務(wù)器端程序功能的 WEB 站點推出了免費的頁面訪問計數(shù)器,只要在位于任何站點的一個靜態(tài) HTML 頁面中增加一條該站點提供的 HTML 語句,該語句就能顯示出該靜態(tài)頁面的訪問次數(shù),從而幫助靜態(tài) HTML 頁面實現(xiàn)了訪問次數(shù)的統(tǒng)計和顯示功能。一個站點要想能統(tǒng)計另外一個站點上的某個 HTML 頁面的訪問次數(shù),必須讓任何一個瀏覽器在每次訪問那個 HTML 頁面都通知這個一下站點,這可以通過在靜態(tài) HTML 頁面中增加兩種特殊的標簽來實現(xiàn): <img> 標簽和設(shè)置 src 屬性的 <script> 標簽。下面只分析使用 <img> 標簽的應(yīng)用情況,對于使用設(shè)置 src 屬性的 <script> 標簽的應(yīng)用情況,則作為一道習題交給讀者自己去完成。
要利用 <img> 標簽為靜態(tài) HTML 頁面實現(xiàn)訪問次數(shù)的統(tǒng)計和顯示功能,需要理解 <img> 標簽的三個重要特性:
( 1 )一個包含有圖像的網(wǎng)頁文件中并沒有包含真正的圖像數(shù)據(jù)內(nèi)容,而只是使用 <img> 標簽指明了圖像的 URL 地址,如下所示:
本網(wǎng)頁已被瀏覽了 <img src= "count.gif "> 次
如果瀏覽器在解析網(wǎng)頁文檔 的過程中遇到了 <img> 標簽 ,它根據(jù) <img> 標簽的 src 屬性所指定的 URL 地址 去訪問 WEB 服務(wù)器,從 WEB 服務(wù)器上獲取圖像數(shù)據(jù)后,再在 <img> 標簽的位置處顯示出來。
( 2 ) <img> 標簽的 src 屬性也可以指向當前頁面所在 WEB 服務(wù)器之外的其他 WEB 服務(wù)器上的圖像文件。
( 3 )瀏覽器并不關(guān)心 <img> 標簽所需的圖像數(shù)據(jù)在服務(wù)器端是如何產(chǎn)生,它只知道去訪問 src 屬性指定的 URL 資源,并把服務(wù)器返回的數(shù)據(jù)當作一個圖像的內(nèi)容來顯示。服務(wù)器返回的圖像數(shù)據(jù)可以直接從一個靜態(tài)圖像文件中讀取,也可以通過 Servlet 程序在內(nèi)存中動態(tài)創(chuàng)建。所以, <img> 標簽的 src 屬性指向的 URL 不一定非得是事先靜態(tài)存在的靜態(tài)圖像文件,也可以是一個 Servlet 程序。
在靜態(tài) HTML 頁面中使用 <img> 標簽實現(xiàn)免費頁面訪問計數(shù)器的工作原理如圖 5.17 所示, WEB 站點 A 上的靜態(tài)頁面 count.html 內(nèi)有一條 <img> 標簽語句, <img> 標簽的 src 屬性指向了 WEB 站點 B 上的一個名為 CountServlet 的 Serlvet 程序,當瀏覽器顯示從站點 A 上獲得的 count.html 頁面時,它將根據(jù)其中的 <img> 標簽的 src 屬性去訪問 WEB 站點 B 上的 CountServlet 程序以獲得要顯示的圖像數(shù)據(jù), CountServlet 則創(chuàng)建出具有該頁面的訪問次數(shù)的圖像回送給瀏覽器顯示。
<shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></path><lock v:ext="edit" aspectratio="t"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 368.25pt; HEIGHT: 236.25pt" type="#_x0000_t75"><imagedata src="file:///C:%5CDOCUME~1%5Cgaocao%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image001.png" o:title='耠"耨"X'></imagedata></shape>
圖 5.17
因為 WEB 站點 B 上并不存在客戶端要訪問的圖像文件,而是由 Servlet 程序在內(nèi)存中臨時動態(tài)生成圖像內(nèi)容后傳送到客戶端的,所以,盡管靜態(tài)頁面內(nèi)的 <img> 標簽所指向的這個 Servlet 程序的 URL 地址是固定不變的,但是,它每次被訪問時所返回的圖像內(nèi)容卻是可以不斷變化的。
要編寫一個用 <img> 標簽統(tǒng)計和顯示靜態(tài) HTML 頁面的訪問次數(shù)的 Servlet 程序,需要考慮以下一些技術(shù)細節(jié):
l Servlet 程序輸出的圖像格式為 jpeg ,所以,它應(yīng)告訴瀏覽器其所輸出的實體內(nèi)容的 MIME 類型為 image/jpeg ,瀏覽器才會將它所接收到的數(shù)據(jù)當作一個圖像進行處理。
l 因為圖像是二進制數(shù)據(jù),所以應(yīng)該調(diào)用 HttpServletResponse.getOutputStream 方法返回的 ServletOutputStream 對象來向客戶端寫入圖像數(shù)據(jù),而不應(yīng)使用 HttpServletResponse.getWriter 方法返回的 PrintWriter 對象。
l java.awt.image.BufferedImage 類用于在內(nèi)存中創(chuàng)建一幅圖像,具體的圖像內(nèi)容則可以通過調(diào)用其圖形上下文對象( java.awt.Graphics )的各種繪圖方法生成,這里僅僅需要繪制一串數(shù)字,調(diào)用 Graphics.drawString 方法即可。 BufferedImage 類創(chuàng)建的內(nèi)存圖像的初始背景顏色和繪圖顏色都是黑色的,如果想改變背景顏色,還需要先設(shè)置相應(yīng)的繪圖顏色,然后調(diào)用 Graphics.fillRect 填充整個背景。
l 在內(nèi)存圖像中繪制訪問次數(shù)時,必須限定顯示的位數(shù),如果訪問次數(shù)超過七位,則用數(shù)字 9999999 顯示,如果訪問次數(shù)不足七位,則在前面補充相應(yīng)個數(shù)的 0 。
l 每個引用該 Servlet 程序的靜態(tài)頁面的 URL 都對應(yīng)一個各自的訪問次數(shù),每個 URL 及其訪問次數(shù)需要使用數(shù)據(jù)庫系統(tǒng)來進行存儲,對于簡單的實驗,也可以采用一個屬性文件來進行存儲。程序首先使用 Referer 請求頭獲得當前引用頁面的 URL ,然后去數(shù)據(jù)庫或?qū)傩晕募袡z索該 URL 的訪問次數(shù),再將訪問次數(shù)加 1 后保存進數(shù)據(jù)庫或?qū)傩晕募⒃L問次數(shù)繪制在內(nèi)存圖像中。如果屬性文件中不存在該 URL 的信息,則說明該 URL 頁面屬于第一次統(tǒng)計訪問。關(guān)于如何獲得 Referer 請求頭,請參看 6.4 節(jié)的講解。
l JDK 中提供了一個 javax.imageio.ImageIO 類,它的 write 方法可以將 BufferedImage 對象中的圖像編碼成 jpeg 格式的圖像數(shù)據(jù)后寫入到一個 OutputStream 流對象中。因此,只需要調(diào)用 ImageIO.write 方法將 BufferedImage 對象中的圖像編碼成 jpeg 格式后寫入到 ServletOutputStream 流對象中,就將整個圖像數(shù)據(jù)輸出給了客戶端。
: 動手體驗: 使用 <img> 標簽實現(xiàn)靜態(tài) HTML 頁面的訪問次數(shù)統(tǒng)計和顯示
( 1 )編寫一個能統(tǒng)計靜態(tài) HTML 頁面的訪問次數(shù)和將訪問次數(shù)以圖像形式返回給客戶端的 Servlet 程序,每個頁面的 URL 及訪問次數(shù)用一個屬性文件進行存儲,如例程 5-10 所示。
例程 5-10 CountServlet.java
<wrap side="left"><font face="Times New Roman" size="3"></font></wrap>
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.awt.*;
import java.awt.image.*;
import javax.imageio.ImageIO;
import java.util.Properties;
public class CountServlet extends HttpServlet
{
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException,IOException
{
response.setContentType("image/jpeg");
// 設(shè)置瀏覽器不要緩存此圖片
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0);
ServletOutputStream sos = response.getOutputStream();
BufferedImage image =
new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
/*g.setColor(Color.BLACK);
g.fillRect(0, 0, width, height);*/
g.setColor(Color.WHITE);
g.setFont(new Font(null,Font.ITALIC|Font.BOLD,18));
String value = getAccessCount(request);
int len = value.length();
// 最大訪問次數(shù)不能超過 9999999
if(len > 7)
{
value = "9999999";
}
else
{
String tmp="";
for(int i=0;i<7-len;i++)
{
tmp = tmp +"0";
}
value = tmp + value;
}
g.drawString(value,0,18);
// 結(jié)束圖像 的繪制 過程, 完成圖像
g.dispose();
ImageIO.write(image, "JPEG", sos);
sos.close();
}
private String getAccessCount(HttpServletRequest request)
{
// 得到引用頁面的 URL 地址,并以此作為訪問次數(shù)的檢索關(guān)鍵字
String pageKey = request.getHeader("referer");
if(pageKey == null)
{
return "0";
}
Properties settings = new Properties();
//count.txt 等內(nèi)部文件最好是保存在 WEB-INF 目錄中
String countFilePath = getServletContext().getRealPath("/count.txt");
try
{
// 下面的語句沒有使用 close 方法關(guān)閉流,有缺陷!
settings.load(new FileInputStream(countFilePath));
}
catch(Exception e){}
String count = "0";
try
{
count = settings.getProperty(pageKey);
if(count == null)
{
count = "0";
}
int c = Integer.parseInt(count) + 1;
count = new Integer(c).toString();
settings.put(pageKey,count);
// 下面的語句沒有使用 close 方法關(guān)閉流,有缺陷!
settings.store(new FileOutputStream(countFilePath),
"the page is accessed:");
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
return count;
}
}
<wrap side="left"><font face="Times New Roman" size="3"></font></wrap>
編譯 CountServlet.java 源文件,確保編譯后生成的 class 文件存放在了 < tomcat 的安裝目錄 >\webapps\it315\WEB-INF\classes 目錄中。
( 2 )修改 < tomcat 的安裝目錄 > \webapps\it315\WEB-INF\web.xml 文件,在其中的相應(yīng)位置處增加如下兩段內(nèi)容:
<servlet>
<servlet-name>CountServlet</servlet-name>
<servlet-class>CountServlet</servlet-class>
</servlet>
……
……
<servlet-mapping>
<servlet-name>CountServlet</servlet-name>
<url-pattern>/servlet/CountServlet</url-pattern>
</servlet-mapping>
保存 web.xml 文件后,重新啟動 Tomcat 。
( 3 )在任何計算機上的任何 HTML 頁面中只要加入如下語句:
<img src="http:// 可對外訪問的主機地址 :8080/it315/servlet/CountServlet">
就可以統(tǒng)計和顯示該頁面的訪問次數(shù)了。在 <tomcat 安裝目錄 >\webapps\it315 目錄中編寫一個名為 count.html 的 html 文件,如 例程 5-11 所示 。
例程 5-11 count.html
<wrap side="left"><font face="Times New Roman" size="3"></font></wrap>
<meta http-equiv="Content-Type" content="text/html;charset=GB2312">
本網(wǎng)頁已被瀏覽了 <img src="http://localhost:8080/it315/servlet/CountServlet"> 次。
<wrap side="left"><font size="3"></font></wrap>
在瀏覽器地址欄中輸入如下地址:
http://localhost:8080/it315/count.html
瀏覽器中顯示的結(jié)果如圖 5.18 所示。
<shape id="_x0000_i1026" style="WIDTH: 363.75pt; HEIGHT: 201pt" type="#_x0000_t75"><imagedata src="file:///C:%5CDOCUME~1%5Cgaocao%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image004.png" o:title=""><font size="3"></font></imagedata></shape>
圖 5.18
刷新瀏覽器的訪問幾次,可以看到圖片中的數(shù)值隨之增長。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
