Java通用验证码程序及应用示例(提供源码下载) (转:http://www.blogjava.net/hufoking/archive/2009/11/27/java_verifycode.html)
把之前项目中写的一个Java通用验证码程序整理了一下,与大家分享,希望能抛砖引玉。
2、ok.jsp 留言发布成功页面(示意)
3、org.javachina.util.VerifyCode.java 验证码生成器类
4、org.javachina.servlet.VerifyCodeServlet.java 接受客户端请求,向客户端输出验证码
5、org.javachina.servlet.PubMsgServlet.java 保存留言信息(比对验证码)
一、主要功能:
1、支持纯数字、大写字母、小写字母,及两两混合或三者混合类型验证码;
2、支持自定义特殊字符排除(如0oOi1jI);
3、支持图片及文字两种类型验证码;
4、支持自定义验证码图片大小;
5、支持自定义干扰线条数;
6、支持自定义及随机定义图片、文字、干扰线颜色;
其他:示例页面提供了<iframe>和<img>两种页面显示验证码的方式。
a、仅阿拉伯数字
b、仅字母(大小写混合)
c、仅小写字母
d、仅大写字母
d、数字与小写字母混合
e、数字与大写字母混合
f、数字与大小写字母混合
g、自定义字符颜色(或随机)
h、自定义图片颜色(或随机)
i、自定义干扰线的条数及颜色(或随机)
j、自定义验证码图片大小
k、自定义需排除的特殊字符(如0o等难分辨字符)
二、代码说明:
1、pubMsg.jsp 发表留言页面,实现<iframe>和<img>两种显示验证码方式,及ajax提交功能
<%@ page language="java" import="java.util.*" pageEncoding="gbk"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title><%=basePath%></title>
</head>
<script type="text/javascript">
var req;
//提交留言
function pubMsg(){
msgTitle=document.msgForm.msgTitle.value;
msgContent=document.msgForm.msgContent.value;
verifyCode=document.msgForm.verifyCode.value;
//检查输入内容格式
if(msgTitle.length<5||msgContent.length<5)
{
alert("标题和内容不能少于5个字符");
return;
}
if(verifyCode.length==0){
alert("请输入验证码");
return;
}
//获得XMLHttpRequest对象
if(window.XMLHttpRequest)
req=new XMLHttpRequest();
else if(window.ActiveXObject)
req=new ActiveXObject("Microsoft.XMLHTTP");
//提交请求
if(req){
req.onreadystatechange=callBack;//指定服务器响应结果处理函数(注意仅函数名无括号)
url="<%=path%>/servlet/PubMsgServlet?msgTitle="+msgTitle+"&msgContent="+msgContent+"&verifyCode="+verifyCode;
req.open("GET",url,false);
req.send();
}
}
//服务器响应结果处理函数
function callBack(){
if(req.readyState==4){
if(req.status==200){
next=req.responseText;//获得服务器处理结果
if(next=="this"){
alert("验证码不正确,请重新输入");
verifyCodeFrame.location.reload();//刷新验证码
}
else{
document.msgForm.msgTitle.value="";
document.msgForm.msgContent.value="";
window.location=next;//跳转页面
}
}else
{
alert(req.status+":"+req.statusText);
}
}
document.msgForm.verifyCode.value="";
}
//更换验证码
function changeVerifyCode(){
//1、如果用<iframe>实现,则重新加载<iframe>的内容
//verifyCodeFrame.location.reload();
//2、如果用<img>实现,则修改<img src=url>的url
//这里有一个小技巧,如果给url赋相同的值,浏览器不会重新发出请求,因此用js生成一个即时毫秒数做url中的参数
t=new Date().getTime();
document.msgForm.verifyCodeImg.src="<%=path%>/servlet/VerifyCodeServlet?t="+t;
}
</script>
<body>
<form name="msgForm" action="" method="post">
<table border=0>
<tr><td>标题:</td><td><input name="msgTitle" size="65"/></td></tr>
<tr><td>内容:</td><td><textarea name="msgContent" rows="10" cols="64"></textarea></td></tr>
<tr><td>验证码:</td><td><input name="verifyCode" style="height:29px;width=70px;font-size:25px"/>
<!-- 以下:两种显示验证码的方式 -->
<!-- 1、采用<iframe>实现 -->
<!--
<iframe name="verifyCodeFrame" src="<%=path+"/servlet/VerifyCodeServlet"%>" width="100" height="30" frameborder=0 align="top" marginheight=0 marginwidth=0 scrolling=no></iframe>
-->
<!-- 2、采用<img>实现 -->
<img name="verifyCodeImg" src="<%=path%>/servlet/VerifyCodeServlet" style="cursor:hand" align="top" onClick="changeVerifyCode()"/>
<!-- 以上:两种显示验证码的方式 -->
<font style="color:blue;font-size=14"><a href="javascript:changeVerifyCode()">看不清?</a></font>
<input type="button" value=" 发表留言 " onClick="pubMsg()"/></td></tr>
</table>
</form>
</body>
</html>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title><%=basePath%></title>
</head>
<script type="text/javascript">
var req;
//提交留言
function pubMsg(){
msgTitle=document.msgForm.msgTitle.value;
msgContent=document.msgForm.msgContent.value;
verifyCode=document.msgForm.verifyCode.value;
//检查输入内容格式
if(msgTitle.length<5||msgContent.length<5)
{
alert("标题和内容不能少于5个字符");
return;
}
if(verifyCode.length==0){
alert("请输入验证码");
return;
}
//获得XMLHttpRequest对象
if(window.XMLHttpRequest)
req=new XMLHttpRequest();
else if(window.ActiveXObject)
req=new ActiveXObject("Microsoft.XMLHTTP");
//提交请求
if(req){
req.onreadystatechange=callBack;//指定服务器响应结果处理函数(注意仅函数名无括号)
url="<%=path%>/servlet/PubMsgServlet?msgTitle="+msgTitle+"&msgContent="+msgContent+"&verifyCode="+verifyCode;
req.open("GET",url,false);
req.send();
}
}
//服务器响应结果处理函数
function callBack(){
if(req.readyState==4){
if(req.status==200){
next=req.responseText;//获得服务器处理结果
if(next=="this"){
alert("验证码不正确,请重新输入");
verifyCodeFrame.location.reload();//刷新验证码
}
else{
document.msgForm.msgTitle.value="";
document.msgForm.msgContent.value="";
window.location=next;//跳转页面
}
}else
{
alert(req.status+":"+req.statusText);
}
}
document.msgForm.verifyCode.value="";
}
//更换验证码
function changeVerifyCode(){
//1、如果用<iframe>实现,则重新加载<iframe>的内容
//verifyCodeFrame.location.reload();
//2、如果用<img>实现,则修改<img src=url>的url
//这里有一个小技巧,如果给url赋相同的值,浏览器不会重新发出请求,因此用js生成一个即时毫秒数做url中的参数
t=new Date().getTime();
document.msgForm.verifyCodeImg.src="<%=path%>/servlet/VerifyCodeServlet?t="+t;
}
</script>
<body>
<form name="msgForm" action="" method="post">
<table border=0>
<tr><td>标题:</td><td><input name="msgTitle" size="65"/></td></tr>
<tr><td>内容:</td><td><textarea name="msgContent" rows="10" cols="64"></textarea></td></tr>
<tr><td>验证码:</td><td><input name="verifyCode" style="height:29px;width=70px;font-size:25px"/>
<!-- 以下:两种显示验证码的方式 -->
<!-- 1、采用<iframe>实现 -->
<!--
<iframe name="verifyCodeFrame" src="<%=path+"/servlet/VerifyCodeServlet"%>" width="100" height="30" frameborder=0 align="top" marginheight=0 marginwidth=0 scrolling=no></iframe>
-->
<!-- 2、采用<img>实现 -->
<img name="verifyCodeImg" src="<%=path%>/servlet/VerifyCodeServlet" style="cursor:hand" align="top" onClick="changeVerifyCode()"/>
<!-- 以上:两种显示验证码的方式 -->
<font style="color:blue;font-size=14"><a href="javascript:changeVerifyCode()">看不清?</a></font>
<input type="button" value=" 发表留言 " onClick="pubMsg()"/></td></tr>
</table>
</form>
</body>
</html>
2、ok.jsp 留言发布成功页面(示意)
<%@ page language="java" import="java.util.*" pageEncoding="gbk"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<body>
您的留言已提交!<input type="button" value=" OK " onClick="window.history.go(-1)"/><br>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<body>
您的留言已提交!<input type="button" value=" OK " onClick="window.history.go(-1)"/><br>
</body>
</html>
3、org.javachina.util.VerifyCode.java 验证码生成器类
package org.javachina.util;
import java.util.Random;
import java.awt.image.BufferedImage;
import java.awt.Graphics;
import java.awt.Font;
import java.awt.Color;
/**
* 验证码生成器类,可生成数字、大写、小写字母及三者混合类型的验证码。
* 支持自定义验证码字符数量;
* 支持自定义验证码图片的大小;
* 支持自定义需排除的特殊字符;
* 支持自定义干扰线的数量;
* 支持自定义验证码图文颜色
* @author org.javachina
* @version 1.01
*/
public class VerifyCode {
/**
* 验证码类型为仅数字 0~9
*/
public static final int TYPE_NUM_ONLY=0;
/**
* 验证码类型为仅字母,即大写、小写字母混合
*/
public static final int TYPE_LETTER_ONLY=1;
/**
* 验证码类型为数字、大写字母、小写字母混合
*/
public static final int TYPE_ALL_MIXED=2;
/**
* 验证码类型为数字、大写字母混合
*/
public static final int TYPE_NUM_UPPER=3;
/**
* 验证码类型为数字、小写字母混合
*/
public static final int TYPE_NUM_LOWER=4;
/**
* 验证码类型为仅大写字母
*/
public static final int TYPE_UPPER_ONLY=5;
/**
* 验证码类型为仅小写字母
*/
public static final int TYPE_LOWER_ONLY=6;
private VerifyCode(){}
/**
* 生成验证码字符串
* @param type 验证码类型,参见本类的静态属性
* @param length 验证码长度,大于0的整数
* @param exChars 需排除的特殊字符(仅对数字、字母混合型验证码有效,无需排除则为null)
* @return 验证码字符串
*/
public static String generateTextCode(int type,int length,String exChars){
if(length<=0) return "";
StringBuffer code=new StringBuffer();
int i=0;
Random r=new Random();
switch(type)
{
//仅数字
case TYPE_NUM_ONLY:
while(i<length){
int t=r.nextInt(10);
if(exChars==null||exChars.indexOf(t+"")<0){//排除特殊字符
code.append(t);
i++;
}
}
break;
//仅字母(即大写字母、小写字母混合)
case TYPE_LETTER_ONLY:
while(i<length){
int t=r.nextInt(123);
if((t>=97||(t>=65&&t<=90))&&(exChars==null||exChars.indexOf((char)t)<0)){
code.append((char)t);
i++;
}
}
break;
//数字、大写字母、小写字母混合
case TYPE_ALL_MIXED:
while(i<length){
int t=r.nextInt(123);
if((t>=97||(t>=65&&t<=90)||(t>=48&&t<=57))&&(exChars==null||exChars.indexOf((char)t)<0)){
code.append((char)t);
i++;
}
}
break;
//数字、大写字母混合
case TYPE_NUM_UPPER:
while(i<length){
int t=r.nextInt(91);
if((t>=65||(t>=48&&t<=57))&&(exChars==null||exChars.indexOf((char)t)<0)){
code.append((char)t);
i++;
}
}
break;
//数字、小写字母混合
case TYPE_NUM_LOWER:
while(i<length){
int t=r.nextInt(123);
if((t>=97||(t>=48&&t<=57))&&(exChars==null||exChars.indexOf((char)t)<0)){
code.append((char)t);
i++;
}
}
break;
//仅大写字母
case TYPE_UPPER_ONLY:
while(i<length){
int t=r.nextInt(91);
if((t>=65)&&(exChars==null||exChars.indexOf((char)t)<0)){
code.append((char)t);
i++;
}
}
break;
//仅小写字母
case TYPE_LOWER_ONLY:
while(i<length){
int t=r.nextInt(123);
if((t>=97)&&(exChars==null||exChars.indexOf((char)t)<0)){
code.append((char)t);
i++;
}
}
break;
}
return code.toString();
}
/**
* 已有验证码,生成验证码图片
* @param textCode 文本验证码
* @param width 图片宽度
* @param height 图片高度
* @param interLine 图片中干扰线的条数
* @param randomLocation 每个字符的高低位置是否随机
* @param backColor 图片颜色,若为null,则采用随机颜色
* @param foreColor 字体颜色,若为null,则采用随机颜色
* @param lineColor 干扰线颜色,若为null,则采用随机颜色
* @return 图片缓存对象
*/
public static BufferedImage generateImageCode(String textCode,int width,int height,int interLine,boolean randomLocation,Color backColor,Color foreColor,Color lineColor){
BufferedImage bim=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
Graphics g=bim.getGraphics();
//画背景图
g.setColor(backColor==null?getRandomColor():backColor);
g.fillRect(0,0,width,height);
//画干扰线
Random r=new Random();
if(interLine>0){
int x=0,y=0,x1=width,y1=0;
for(int i=0;i<interLine;i++){
g.setColor(lineColor==null?getRandomColor():lineColor);
y=r.nextInt(height);
y1=r.nextInt(height);
g.drawLine(x,y,x1,y1);
}
}
//写验证码
//字体大小为图片高度的80%
int fsize=(int)(height*0.8);
int fx=0;
int fy=fsize;
g.setFont(new Font(Font.DIALOG,Font.PLAIN,fsize));
//写验证码字符
for(int i=0;i<textCode.length();i++){
fy=randomLocation?(int)((Math.random()*0.3+0.6)*height):fy;//每个字符高低是否随机
g.setColor(foreColor==null?getRandomColor():foreColor);
g.drawString(textCode.charAt(i)+"",fx,fy);
fx+=(width / textCode.length()) * (Math.random() * 0.3 + 0.8); //星风兄的高见,依据宽度浮动
}
g.dispose();
return bim;
}
/**
* 产生随机颜色
* @return
*/
private static Color getRandomColor(){
Random r=new Random();
Color c=new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256));
return c;
}
}
import java.util.Random;
import java.awt.image.BufferedImage;
import java.awt.Graphics;
import java.awt.Font;
import java.awt.Color;
/**
* 验证码生成器类,可生成数字、大写、小写字母及三者混合类型的验证码。
* 支持自定义验证码字符数量;
* 支持自定义验证码图片的大小;
* 支持自定义需排除的特殊字符;
* 支持自定义干扰线的数量;
* 支持自定义验证码图文颜色
* @author org.javachina
* @version 1.01
*/
public class VerifyCode {
/**
* 验证码类型为仅数字 0~9
*/
public static final int TYPE_NUM_ONLY=0;
/**
* 验证码类型为仅字母,即大写、小写字母混合
*/
public static final int TYPE_LETTER_ONLY=1;
/**
* 验证码类型为数字、大写字母、小写字母混合
*/
public static final int TYPE_ALL_MIXED=2;
/**
* 验证码类型为数字、大写字母混合
*/
public static final int TYPE_NUM_UPPER=3;
/**
* 验证码类型为数字、小写字母混合
*/
public static final int TYPE_NUM_LOWER=4;
/**
* 验证码类型为仅大写字母
*/
public static final int TYPE_UPPER_ONLY=5;
/**
* 验证码类型为仅小写字母
*/
public static final int TYPE_LOWER_ONLY=6;
private VerifyCode(){}
/**
* 生成验证码字符串
* @param type 验证码类型,参见本类的静态属性
* @param length 验证码长度,大于0的整数
* @param exChars 需排除的特殊字符(仅对数字、字母混合型验证码有效,无需排除则为null)
* @return 验证码字符串
*/
public static String generateTextCode(int type,int length,String exChars){
if(length<=0) return "";
StringBuffer code=new StringBuffer();
int i=0;
Random r=new Random();
switch(type)
{
//仅数字
case TYPE_NUM_ONLY:
while(i<length){
int t=r.nextInt(10);
if(exChars==null||exChars.indexOf(t+"")<0){//排除特殊字符
code.append(t);
i++;
}
}
break;
//仅字母(即大写字母、小写字母混合)
case TYPE_LETTER_ONLY:
while(i<length){
int t=r.nextInt(123);
if((t>=97||(t>=65&&t<=90))&&(exChars==null||exChars.indexOf((char)t)<0)){
code.append((char)t);
i++;
}
}
break;
//数字、大写字母、小写字母混合
case TYPE_ALL_MIXED:
while(i<length){
int t=r.nextInt(123);
if((t>=97||(t>=65&&t<=90)||(t>=48&&t<=57))&&(exChars==null||exChars.indexOf((char)t)<0)){
code.append((char)t);
i++;
}
}
break;
//数字、大写字母混合
case TYPE_NUM_UPPER:
while(i<length){
int t=r.nextInt(91);
if((t>=65||(t>=48&&t<=57))&&(exChars==null||exChars.indexOf((char)t)<0)){
code.append((char)t);
i++;
}
}
break;
//数字、小写字母混合
case TYPE_NUM_LOWER:
while(i<length){
int t=r.nextInt(123);
if((t>=97||(t>=48&&t<=57))&&(exChars==null||exChars.indexOf((char)t)<0)){
code.append((char)t);
i++;
}
}
break;
//仅大写字母
case TYPE_UPPER_ONLY:
while(i<length){
int t=r.nextInt(91);
if((t>=65)&&(exChars==null||exChars.indexOf((char)t)<0)){
code.append((char)t);
i++;
}
}
break;
//仅小写字母
case TYPE_LOWER_ONLY:
while(i<length){
int t=r.nextInt(123);
if((t>=97)&&(exChars==null||exChars.indexOf((char)t)<0)){
code.append((char)t);
i++;
}
}
break;
}
return code.toString();
}
/**
* 已有验证码,生成验证码图片
* @param textCode 文本验证码
* @param width 图片宽度
* @param height 图片高度
* @param interLine 图片中干扰线的条数
* @param randomLocation 每个字符的高低位置是否随机
* @param backColor 图片颜色,若为null,则采用随机颜色
* @param foreColor 字体颜色,若为null,则采用随机颜色
* @param lineColor 干扰线颜色,若为null,则采用随机颜色
* @return 图片缓存对象
*/
public static BufferedImage generateImageCode(String textCode,int width,int height,int interLine,boolean randomLocation,Color backColor,Color foreColor,Color lineColor){
BufferedImage bim=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
Graphics g=bim.getGraphics();
//画背景图
g.setColor(backColor==null?getRandomColor():backColor);
g.fillRect(0,0,width,height);
//画干扰线
Random r=new Random();
if(interLine>0){
int x=0,y=0,x1=width,y1=0;
for(int i=0;i<interLine;i++){
g.setColor(lineColor==null?getRandomColor():lineColor);
y=r.nextInt(height);
y1=r.nextInt(height);
g.drawLine(x,y,x1,y1);
}
}
//写验证码
//字体大小为图片高度的80%
int fsize=(int)(height*0.8);
int fx=0;
int fy=fsize;
g.setFont(new Font(Font.DIALOG,Font.PLAIN,fsize));
//写验证码字符
for(int i=0;i<textCode.length();i++){
fy=randomLocation?(int)((Math.random()*0.3+0.6)*height):fy;//每个字符高低是否随机
g.setColor(foreColor==null?getRandomColor():foreColor);
g.drawString(textCode.charAt(i)+"",fx,fy);
fx+=(width / textCode.length()) * (Math.random() * 0.3 + 0.8); //星风兄的高见,依据宽度浮动
}
g.dispose();
return bim;
}
/**
* 产生随机颜色
* @return
*/
private static Color getRandomColor(){
Random r=new Random();
Color c=new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256));
return c;
}
}
4、org.javachina.servlet.VerifyCodeServlet.java 接受客户端请求,向客户端输出验证码
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//设置浏览器不缓存本页
response.setHeader("Cache-Control", "no-cache");
//生成验证码,写入用户session
String verifyCode=VerifyCode.generateTextCode(VerifyCode.TYPE_UPPER_ONLY,4,null);
request.getSession().setAttribute("verifyCode",verifyCode);
//输出验证码给客户端
response.setContentType("image/jpeg");
BufferedImage bim=VerifyCode.generateImageCode(verifyCode, 90, 30, 3,true,Color.WHITE,Color.BLACK,null);
ImageIO.write(bim, "JPEG",response.getOutputStream());
}
throws ServletException, IOException {
//设置浏览器不缓存本页
response.setHeader("Cache-Control", "no-cache");
//生成验证码,写入用户session
String verifyCode=VerifyCode.generateTextCode(VerifyCode.TYPE_UPPER_ONLY,4,null);
request.getSession().setAttribute("verifyCode",verifyCode);
//输出验证码给客户端
response.setContentType("image/jpeg");
BufferedImage bim=VerifyCode.generateImageCode(verifyCode, 90, 30, 3,true,Color.WHITE,Color.BLACK,null);
ImageIO.write(bim, "JPEG",response.getOutputStream());
}
5、org.javachina.servlet.PubMsgServlet.java 保存留言信息(比对验证码)
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//得到留言标题、内容及用户输入的验证码
String msgTitle=request.getParameter("msgTitle");
String msgContent=request.getParameter("msgContent");
String verifyCode=request.getParameter("verifyCode");
//取session中的正确验证码
String legalCode=null;
if(request.getSession().getAttribute("verifyCode")!=null)
legalCode=(String)(request.getSession().getAttribute("verifyCode"));
String next;
//比较session中的验证码与用户输入是否一致(这里忽略了大小写)
if(verifyCode!=null&&verifyCode.equalsIgnoreCase(legalCode)){
/*
* 保存留言内容(省略)
*/
//指定下一个URL
next=request.getContextPath()+"/ok.jsp";
}else
next="this";
response.setContentType("text/plain");
PrintWriter out = response.getWriter();
out.print(next);
out.flush();
out.close();
}
throws ServletException, IOException {
//得到留言标题、内容及用户输入的验证码
String msgTitle=request.getParameter("msgTitle");
String msgContent=request.getParameter("msgContent");
String verifyCode=request.getParameter("verifyCode");
//取session中的正确验证码
String legalCode=null;
if(request.getSession().getAttribute("verifyCode")!=null)
legalCode=(String)(request.getSession().getAttribute("verifyCode"));
String next;
//比较session中的验证码与用户输入是否一致(这里忽略了大小写)
if(verifyCode!=null&&verifyCode.equalsIgnoreCase(legalCode)){
/*
* 保存留言内容(省略)
*/
//指定下一个URL
next=request.getContextPath()+"/ok.jsp";
}else
next="this";
response.setContentType("text/plain");
PrintWriter out = response.getWriter();
out.print(next);
out.flush();
out.close();
}
以上源码、文档下载地址: http://download.csdn.net/source/1851509
以上,望抛砖引玉,欢迎交流:hufoking@hotmail.com!