验证码生成工具
验证码生成工具
1 /** 2 * <html> 3 * <body> 4 * <P> Copyright 1994 JsonInternational</p> 5 * <p> All rights reserved.</p> 6 * <p> Created on 19941115</p> 7 * <p> Created by Jason</p> 8 * </body> 9 * </html> 10 */ 11 package cn.ucaner.alpaca.framework.utils.validate; 12 13 import java.awt.Color; 14 import java.awt.Font; 15 import java.awt.Graphics; 16 import java.awt.Graphics2D; 17 import java.awt.image.BufferedImage; 18 import java.io.FileOutputStream; 19 import java.io.IOException; 20 import java.io.OutputStream; 21 import java.util.Date; 22 import java.util.Random; 23 24 import javax.imageio.ImageIO; 25 26 /** 27 * @Package:cn.ucaner.framework.utils 28 * @ClassName:ValidateCode 29 * @Description: <p> [验证码生成工具.]可生成数字,大写,小写字母及三者混合类型的验证码. 30 * 支持自定义验证码字符数量; 支持自定义验证码图片的大小; 支持自定义需排除的特殊字符; 31 * 支持自定义干扰线的数量; 支持自定义验证码图文颜色</p> 32 * @Author: - Jason 33 * @CreatTime:2017年10月20日 下午4:04:15 34 * @Modify By: 35 * @ModifyTime: 36 * @Modify marker: 37 * @version V1.0 38 */ 39 public class ValidateCode { 40 41 // 图片的宽度。 42 private int width = 160; 43 // 图片的高度。 44 private int height = 40; 45 // 验证码字符个数 46 private int codeCount = 5; 47 // 验证码干扰线数 48 private int lineCount = 150; 49 // 验证码 50 private String code = null; 51 // 验证码图片Buffer 52 private BufferedImage buffImg = null; 53 54 // 验证码范围,去掉0(数字)和O(拼音)容易混淆的(小写的1和L也可以去掉,大写不用了) 55 private char[] codeSequence = { '0', 56 // 'B', 57 // 'C', 58 // 'D', 59 // 'E', 60 // 'F', 61 // 'G', 62 // 'H', 63 // 'I', 64 // 'J', 65 // 'K', 66 // 'L', 67 // 'M', 68 // 'N', 69 // 'P', 70 // 'Q', 71 // 'R', 72 // 'S', 73 // 'T', 74 // 'U', 75 // 'V', 76 // 'W', 77 // 'X', 78 // 'Y', 79 // 'Z', 80 '1', 81 '2', 82 '3', 83 '4', 84 '5', 85 '6', 86 '7', 87 '8', 88 '9' }; 89 90 /** 91 * @param width 图片宽 92 * @param height 图片高 93 */ 94 public ValidateCode(int width, int height) { 95 this.width = width; 96 this.height = height; 97 this.createCode(); 98 } 99 100 /** 101 * @param width 图片宽 102 * @param height 图片高 103 * @param codeCount 字符个数 104 * @param lineCount 干扰线条数 105 */ 106 public ValidateCode(int width, int height, int codeCount, int lineCount) { 107 this.width = width; 108 this.height = height; 109 this.codeCount = codeCount; 110 this.lineCount = lineCount; 111 this.createCode(); 112 } 113 114 public void createCode() { 115 int x = 0, fontHeight = 0, codeY = 0; 116 int red = 0, green = 0, blue = 0; 117 118 x = width / ( codeCount + 2 );//每个字符的宽度(左右各空出一个字符) 119 fontHeight = height - 2;//字体的高度 120 codeY = height - 4; 121 122 // 图像buffer 123 buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 124 Graphics2D g = buffImg.createGraphics(); 125 // 生成随机数 126 Random random = new Random(); 127 // 将图像填充为白色 128 g.setColor(Color.WHITE); 129 g.fillRect(0, 0, width, height); 130 // 创建字体,可以修改为其它的 131 Font font = new Font("Fixedsys", Font.PLAIN, fontHeight); 132 // Font font = new Font("Times New Roman", Font.ROMAN_BASELINE, fontHeight); 133 g.setFont(font); 134 135 for (int i = 0; i < lineCount; i++) { 136 // 设置随机开始和结束坐标 137 int xs = random.nextInt(width);//x坐标开始 138 int ys = random.nextInt(height);//y坐标开始 139 int xe = xs + random.nextInt(width / 8);//x坐标结束 140 int ye = ys + random.nextInt(height / 8);//y坐标结束 141 142 // 产生随机的颜色值,让输出的每个干扰线的颜色值都将不同。 143 red = random.nextInt(255); 144 green = random.nextInt(255); 145 blue = random.nextInt(255); 146 g.setColor(new Color(red, green, blue)); 147 g.drawLine(xs, ys, xe, ye); 148 } 149 150 // randomCode记录随机产生的验证码 151 StringBuffer randomCode = new StringBuffer(); 152 // 随机产生codeCount个字符的验证码。 153 for (int i = 0; i < codeCount; i++) { 154 String strRand = String.valueOf(codeSequence[random.nextInt(codeSequence.length)]); 155 // 产生随机的颜色值,让输出的每个字符的颜色值都将不同。 156 red = random.nextInt(255); 157 green = random.nextInt(255); 158 blue = random.nextInt(255); 159 g.setColor(new Color(red, green, blue)); 160 g.drawString(strRand, ( i + 1 ) * x, codeY); 161 // 将产生的四个随机数组合在一起。 162 randomCode.append(strRand); 163 } 164 // 将四位数字的验证码保存到Session中。 165 code = randomCode.toString(); 166 } 167 168 public void write(String path) throws IOException { 169 OutputStream sos = new FileOutputStream(path); 170 this.write(sos); 171 } 172 173 public void write(OutputStream sos) throws IOException { 174 ImageIO.write(buffImg, "png", sos); 175 sos.close(); 176 } 177 178 public BufferedImage getBuffImg() { 179 return buffImg; 180 } 181 182 public String getCode() { 183 return code; 184 } 185 186 /** 187 * 测试函数,默认生成到d盘 188 * @param args 189 */ 190 public static void main(String[] args) { 191 ValidateCode vCode = new ValidateCode(160, 40, 4, 150); 192 try { 193 String path = "D:/" + new Date().getTime() + ".png"; 194 System.out.println(vCode.getCode() + " >" + path); 195 vCode.write(path); 196 } catch (IOException e) { 197 e.printStackTrace(); 198 } 199 } 200 201 /** 202 * 验证码类型为仅数字 0~9 203 */ 204 public static final int TYPE_NUM_ONLY = 0; 205 206 /** 207 * 验证码类型为仅字母,即大写、小写字母混合 208 */ 209 public static final int TYPE_LETTER_ONLY = 1; 210 211 /** 212 * 验证码类型为数字、大写字母、小写字母混合 213 */ 214 public static final int TYPE_ALL_MIXED = 2; 215 216 /** 217 * 验证码类型为数字、大写字母混合 218 */ 219 public static final int TYPE_NUM_UPPER = 3; 220 221 /** 222 * 验证码类型为数字、小写字母混合 223 */ 224 public static final int TYPE_NUM_LOWER = 4; 225 226 /** 227 * 验证码类型为仅大写字母 228 */ 229 public static final int TYPE_UPPER_ONLY = 5; 230 231 /** 232 * 验证码类型为仅小写字母 233 */ 234 public static final int TYPE_LOWER_ONLY = 6; 235 236 /** 237 * 生成验证码字符串 238 * 239 * @param type 240 * 验证码类型,参见本类的静态属性 241 * @param length 242 * 验证码长度,大于0的整数 243 * @param exChars 244 * 需排除的特殊字符(仅对数字、字母混合型验证码有效,无需排除则为null) 245 * @return 验证码字符串 246 */ 247 public static String generateTextCode(int type, int length, String exChars) { 248 249 if (length <= 0) { 250 return ""; 251 } 252 StringBuffer code = new StringBuffer(); 253 int i = 0; 254 Random r = new Random(); 255 256 switch (type) { 257 258 // 仅数字 259 case TYPE_NUM_ONLY: 260 while (i < length) { 261 int t = r.nextInt(10); 262 // 排除特殊字符 263 if (exChars == null || exChars.indexOf(t + "") < 0) { 264 code.append(t); 265 i++; 266 } 267 } 268 break; 269 270 // 仅字母(即大写字母、小写字母混合) 271 case TYPE_LETTER_ONLY: 272 while (i < length) { 273 int t = r.nextInt(123); 274 if ( ( t >= 97 || ( t >= 65 && t <= 90 ) ) && ( exChars == null || exChars.indexOf((char) t) < 0 )) { 275 code.append((char) t); 276 i++; 277 } 278 } 279 break; 280 281 // 数字、大写字母、小写字母混合 282 case TYPE_ALL_MIXED: 283 while (i < length) { 284 int t = r.nextInt(123); 285 if ( ( t >= 97 || ( t >= 65 && t <= 90 ) || ( t >= 48 && t <= 57 ) ) && ( exChars == null || exChars.indexOf((char) t) < 0 )) { 286 code.append((char) t); 287 i++; 288 } 289 } 290 break; 291 292 // 数字、大写字母混合 293 case TYPE_NUM_UPPER: 294 while (i < length) { 295 int t = r.nextInt(91); 296 if ( ( t >= 65 || ( t >= 48 && t <= 57 ) ) && ( exChars == null || exChars.indexOf((char) t) < 0 )) { 297 code.append((char) t); 298 i++; 299 } 300 } 301 break; 302 303 // 数字、小写字母混合 304 case TYPE_NUM_LOWER: 305 while (i < length) { 306 int t = r.nextInt(123); 307 if ( ( t >= 97 || ( t >= 48 && t <= 57 ) ) && ( exChars == null || exChars.indexOf((char) t) < 0 )) { 308 code.append((char) t); 309 i++; 310 } 311 } 312 break; 313 314 // 仅大写字母 315 case TYPE_UPPER_ONLY: 316 while (i < length) { 317 int t = r.nextInt(91); 318 if ( ( t >= 65 ) && ( exChars == null || exChars.indexOf((char) t) < 0 )) { 319 code.append((char) t); 320 i++; 321 } 322 } 323 break; 324 325 // 仅小写字母 326 case TYPE_LOWER_ONLY: 327 while (i < length) { 328 int t = r.nextInt(123); 329 if ( ( t >= 97 ) && ( exChars == null || exChars.indexOf((char) t) < 0 )) { 330 code.append((char) t); 331 i++; 332 } 333 } 334 break; 335 default: 336 break; 337 } 338 339 return code.toString(); 340 } 341 342 /** 343 * 已有验证码,生成验证码图片 344 * 345 * @param textCode 346 * 文本验证码 347 * @param width 348 * 图片宽度 349 * @param height 350 * 图片高度 351 * @param interLine 352 * 图片中干扰线的条数 353 * @param randomLocation 354 * 每个字符的高低位置是否随机 355 * @param backColor 356 * 图片颜色,若为null,则采用随机颜色 357 * @param foreColor 358 * 字体颜色,若为null,则采用随机颜色 359 * @param lineColor 360 * 干扰线颜色,若为null,则采用随机颜色 361 * @return 图片缓存对象 362 */ 363 public static BufferedImage generateImageCode(String textCode, int width, int height, int interLine, boolean randomLocation, Color backColor, 364 Color foreColor, Color lineColor) { 365 366 BufferedImage bim = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 367 Graphics g = bim.getGraphics(); 368 369 // 画背景图 370 g.setColor(backColor == null ? getRandomColor() : backColor); 371 g.fillRect(0, 0, width, height); 372 373 // 画干扰线 374 Random r = new Random(); 375 if (interLine > 0) { 376 377 int x = 0, y = 0, x1 = width, y1 = 0; 378 for (int i = 0; i < interLine; i++) { 379 g.setColor(lineColor == null ? getRandomColor() : lineColor); 380 y = r.nextInt(height); 381 y1 = r.nextInt(height); 382 383 g.drawLine(x, y, x1, y1); 384 } 385 } 386 387 // 写验证码 388 389 // g.setColor(getRandomColor()); 390 // g.setColor(isSimpleColor?Color.BLACK:Color.WHITE); 391 392 // 字体大小为图片高度的80% 393 int fsize = (int) ( height * 0.8 ); 394 int fx = height - fsize; 395 int fy = fsize; 396 397 g.setFont(new Font("Default", Font.PLAIN, fsize)); 398 399 // 写验证码字符 400 for (int i = 0; i < textCode.length(); i++) { 401 // 每个字符高低是否随机 402 fy = randomLocation ? (int) ( ( Math.random() * 0.3 + 0.6 ) * height ) : fy; 403 g.setColor(foreColor == null ? getRandomColor() : foreColor); 404 g.drawString(textCode.charAt(i) + "", fx, fy); 405 fx += fsize * 0.9; 406 } 407 408 g.dispose(); 409 410 return bim; 411 } 412 413 /** 414 * 生成图片验证码 415 * 416 * @param type 417 * 验证码类型,参见本类的静态属性 418 * @param length 419 * 验证码字符长度,大于0的整数 420 * @param exChars 421 * 需排除的特殊字符 422 * @param width 423 * 图片宽度 424 * @param height 425 * 图片高度 426 * @param interLine 427 * 图片中干扰线的条数 428 * @param randomLocation 429 * 每个字符的高低位置是否随机 430 * @param backColor 431 * 图片颜色,若为null,则采用随机颜色 432 * @param foreColor 433 * 字体颜色,若为null,则采用随机颜色 434 * @param lineColor 435 * 干扰线颜色,若为null,则采用随机颜色 436 * @return 图片缓存对象 437 */ 438 public static BufferedImage generateImageCode(int type, int length, String exChars, int width, int height, int interLine, boolean randomLocation, 439 Color backColor, Color foreColor, Color lineColor) { 440 String textCode = generateTextCode(type, length, exChars); 441 BufferedImage bim = generateImageCode(textCode, width, height, interLine, randomLocation, backColor, foreColor, lineColor); 442 443 return bim; 444 } 445 446 /** 447 * 产生随机颜色 448 * 449 * @return 450 */ 451 private static Color getRandomColor() { 452 Random r = new Random(); 453 Color c = new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)); 454 return c; 455 } 456 457 }
--------------------------------------
勿忘初心 方得始终
--------------------------------------