只需几步就可以生成动态随机的验证码,最终效果如下图:
一 前台显示页面login.jsp
其中验证码显示的是一张图片,链接指向的是生成验证码的servlet,同时点击图片后触发changeImg()这个js函数,使其动态生成一个新的验证码,这个函数中的参数t=Math.random()并不会参与验证码的生成,它的作用仅仅只是表示每次提交的并不是同一个请求,需要单独处理,完整的login.jsp代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<
html
>
<
head
>
<
meta
http-equiv
=
"Content-Type"
content
=
"text/html; charset=UTF-8"
>
<
base
href="<%=basePath%>">
<%@ include file="head.txt"%>
<
script
type
=
"text/javascript"
>
//刷新验证码
function changeImg(){
document.getElementById("validateCodeImg").src="helpDrawValidateCode?t=" + Math.random();
}
</
script
>
</
head
>
<
body
>
<
font
size
=
3
>
<
center
>
<
form
action
=
"helpLogin"
name
=
""
method
=
"post"
>
<
table
>
<
tr
><
th
>请您登陆:</
th
></
tr
>
<
tr
><
td
align
=
left
>会员名称:</
td
><
td
><
input
type
=
text
name
=
"id"
></
td
></
tr
>
<
tr
><
td
align
=
left
>输入密码:</
td
><
td
><
input
type
=
password
name
=
"password"
></
td
></
tr
>
</
table
>
<
br
>验证码:<
input
type
=
"text"
name
=
"validateCode"
style
=
"width:50px"
>
<
img
alt
=
"看不清?换一张"
src
=
"helpDrawValidateCode"
id
=
"validateCodeImg"
onclick
=
"changeImg()"
>
<
br
><
input
type
=
"submit"
value
=
"提交"
>
</
form
>
</
center
>
</
font
>
</
body
>
</
html
>
|
二 修改web.xml
新增一个节点,代码如下:
1
2
3
4
5
6
7
8
9
|
<!-- 验证码绘制 -->
<
servlet
>
<
servlet-name
>drawValidateCode</
servlet-name
>
<
servlet-class
>com.zifangsky.OnlineFriend.servlet.member.HandleDrawValidateCode</
servlet-class
>
</
servlet
>
<
servlet-mapping
>
<
servlet-name
>drawValidateCode</
servlet-name
>
<
url-pattern
>/helpDrawValidateCode</
url-pattern
>
</
servlet-mapping
>
|
三 后台的servlet文件HandleDrawValidateCode.java
这个文件主要负责处理前台请求,并返回生成的验证码图片,同时将图片上的随机字符存入session中,以供登录时进行验证,HandleDrawValidateCode.java完整代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
package
com.zifangsky.OnlineFriend.servlet.member;
import
java.awt.Color;
import
java.awt.Font;
import
java.awt.Graphics;
import
java.awt.Graphics2D;
import
java.awt.image.BufferedImage;
import
java.io.IOException;
import
java.util.Random;
import
javax.imageio.ImageIO;
import
javax.servlet.ServletConfig;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
javax.servlet.http.HttpSession;
/**
* 生成随机图片用做验证码
* */
public
class
HandleDrawValidateCode
extends
HttpServlet{
private
static
final
long
serialVersionUID = 1L;
private
static
final
int
WIDTH =
120
;
//图片宽度
private
static
final
int
HEIGHT =
30
;
//图片高度
public
void
init(ServletConfig config)
throws
ServletException{
super
.init(config);
}
public
void
doPost(HttpServletRequest request,HttpServletResponse response)
throws
ServletException,IOException{
request.setCharacterEncoding(
"utf-8"
);
response.setCharacterEncoding(
"utf-8"
);
HttpSession session = request.getSession(
true
);
//创建一张图片
BufferedImage bufferedImage =
new
BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
//得到图片
Graphics graphics = bufferedImage.getGraphics();
//设置图片背景色
setBackGround(graphics);
//设置图片边框
setBordor(graphics);
//在图片上画干扰线,用了4种颜色,共20条线条
drawRandomLine(graphics,Color.GREEN);
drawRandomLine(graphics,
new
Color(
246
,
255
,
145
));
drawRandomLine(graphics,
new
Color(
225
,
174
,
252
));
drawRandomLine(graphics,
new
Color(
120
,
202
,
254
));
//在图片上写随机字符,并记录生成的序列
String randomText = drawRandomText((Graphics2D) graphics);
//将生成的字符存入session中
session.setAttribute(
"checkcode"
, randomText);
//设置响应头通知浏览器以图片的形式打开
response.setContentType(
"image/jpeg"
);
//设置响应头控制浏览器不要缓存
response.setDateHeader(
"expries"
, -
1
);
response.setHeader(
"Cache-Control"
,
"no-cache"
);
response.setHeader(
"Pragma"
,
"no-cache"
);
//将图片写给浏览器
ImageIO.write(bufferedImage,
"jpg"
, response.getOutputStream());
}
/**
* 设置图片背景色
* */
private
void
setBackGround(Graphics graphics) {
graphics.setColor(Color.WHITE);
graphics.fillRect(
0
,
0
, WIDTH, HEIGHT);
}
/**
* 设置图片边框
* */
private
void
setBordor(Graphics graphics) {
graphics.setColor(Color.BLUE);
graphics.drawRect(
1
,
1
, WIDTH -
2
, HEIGHT -
2
);
}
/**
* 在图片上画干扰线
* */
private
void
drawRandomLine(Graphics graphics,Color color) {
graphics.setColor(color);
//设置线条个数并画线
for
(
int
i =
0
;i <
5
;i++){
int
x1 =
new
Random().nextInt(WIDTH);
int
x2 =
new
Random().nextInt(WIDTH);
int
y1 =
new
Random().nextInt(HEIGHT);
int
y2 =
new
Random().nextInt(HEIGHT);
graphics.drawLine(x1, y1, x2, y2);
}
}
/**
* 在图片上写随机字符,数字和字母的组合
* @param length 字符串的长度
*
* @return 返回生成的字符串序列
* */
private
String drawRandomText(Graphics2D graphics) {
graphics.setColor(Color.RED);
graphics.setFont(
new
Font(
"宋体"
, Font.BOLD,
20
));
//数字和字母的组合
String baseNumLetter =
"123456789ABCDEFGHJKLMNPQRSTUVWXYZ"
;
StringBuffer sBuffer =
new
StringBuffer();
int
x =
5
;
//旋转原点的 x 坐标
String ch =
""
;
Random random =
new
Random();
for
(
int
i =
0
;i <
4
;i++){
//设置字体旋转角度
int
degree = random.nextInt() %
30
;
//角度小于30度
int
dot = random.nextInt(baseNumLetter.length());
ch = baseNumLetter.charAt(dot) +
""
;
sBuffer.append(ch);
//正向旋转
graphics.rotate(degree * Math.PI /
180
, x,
20
);
graphics.drawString(ch, x,
20
);
//反向旋转
graphics.rotate(-degree * Math.PI /
180
, x,
20
);
x +=
30
;
}
return
sBuffer.toString();
}
public
void
doGet(HttpServletRequest request,HttpServletResponse response)
throws
ServletException,IOException{
doPost(request, response);
}
}
|
注:
在这里,干扰线的颜色和数目都可以自己设定,颜色可以使用随机色,同时显示的每个文字也可以使用随机的颜色,可以增加验证码识别难度,当然在这里我把比较容易混淆的0和O以及I都给去掉了。如果选用经过编码的中文字符的话,也是可以生成中文验证码的
四 login.jsp页面提交表单后,后台的servlet文件HandleLogin.java校验验证码,并进行登录验证
经过上面的三个步骤后,login.jsp应该是可以正确显示验证码了,同时点击验证码图片后会生成一个新的验证码,login.jsp提交表单后HandleLogin.java文件验证验证码时主要是:将输入的验证码中的小写字母转换成大写,再和验证码生成时保存在session中的字符串比较,如果相同,则表示输入正确,同时移除session中设置的值,防止重复提交,爆破密码,HandleLogin.java相关代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
package
com.zifangsky.OnlineFriend.servlet.member;
import
java.io.IOException;
import
java.sql.Connection;
import
java.sql.PreparedStatement;
import
java.sql.ResultSet;
import
java.sql.SQLException;
import
javax.servlet.RequestDispatcher;
import
javax.servlet.ServletConfig;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
javax.servlet.http.HttpSession;
import
com.zifangsky.OnlineFriend.model.member.Login;
import
com.zifangsky.OnlineFriend.util.DbConn;
import
com.zifangsky.OnlineFriend.util.StringUtil;
public
class
HandleLogin
extends
HttpServlet{
|