最近有需求在项目的登录模块加上验证码,在网上找了一些java写的验证码,总算是找到了一个比较炫酷的,废话不多说,上代码: 1.首先是生成随机数的Randoms类: 1 2 3 import java.util.Random; 4 5 public class Randoms { 6 private static final Random RANDOM = new Random(); 7 //定义验证码字符.去除了O和I等容易混淆的字母 8 public static final char ALPHA[]={'A','B','C','D','E','F','G','H','G','K','M','N','P','Q','R','S','T','U','V','W','X','Y','Z' 9 ,'a','b','c','d','e','f','g','h','i','j','k','m','n','p','q','r','s','t','u','v','w','x','y','z','2','3','4','5','6','7','8','9'}; 10 11 /** 12 * 产生两个数之间的随机数 13 * @param min 小数 14 * @param max 比min大的数 15 * @return int 随机数字 16 */ 17 public static int num(int min, int max) 18 { 19 return min + RANDOM.nextInt(max - min); 20 } 21 22 /** 23 * 产生0--num的随机数,不包括num 24 * @param num 数字 25 * @return int 随机数字 26 */ 27 public static int num(int num) 28 { 29 return RANDOM.nextInt(num); 30 } 31 32 public static char alpha() 33 { 34 return ALPHA[num(0, ALPHA.length)]; 35 } 36 37 } 2.然后是生成验证码接口Captcha(需要注意这里Randoms类是静态导包,对应我上面第1步中的Randoms包路径): 1 2 3 import java.awt.*; 4 import java.awt.image.BufferedImage; 5 import java.io.OutputStream; 6 7 8 import static com.gmsz.ylpt.common.utils.Randoms.num; 9 import static com.gmsz.ylpt.common.utils.Randoms.alpha; 10 /** 11 * <p>验证码抽象类,暂时不支持中文</p> 12 * 13 * @author: cjz 14 * 15 */ 16 public abstract class Captcha 17 { 18 protected Font font = new Font("Verdana", Font.ITALIC|Font.BOLD, 28); // 字体 19 protected int len = 5; // 验证码随机字符长度 20 protected int width = 150; // 验证码显示跨度 21 protected int height = 40; // 验证码显示高度 22 private String chars = null; // 随机字符串 23 24 /** 25 * 生成随机字符数组 26 * @return 字符数组 27 */ 28 protected char[] alphas() 29 { 30 char[] cs = new char[len]; 31 for(int i = 0;i<len;i++) 32 { 33 cs[i] = alpha(); 34 } 35 chars = new String(cs); 36 return cs; 37 } 38 public Font getFont() 39 { 40 return font; 41 } 42 43 public void setFont(Font font) 44 { 45 this.font = font; 46 } 47 48 public int getLen() 49 { 50 return len; 51 } 52 53 public void setLen(int len) 54 { 55 this.len = len; 56 } 57 58 public int getWidth() 59 { 60 return width; 61 } 62 63 public void setWidth(int width) 64 { 65 this.width = width; 66 } 67 68 public int getHeight() 69 { 70 return height; 71 } 72 73 public void setHeight(int height) 74 { 75 this.height = height; 76 } 77 78 /** 79 * 给定范围获得随机颜色 80 * @return Color 随机颜色 81 */ 82 protected Color color(int fc, int bc) 83 { 84 if (fc > 255) 85 fc = 255; 86 if (bc > 255) 87 bc = 255; 88 int r = fc + num(bc - fc); 89 int g = fc + num(bc - fc); 90 int b = fc + num(bc - fc); 91 return new Color(r, g, b); 92 } 93 94 /** 95 * 验证码输出,抽象方法,由子类实现 96 * @param os 输出流 97 */ 98 public abstract BufferedImage out(OutputStream os); 99 100 /** 101 * 获取随机字符串 102 * @return string 103 */ 104 public String text() 105 { 106 return chars; 107 } 108 } 3.继承Captcha接口的SpecCaptcha类实现了父类的生成验证码的抽象方法: 1 2 3 import static com.gmsz.ylpt.common.utils.Randoms.num; 4 5 import java.awt.AlphaComposite; 6 import java.awt.Color; 7 import java.awt.Font; 8 import java.awt.Graphics2D; 9 import java.awt.image.BufferedImage; 10 import java.io.OutputStream; 11 12 public class SpecCaptcha extends Captcha{ 13 public SpecCaptcha() 14 { 15 } 16 public SpecCaptcha(int width, int height) 17 { 18 this.width = width; 19 this.height = height; 20 } 21 public SpecCaptcha(int width, int height, int len){ 22 this(width,height); 23 this.len = len; 24 } 25 public SpecCaptcha(int width, int height, int len, Font font){ 26 this(width,height,len); 27 this.font = font; 28 } 29 /** 30 * 生成验证码 31 * @throws java.io.IOException IO异常 32 */ 33 @Override 34 public BufferedImage out(OutputStream out){ 35 return graphicsImage(alphas(), out); 36 } 37 38 /** 39 * 画随机码图 40 * @param strs 文本 41 * @param out 输出流 42 */ 43 private BufferedImage graphicsImage(char[] strs, OutputStream out){ 44 BufferedImage bi =null; 45 bi = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); 46 Graphics2D g = (Graphics2D)bi.getGraphics(); 47 AlphaComposite ac3; 48 Color color ; 49 int len = strs.length; 50 g.setColor(Color.WHITE); 51 g.fillRect(0,0,width,height); 52 // 随机画干扰的蛋蛋 53 for(int i=0;i<15;i++){ 54 color = color(150, 250); 55 g.setColor(color); 56 g.drawOval(num(width), num(height), 5+num(10), 5+num(10));// 画蛋蛋,有蛋的生活才精彩 57 color = null; 58 } 59 g.setFont(font); 60 int h = height - ((height - font.getSize()) >>1), 61 w = width/len, 62 size = w-font.getSize()+1; 63 /* 画字符串 */ 64 for(int i=0;i<len;i++) 65 { 66 ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f);// 指定透明度 67 g.setComposite(ac3); 68 color = new Color(20 + num(110), 20 + num(110), 20 + num(110));// 对每个字符都用随机颜色 69 g.setColor(color); 70 g.drawString(strs[i]+"",(width-(len-i)*w)+size, h-4); 71 color = null; 72 ac3 = null; 73 } 74 return bi; 75 } 76 77 } 好了,到这里,这三个类就可以生成验证码了,那么如何将生成好的验证码加到项目中呢?我用的是SpringMVC框架,用户打开登录界面,会到controller中将生成好的验证码字符串放到session中(接口Captcha中有个text()方法返回一个验证码字符串),然后将生成好的验证码图片放到servlert的输出流中,jsp页面去输出流中把图片取出来展示到前台即可。说干就干,首先上我的前台jsp代码: 1 <div class="login-content-input login-content-input-code"> 2 <div> 3 验证码<input type="code" name="password" id="validateCode" value="" /> 4 <img id="validateCodeImg" src="<%=actionPath%>/getCode" onclick="login.reloadValidateCode();" /> 5 </div> 6 </div> 这里我只贴出了我项目中的验证码模块的关键部分代码,那些引入jquery.js, jstl之类的我就忽略了。这里的<%=actionPath%>可以根据自己的项目路径自行修改。下面是我的后台java代码,也就是controller中的代码: /** * 生成验证码 * @param request * @param response * @throws IOException */ @RequestMapping(value = "getCode") public void validateCode(HttpServletRequest request, HttpServletResponse response) throws IOException { //禁止图像缓存 response.setHeader("Cache-Control", "no-cache"); response.setHeader("Pragma", "no-cache"); response.setDateHeader("Expires", 0); Captcha captcha = new SpecCaptcha(150,40,5);// png格式验证码 ServletOutputStream out = response.getOutputStream(); BufferedImage bi = captcha.out(out); //获取验证码字符串放到session中,用于登录时取出来验证 String verifyCode = captcha.text(); request.getSession().setAttribute("validateCode", verifyCode); //将图像输出到 servlet的输出流中 ImageIO.write(bi, "png", out); try { out.flush(); } finally { out.close(); } } 这里注释也很详细了,最终前台展示效果图: /** * 点击验证码刷新 */ var login = login || {}; login.reloadValidateCode = function(){ /** * 给url后面加一个随机数,这样,每次请求都会从后台取新生成的验证码 * 不会再去缓存中取验证码 */ var randomNumber = new Date()+Math.floor(Math.random() * Math.pow(10, 8)); $("#validateCodeImg").attr("src",commonutil.actionPath+"/getCode?random="+randomNumber); } 这里需要稍微注意下的就是url后面的随机数,保证不会从缓存中取验证码,说白了就是每次发送新的url请求去后台获取验证码 。
|
|