`

md5加密 与 JSP(转)验证码

阅读更多
验证码 getOutputStream() has already been called for this response异常的原因和解决方法
2009-03-12 18:59

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();

最后这里是一个输出彩色验证码例子(这样的例子几乎随处可见)
imag.jsp

<%@ page import="java.awt.*,java.awt.image.*,java.util.*,javax.imageio.*" %>
<%@ page import="java.io.OutputStream" %>
<%!
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);
}
%>
<%
try{
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0);
int width=60, height=20;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
OutputStream os=response.getOutputStream();
Graphics g = image.getGraphics();
Random random = new Random();
g.setColor(getRandColor(200,250));
g.fillRect(0, 0, width, height);

g.setFont(new Font("Times New Roman",Font.PLAIN,18));
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);
}
String sRand="";
for (int j=0;j<4;j++){
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*j+6,16);
}
session.setAttribute("rand",sRand);
g.dispose();

ImageIO.write(image, "JPEG",os);
os.flush();
os.close();
os=null;
response.flushBuffer();
out.clear();
out = pageContext.pushBody();
}
catch(IllegalStateException e)
{
System.out.println(e.getMessage());
e.printStackTrace();
}%>


如有不足之处,欢迎斧正!

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)



1、直接复制以下代码创建类
public class MD5Code {
	/*
	 * 下面这些S11-S44实际上是一个4*4的矩阵,在原始的C实现中是用#define 实现的, 这里把它们实现成为static
	 * final是表示了只读,切能在同一个进程空间内的多个 Instance间共享
	 */
	static final int S11 = 7;

	static final int S12 = 12;

	static final int S13 = 17;

	static final int S14 = 22;

	static final int S21 = 5;

	static final int S22 = 9;

	static final int S23 = 14;

	static final int S24 = 20;

	static final int S31 = 4;

	static final int S32 = 11;

	static final int S33 = 16;

	static final int S34 = 23;

	static final int S41 = 6;

	static final int S42 = 10;

	static final int S43 = 15;

	static final int S44 = 21;

	static final byte[] PADDING = { -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 0, 0, 0, 0 };

	/*
	 * 下面的三个成员是MD5计算过程中用到的3个核心数据,在原始的C实现中 被定义到MD5_CTX结构中
	 */
	private long[] state = new long[4];// state (ABCD)

	private long[] count = new long[2];// number of bits, modulo 2^64 (lsb

	// first)

	private byte[] buffer = new byte[64]; // input buffer

	/*
	 * digestHexStr是MD5的唯一一个公共成员,是最新一次计算结果的 16进制ASCII表示.
	 */

	public String digestHexStr;

	/*
	 * digest,是最新一次计算结果的2进制内部表示,表示128bit的MD5值.
	 */
	private byte[] digest = new byte[16];

	/*
	 * getMD5ofStr是类MD5最主要的公共方法,入口参数是你想要进行MD5变换的字符串
	 * 返回的是变换完的结果,这个结果是从公共成员digestHexStr取得的.
	 */
	public String getMD5ofStr(String inbuf) {
		md5Init();
		md5Update(inbuf.getBytes(), inbuf.length());
		md5Final();
		digestHexStr = "";
		for (int i = 0; i < 16; i++) {
			digestHexStr += byteHEX(digest[i]);
		}
		return digestHexStr;
	}

	// 这是MD5这个类的标准构造函数,JavaBean要求有一个public的并且没有参数的构造函数
	public MD5Code() {
		md5Init();
		return;
	}

	/* md5Init是一个初始化函数,初始化核心变量,装入标准的幻数 */
	private void md5Init() {
		count[0] = 0L;
		count[1] = 0L;
		// /* Load magic initialization constants.
		state[0] = 0x67452301L;
		state[1] = 0xefcdab89L;
		state[2] = 0x98badcfeL;
		state[3] = 0x10325476L;
		return;
	}

	/*
	 * F, G, H ,I 是4个基本的MD5函数,在原始的MD5的C实现中,由于它们是
	 * 简单的位运算,可能出于效率的考虑把它们实现成了宏,在java中,我们把它们 实现成了private方法,名字保持了原来C中的。
	 */
	private long F(long x, long y, long z) {
		return (x & y) | ((~x) & z);
	}

	private long G(long x, long y, long z) {
		return (x & z) | (y & (~z));
	}

	private long H(long x, long y, long z) {
		return x ^ y ^ z;
	}

	private long I(long x, long y, long z) {
		return y ^ (x | (~z));
	}

	/*
	 * FF,GG,HH和II将调用F,G,H,I进行近一步变换 FF, GG, HH, and II transformations for
	 * rounds 1, 2, 3, and 4. Rotation is separate from addition to prevent
	 * recomputation.
	 */
	private long FF(long a, long b, long c, long d, long x, long s, long ac) {
		a += F(b, c, d) + x + ac;
		a = ((int) a << s) | ((int) a >>> (32 - s));
		a += b;
		return a;
	}

	private long GG(long a, long b, long c, long d, long x, long s, long ac) {
		a += G(b, c, d) + x + ac;
		a = ((int) a << s) | ((int) a >>> (32 - s));
		a += b;
		return a;
	}

	private long HH(long a, long b, long c, long d, long x, long s, long ac) {
		a += H(b, c, d) + x + ac;
		a = ((int) a << s) | ((int) a >>> (32 - s));
		a += b;
		return a;
	}

	private long II(long a, long b, long c, long d, long x, long s, long ac) {
		a += I(b, c, d) + x + ac;
		a = ((int) a << s) | ((int) a >>> (32 - s));
		a += b;
		return a;
	}

	/*
	 * md5Update是MD5的主计算过程,inbuf是要变换的字节串,inputlen是长度,这个
	 * 函数由getMD5ofStr调用,调用之前需要调用md5init,因此把它设计成private的
	 */
	private void md5Update(byte[] inbuf, int inputLen) {
		int i, index, partLen;
		byte[] block = new byte[64];
		index = (int) (count[0] >>> 3) & 0x3F;
		// /* Update number of bits */
		if ((count[0] += (inputLen << 3)) < (inputLen << 3))
			count[1]++;
		count[1] += (inputLen >>> 29);
		partLen = 64 - index;
		// Transform as many times as possible.
		if (inputLen >= partLen) {
			md5Memcpy(buffer, inbuf, index, 0, partLen);
			md5Transform(buffer);
			for (i = partLen; i + 63 < inputLen; i += 64) {
				md5Memcpy(block, inbuf, 0, i, 64);
				md5Transform(block);
			}
			index = 0;
		} else
			i = 0;
		// /* Buffer remaining input */
		md5Memcpy(buffer, inbuf, index, i, inputLen - i);
	}

	/*
	 * md5Final整理和填写输出结果
	 */
	private void md5Final() {
		byte[] bits = new byte[8];
		int index, padLen;
		// /* Save number of bits */
		Encode(bits, count, 8);
		// /* Pad out to 56 mod 64.
		index = (int) (count[0] >>> 3) & 0x3f;
		padLen = (index < 56) ? (56 - index) : (120 - index);
		md5Update(PADDING, padLen);
		// /* Append length (before padding) */
		md5Update(bits, 8);
		// /* Store state in digest */
		Encode(digest, state, 16);
	}

	/*
	 * md5Memcpy是一个内部使用的byte数组的块拷贝函数,从input的inpos开始把len长度的
	 * 字节拷贝到output的outpos位置开始
	 */
	private void md5Memcpy(byte[] output, byte[] input, int outpos, int inpos,
			int len) {
		int i;
		for (i = 0; i < len; i++)
			output[outpos + i] = input[inpos + i];
	}

	/*
	 * md5Transform是MD5核心变换程序,有md5Update调用,block是分块的原始字节
	 */
	private void md5Transform(byte block[]) {
		long a = state[0], b = state[1], c = state[2], d = state[3];
		long[] x = new long[16];
		Decode(x, block, 64);
		/* Round 1 */
		a = FF(a, b, c, d, x[0], S11, 0xd76aa478L); /* 1 */
		d = FF(d, a, b, c, x[1], S12, 0xe8c7b756L); /* 2 */
		c = FF(c, d, a, b, x[2], S13, 0x242070dbL); /* 3 */
		b = FF(b, c, d, a, x[3], S14, 0xc1bdceeeL); /* 4 */
		a = FF(a, b, c, d, x[4], S11, 0xf57c0fafL); /* 5 */
		d = FF(d, a, b, c, x[5], S12, 0x4787c62aL); /* 6 */
		c = FF(c, d, a, b, x[6], S13, 0xa8304613L); /* 7 */
		b = FF(b, c, d, a, x[7], S14, 0xfd469501L); /* 8 */
		a = FF(a, b, c, d, x[8], S11, 0x698098d8L); /* 9 */
		d = FF(d, a, b, c, x[9], S12, 0x8b44f7afL); /* 10 */
		c = FF(c, d, a, b, x[10], S13, 0xffff5bb1L); /* 11 */
		b = FF(b, c, d, a, x[11], S14, 0x895cd7beL); /* 12 */
		a = FF(a, b, c, d, x[12], S11, 0x6b901122L); /* 13 */
		d = FF(d, a, b, c, x[13], S12, 0xfd987193L); /* 14 */
		c = FF(c, d, a, b, x[14], S13, 0xa679438eL); /* 15 */
		b = FF(b, c, d, a, x[15], S14, 0x49b40821L); /* 16 */
		/* Round 2 */
		a = GG(a, b, c, d, x[1], S21, 0xf61e2562L); /* 17 */
		d = GG(d, a, b, c, x[6], S22, 0xc040b340L); /* 18 */
		c = GG(c, d, a, b, x[11], S23, 0x265e5a51L); /* 19 */
		b = GG(b, c, d, a, x[0], S24, 0xe9b6c7aaL); /* 20 */
		a = GG(a, b, c, d, x[5], S21, 0xd62f105dL); /* 21 */
		d = GG(d, a, b, c, x[10], S22, 0x2441453L); /* 22 */
		c = GG(c, d, a, b, x[15], S23, 0xd8a1e681L); /* 23 */
		b = GG(b, c, d, a, x[4], S24, 0xe7d3fbc8L); /* 24 */
		a = GG(a, b, c, d, x[9], S21, 0x21e1cde6L); /* 25 */
		d = GG(d, a, b, c, x[14], S22, 0xc33707d6L); /* 26 */
		c = GG(c, d, a, b, x[3], S23, 0xf4d50d87L); /* 27 */
		b = GG(b, c, d, a, x[8], S24, 0x455a14edL); /* 28 */
		a = GG(a, b, c, d, x[13], S21, 0xa9e3e905L); /* 29 */
		d = GG(d, a, b, c, x[2], S22, 0xfcefa3f8L); /* 30 */
		c = GG(c, d, a, b, x[7], S23, 0x676f02d9L); /* 31 */
		b = GG(b, c, d, a, x[12], S24, 0x8d2a4c8aL); /* 32 */
		/* Round 3 */
		a = HH(a, b, c, d, x[5], S31, 0xfffa3942L); /* 33 */
		d = HH(d, a, b, c, x[8], S32, 0x8771f681L); /* 34 */
		c = HH(c, d, a, b, x[11], S33, 0x6d9d6122L); /* 35 */
		b = HH(b, c, d, a, x[14], S34, 0xfde5380cL); /* 36 */
		a = HH(a, b, c, d, x[1], S31, 0xa4beea44L); /* 37 */
		d = HH(d, a, b, c, x[4], S32, 0x4bdecfa9L); /* 38 */
		c = HH(c, d, a, b, x[7], S33, 0xf6bb4b60L); /* 39 */
		b = HH(b, c, d, a, x[10], S34, 0xbebfbc70L); /* 40 */
		a = HH(a, b, c, d, x[13], S31, 0x289b7ec6L); /* 41 */
		d = HH(d, a, b, c, x[0], S32, 0xeaa127faL); /* 42 */
		c = HH(c, d, a, b, x[3], S33, 0xd4ef3085L); /* 43 */
		b = HH(b, c, d, a, x[6], S34, 0x4881d05L); /* 44 */
		a = HH(a, b, c, d, x[9], S31, 0xd9d4d039L); /* 45 */
		d = HH(d, a, b, c, x[12], S32, 0xe6db99e5L); /* 46 */
		c = HH(c, d, a, b, x[15], S33, 0x1fa27cf8L); /* 47 */
		b = HH(b, c, d, a, x[2], S34, 0xc4ac5665L); /* 48 */
		/* Round 4 */
		a = II(a, b, c, d, x[0], S41, 0xf4292244L); /* 49 */
		d = II(d, a, b, c, x[7], S42, 0x432aff97L); /* 50 */
		c = II(c, d, a, b, x[14], S43, 0xab9423a7L); /* 51 */
		b = II(b, c, d, a, x[5], S44, 0xfc93a039L); /* 52 */
		a = II(a, b, c, d, x[12], S41, 0x655b59c3L); /* 53 */
		d = II(d, a, b, c, x[3], S42, 0x8f0ccc92L); /* 54 */
		c = II(c, d, a, b, x[10], S43, 0xffeff47dL); /* 55 */
		b = II(b, c, d, a, x[1], S44, 0x85845dd1L); /* 56 */
		a = II(a, b, c, d, x[8], S41, 0x6fa87e4fL); /* 57 */
		d = II(d, a, b, c, x[15], S42, 0xfe2ce6e0L); /* 58 */
		c = II(c, d, a, b, x[6], S43, 0xa3014314L); /* 59 */
		b = II(b, c, d, a, x[13], S44, 0x4e0811a1L); /* 60 */
		a = II(a, b, c, d, x[4], S41, 0xf7537e82L); /* 61 */
		d = II(d, a, b, c, x[11], S42, 0xbd3af235L); /* 62 */
		c = II(c, d, a, b, x[2], S43, 0x2ad7d2bbL); /* 63 */
		b = II(b, c, d, a, x[9], S44, 0xeb86d391L); /* 64 */
		state[0] += a;
		state[1] += b;
		state[2] += c;
		state[3] += d;
	}

	/*
	 * Encode把long数组按顺序拆成byte数组,因为java的long类型是64bit的, 只拆低32bit,以适应原始C实现的用途
	 */
	private void Encode(byte[] output, long[] input, int len) {
		int i, j;
		for (i = 0, j = 0; j < len; i++, j += 4) {
			output[j] = (byte) (input[i] & 0xffL);
			output[j + 1] = (byte) ((input[i] >>> 8) & 0xffL);
			output[j + 2] = (byte) ((input[i] >>> 16) & 0xffL);
			output[j + 3] = (byte) ((input[i] >>> 24) & 0xffL);
		}
	}

	/*
	 * Decode把byte数组按顺序合成成long数组,因为java的long类型是64bit的,
	 * 只合成低32bit,高32bit清零,以适应原始C实现的用途
	 */
	private void Decode(long[] output, byte[] input, int len) {
		int i, j;
		for (i = 0, j = 0; j < len; i++, j += 4)
			output[i] = b2iu(input[j]) | (b2iu(input[j + 1]) << 8)
					| (b2iu(input[j + 2]) << 16) | (b2iu(input[j + 3]) << 24);
		return;
	}

	/*
	 * b2iu是我写的一个把byte按照不考虑正负号的原则的"升位"程序,因为java没有unsigned运算
	 */
	public static long b2iu(byte b) {
		return b < 0 ? b & 0x7F + 128 : b;
	}

	/*
	 * byteHEX(),用来把一个byte类型的数转换成十六进制的ASCII表示,
	 * 因为java中的byte的toString无法实现这一点,我们又没有C语言中的 sprintf(outbuf,"%02X",ib)
	 */
	public static String byteHEX(byte ib) {
		char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
				'B', 'C', 'D', 'E', 'F' };
		char[] ob = new char[2];
		ob[0] = Digit[(ib >>> 4) & 0X0F];
		ob[1] = Digit[ib & 0X0F];
		String s = new String(ob);
		return s;
	}
}

2、调用方法 getMD5ofStr(String inbuf)取得md5码
3、然后可使用"数据库密码".equals(xx.getMD5ofStr("pwd"))进行验证


二JSP验证码
1、image.jsp
<%@ page contentType="image/jpeg" import="java.awt.*,java.awt.image.*,java.util.*,javax.imageio.*" %>
<%!
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);

// 在内存中创建图象
int width=60, height=20;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

// 获取图形上下文
Graphics g = image.getGraphics();

//生成随机类
Random random = new Random();

// 设定背景色
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 rand = request.getParameter("rand");
//rand = rand.substring(0,rand.indexOf("."));
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("ccode",sRand);


// 图象生效
g.dispose();

// 输出图象到页面
ImageIO.write(image, "JPEG", response.getOutputStream());


%> 

2另外还有一个源码,下面的这个源码是生成中文验证码的:
<%@ page contentType="image/jpeg" import="java.awt.*,java.awt.image.*,java.util.*,javax.imageio.*" %>   
<%!   
//create by smallnest   
//email: smallnest@gmail.com   
//website:www.kuaff.com   
  
  
  
  
//生成随机颜色   
Color getRandColor(Random random,int fc,int bc)   
{   
        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);   
  
  
// 设置图片的长宽   
int width=176, height=30;   
//设置备选汉字,剔除一些不雅的汉字   
String base = "\u7684\u4e00\u4e86\u662f\u6211\u4e0d\u5728\u4eba\u4eec\u6709\u6765\u4ed6\u8fd9\u4e0a\u7740\u4e2a\u5730\u5230\u5927\u91cc\u8bf4\u5c31\u53bb\u5b50\u5f97\u4e5f\u548c\u90a3\u8981\u4e0b\u770b\u5929\u65f6\u8fc7\u51fa\u5c0f\u4e48\u8d77\u4f60\u90fd\u628a\u597d\u8fd8\u591a\u6ca1\u4e3a\u53c8\u53ef\u5bb6\u5b66\u53ea\u4ee5\u4e3b\u4f1a\u6837\u5e74\u60f3\u751f\u540c\u8001\u4e2d\u5341\u4ece\u81ea\u9762\u524d\u5934\u9053\u5b83\u540e\u7136\u8d70\u5f88\u50cf\u89c1\u4e24\u7528\u5979\u56fd\u52a8\u8fdb\u6210\u56de\u4ec0\u8fb9\u4f5c\u5bf9\u5f00\u800c\u5df1\u4e9b\u73b0\u5c71\u6c11\u5019\u7ecf\u53d1\u5de5\u5411\u4e8b\u547d\u7ed9\u957f\u6c34\u51e0\u4e49\u4e09\u58f0\u4e8e\u9ad8\u624b\u77e5\u7406\u773c\u5fd7\u70b9\u5fc3\u6218\u4e8c\u95ee\u4f46\u8eab\u65b9\u5b9e\u5403\u505a\u53eb\u5f53\u4f4f\u542c\u9769\u6253\u5462\u771f\u5168\u624d\u56db\u5df2\u6240\u654c\u4e4b\u6700\u5149\u4ea7\u60c5\u8def\u5206\u603b\u6761\u767d\u8bdd\u4e1c\u5e2d\u6b21\u4eb2\u5982\u88ab\u82b1\u53e3\u653e\u513f\u5e38\u6c14\u4e94\u7b2c\u4f7f\u5199\u519b\u5427\u6587\u8fd0\u518d\u679c\u600e\u5b9a\u8bb8\u5feb\u660e\u884c\u56e0\u522b\u98de\u5916\u6811\u7269\u6d3b\u90e8\u95e8\u65e0\u5f80\u8239\u671b\u65b0\u5e26\u961f\u5148\u529b\u5b8c\u5374\u7ad9\u4ee3\u5458\u673a\u66f4\u4e5d\u60a8\u6bcf\u98ce\u7ea7\u8ddf\u7b11\u554a\u5b69\u4e07\u5c11\u76f4\u610f\u591c\u6bd4\u9636\u8fde\u8f66\u91cd\u4fbf\u6597\u9a6c\u54ea\u5316\u592a\u6307\u53d8\u793e\u4f3c\u58eb\u8005\u5e72\u77f3\u6ee1\u65e5\u51b3\u767e\u539f\u62ff\u7fa4\u7a76\u5404\u516d\u672c\u601d\u89e3\u7acb\u6cb3\u6751\u516b\u96be\u65e9\u8bba\u5417\u6839\u5171\u8ba9\u76f8\u7814\u4eca\u5176\u4e66\u5750\u63a5\u5e94\u5173\u4fe1\u89c9\u6b65\u53cd\u5904\u8bb0\u5c06\u5343\u627e\u4e89\u9886\u6216\u5e08\u7ed3\u5757\u8dd1\u8c01\u8349\u8d8a\u5b57\u52a0\u811a\u7d27\u7231\u7b49\u4e60\u9635\u6015\u6708\u9752\u534a\u706b\u6cd5\u9898\u5efa\u8d76\u4f4d\u5531\u6d77\u4e03\u5973\u4efb\u4ef6\u611f\u51c6\u5f20\u56e2\u5c4b\u79bb\u8272\u8138\u7247\u79d1\u5012\u775b\u5229\u4e16\u521a\u4e14\u7531\u9001\u5207\u661f\u5bfc\u665a\u8868\u591f\u6574\u8ba4\u54cd\u96ea\u6d41\u672a\u573a\u8be5\u5e76\u5e95\u6df1\u523b\u5e73\u4f1f\u5fd9\u63d0\u786e\u8fd1\u4eae\u8f7b\u8bb2\u519c\u53e4\u9ed1\u544a\u754c\u62c9\u540d\u5440\u571f\u6e05\u9633\u7167\u529e\u53f2\u6539\u5386\u8f6c\u753b\u9020\u5634\u6b64\u6cbb\u5317\u5fc5\u670d\u96e8\u7a7f\u5185\u8bc6\u9a8c\u4f20\u4e1a\u83dc\u722c\u7761\u5174\u5f62\u91cf\u54b1\u89c2\u82e6\u4f53\u4f17\u901a\u51b2\u5408\u7834\u53cb\u5ea6\u672f\u996d\u516c\u65c1\u623f\u6781\u5357\u67aa\u8bfb\u6c99\u5c81\u7ebf\u91ce\u575a\u7a7a\u6536\u7b97\u81f3\u653f\u57ce\u52b3\u843d\u94b1\u7279\u56f4\u5f1f\u80dc\u6559\u70ed\u5c55\u5305\u6b4c\u7c7b\u6e10\u5f3a\u6570\u4e61\u547c\u6027\u97f3\u7b54\u54e5\u9645\u65e7\u795e\u5ea7\u7ae0\u5e2e\u5566\u53d7\u7cfb\u4ee4\u8df3\u975e\u4f55\u725b\u53d6\u5165\u5cb8\u6562\u6389\u5ffd\u79cd\u88c5\u9876\u6025\u6797\u505c\u606f\u53e5\u533a\u8863\u822c\u62a5\u53f6\u538b\u6162\u53d4\u80cc\u7ec6";   
//备选汉字的长度   
int length = base.length();   
  
  
//创建内存图像   
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);   
// 获取图形上下文   
Graphics g = image.getGraphics();   
  
  
//创建随机类的实例   
Random random = new Random();   
  
  
// 设定图像背景色(因为是做背景,所以偏淡)   
g.setColor(getRandColor(random,200,250));   
g.fillRect(0, 0, width, height);   
  
  
//备选字体   
String[] fontTypes = {"\u5b8b\u4f53","\u65b0\u5b8b\u4f53","\u9ed1\u4f53","\u6977\u4f53","\u96b6\u4e66"};   
int fontTypesLength = fontTypes.length;   
  
  
//在图片背景上增加噪点   
g.setColor(getRandColor(random,160,200));   
g.setFont(new Font("Times New Roman",Font.PLAIN,14));   
for (int i=0;i<6;i++)   
{   
    g.drawString("*********************************************",0,5*(i+2));   
}   
  
  
  
  
//取随机产生的认证码(6个汉字)   
  
  
//保存生成的汉字字符串   
String sRand="";   
for (int i=0;i<6;i++)   
{   
    int start = random.nextInt(length);   
    String rand=base.substring(start,start+1);   
    sRand+=rand;   
  
    //设置字体的颜色   
    g.setColor(getRandColor(random,10,150));   
    //设置字体   
    g.setFont(new Font(fontTypes[random.nextInt(fontTypesLength)],Font.BOLD,18 + random.nextInt(6)));   
    //将此汉字画到图片上   
    g.drawString(rand,24*i+ 10 + random.nextInt(8),24);   
}   
  
  
//将认证码存入session   
session.setAttribute("hanzirand",sRand);   
  
  
g.dispose();   
  
  
//输出图象到页面   
ImageIO.write(image, "JPEG", response.getOutputStream());   
%>  

把上面两个文件保存为image.jsp(数字)和hanzi.jsp(汉字),然后我们编写一个测试文件test.jsp来测试,源码如下:
<%@ page contentType="text/html; charset=gb2312" %>   
<%   
String incode = (String)request.getParameter("code");   
String rightcode = (String)session.getAttribute("numrand");//汉字验证码的话则是hanzirand   
if (incode != null && rightcode != null)   
if (rightcode.equals(incode))   
{   
out.println("验证码输入正确!");   
}   
else  
{   
out.println("验证码错误,请重新输入!");   
}   
  
%>   
  
<form action="test.jsp" method="post">   
请输入验证码:<img src="image.jsp" />//如果是要用汉字验证码的就换成hanzi.jsp   
      
<input type="text" name="code">   
<input type="submit" value="验证"></form>  


只要运行test.jsp即可看到结果!!!
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    验证码代码与md5加密和分页代码

    在IT行业中,验证码、MD5加密以及分页是常见的编程技术,主要应用于网站的安全和用户体验优化。SSH(Struts2 + Spring + Hibernate)是一个流行的Java Web开发框架,它整合了这三个技术来构建高效且安全的Web应用。...

    servlet+jsp实现的有验证码和MD5加密的登陆

    本项目"Servlet+jsp实现的有验证码和MD5加密的登陆"是一个典型的Web登录系统,它结合了数据库操作、前端展示和安全机制,具体涉及以下几个关键知识点: 1. **Servlet**:Servlet是Java编写服务器端应用程序的接口,...

    有验证码和MD5加密的登陆

    有验证码和MD5加密的登陆,希望对大家有帮助!

    jsp+mysql 用户注册登录模块(包含MD5,验证码)

    【标题】:“jsp+mysql 用户注册登录模块(包含MD5,验证码)” 【知识点详解】: 1. JSP(JavaServer Pages):JSP是一种基于Java的技术,用于创建动态网页。开发者可以在HTML页面中嵌入Java代码,实现服务器端的...

    jsp常用经典代码(md5java实现,生成中文/数字验证码,解决中文乱码)

    本主题聚焦于一些关键的jsp编程实践中涉及的知识点,包括`MD5`加密,生成中文/数字验证码以及处理中文乱码问题。 首先,`MD5`是一种广泛使用的加密散列函数,产生一个128位(16字节)的散列值,通常以32个十六进制...

    jspbook.rar_java 验证码_jsp JavaBean_jsp tomcat_验证码 加密

    该留言本采用JSP+JavaBean+Access开发,直接放到Tomcat下就能运行,不用配置数据源。 含有UBB代码和UBB头像,采用正则表达式制作。 管理登陆加入验证码,数据库管理密码采用MD5加密。

    jspbook.rar_java md5_java 管理_jsp tomcat_md5_正则表达式

    综上所述,这个压缩包提供了一个完整的JSP+JavaBean+Access的Web应用实例,涵盖了从用户界面到数据管理的关键环节,并且特别关注了安全性,特别是通过MD5加密的密码保护和验证码机制。对于学习Java Web开发、尤其是...

    liuyanban.rar_jsp access_liuyanb_验证码 加密

    该留言本采用JSP+JavaBean+Access开发,直接放到Tomcat下就能运行,不用配置数据源。 含有UBB代码和UBB头像,采用正则表达式制作。 管理登陆加入验证码,数据库管理密码采用MD5加密。

    jsp登陆页面(有验证码样式).zip

    为了确保用户输入的安全性,开发者需要对登陆信息进行**加密处理**,例如使用MD5或SHA家族的哈希算法。同时,使用**预编译JSP**可以提高应用的性能,因为JSP会被转换成Servlet并在首次请求时编译。 在实际的登陆...

    登录注册找回密码以及验证(jsp+servlet+mysql+mvc)

    还有头像,验证码,密码采用MD5加密模式保存,完全采用mvc模式,数据库就一个表,自己通过实体类创建(很简单),加载服务器后直接运行frontground/jsp/login.jsp就可以,这个登录界面上面有注册、找回密码的链接,...

    jsp实现留言板

    5. **MD5加密**:MD5(Message-Digest Algorithm 5)是一种广泛使用的哈希函数,可以将任意长度的信息转化为固定长度的哈希值。在数据库管理密码时,通常会先对原始密码进行MD5加密,然后存储加密后的值,这样即使...

    JSP+MYSQL小型博客系统

    "JSP+MySQL小型博客系统"正是这样一个解决方案,它采用Java服务器页面(JSP)技术和关系型数据库管理系统MySQL构建,提供了用户注册、登录、验证码验证以及文章管理等一系列功能。 首先,我们来看看JSP(JavaServer...

    基于mvc模式开发的jsp用户管理小项目全部代码以及jar包

    一个基于mvc模式开发的用户管理项目的全部源代码,可以运行,包含文件上传和下载,MD5加密使用,生成验证码, JSTL技术和Servlet和Jsp混合使用技术,全部页面用标签实现,Java代码有注释说明,绝对可以让你的jsp技术...

    页面密码加密传输代码

    4. **Spark-MD5库**:`spark-md5.min.js`可能用于JavaScript环境中的哈希计算。虽然主要应用是服务器端的PHP,但在前端,Spark-MD5可以用于在浏览器端预处理密码,生成一个哈希值,再发送到服务器,增加安全性。 5....

    验证码图片

    4. **保存验证码值**:为了后续验证用户输入的验证码是否正确,需要将生成的验证码字符串保存到session中,这里采用了MD5加密处理。 ```java request.getSession().setAttribute("yzm", MD5.md5(sb.toString()....

    Java EE--注册登录系统

    4. **MD5加密**:MD5(Message-Digest Algorithm 5)是一种广泛使用的哈希函数,可以将任意长度的数据转化为固定长度的摘要。在用户注册时,系统会将用户输入的密码通过MD5算法加密,存储在数据库中。当用户登录时,...

    JAVAEE课程设计--注册登录系统.pdf

    **MD5加密** 为了保护用户密码的安全性,系统采用了MD5加密算法。在Java中,MD5算法可以通过`java.security.MessageDigest`类实现。在用户注册时,原始密码会通过MD5加密后存储在数据库中,登录时再对输入的密码进行...

    jsp实验手册

    讲解常见的加密算法,如MD5、SHA系列,以及如何在JSP和Servlet中实现数据的安全加密。 实验十:JSP/SERVLET的重定向技术 重定向是Web应用中的重要概念,实验会讲解如何使用sendRedirect()方法在不同URL间切换,以及...

    javaEE注册登录系统

    3. **MD5加密** 为了确保用户密码的安全,不建议直接存储明文密码。MD5(Message-Digest Algorithm 5)是一种常用的密码哈希函数,可以将任意长度的信息转化为固定长度的哈希值。在注册过程中,用户输入的密码经过...

    JSP+JavaBean留言本

    该留言本采用JSP+JavaBean+Access开发,直接放到Tomcat下就能运行,不用配置数据源。 含有UBB代码和UBB头像,采用正则表达式制作。 管理登陆加入验证码,数据库管理密码采用MD5加密。

Global site tag (gtag.js) - Google Analytics