自己写一个图片验证码程序

本程序基于struts2,用action响应请求。

一、首先,创建一个用于产生随即验证码图片的类ImageCode.java.

  1 package com.exp.image;
  2 
  3 import java.awt.BasicStroke;
  4 import java.awt.Color;
  5 import java.awt.Font;
  6 import java.awt.Graphics;
  7 import java.awt.Graphics2D;
  8 import java.awt.RenderingHints;
  9 import java.awt.geom.AffineTransform;
 10 import java.awt.image.BufferedImage;
 11 import java.io.ByteArrayInputStream;
 12 import java.io.ByteArrayOutputStream;
 13 import java.io.File;
 14 import java.io.FileNotFoundException;
 15 import java.io.FileOutputStream;
 16 import java.io.IOException;
 17 import java.io.OutputStream;
 18 import java.util.Random;
 19 
 20 import javax.ejb.Init;
 21 import javax.imageio.ImageIO;
 22 import javax.imageio.stream.ImageOutputStream;
 23 
 24 public class ImageCode {
 25     private static Random random = new Random();// 随机数对象
 26     private static ByteArrayInputStream inputStream;// 字节数组输入流对象
 27     private static String randString;// 随机生成的字符串
 28     private static ImageCode imageCode;// 本类对象
 29     // 以下是系统默认参数
 30     private static int nums = 6;// 验证码位数
 31     private static int width = 80;// 图片宽
 32     private static int height = 22;// 图片高
 33     private static int left = 4;// 字符输出左边距
 34     private static int top = 18;// 字符输出上边距
 35     private static int fontSize = 22;// 字符输出上边距
 36     private static String charSet = "0123456789abcdefghijklmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ";// 验证码字符集合
 37     private static int stringMinColor = 100;// 字符最低颜色值
 38     private static int stringMaxColor = 177;// 字符最高颜色值
 39     private static int otherMinColor = 178;// 干扰线和噪点最低颜色值
 40     private static int otherMaxColor = 255;// 干扰线和噪点最高颜色值
 41     private static Color backgroundColor = Color.cyan;// 图片背景色
 42     private static boolean isShear = false;// 是否进行字符扭曲
 43 
 44     /**
 45      * 单例模式
 46      */
 47     static {
 48         if (imageCode == null) {
 49             imageCode = new ImageCode();
 50         }
 51     }
 52 
 53     /**
 54      * 设置综合信息
 55      * 
 56      * @param nums
 57      *            验证码位数
 58      * @param width
 59      *            图片宽度,默认值80
 60      * @param height
 61      *            图片高度,默认值22
 62      * @param left
 63      *            字符输出左边距,默认4
 64      * @param top
 65      *            字符输出上边距,默认20
 66      * @param fontSize
 67      *            字符大小,默认22
 68      * @param charSet
 69      *            验证码字符集合字符串,默认为
 70      *            "0123456789abcdefghijklmnpqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
 71      * @param stringMinColor
 72      *            字符输出最小颜色值,默认100
 73      * @param stringMaxColor
 74      *            字符输出最大颜色值,默认177
 75      * @param otherMinColor
 76      *            干扰线和噪点最小颜色值,默认178
 77      * @param otherMaxColor
 78      *            干扰线和噪点最大颜色值,默认255
 79      * @param backgroundColor
 80      *            图片背景色,默认Color.cyan
 81      * @param isShear
 82      *            是否进行单个字符扭曲,默认false
 83      */
 84     public static void set(int nums, int width, int height, int left, int top,
 85             int fontSize, String charSet, int stringMinColor,
 86             int stringMaxColor, int otherMinColor, int otherMaxColor,
 87             Color backgroundColor,boolean isShear) {
 88         // 设置验证码位数
 89         if (nums != 0) {
 90             ImageCode.nums = nums;
 91         }
 92         // 设置验证码图片宽度
 93         if (width != 0) {
 94             ImageCode.width = width;
 95         }
 96         // 设置验证码图片高度
 97         if (height != 0) {
 98             ImageCode.height = height;
 99         }
100         // 设置验证码字符输出左边距
101         if (left != 0) {
102             ImageCode.left = left;
103         }
104         // 设置验证码字符输出上边距
105         if (top != 0) {
106             ImageCode.top = top;
107         }
108         // 设置验证码字符大小
109         if (fontSize != 0) {
110             ImageCode.fontSize = fontSize;
111         }
112         // 设置验证码字符集合字符串
113         if (charSet != null) {
114             ImageCode.charSet = charSet;
115         }
116         // 设置验证码字符输出最小颜色值
117         if (stringMinColor != 0) {
118             ImageCode.stringMinColor = stringMinColor;
119         }
120         // 设置验证码字符输出最大颜色值
121         if (stringMaxColor != 0) {
122             ImageCode.stringMaxColor = stringMaxColor;
123         }
124         // 设置验证码干扰线和噪点最小颜色值
125         if (otherMinColor != 0) {
126             ImageCode.otherMinColor = otherMinColor;
127         }
128         // 设置验证码干扰线和噪点最大颜色值
129         if (otherMaxColor != 0) {
130             ImageCode.otherMaxColor = otherMaxColor;
131         }
132         // 设置验证码图片背景色
133         if (backgroundColor != null) {
134             ImageCode.backgroundColor = backgroundColor;
135         }
136         // 设置验证码图片背景色
137             ImageCode.isShear = isShear;
138     }
139 
140     /**
141      * 创建随机图片,生成随机字符串
142      */
143     public static void createRandomImage() {
144         // 建立内存图像
145         BufferedImage image = new BufferedImage(width, height,
146                 BufferedImage.TYPE_INT_RGB);
147         // 创建图形上下文
148         Graphics2D g = image.createGraphics();
149         // 消除线段的锯齿边缘
150         g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
151                 RenderingHints.VALUE_ANTIALIAS_ON);
152         // 设置底色
153         g.setColor(Color.PINK);
154         // 绘制填充矩形
155         g.fillRect(0, 0, width, height);
156         // 绘制干扰线
157         for (int i = 0; i < 200; i++) {
158             g.setColor(getRandColor(otherMinColor, otherMaxColor));
159             g.setStroke(new BasicStroke(1f));
160             int x1 = random.nextInt(width);
161             int y1 = random.nextInt(height);
162             int x2 = random.nextInt(width * 2);
163             int y2 = random.nextInt(height * 2);
164             g.drawLine(x1, y1, x2, y2);
165         }
166 
167         // 获得字符串
168         StringBuffer sBuffer = new StringBuffer();
169 
170         // 按位数拼接随机字符串
171         for (int i = 0; i < nums; i++) {
172             // 根据随机数在charSet中寻找字符
173             sBuffer.append(charSet.charAt(random.nextInt(charSet.length())));
174         }
175         String code = sBuffer.toString();// 这个字符串是包含大小写字母的,不包括Oo
176         setRandString(code.toLowerCase());// 所有字母转小写
177 
178         // 绘制字符串
179         if (isShear) {
180             // 字符逐个扭曲输出
181             shearEveryChar(g, code, 0, 127);
182         } else {
183             // 输出字符串,这是不进行单个字符扭曲的选择
184             g.setColor(getRandColor(stringMinColor, stringMaxColor));
185             g.setFont(new Font("黑体", Font.BOLD + Font.ITALIC, 22));
186             g.drawString(code, left, top);
187         }
188 
189         // 绘制噪点
190         drawNoise(g, image, 0.05f);
191 
192         // 扭曲整个图片
193         // shear(g, width, height, getRandColor(128, 255));// 使图片扭曲
194 
195         // 设置输出流
196         ByteArrayOutputStream bos = new ByteArrayOutputStream();
197         try {
198             ImageOutputStream ios = ImageIO.createImageOutputStream(bos);
199             ImageIO.write(image, "jpg", ios);
200             ByteArrayInputStream bis = new ByteArrayInputStream(
201                     bos.toByteArray());
202             setInputStream(bis);
203             bos.flush();
204             bis.close();
205             ios.close();
206         } catch (IOException e) {
207             e.printStackTrace();
208         } finally {
209             try {
210                 bos.flush();
211                 bos.close();
212             } catch (IOException e) {
213                 e.printStackTrace();
214             }
215         }
216 
217     }
218 
219     /**
220      * 绘制噪点
221      * 
222      * @param g
223      * @param image
224      * @param yRote
225      */
226     public static void drawNoise(Graphics2D g, BufferedImage image, float yRote) {
227         int area = (int) (yRote * width * height);
228         for (int i = 0; i < area; i++) {
229             g.setStroke(new BasicStroke(2f));
230             int x = random.nextInt(width);
231             int y = random.nextInt(height);
232             int rgb = getRandomIntColor();
233             image.setRGB(x, y, rgb);
234         }
235     }
236 
237     /**
238      * 字符逐个扭曲输出
239      * 
240      * @param g
241      * @param code
242      */
243     public static void shearEveryChar(Graphics2D g, String code,
244             int stringMinColor, int stringMaxColor) {
245         int fontSize = height - 4;
246         Font font = new Font("黑体", Font.BOLD + Font.ITALIC, fontSize);
247         g.setFont(font);
248         char[] chars = code.toCharArray();
249         for (int i = 0; i < code.length(); i++) {
250             g.setColor(getRandColor(stringMinColor, stringMaxColor));
251             AffineTransform affine = new AffineTransform();
252             affine.setToRotation(
253                     Math.PI / 4 * random.nextDouble()
254                             * (random.nextBoolean() ? 1 : -1),
255                     (width / code.length()) * i + fontSize / 2, height / 2);
256             g.setTransform(affine);
257             g.drawChars(chars, i, 1, ((width - 10) / code.length()) * i + 5,
258                     height / 2 + fontSize / 2 - 3);
259         }
260     }
261 
262     /**
263      * 获得随机颜色
264      * 
265      * @param fc
266      *            颜色起始值
267      * @param bc
268      *            颜色终止值
269      * @return 返回Color对象
270      */
271     private static Color getRandColor(int fc, int bc) {
272         if (fc > 255)
273             fc = 255;
274         if (bc > 255)
275             bc = 255;
276         int r = fc + random.nextInt(bc - fc);
277         int g = fc + random.nextInt(bc - fc);
278         int b = fc + random.nextInt(bc - fc);
279         return new Color(r, g, b);
280     }
281 
282     /**
283      * 获得整型随机色
284      * 
285      * @return
286      */
287     private static int getRandomIntColor() {
288         int[] rgb = getRandomRgb();
289         int color = 0;
290         for (int c : rgb) {
291             color = color << 8;
292             color = color | c;
293         }
294         return color;
295     }
296 
297     /**
298      * 获得随机数组,适配整数类型的颜色值
299      * 
300      * @return
301      */
302     private static int[] getRandomRgb() {
303         int[] rgb = new int[3];
304         for (int i = 0; i < 3; i++) {
305             rgb[i] = random.nextInt(255);
306         }
307         return rgb;
308     }
309 
310     // 整个图片扭曲
311     private static void shear(Graphics g, int w1, int h1, Color color) {
312         shearX(g, w1, h1, color);
313         shearY(g, w1, h1, color);
314     }
315 
316     // X轴扭曲
317     private static void shearX(Graphics g, int w1, int h1, Color color) {
318         int period = random.nextInt(2);
319         boolean borderGap = true;
320         int frames = 1;
321         int phase = random.nextInt(2);
322 
323         for (int i = 0; i < h1; i++) {
324             double d = (double) (period >> 1)
325                     * Math.sin((double) i / (double) period
326                             + (6.2831853071795862D * (double) phase)
327                             / (double) frames);
328             g.copyArea(0, i, w1, 1, (int) d, 0);
329             if (borderGap) {
330                 g.setColor(color);
331                 g.drawLine((int) d, i, 0, i);
332                 g.drawLine((int) d + w1, i, w1, i);
333             }
334         }
335 
336     }
337 
338     // Y轴扭曲
339     private static void shearY(Graphics g, int w1, int h1, Color color) {
340         int period = random.nextInt(40) + 10; // 50;
341         boolean borderGap = true;
342         int frames = 20;
343         int phase = 7;
344         for (int i = 0; i < w1; i++) {
345             double d = (double) (period >> 1)
346                     * Math.sin((double) i / (double) period
347                             + (6.2831853071795862D * (double) phase)
348                             / (double) frames);
349             g.copyArea(i, 0, 1, h1, 0, (int) d);
350             if (borderGap) {
351                 g.setColor(color);
352                 g.drawLine(i, (int) d, i, 0);
353                 g.drawLine(i, (int) d + h1, i, h1);
354             }
355 
356         }
357 
358     }
359 
360     // 封装
361     public static ByteArrayInputStream getInputStream() {
362         return inputStream;
363     }
364 
365     public static void setInputStream(ByteArrayInputStream inputStream) {
366         ImageCode.inputStream = inputStream;
367     }
368 
369     public static String getRandString() {
370         return randString;
371     }
372 
373     public static int getNums() {
374         return nums;
375     }
376 
377     public static void setNums(int nums) {
378         ImageCode.nums = nums;
379     }
380 
381     public static int getWidth() {
382         return width;
383     }
384 
385     public static void setWidth(int width) {
386         ImageCode.width = width;
387     }
388 
389     public static int getHeight() {
390         return height;
391     }
392 
393     public static void setHeight(int height) {
394         ImageCode.height = height;
395     }
396 
397     public static int getLeft() {
398         return left;
399     }
400 
401     public static void setLeft(int left) {
402         ImageCode.left = left;
403     }
404 
405     public static int getTop() {
406         return top;
407     }
408 
409     public static void setTop(int top) {
410         ImageCode.top = top;
411     }
412 
413     public static String getCharSet() {
414         return charSet;
415     }
416 
417     public static void setCharSet(String charSet) {
418         ImageCode.charSet = charSet;
419     }
420 
421     public static int getStringMinColor() {
422         return stringMinColor;
423     }
424 
425     public static void setStringMinColor(int stringMinColor) {
426         ImageCode.stringMinColor = stringMinColor;
427     }
428 
429     public static int getStringMaxColor() {
430         return stringMaxColor;
431     }
432 
433     public static void setStringMaxColor(int stringMaxColor) {
434         ImageCode.stringMaxColor = stringMaxColor;
435     }
436 
437     public static int getOtherMinColor() {
438         return otherMinColor;
439     }
440 
441     public static void setOtherMinColor(int otherMinColor) {
442         ImageCode.otherMinColor = otherMinColor;
443     }
444 
445     public static int getOtherMaxColor() {
446         return otherMaxColor;
447     }
448 
449     public static void setOtherMaxColor(int otherMaxColor) {
450         ImageCode.otherMaxColor = otherMaxColor;
451     }
452 
453     public static Color getBackgroundColor() {
454         return backgroundColor;
455     }
456 
457     public static void setBackgroundColor(Color backgroundColor) {
458         ImageCode.backgroundColor = backgroundColor;
459     }
460 
461     public static ImageCode getImageCode() {
462         return imageCode;
463     }
464 
465     public static void setImageCode(ImageCode imageCode) {
466         ImageCode.imageCode = imageCode;
467     }
468 
469     public static void setRandString(String randString) {
470         ImageCode.randString = randString;
471     }
472 
473     public static int getFontSize() {
474         return fontSize;
475     }
476 
477     public static void setFontSize(int fontSize) {
478         ImageCode.fontSize = fontSize;
479     }
480 
481     public static boolean isShear() {
482         return isShear;
483     }
484 
485     public static void setShear(boolean isShear) {
486         ImageCode.isShear = isShear;
487     }
488 
489 }

基本思路:

1.用字符集合确定验证码显示的字符;

2.用参数确定各种控制数据;

3.生成一个字符串,赋予一个成员变量,用这个字符串循环绘制在画布上,给图片添加干扰线、噪点和文字扭曲等效果;

4.图片最终赋给一个字节数组输入流对象。

二、创建TestAction.java

 1 package com.exp.action;
 2 
 3 import java.io.ByteArrayInputStream;
 4 
 5 import javax.servlet.http.HttpServletResponse;
 6 
 7 import com.exp.image.ImageCode;
 8 import com.opensymphony.xwork2.ActionContext;
 9 
10 public class TestAction {
11     private String usercode;// 用户输入的验证码
12     private ByteArrayInputStream inputStream;// 图片输入流
13     private String info;
14 
15     /**
16      * 登录
17      * 
18      * @return
19      */
20     public String login() {
21         // 输出测试
22         System.out.println(ImageCode.getRandString());
23         if (ImageCode.getRandString().equals(usercode.toLowerCase())) {
24             System.out.println("没问题");
25             info = "验证码输入正确";
26         } else {
27             System.out.println("不对");
28             info = "验证码输入不正确";
29         }
30         return "test_login_success";
31     }
32 
33     /**
34      * 获取图片验证码
35      * 
36      * @return
37      */
38     public String getimagecode() {
39         // 创建图片验证码
40         ImageCode.createRandomImage();
41         ImageCode.setHeight(21);// 设置高度
42         // 输出测试
43         System.out.println(ImageCode.getRandString());
44         // 将图片输入自字节流赋予inputStream
45         this.setInputStream(ImageCode.getInputStream());
46         return "test_getimagecode_success";
47     }
48 
49     // 封装
50     public String getUsercode() {
51         return usercode;
52     }
53 
54     public void setUsercode(String usercode) {
55         this.usercode = usercode;
56     }
57 
58     public ByteArrayInputStream getInputStream() {
59         return inputStream;
60     }
61 
62     public void setInputStream(ByteArrayInputStream inputStream) {
63         this.inputStream = inputStream;
64     }
65 
66     public String getInfo() {
67         return info;
68     }
69 
70     public void setInfo(String info) {
71         this.info = info;
72     }
73 }

思路:使用单例模式,获取验证码字节数组输入流对象,并且声称验证码字符串。

三、配置struts.xml

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
 3 <struts>
 4     <package name="test" namespace="/" extends="struts-default">
 5         <action name="*_*" class="com.exp.action.{1}Action" method="{2}">
 6         <result name="test_login_success">/index2.jsp</result>
 7             <!-- 图片验证码 -->
 8             <result name="test_getimagecode_success" type="stream">        
 9                 <param name="contentType">image/jpeg</param>        
10                 <param name="inputName">inputStream</param>        
11             </result>  
12         </action>
13     </package>
14 </struts>    

思路:规定结果类型为流,设定参数类型为图片,设定inputName的值为TestAction中的字节数组输入流对象。

四、设计测试页面index2.jsp

 1 <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
 2 <%@ taglib uri="/struts-tags" prefix="s" %>
 3 <%
 4     String path = request.getContextPath();
 5     String basePath = request.getScheme() + "://"
 6             + request.getServerName() + ":" + request.getServerPort()
 7             + path + "/";
 8 %>
 9 
10 <!DOCTYPE html>
11 <html>
12 <head>
13 <base href="<%=basePath%>">
14 <title>My JSP 'index.jsp' starting page</title>
15 <script type="text/javascript" src="js/jquery-2.1.4.js"></script>
16 </head>
17 
18 <body>
19     <form action="Test_login" method="post">
20     <input id="othertext" placeholder="验证异步刷新" style="float:left;">
21         <input name="usercode" maxlength="6" style="float:left;"> <span style="display:block;float:left;width:80px;height:22px;border:0px solid green;"><img
22             id="randimg" src="Test_getimagecode" οnclick="changeRandomImage();" style="border:0px solid red;"></span><br>
23         <input type="submit" value="OK" style="width:100px;height:21px;float:left;margin:-19px 0 0 10px;">
24     </form>
25     <div style="width:200px;height:22px;float:left;margin:-18px 0 0 10px;color:red;"><s:property value="info"/></div>
26     
27     <script type="text/javascript">
28     //异步刷新图片验证码
29         function changeRandomImage() {
30             var imgSrc = $("#randimg");
31             var src = imgSrc.attr("src");
32             imgSrc.attr("src", changeGetImageUrl(src));
33         }
34         //时间戳
35         //为了使每次生成图片不一致,即不让浏览器读缓存,所以需要加上时间戳,让每次都有新的请求
36         function changeGetImageUrl(url) {
37             var timestamp = (new Date()).valueOf();
38             if ((url.indexOf("&") >= 0)) {
39                 url = url + "×tamp=" + timestamp;
40             } else {
41                 url = url + "?timestamp=" + timestamp;
42             }
43             return url;
44         }
45     </script>
46 </body>
47 </html>

思路:点击图片进行异步刷新。为了防止每次刷新时页面读取缓存导致不变,特意设置一个没有实际作用的时间戳为参数形成不同的请求,获得新的结果

五、运行效果

 

转载于:https://www.cnblogs.com/xxkalychen/p/5796679.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值