把之前项目中写的一个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提交功能
<%
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 留言发布成功页面(示意)
<!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 验证码生成器类
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 接受客户端请求,向客户端输出验证码
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 保存留言信息(比对验证码)
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();
}
一些小瑕疵:
1.生成图片时,传入的宽度没用上导致宽度过小时字符超出图片宽度。
// 写验证码字符
...
// fx += fsize * 0.9; // 原代码
// 根据传入宽度调整字距并随机±20%浮动
fx += (width / textCode.length()) * (Math.random() * 0.4 + 0.8);
...
2.VerifyCode.generateImageCode()的第二个重载无法拿到随机生成的字符串,没有任何意义。可以增加一个方法getLastTextCode()获取但又必须保证线程安全,还不如删掉。
3.随机颜色里
Color c = new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255));
应该是256
4.生成验证码字符串的那一大段swich完全可以简化,这样太繁冗了。
可以这样写(只是一个思路,没有测试):
// 添加一个静态字段
static char[] chars = {数字,大写字母,小写字母};
...
// 方法内替换switch
int begin = 0;
int end = 0;
switch (type) {
case TYPE_NUM_ONLY:
begin = 0;
end = 10; // 第10个不是数字
break;
// 其他的case...
}
while (i < length) {
int t = r.nextInt(end - begin); // 如果end设为9,这里要+1
code.append(chars[t + begin]);
i++;
}
...
相关推荐
以下是对"Java通用验证码及应用示例"的详细解释: 1. **验证码的基本原理**: 验证码通常由随机生成的一串字符或数字组成,这些字符在显示时被扭曲、旋转或以其他方式混淆,以增加机器识别的难度。用户需要正确...
可供多种编程语言调用(vc、vb、delphi、java、c#、vb.net、asp、模拟精灵等),调用简单、灵活,可以通过传递文件名或图片数据流两种方式进行识别,提供函数调用说明及各种语言的调用代码示例。详请请访问官方网站...
**正文** ...通过这个Java实现的SMGP协议,开发者可以轻松地集成短信功能到自己的应用程序中,提高系统的通信能力。同时,提供的示例代码可以帮助初学者更好地理解和实践SMGP协议,降低开发难度。
Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...
Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...
Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...
Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...
Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...
Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...
Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...
SSH是三个开源Java框架的缩写,分别是Struts2、Hibernate3和Spring2.5,它们常被用于构建企业级的Web应用程序。SSH框架的整合提供了模型-视图-控制器(MVC)架构,持久层管理和依赖注入等功能,极大地提高了开发效率...
Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...
Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...
短信接口是服务提供商提供的一种API(应用程序编程接口),允许开发者通过编程方式发送和接收短信。这种接口通常包括发送验证码、订单通知等功能,可以极大地提高用户体验和业务效率。 在提供的"SDK二次接口文档...
Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...
Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...
Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...
中国联通作为中国三大电信运营商之一,提供了丰富的API和SDK供开发者使用,以便在各种应用程序中发送和接收短信。 联通短信服务的Java代码实现主要包括以下几个核心概念和技术: 1. **SMS协议**:联通短信服务可能...