把之前項(xiàng)目中寫的一個(gè)Java通用驗(yàn)證碼程序整理了一下,與大家分享,希望能拋磚引玉。
一、主要功能:
1、支持純數(shù)字、大寫字母、小寫字母,及兩兩混合或三者混合類型驗(yàn)證碼;
2、支持自定義特殊字符排除(如0oOi1jI);
3、支持圖片及文字兩種類型驗(yàn)證碼;
4、支持自定義驗(yàn)證碼圖片大小;
5、支持自定義干擾線條數(shù);
6、支持自定義及隨機(jī)定義圖片、文字、干擾線顏色;
其他:示例頁面提供了<iframe>和<img>兩種頁面顯示驗(yàn)證碼的方式。
a、僅阿拉伯?dāng)?shù)字

b、僅字母(大小寫混合)

c、僅小寫字母

d、僅大寫字母

d、數(shù)字與小寫字母混合

e、數(shù)字與大寫字母混合

f、數(shù)字與大小寫字母混合

g、自定義字符顏色(或隨機(jī))

h、自定義圖片顏色(或隨機(jī))

i、自定義干擾線的條數(shù)及顏色(或隨機(jī))

j、自定義驗(yàn)證碼圖片大小

k、自定義需排除的特殊字符(如0o等難分辨字符)

二、代碼說明:
1、pubMsg.jsp 發(fā)表留言頁面,實(shí)現(xiàn)<iframe>和<img>兩種顯示驗(yàn)證碼方式,及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;
//檢查輸入內(nèi)容格式
if(msgTitle.length<5||msgContent.length<5)
{
alert("標(biāo)題和內(nèi)容不能少于5個(gè)字符");
return;
}
if(verifyCode.length==0){
alert("請輸入驗(yàn)證碼");
return;
}
//獲得XMLHttpRequest對象
if(window.XMLHttpRequest)
req=new XMLHttpRequest();
else if(window.ActiveXObject)
req=new ActiveXObject("Microsoft.XMLHTTP");
//提交請求
if(req){
req.onreadystatechange=callBack;//指定服務(wù)器響應(yīng)結(jié)果處理函數(shù)(注意僅函數(shù)名無括號)
url="<%=path%>/servlet/PubMsgServlet?msgTitle="+msgTitle+"&msgContent="+msgContent+"&verifyCode="+verifyCode;
req.open("GET",url,false);
req.send();
}
}
//服務(wù)器響應(yīng)結(jié)果處理函數(shù)
function callBack(){
if(req.readyState==4){
if(req.status==200){
next=req.responseText;//獲得服務(wù)器處理結(jié)果
if(next=="this"){
alert("驗(yàn)證碼不正確,請重新輸入");
verifyCodeFrame.location.reload();//刷新驗(yàn)證碼
}
else{
document.msgForm.msgTitle.value="";
document.msgForm.msgContent.value="";
window.location=next;//跳轉(zhuǎn)頁面
}
}else
{
alert(req.status+":"+req.statusText);
}
}
document.msgForm.verifyCode.value="";
}
//更換驗(yàn)證碼
function changeVerifyCode(){
//1、如果用<iframe>實(shí)現(xiàn),則重新加載<iframe>的內(nèi)容
//verifyCodeFrame.location.reload();
//2、如果用<img>實(shí)現(xiàn),則修改<img src=url>的url
//這里有一個(gè)小技巧,如果給url賦相同的值,瀏覽器不會(huì)重新發(fā)出請求,因此用js生成一個(gè)即時(shí)毫秒數(shù)做url中的參數(shù)
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>標(biāo)題:</td><td><input name="msgTitle" size="65"/></td></tr>
<tr><td>內(nèi)容:</td><td><textarea name="msgContent" rows="10" cols="64"></textarea></td></tr>
<tr><td>驗(yàn)證碼:</td><td><input name="verifyCode" style="height:29px;width=70px;font-size:25px"/>
<!-- 以下:兩種顯示驗(yàn)證碼的方式 -->
<!-- 1、采用<iframe>實(shí)現(xiàn) -->
<!--
<iframe name="verifyCodeFrame" src="<%=path+"/servlet/VerifyCodeServlet"%>" width="100" height="30" frameborder=0 align="top" marginheight=0 marginwidth=0 scrolling=no></iframe>
-->
<!-- 2、采用<img>實(shí)現(xiàn) -->
<img name="verifyCodeImg" src="<%=path%>/servlet/VerifyCodeServlet" style="cursor:hand" align="top" onClick="changeVerifyCode()"/>
<!-- 以上:兩種顯示驗(yàn)證碼的方式 -->
<font style="color:blue;font-size=14"><a href="javascript:changeVerifyCode()">看不清?</a></font>
<input type="button" value=" 發(fā)表留言 " onClick="pubMsg()"/></td></tr>
</table>
</form>
</body>
</html>
2、ok.jsp 留言發(fā)布成功頁面(示意)

<%@ 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 驗(yàn)證碼生成器類
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;
/**
* 驗(yàn)證碼生成器類,可生成數(shù)字、大寫、小寫字母及三者混合類型的驗(yàn)證碼。
* 支持自定義驗(yàn)證碼字符數(shù)量;
* 支持自定義驗(yàn)證碼圖片的大小;
* 支持自定義需排除的特殊字符;
* 支持自定義干擾線的數(shù)量;
* 支持自定義驗(yàn)證碼圖文顏色
* @author org.javachina
* @version 1.01
*/
public class VerifyCode {
/**
* 驗(yàn)證碼類型為僅數(shù)字 0~9
*/
public static final int TYPE_NUM_ONLY=0;
/**
* 驗(yàn)證碼類型為僅字母,即大寫、小寫字母混合
*/
public static final int TYPE_LETTER_ONLY=1;
/**
* 驗(yàn)證碼類型為數(shù)字、大寫字母、小寫字母混合
*/
public static final int TYPE_ALL_MIXED=2;
/**
* 驗(yàn)證碼類型為數(shù)字、大寫字母混合
*/
public static final int TYPE_NUM_UPPER=3;
/**
* 驗(yàn)證碼類型為數(shù)字、小寫字母混合
*/
public static final int TYPE_NUM_LOWER=4;
/**
* 驗(yàn)證碼類型為僅大寫字母
*/
public static final int TYPE_UPPER_ONLY=5;
/**
* 驗(yàn)證碼類型為僅小寫字母
*/
public static final int TYPE_LOWER_ONLY=6;
private VerifyCode(){}
/**
* 生成驗(yàn)證碼字符串
* @param type 驗(yàn)證碼類型,參見本類的靜態(tài)屬性
* @param length 驗(yàn)證碼長度,大于0的整數(shù)
* @param exChars 需排除的特殊字符(僅對數(shù)字、字母混合型驗(yàn)證碼有效,無需排除則為null)
* @return 驗(yàn)證碼字符串
*/
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)
{
//僅數(shù)字
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;
//數(shù)字、大寫字母、小寫字母混合
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;
//數(shù)字、大寫字母混合
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;
//數(shù)字、小寫字母混合
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();
}
/**
* 已有驗(yàn)證碼,生成驗(yàn)證碼圖片
* @param textCode 文本驗(yàn)證碼
* @param width 圖片寬度
* @param height 圖片高度
* @param interLine 圖片中干擾線的條數(shù)
* @param randomLocation 每個(gè)字符的高低位置是否隨機(jī)
* @param backColor 圖片顏色,若為null,則采用隨機(jī)顏色
* @param foreColor 字體顏色,若為null,則采用隨機(jī)顏色
* @param lineColor 干擾線顏色,若為null,則采用隨機(jī)顏色
* @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);
}
}
//寫驗(yàn)證碼
//字體大小為圖片高度的80%
int fsize=(int)(height*0.8);
int fx=0;
int fy=fsize;
g.setFont(new Font(Font.DIALOG,Font.PLAIN,fsize));
//寫驗(yàn)證碼字符
for(int i=0;i<textCode.length();i++){
fy=randomLocation?(int)((Math.random()*0.3+0.6)*height):fy;//每個(gè)字符高低是否隨機(jī)
g.setColor(foreColor==null?getRandomColor():foreColor);
g.drawString(textCode.charAt(i)+"",fx,fy);
fx+=(width / textCode.length()) * (Math.random() * 0.3 + 0.8); //星風(fēng)兄的高見,依據(jù)寬度浮動(dòng)
}
g.dispose();
return bim;
}
/**
* 產(chǎn)生隨機(jī)顏色
* @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 接受客戶端請求,向客戶端輸出驗(yàn)證碼
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//設(shè)置瀏覽器不緩存本頁
response.setHeader("Cache-Control", "no-cache");
//生成驗(yàn)證碼,寫入用戶session
String verifyCode=VerifyCode.generateTextCode(VerifyCode.TYPE_UPPER_ONLY,4,null);
request.getSession().setAttribute("verifyCode",verifyCode);
//輸出驗(yàn)證碼給客戶端
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 保存留言信息(比對驗(yàn)證碼)
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//得到留言標(biāo)題、內(nèi)容及用戶輸入的驗(yàn)證碼
String msgTitle=request.getParameter("msgTitle");
String msgContent=request.getParameter("msgContent");
String verifyCode=request.getParameter("verifyCode");
//取session中的正確驗(yàn)證碼
String legalCode=null;
if(request.getSession().getAttribute("verifyCode")!=null)
legalCode=(String)(request.getSession().getAttribute("verifyCode"));
String next;
//比較session中的驗(yàn)證碼與用戶輸入是否一致(這里忽略了大小寫)
if(verifyCode!=null&&verifyCode.equalsIgnoreCase(legalCode)){
/*
* 保存留言內(nèi)容(省略)
*/
//指定下一個(gè)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!