`
yxw22
  • 浏览: 24956 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java通用验证码程序及应用示例

阅读更多

把之前项目中写的一个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提交功能


<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><%@ 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"><href="javascript:changeVerifyCode()">看不清?</a></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
  
<input type="button" value=" 发表留言 " onClick="pubMsg()"/></td></tr>

  
</table>
  
</form>
  
  
</body>
  
</html>

 


2、ok.jsp 留言发布成功页面(示意)

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><%@ 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>


3、org.javachina.util.VerifyCode.java 验证码生成器类

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->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<=0return "";
        
        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 接受客户端请求,向客户端输出验证码

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->    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, 90303,true,Color.WHITE,Color.BLACK,null);
        ImageIO.write(bim, 
"JPEG",response.getOutputStream());    
        
    }


5、org.javachina.servlet.PubMsgServlet.java 保存留言信息(比对验证码)

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->    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();
        
    }

一些小瑕疵:
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通用验证码及应用示例

    强大的JAVA通用验证码程序,含源码、示例及文档

    通用图形验证码识别程序(引擎)

    可供多种编程语言调用(vc、vb、delphi、java、c#、vb.net、asp、模拟精灵等),调用简单、灵活,可以通过传递文件名或图片数据流两种方式进行识别,提供函数调用说明及各种语言的调用代码示例。详请请访问官方网站...

    经典JAVA.EE企业应用实战.基于WEBLOGIC_JBOSS的JSF_EJB3_JPA整合开发.pdf

    中文名: 经典Java EE企业应用实战--基于WebLogic/JBoss的JSF+EJB 3+JPA整合开发 原名: 经典Java EE企业应用实战--基于WebLogic/JBoss的JSF+EJB 3+JPA整合开发 作者: 李刚 资源格式: PDF 版本: 第一版 出版社: 电子...

    java开源包4

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包11

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包6

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包101

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包9

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包5

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包8

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包10

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    JAVA上百实例源码以及开源项目

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...

    java开源包1

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包3

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    JAVA上百实例源码以及开源项目源代码

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...

    java开源包2

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    java开源包7

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

    Java资源包01

    Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端...

Global site tag (gtag.js) - Google Analytics