TA的每日心情 | 开心 2021-3-12 23:18 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
把之前项目中写的一个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
>
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
>
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);
}
}
//
写验证码
//
g.setColor(getRandomColor());
//
g.setColor(isSimpleColor?Color.BLACK:Color.WHITE);
//
字体大小为图片高度的80%
int
fsize
=
(
int
)(height
*
0.8
);
int
fx
=
height
-
fsize;
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
+=
fsize
*
0.9
;
}
g.dispose();
return
bim;
}
/**
* 生成图片验证码
*
@param
type 验证码类型,参见本类的静态属性
*
@param
length 验证码字符长度,大于0的整数
*
@param
exChars 需排除的特殊字符
*
@param
width 图片宽度
*
@param
height 图片高度
*
@param
interLine 图片中干扰线的条数
*
@param
randomLocation 每个字符的高低位置是否随机
*
@param
backColor 图片颜色,若为null,则采用随机颜色
*
@param
foreColor 字体颜色,若为null,则采用随机颜色
*
@param
lineColor 干扰线颜色,若为null,则采用随机颜色
*
@return
图片缓存对象
*/
public
static
BufferedImage generateImageCode(
int
type,
int
length,String exChars,
int
width,
int
height,
int
interLine,
boolean
randomLocation,Color backColor,Color foreColor,Color lineColor){
String textCode
=
generateTextCode(type,length,exChars);
BufferedImage bim
=
generateImageCode(textCode,width,height,interLine,randomLocation,backColor,foreColor,lineColor);
return
bim;
}
/**
* 产生随机颜色
*
@return
*/
private
static
Color getRandomColor(){
Random r
=
new
Random();
Color c
=
new
Color(r.nextInt(
255
),r.nextInt(
255
),r.nextInt(
255
));
return
c;
}
public
static
void
main(String[] args){
}
}
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());
}
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();
}
源码下载:http://file.javaxxz.com/2014/10/2/085400516.zip |
|