Java實(shí)現(xiàn)動(dòng)態(tài)驗(yàn)證碼生成
本文實(shí)例為大家分享了Java動(dòng)態(tài)驗(yàn)證碼生成的具體代碼,供大家參考,具體內(nèi)容如下
說明:今天給大家來帶來一個(gè)自動(dòng)生成驗(yàn)證碼的處理方法。驗(yàn)證碼的出現(xiàn)有效減少了注入灌水以及破解密碼等惡意操作,提高了系統(tǒng)運(yùn)行的流暢性,保護(hù)了系統(tǒng)用戶的隱私安全,具體實(shí)現(xiàn)方法如下:
1.首先我們先編寫一個(gè)專門的驗(yàn)證碼生成工具類,該工具類代碼如下:
package com.ordering.util; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.util.Random; /** ?* 驗(yàn)證碼生成器 ?* @author 諾坎普10號(hào) ?* @date 2020-2-25 ?*/ public class CpachaUtil { ?? ? ?? ?/** ?? ? * 驗(yàn)證碼來源 ?? ? */ ?? ?final private char[] code = { ?? ??? ?'2', '3', '4', '5', '6', '7', '8', '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', 'A', 'B', 'C', 'D', 'E', 'F', ?? ??? ?'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', ?? ??? ?'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ?? ?}; ?? ?/** ?? ? * 字體 ?? ? */ ?? ?final private String[] fontNames = new String[]{ ?? ??? ??? ?"黑體", "宋體", "Courier", "Arial",? ?? ??? ??? ?"Verdana", "Times", "Tahoma", "Georgia"}; ?? ?/** ?? ? * 字體樣式 ?? ? */ ?? ?final private int[] fontStyles = new int[]{ ?? ??? ??? ?Font.BOLD, Font.ITALIC|Font.BOLD ?? ?}; ?? ? ?? ?/** ?? ? * 驗(yàn)證碼長度 ?? ? * 默認(rèn)4個(gè)字符 ?? ? */ ?? ?private int vcodeLen = 4; ?? ?/** ?? ? * 驗(yàn)證碼圖片字體大小 ?? ? * 默認(rèn)17 ?? ? */ ?? ?private int fontsize = 21; ?? ?/** ?? ? * 驗(yàn)證碼圖片寬度 ?? ? */ ?? ?private int width = (fontsize+1)*vcodeLen+10; ?? ?/** ?? ? * 驗(yàn)證碼圖片高度 ?? ? */ ?? ?private int height = fontsize+12; ?? ?/** ?? ? * 干擾線條數(shù) ?? ? * 默認(rèn)3條 ?? ? */ ?? ?private int disturbline = 3; ?? ? ?? ? ?? ?public CpachaUtil(){} ?? ? ?? ?/** ?? ? * 指定驗(yàn)證碼長度 ?? ? * @param vcodeLen 驗(yàn)證碼長度 ?? ? */ ?? ?public CpachaUtil(int vcodeLen) { ?? ??? ?this.vcodeLen = vcodeLen; ?? ??? ?this.width = (fontsize+1)*vcodeLen+10; ?? ?} ?? ? ?? ?/** ?? ? * 指定驗(yàn)證碼長度、圖片寬度、高度 ?? ? * @param vcodeLen ?? ? * @param width ?? ? * @param height ?? ? */ ?? ?public CpachaUtil(int vcodeLen,int width,int height) { ?? ??? ?this.vcodeLen = vcodeLen; ?? ??? ?this.width = width; ?? ??? ?this.height = height; ?? ?} ?? ? ?? ?/** ?? ? * 生成驗(yàn)證碼圖片 ?? ? * @param vcode 要畫的驗(yàn)證碼 ?? ? * @param drawline 是否畫干擾線 ?? ? * @return ?? ? */ ?? ?public BufferedImage generatorVCodeImage(String vcode, boolean drawline){ ?? ??? ?//創(chuàng)建驗(yàn)證碼圖片 ?? ??? ?BufferedImage vcodeImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); ?? ??? ?Graphics g = vcodeImage.getGraphics(); ?? ??? ?//填充背景色 ?? ??? ?g.setColor(new Color(246, 240, 250)); ?? ??? ?g.fillRect(0, 0, width, height); ?? ??? ?if(drawline){ ?? ??? ??? ?drawDisturbLine(g); ?? ??? ?} ?? ??? ?//用于生成偽隨機(jī)數(shù) ?? ??? ?Random ran = new Random(); ?? ??? ?//在圖片上畫驗(yàn)證碼 ?? ??? ?for(int i = 0;i < vcode.length();i++){ ?? ??? ??? ?//設(shè)置字體 ?? ??? ??? ?g.setFont(new Font(fontNames[ran.nextInt(fontNames.length)], fontStyles[ran.nextInt(fontStyles.length)], fontsize)); ?? ??? ??? ?//隨機(jī)生成顏色 ?? ??? ??? ?g.setColor(getRandomColor()); ?? ??? ??? ?//畫驗(yàn)證碼 ?? ??? ??? ?g.drawString(vcode.charAt(i)+"", i*fontsize+10, fontsize+5); ?? ??? ?} ?? ??? ?//釋放此圖形的上下文以及它使用的所有系統(tǒng)資源 ?? ??? ?g.dispose(); ?? ??? ? ?? ??? ?return vcodeImage; ?? ?} ?? ?/** ?? ? * 獲得旋轉(zhuǎn)字體的驗(yàn)證碼圖片 ?? ? * @param vcode ?? ? * @param drawline 是否畫干擾線 ?? ? * @return ?? ? */ ?? ?public BufferedImage generatorRotateVCodeImage(String vcode, boolean drawline){ ?? ??? ?//創(chuàng)建驗(yàn)證碼圖片 ?? ??? ?BufferedImage rotateVcodeImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); ?? ??? ?Graphics2D g2d = rotateVcodeImage.createGraphics(); ?? ??? ?//填充背景色 ?? ??? ?g2d.setColor(new Color(246, 240, 250)); ?? ??? ?g2d.fillRect(0, 0, width, height); ?? ??? ?if(drawline){ ?? ??? ??? ?drawDisturbLine(g2d); ?? ??? ?} ?? ??? ?//在圖片上畫驗(yàn)證碼 ?? ??? ?for(int i = 0;i < vcode.length();i++){ ?? ??? ??? ?BufferedImage rotateImage = getRotateImage(vcode.charAt(i)); ?? ??? ??? ?g2d.drawImage(rotateImage, null, (int) (this.height * 0.7) * i, 0); ?? ??? ?} ?? ??? ?g2d.dispose(); ?? ??? ?return rotateVcodeImage; ?? ?} ?? ?/** ?? ? * 生成驗(yàn)證碼 ?? ? * @return 驗(yàn)證碼 ?? ? */ ?? ?public String generatorVCode(){ ?? ??? ?int len = code.length; ?? ??? ?Random ran = new Random(); ?? ??? ?StringBuffer sb = new StringBuffer(); ?? ??? ?for(int i = 0;i < vcodeLen;i++){ ?? ??? ??? ?int index = ran.nextInt(len); ?? ??? ??? ?sb.append(code[index]); ?? ??? ?} ?? ??? ?return sb.toString(); ?? ?} ?? ?/** ?? ? * 為驗(yàn)證碼圖片畫一些干擾線 ?? ? * @param g? ?? ? */ ?? ?private void drawDisturbLine(Graphics g){ ?? ??? ?Random ran = new Random(); ?? ??? ?for(int i = 0;i < disturbline;i++){ ?? ??? ??? ?int x1 = ran.nextInt(width); ?? ??? ??? ?int y1 = ran.nextInt(height); ?? ??? ??? ?int x2 = ran.nextInt(width); ?? ??? ??? ?int y2 = ran.nextInt(height); ?? ??? ??? ?g.setColor(getRandomColor()); ?? ??? ??? ?//畫干擾線 ?? ??? ??? ?g.drawLine(x1, y1, x2, y2); ?? ??? ?} ?? ?} ?? ?/** ?? ? * 獲取一張旋轉(zhuǎn)的圖片 ?? ? * @param c 要畫的字符 ?? ? * @return ?? ? */ ?? ?private BufferedImage getRotateImage(char c){ ?? ??? ?BufferedImage rotateImage = new BufferedImage(height, height, BufferedImage.TYPE_INT_ARGB); ?? ??? ?Graphics2D g2d = rotateImage.createGraphics(); ?? ??? ?//設(shè)置透明度為0 ?? ??? ?g2d.setColor(new Color(255, 255, 255, 0)); ?? ??? ?g2d.fillRect(0, 0, height, height); ?? ??? ?Random ran = new Random(); ?? ??? ?g2d.setFont(new Font(fontNames[ran.nextInt(fontNames.length)], fontStyles[ran.nextInt(fontStyles.length)], fontsize)); ?? ??? ?g2d.setColor(getRandomColor()); ?? ??? ?double theta = getTheta(); ?? ??? ?//旋轉(zhuǎn)圖片 ?? ??? ?g2d.rotate(theta, height/2, height/2); ?? ??? ?g2d.drawString(Character.toString(c), (height-fontsize)/2, fontsize+5); ?? ??? ?g2d.dispose(); ?? ??? ? ?? ??? ?return rotateImage; ?? ?} ?? ?/** ?? ? * @return 返回一個(gè)隨機(jī)顏色 ?? ? */ ?? ?private Color getRandomColor(){ ?? ??? ?Random ran = new Random(); ?? ??? ?return new Color(ran.nextInt(220), ran.nextInt(220), ran.nextInt(220));? ?? ?} ?? ?/** ?? ? * @return 角度 ?? ? */ ?? ?private double getTheta(){ ?? ??? ?return ((int) (Math.random()*1000) % 2 == 0 ? -1 : 1)*Math.random(); ?? ?} ?? ?/** ?? ? * @return 驗(yàn)證碼字符個(gè)數(shù) ?? ? */ ?? ?public int getVcodeLen() { ?? ??? ?return vcodeLen; ?? ?} ?? ?/** ?? ? * 設(shè)置驗(yàn)證碼字符個(gè)數(shù) ?? ? * @param vcodeLen ?? ? */ ?? ?public void setVcodeLen(int vcodeLen) { ?? ??? ?this.width = (fontsize+3)*vcodeLen+10; ?? ??? ?this.vcodeLen = vcodeLen; ?? ?} ?? ?/** ?? ? * @return 字體大小 ?? ? */ ?? ?public int getFontsize() { ?? ??? ?return fontsize; ?? ?} ?? ?/** ?? ? * 設(shè)置字體大小 ?? ? * @param fontsize ?? ? */ ?? ?public void setFontsize(int fontsize) { ?? ??? ?this.width = (fontsize+3)*vcodeLen+10; ?? ??? ?this.height = fontsize+15; ?? ??? ?this.fontsize = fontsize; ?? ?} ?? ?/** ?? ? * @return 圖片寬度 ?? ? */ ?? ?public int getWidth() { ?? ??? ?return width; ?? ?} ?? ?/** ?? ? * 設(shè)置圖片寬度 ?? ? * @param width ?? ? */ ?? ?public void setWidth(int width) { ?? ??? ?this.width = width; ?? ?} ?? ?/** ?? ? * @return 圖片高度 ?? ? */ ?? ?public int getHeight() { ?? ??? ?return height; ?? ?} ?? ?/** ?? ? * 設(shè)置圖片高度 ?? ? * @param height? ?? ? */ ?? ?public void setHeight(int height) { ?? ??? ?this.height = height; ?? ?} ?? ?/** ?? ? * @return 干擾線條數(shù) ?? ? */ ?? ?public int getDisturbline() { ?? ??? ?return disturbline; ?? ?} ?? ?/** ?? ? * 設(shè)置干擾線條數(shù) ?? ? * @param disturbline ?? ? */ ?? ?public void setDisturbline(int disturbline) { ?? ??? ?this.disturbline = disturbline; ?? ?} ?? ? }
2.然后在頁面端定義一個(gè)顯示驗(yàn)證碼的控件,再寫一個(gè)js函數(shù)來對(duì)后臺(tái)動(dòng)態(tài)生成驗(yàn)證碼方法進(jìn)行調(diào)用,主要代碼如下:
<div class="login-center-input-text">驗(yàn)證碼</div> <img id="cpacha-img" title="點(diǎn)擊切換驗(yàn)證碼" style="cursor:pointer;" src="get_cpacha?vl=4&w=150&h=40&type=loginCpacha" width="110px" height="30px" onclick="changeCpacha()"> </div> <script type="text/javascript"> function changeCpacha(){ ?? ??? ?$("#cpacha-img").attr("src",'get_cpacha?vl=4&w=150&h=40&type=loginCpacha&t=' + new Date().getTime()); ?? ?} </script>
3.控制器中代碼如下:
/** ?? ? * 本系統(tǒng)所有的驗(yàn)證碼均采用此方法 ?? ? *? ?? ? * @param vcodeLen ?? ? * @param width ?? ? * @param height ?? ? * @param cpachaType:用來區(qū)別驗(yàn)證碼的類型,傳入字符串 ?? ? * @param request ?? ? * @param response ?? ? */ ?? ?@RequestMapping(value = "/get_cpacha", method = RequestMethod.GET) ?? ?public void generateCpacha(@RequestParam(name = "vl", required = false, defaultValue = "4") Integer vcodeLen, ?? ??? ??? ?@RequestParam(name = "w", required = false, defaultValue = "100") Integer width, ?? ??? ??? ?@RequestParam(name = "h", required = false, defaultValue = "30") Integer height, ?? ??? ??? ?@RequestParam(name = "type", required = true, defaultValue = "loginCpacha") String cpachaType, ?? ??? ??? ?HttpServletRequest request, HttpServletResponse response) { ?? ??? ?//根據(jù)頁面?zhèn)魅氲尿?yàn)證碼長度、圖片寬度以及圖片長度來實(shí)例化驗(yàn)證碼實(shí)體 ?? ??? ?CpachaUtil cpachaUtil = new CpachaUtil(vcodeLen, width, height); ?? ??? ?//生成驗(yàn)證碼 ?? ??? ?String generatorVCode = cpachaUtil.generatorVCode(); ?? ??? ?//把驗(yàn)證碼存入session ?? ??? ?request.getSession().setAttribute(cpachaType, generatorVCode); ?? ??? ?//根據(jù)驗(yàn)證碼生成相應(yīng)的驗(yàn)證碼圖片 ?? ??? ?BufferedImage generatorRotateVCodeImage = cpachaUtil.generatorRotateVCodeImage(generatorVCode, true); ?? ??? ?try { ?? ??? ??? ?ImageIO.write(generatorRotateVCodeImage, "gif", response.getOutputStream()); ?? ??? ?} catch (IOException e) { ?? ??? ??? ?// TODO Auto-generated catch block ?? ??? ??? ?e.printStackTrace(); ?? ??? ?} ?? ?}
4.實(shí)現(xiàn)效果如下圖所示:
5.控制器驗(yàn)證碼驗(yàn)證部分如下圖所示:
//若驗(yàn)證碼為空 if (StringUtils.isEmpty(cpacha)) { ?? ??? ??? ?ret.put("type", "error"); ?? ??? ??? ?ret.put("msg", "請(qǐng)?zhí)顚戲?yàn)證碼!"); ?? ??? ??? ?return ret; ?? ??? ?} ?? ??? ?//獲取保存在session中的登錄驗(yàn)證碼對(duì)象 ?? ??? ?Object loginCpacha = request.getSession().getAttribute("loginCpacha"); ?? ??? ?//若登錄驗(yàn)證碼實(shí)體對(duì)象為空 ?? ??? ?if (loginCpacha == null) { ?? ??? ??? ?ret.put("type", "error"); ?? ??? ??? ?ret.put("msg", "會(huì)話超時(shí),請(qǐng)刷新頁面!"); ?? ??? ??? ?return ret; ?? ??? ?} ?? ??? ?//若輸入的驗(yàn)證碼轉(zhuǎn)化成大寫之后不等于轉(zhuǎn)換成大寫的session中保存的驗(yàn)證碼 ?? ??? ?if (!cpacha.toUpperCase().equals(loginCpacha.toString().toUpperCase())) { ?? ??? ??? ?ret.put("type", "error"); ?? ??? ??? ?ret.put("msg", "驗(yàn)證碼錯(cuò)誤!"); ?? ??? ??? ?//實(shí)例化日志信息實(shí)體 ?? ??? ??? ?OrderingLog orderingLog = new OrderingLog("用戶名為" + user.getOuUsername() + "的用戶登錄時(shí)輸入驗(yàn)證碼錯(cuò)誤!", new Date()); ?? ??? ??? ?//添加日志信息 ?? ??? ??? ?logService.addLog(orderingLog); ?? ??? ??? ?return ret; ?? ??? ?}
注意:
只有當(dāng)你把當(dāng)前系統(tǒng)時(shí)間傳入該驗(yàn)證碼生成工具類中,才能實(shí)現(xiàn)點(diǎn)擊驗(yàn)證碼圖片,實(shí)時(shí)自動(dòng)替換驗(yàn)證碼,如下圖所示:
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Spring?Boot中優(yōu)雅地處理參數(shù)傳遞的技巧分享
最近一直在學(xué)習(xí)Spring Boot,今天將其中的從前臺(tái)過來的參數(shù)傳遞總結(jié)一下,下面這篇文章主要給大家介紹了關(guān)于Spring?Boot中優(yōu)雅地處理參數(shù)傳遞的技巧,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05java集合類arraylist循環(huán)中刪除特定元素的方法
下面小編就為大家?guī)硪黄狫ava集合類ArrayList循環(huán)中刪除特定元素的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11后端如何接收格式為x-www-form-urlencoded的數(shù)據(jù)
x-www-form-urlencoded格式是一種常見的HTTP請(qǐng)求數(shù)據(jù)格式,它將請(qǐng)求參數(shù)編碼為鍵值對(duì)的形式,以便于傳輸和解析,下面這篇文章主要給大家介紹了關(guān)于后端如何接收格式為x-www-form-urlencoded的數(shù)據(jù),需要的朋友可以參考下2023-05-05Java static方法用法實(shí)戰(zhàn)案例總結(jié)
這篇文章主要介紹了Java static方法用法,結(jié)合具體案例形式總結(jié)分析了java static方法功能、使用方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2019-09-09關(guān)于Mybatis-plus設(shè)置字段為空的正確寫法
這篇文章主要介紹了關(guān)于Mybatis-plus設(shè)置字段為空的正確寫法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07idea中使用Inputstream流導(dǎo)致中文亂碼解決方法
很多朋友遇到一個(gè)措手不及的問題當(dāng)idea中使用Inputstream流導(dǎo)致中文亂碼及Java FileInputStream讀中文亂碼問題,針對(duì)這兩個(gè)問題很多朋友不知道該如何解決,下面小編把解決方案分享給大家供大家參考2021-05-05Java連接合并2個(gè)數(shù)組(Array)的5種方法例子
最近在寫代碼時(shí)遇到了需要合并兩個(gè)數(shù)組的需求,突然發(fā)現(xiàn)以前沒用過,于是研究了一下合并數(shù)組的方式,這篇文章主要給大家介紹了關(guān)于Java連接合并2個(gè)數(shù)組(Array)的5種方法,需要的朋友可以參考下2023-12-12