驗(yàn)證碼圖片生成步驟
創(chuàng)建BufferedImage對(duì)象。
獲取BufferedImage的畫筆,即調(diào)用getGraphics()方法獲取Graphics對(duì)象。
調(diào)用Graphics對(duì)象的setColor()方法和fillRect()方法設(shè)置圖片背景顏色。
調(diào)用Graphics對(duì)象的setColor()方法和drawLine()方法設(shè)置圖片干擾線。
調(diào)用BufferedImaged對(duì)象的setRGB()方法設(shè)置圖片的噪點(diǎn)。
調(diào)用Graphics對(duì)象的setColor()方法、setFont()方法和drawString()方法設(shè)置圖片驗(yàn)證碼。
因?yàn)轵?yàn)證碼的圖片的寬度和高度要根據(jù)網(wǎng)站的風(fēng)格來(lái)確定的,所以字體的大小需要根據(jù)圖片的寬度和高度來(lái)確定,用到了小小的技巧。
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
package util; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Image; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Random; import javax.imageio.ImageIO; public class Verification { private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890" ; /** * 生成一個(gè)寬為width, 高為height, 驗(yàn)證碼為code的圖片 * @param width 圖片的寬 * @param height 圖片的高 * @param code 驗(yàn)證碼字符串 * @return 返回圖片驗(yàn)證碼 */ public static BufferedImage getImage( int width, int height, String code){ return getImage(width, height, code, 20 ); } /** * 生成一個(gè)寬為width, 高為height, 驗(yàn)證碼為code的圖片,圖片中干擾線的條數(shù)為lineCnt * @param width 圖片的寬 * @param height 圖片的高 * @param code 驗(yàn)證碼字符串 * @param lineCnt 干擾線的條數(shù),建議為10條左右,可根據(jù)結(jié)果適當(dāng)調(diào)整 * @return 返回圖片驗(yàn)證碼 */ public static BufferedImage getImage( int width, int height, String code, int lineCnt){ return createImage(width, height, code, lineCnt, 0.01 ); } /** * 生成一個(gè)寬為width, 高為height, 驗(yàn)證碼為code的圖片,圖片中干擾線的條數(shù)為lineCnt * 噪聲比為noiseRate,即圖片中噪音像素點(diǎn)的百分比 * @param width 圖片的寬 * @param height 圖片的高 * @param code 驗(yàn)證碼字符串 * @param lineCnt 干擾線的條數(shù),建議為10條左右,可根據(jù)結(jié)果適當(dāng)調(diào)整 * @param noiseRate 圖片中噪音像素點(diǎn)占總像素的百分比 * @return 返回圖片驗(yàn)證碼 */ public static BufferedImage getImage( int width, int height, String code, int lineCnt, double noiseRate){ return createImage(width, height, code, lineCnt, noiseRate); } /** * * 生成一個(gè)寬為width, 高為height, 驗(yàn)證碼為code的圖片,圖片中干擾線的條數(shù)為lineCnt * 噪聲比為noiseRate,即圖片中噪音像素點(diǎn)的百分比 * @param width 圖片的寬 * @param height 圖片的高 * @param code 驗(yàn)證碼字符串 * @param lineCnt 干擾線的條數(shù),建議為10條左右,可根據(jù)結(jié)果適當(dāng)調(diào)整 * @param noiseRate 圖片中噪音像素點(diǎn)占總像素的百分比 * @return 返回圖片驗(yàn)證碼 */ private static BufferedImage createImage( int width, int height, String code, int lineCnt, double noiseRate){ int fontWidth = (( int )(width * 0.8 )) / code.length(); int fontHeight = ( int )(height * 0.7 ); //為了在任意的width和height下都能生成良好的驗(yàn)證碼, //字體的大小為fontWdith何fontHeight中的小者, int fontSize = Math.min(fontWidth, fontHeight); //drawString時(shí)要用到 int paddingX = ( int ) (width * 0.1 ); int paddingY = height - (height - fontSize) / 2 ; //創(chuàng)建圖像 BufferedImage buffimg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); //獲得畫筆 Graphics g = buffimg.getGraphics(); //設(shè)置畫筆的顏色 g.setColor(getRandColor( 200 , 255 )); //然后填充一個(gè)矩形,即設(shè)置背景色 g.fillRect( 0 , 0 , width, height); // 設(shè)置干擾線 for ( int i = 0 ; i < lineCnt; i++) { //隨機(jī)獲取干擾線的起點(diǎn)和終點(diǎn) int xs = ( int )(Math.random() * width); int ys = ( int )(Math.random() * height); int xe = ( int )(Math.random() * width); int ye = ( int )(Math.random() * height); g.setColor(getRandColor( 1 , 255 )); g.drawLine(xs, ys, xe, ye); } // 添加噪點(diǎn) int area = ( int ) (noiseRate * width * height); for ( int i= 0 ; i<area; ++i){ int x = ( int )(Math.random() * width); int y = ( int )(Math.random() * height); buffimg.setRGB(x, y, ( int )(Math.random() * 255 )); } //設(shè)置字體 Font font = new Font( "Ravie" , Font.PLAIN, fontSize); g.setFont(font); for ( int i= 0 ; i<code.length(); ++i){ String ch = code.substring(i, i+ 1 ); g.setColor(getRandColor( 1 , 199 )); g.drawString(ch, paddingX + fontWidth * i, paddingY); } return buffimg; } /** * 獲取隨機(jī)的顏色,r,g,b的取值在L到R之間 * @param L 左區(qū)間 * @param R 右區(qū)間 * @return 返回隨機(jī)顏色值 */ private static Color getRandColor( int L, int R){ if (L > 255 ) L = 255 ; if (R > 255 ) R = 255 ; if (L < 0 ) L = 0 ; if (R < 0 ) R = 0 ; int interval = R - L; int r = L + ( int )(Math.random() * interval); int g = L + ( int )(Math.random() * interval); int b = L + ( int )(Math.random() * interval); return new Color(r, g, b); } /** * 隨機(jī)生成若干個(gè)由大小寫字母和數(shù)字組成的字符串 * @param len 隨機(jī)生成len個(gè)字符 * @return 返回隨機(jī)生成的若干個(gè)由大小寫字母和數(shù)字組成的字符串 */ public static String getRandCode( int len){ String code = "" ; for ( int i= 0 ; i<len; ++i){ int index = ( int )(Math.random() * ALPHABET.length()); code = code + ALPHABET.charAt(index); } return code; } /** * 將圖片轉(zhuǎn)為byte數(shù)組 * @param image 圖片 * @return 返回byte數(shù)組 * @throws IOException */ public static byte [] getByteArray(BufferedImage image) throws IOException{ ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(image, "png" , baos); return baos.toByteArray(); //ByteArrayOutputStream 不需要close } } |
使用驗(yàn)證碼圖片
在verificationCode.java這個(gè)servlet中調(diào)用上面的類生成驗(yàn)證碼圖片,然后將圖片返回給客戶端。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); //隨機(jī)生成字符串,并寫入session String code = Verification.getRandCode( 4 ); session.setAttribute( "verification" , code); BufferedImage image = util.Verification.getImage( 100 , 30 , code, 5 ); response.setContentType( "image/png" ); OutputStream out = response.getOutputStream(); out.write(util.Verification.getByteArray(image)); out.flush(); out.close(); } |
在index.jsp中設(shè)置驗(yàn)證碼,用戶點(diǎn)擊驗(yàn)證碼時(shí),調(diào)用js代碼請(qǐng)求服務(wù)器得到新的驗(yàn)證碼。因?yàn)樯厦娴哪莻€(gè)生成驗(yàn)證碼的servlet會(huì)被瀏覽器緩存,所以js代碼中需要給該servlet一個(gè)隨機(jī)的參數(shù),這樣瀏覽器就會(huì)向服務(wù)器發(fā)請(qǐng)求得到新的驗(yàn)證碼,而不是去緩存中讀取。
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
|
<%@page import="util.Verification"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!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" > < title >Insert title here</ title > < script type = "text/javascript" > function refreshcode(){ document.getElementById("verification").src= "/verificationCode/verificationCode?hehe="+Math.random(); } </ script > </ head > < body > < form action = "<%=request.getContextPath()+" /checkVerification" %>" method="post"> 驗(yàn)證碼:< input type = "text" name = "submitVerification" > < img id = "verification" alt = "" title = "看不清點(diǎn)擊刷新驗(yàn)證碼" src = "<%=request.getContextPath()+" /verificationCode" %>" onclick="refreshcode()">< br > < input type = "submit" name = "submit" value = "提交" > </ form > </ body > </ html > |
最后是在checkVerification.java這個(gè)servlet中判斷用戶輸入的驗(yàn)證碼是否正確,為了方便用戶,驗(yàn)證碼一般都設(shè)置成大小寫不敏感,所以要先轉(zhuǎn)化為小寫字母再比對(duì)。
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
|
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); String verification = (String)session.getAttribute( "verification" ); String submitVerification = request.getParameter( "submitVerification" ); PrintWriter out = response.getWriter(); if (verification!= null && submitVerification!= null ){ if (verification.toLowerCase().equals(submitVerification.toLowerCase())){ out.println( "yes!!!" ); } else { out.println( "no!!!" ); } } else { out.println( "no!!!" ); } session.removeAttribute( "verification" ); //防止用戶重復(fù)提交表單 } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } |
最后運(yùn)行的效果圖如下
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。