您的位置:首页 > 其它

网页图片验证码实验心得

2010-05-25 11:06 316 查看
方法一,直接在JSP页面中写java代码

checkCodeImage.jsp

<%@ page contentType="image/jpeg" import="java.awt.*,java.awt.image.* ,java.util.*,javax.imageio.*,java.io.OutputStream" pageEncoding="gb2312"%>

<%!

Color getRandColor(int fc,int bc){//给定范围获得随机颜色

Random random = new Random();

if(fc>255) fc=255;

if(bc>255) bc=255;

int r=fc+random.nextInt(bc-fc);

int g=fc+random.nextInt(bc-fc);

int b=fc+random.nextInt(bc-fc);

return new Color(r,g,b);

}

%>

<%

//设置页面不缓存

response.setHeader("Pragma","No-cache");

response.setHeader("Cache-Control","no-cache");

response.setDateHeader("Expires", 0);

//生成随机类

Random random = new Random();

// 在内存中创建图象

int width=60;

int height=20;

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

// 获取图形上下文

Graphics g = image.getGraphics();

// 设定背景色

g.setColor(getRandColor(200,250));

g.fillRect(0, 0, width, height);

//设定字体

g.setFont(new Font("Times New Roman",Font.PLAIN,18));

//画边框

//g.setColor(new Color());

//g.drawRect(0,0,width-1,height-1);

// 随机产生155条干扰线,使图象中的认证码不易被其它程序探测到

g.setColor(getRandColor(160,200));

for (int i=0;i<155;i++)

{

int x = random.nextInt(width);

int y = random.nextInt(height);

int xl = random.nextInt(12);

int yl = random.nextInt(12);

g.drawLine(x,y,x+xl,y+yl);

}

// 取随机产生的认证码(4位数字)

String sRand="";

for (int i=0;i<4;i++){

String rand=String.valueOf(random.nextInt(10));

sRand+=rand;

// 将认证码显示到图象中

g.setColor(new Color(20+random.nextInt(110),

20+random.nextInt(110),

20+random.nextInt(110)));//调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成

g.drawString(rand,13*i+6,16);

}

// 将认证码存入SESSION

session.setAttribute("checkCode",sRand);

// 图象生效

g.dispose();

// 输出图象到页面

OutputStream os=response.getOutputStream();

ImageIO.write(image, "JPEG", os);

os.flush();

os.close();

os=null;

response.flushBuffer();

out.clear();

out = pageContext.pushBody();

%>

使用:

<img src="checkCodeImage.jsp " width="60" height="20">

注意:

如果没有红色那段代码会出现

getOutputStream() has already been called for this response异常

解决方法:
http://blog.csdn.net/iron_wang/archive/2009/05/20/4204672.aspx
1.

tomcat5下
jsp 出现
getOutputStream() has already been called for this response
异常的原因和解决方法在 tomcat5
下 jsp
中出现此错误一般都是在 jsp
中使用了输出流(如输出图片验证码,文件下载等), 没有妥善处理好的原因。


具体的原因就是

在tomcat
中 jsp
编译成 servlet
之后在函数 _jspService(HttpServletRequest request, HttpServletResponse response)
的最后

有一段这样的代码

finally {

if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context);

}

这里是在释放在jsp
中使用的对象,会调用 response.getWriter(),
因为这个方法是和

response.getOutputStream()相冲突的!所以会出现以上这个异常。

然后当然是要提出解决的办法,其实挺简单的(并不是和某些朋友说的那样--

将jsp
内的所有空格和回车符号所有都删除掉),

在使用完输出流以后调用以下两行代码即可:

out.clear();

out = pageContext.pushBody();

2

getOutputStream() has already been called for this response问题的解决


在jsp
向页面输出图片的时候 ,
使用 response.getOutputStream()
会有这样的提示:
java.lang.IllegalStateException:getOutputStream() has already been called for this response,
会抛出
Exception


原因一:

JSP默认的输出流为
PrintWriter , 即
<% %> 以外的东西所默认的输出方式
, 如果你尝试在
JSP 中使用
ServletOutputStream 就会引起错误
. 要嘛直接改用
Servlet 输出
( 复写
service 方法
), 要嘛删除除
%><% 中的任何东西

(包括
HTML 标签
, 空格
, 回车等东西
) 应该就可以。

对于这样的情况应该这样来解决,删除%><%
之间的所有内容包括空格和换行符,最后也要消除空格和换行符,

最好再加上一句response.reset()


原因二:

在J2EE
的 API
参考里有这么个 :

ServletResponse的
getWriter() 方法里会抛出这个异常
,

IllegalStateException - if the getOutputStream method has already been called

for this response object

而它的getOutputStream()
方法里会抛出这个异常
.

IllegalStateException - if the getOutputStream method has already been called for this response object

并且两者的函数申明里都有这么样的一句

Either this method or getOutputStream() may be called to write the body, not both.

Either this method or getWriter() may be called to write the body, not both.

以上说明也解释了为什么在往页面中写入图片的时候要使用如下循环格式

OutputStream output=response.getOutputStream();

while((len=in.read(b)) >0)

{

output.write(b,0,len);

}

output.flush();

而不是把response.getOutputStream().write()
放到循环体内

在页面中直接写:

<body bgcolor="#ffffff">

<h1>

<%

response.getOutputStream();

%>

</h1>

</body>

将会出现错误消息如下:

java.lang.IllegalStateException: getOutputStream() has already been called for this response

org.apache.catalina.connector.Response.getWriter(Response.java:604)

org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:198)

org.apache.jasper.runtime.JspWriterImpl.initOut(JspWriterImpl.java:125)

org.apache.jasper.runtime.JspWriterImpl.flushBuffer(JspWriterImpl.java:118)

本文来自CSDN
博客,转载请标明出处: http://blog.csdn.net/iron_wang/archive/2009/05/20/4204672.aspx
方法二:在servlet中处理


我的Servlet代码如下:


注意com.sun.image.codec.jpeg
包位于
jdk 目录的
rt.jar 包中,它不是公开的
api ,需要将
rt.jar 复制到
web 应用程序的
web-inf/lib 下。

import java.io.IOException;

import java.io.OutputStream;

import java.util.Random;

import java.awt.*;

import java.awt.image.*;

import com.sun.image.codec.jpeg.JPEGEncodeParam;

import com.sun.image.codec.jpeg.JPEGImageEncoder;

import com.sun.image.codec.jpeg.JPEGCodec;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

public class ImageProduceServlet extends HttpServlet
{

public void
doGet( HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//设置ContentType

response.setContentType("text/jpeg");

//设置页面不缓存

response.setHeader("Pragma","No-cache");

response.setHeader("Cache-Control","no-cache");

response.setDateHeader("Expires", 0);

//生成并输出图片

String s=this.createImg(response.getOutputStream());

//session记录生成的随机验证码

HttpSession mySession=request.getSession();

mySession.setAttribute("checkCode", s);

}
private String createImg(OutputStream os) {

//生成随机类

Random random = new Random();

// 在内存中创建图象

int width=60;

int height=20;

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

// 获取图形上下文

Graphics g = image.getGraphics();

// 设定背景色

g.setColor(getRandColor(200,250));

g.fillRect(0, 0, width, height);

//设定字体

g.setFont(new Font("Times New Roman",Font.PLAIN,18));

//画边框

//g.setColor(new Color());

//g.drawRect(0,0,width-1,height-1);

// 随机产生155条干扰线,使图象中的认证码不易被其它程序探测到

g.setColor(getRandColor(160,200));

for (int i=0;i<155;i++)

{

int x = random.nextInt(width);

int y = random.nextInt(height);

int xl = random.nextInt(12);

int yl = random.nextInt(12);

g.drawLine(x,y,x+xl,y+yl);

}

// 取随机产生的认证码(4位数字)

String sRand="";

for (int i=0;i<4;i++){

String rand=String.valueOf(random.nextInt(10));

sRand+=rand;

// 将认证码显示到图象中

g.setColor(new Color(20+random.nextInt(110),

20+random.nextInt(110),

20+random.nextInt(110)));//调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成

g.drawString(rand,13*i+6,16);

}

// 图象生效

g.dispose();

// encode:

JPEGImageEncoder encoder =JPEGCodec.createJPEGEncoder(os);

JPEGEncodeParam param = JPEGCodec. getDefaultJPEGEncodeParam(image);

param.setQuality(1.0f, false);

encoder.setJPEGEncodeParam(param);

try {

encoder.encode(image);

} catch(IOException ioe) {

ioe.printStackTrace();

}

return sRand;


}

/**

* 给定范围获得随机颜色

* @param fc

* @param bc

* @return

*/

private Color getRandColor(int fc,int bc) {

Random random = new Random();

if(fc>255) fc=255;

if(bc>255) bc=255;

int r=fc+random.nextInt(bc-fc);

int g=fc+random.nextInt(bc-fc);

int b=fc+random.nextInt(bc-fc);

return new Color(r,g,b);

}

}

使用:

<img src="servlet/ImageProduceServlet " width="60" height="20">



解释:

http://www.computersci.net/articles/jdk1.2/docs/guide/2d/api-jpeg/com/sun/image/codec/jpeg/JPEGCodec.html

以上是类

JPEGCodec 的API

本质上,浏览器向服务器请求静态图片如jpeg
时,服务器返回的仍然是标准的
http 响应, 只不过http
头的
contenttype 不是
text/html , 而是image/jpeg
而已 ,因此,我们在servlet
中 只要设置好contenttype
, 然后发送图像的数据流,浏览器就能正确解析并显示出图片。
在java
中, java.awt
和 java.awt.image
包提供了基本的绘制图像的能力,我们可以在内存中绘制好需要的图形,然后编码成
jpeg 或其他图像格式,最后发送相应给浏览器即可。
下面是使用servlet
动态创建图像的详细步骤:
1
创建bufferedimage
对象,该对象存在内存中,负责保存绘制的图像;
2
创建graphics2d
对象,该对象负责绘制所需的图像;
3
当绘制完成后,调用com.sun.image.codec.jpeg
包的
jpeg 编码器对其编码 ;

4
最后将编码后的数据输出至httpresponse
即可。
注意com.sun.image.codec.jpeg
包位于
jdk 目录的
rt.jar 包中,它不是公开的
api ,需要将
rt.jar 复制到
web 应用程序的
web-inf/lib 下。
1
我们先创建一个最简单的servlet

public class createimageservlet extends httpservlet {

protected void doget(httpservletrequest request, httpservletresponse response)
throws servletexception, ioexception
{

response.setcontenttype("image/jpeg");

}
}

我们首先设置了response
的 contenttype
为 image/jpeg
,这样浏览器就可以正确识别。
2
然后,创建一个大小为100x100
的 bufferedimage
对象,准备绘图:

int width = 100;

int height = 100;

bufferedimage bi = new bufferedimage(width, height, bufferedimage.type_int_rgb);

3
接着,bufferedimage
对象中获取 graphics2d
对象并绘图:

graphics2d g = bi.creategraphics(); // 创建
graphics2d
对象

g.setbackground(color.blue); // 填充背景为白色

g.clearrect(0, 0, width, height);

g.setcolor(color.red);// 设置前景色

// 开始绘图:

g.drawline(0, 0, 99, 99); // 绘制一条直线

g.dispose();

bi.flush();// 绘图完成,释放资源

4
然后,对bufferedimage
进行
jpeg 编码:
JPEGImageEncoder encoder =JPEGCodec.createJPEGEncoder(o
ut );
JPEGEncodeParam param = JPEGCodec. getDefaultJPEGEncodeParam(
bi );
param.setQuality(1.0f, false);

encoder.setJPEGEncodeParam(param);

try {

encoder.encode( bi );

} catch(IOException ioe) {

ioe.printStackTrace();
}

5.
编码后的jpeg
图像直接输出到了 out
对象中,

我们只要传入response. getoutputstream()
就可以直接输出到
httpresponse 中。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: