标签:
本程序基于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" onclick="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>
思路:点击图片进行异步刷新。为了防止每次刷新时页面读取缓存导致不变,特意设置一个没有实际作用的时间戳为参数形成不同的请求,获得新的结果
五、运行效果
标签:
原文地址:http://www.cnblogs.com/xxkalychen/p/5796679.html