最近有需求在項目的登錄模塊加上驗證碼,在網上找了一些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(); } }
這里注釋也很詳細了,最終前台展示效果圖:,哈哈大功告成,當然還有一點就是 刷新驗證碼,刷新驗證碼其實就是重新去后台生成一個驗證碼,這里,我貼出我的js文件代碼:
/** * 點擊驗證碼刷新 */ 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請求去后台獲取驗證碼 。