因为WEB站点B上并不存在客户端要访问的图像文件,而是由Servlet程序在内存中临时动态生成图像内容后传送到 客户端的,所以,尽管静态页面内的<img>标签所指向的这个Servlet程序的URL地址是固定不变的,但是,它每次 被访问时所返回的图像内容却是可以不断变化的。
要编写一个用<img>标签统计和显示静态HTML页面的访问次数的Servlet程序,需要考虑以下一些技术细节:
Servlet程序输出的图像格式为jpeg,所以,它应告诉浏览器其所输出的实体内容的MIME类型为image/jpeg,浏览器才会将它所接收到的数据当作一个图像进行处理。
1. 因为图像是二进制数据,所以应该调用HttpServletResponse.getOutputStream方法返回的ServletOutputStream对象来向客户端写入图像数据,而不应使用HttpServletResponse.getWriter方法返回的PrintWriter对象。
2.java.awt.image.BufferedImage类用于在内存中创建一幅图像,具体的图像内容则可以通过调用其图形上下文对象(java.awt.Graphics)的各种绘图方法生成,这里仅仅需要绘制一串数字,调用Graphics.drawString方法即可。BufferedImage类创建的内存图像的初始背景颜色和绘图颜色都是黑色的,如果想改变背景颜色,还需要先设置相应的绘图颜色,然后调用Graphics.fillRect填充整个背景。
3.在内存图像中绘制访问次数时,必须限定显示的位数,如果访问次数超过七位,则用数字9999999显示,如果访问次数不足七位,则在前面补充相应个数的0。
4.每个引用该Servlet程序的静态页面的URL都对应一个各自的访问次数,每个URL及其访问次数需要使用数据库系统来进行存储,对于简单的实验,也可以采用一个属性文件来进行存储。程序首先使用Referer请求头获得当前引用页面的URL,然后去数据库或属性文件中检索该URL的访问次数,再将访问次数加1后保存进数据库或属性文件,并将访问次数绘制在内存图像中。如果属性文件中不存在该URL的信息,则说明该URL页面属于第一次统计访问。关于如何获得Referer请求头,请参看6.4节的讲解。
5.JDK中提供了一个javax.imageio.ImageIO类,它的write方法可以将BufferedImage对象中的图像编码成jpeg格式的图像数据后写入到一个OutputStream流对象中。因此,只需要调用ImageIO.write方法将BufferedImage对象中的图像编码成jpeg格式后写入到ServletOutputStream流对象中,就将整个图像数据输出给了客户端。
(1)编写一个能统计静态HTML页面的访问次数和将访问次数以图像形式返回给客户端的Servlet程序,每个页面的URL及访问次数用一个属性文件进行存储,如例程5-10所示。
例程5-10 CountServlet.java
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");
//设置浏览器不要缓存此图片
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();
//最大访问次数不能超过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);
//结束图像的绘制过程,完成图像
g.dispose();
ImageIO.write(image, "JPEG", sos);
sos.close();
}
private String getAccessCount(HttpServletRequest request)
{
//得到引用页面的URL地址,并以此作为访问次数的检索关键字
String pageKey = request.getHeader("referer");
if(pageKey == null)
{
return "0";
}
Properties settings = new Properties();
//count.txt等内部文件最好是保存在WEB-INF目录中
String countFilePath = getServletContext().getRealPath("/count.txt");
try
{
//下面的语句没有使用close方法关闭流,有缺陷!
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方法关闭流,有缺陷!
settings.store(new FileOutputStream(countFilePath),
"the page is accessed:");
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
return count;
}
}
编译CountServlet.java源文件,确保编译后生成的class文件存放在了<tomcat的安装目录>\webapps\it315\WEB-INF\classes目录中。
(2)修改<tomcat的安装目录>\webapps\it315\WEB-INF\web.xml文件,在其中的相应位置处增加如下两段内容:
<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">
就可以统计和显示该页面的访问次数了。在<tomcat安装目录>\webapps\it315目录中编写一个名为count.html的html文件,如例程5-11所示。
例程5-11 count.html
<meta http-equiv="Content-Type" content="text/html;charset=GB2312">
本网页已被浏览了<img src="http://localhost:8080/it315/servlet/CountServlet">次。
在浏览器地址栏中输入如下地址:
http://localhost:8080/it315/count.html
浏览器中显示的结果如图5.18所示。
|