J2EE驗(yàn)證碼圖片如何生成和點(diǎn)擊刷新驗(yàn)證碼
驗(yàn)證碼圖片生成步驟
創(chuàng)建BufferedImage對(duì)象。
獲取BufferedImage的畫(huà)筆,即調(diào)用getGraphics()方法獲取Graphics對(duì)象。
調(diào)用Graphics對(duì)象的setColor()方法和fillRect()方法設(shè)置圖片背景顏色。
調(diào)用Graphics對(duì)象的setColor()方法和drawLine()方法設(shè)置圖片干擾線。
調(diào)用BufferedImaged對(duì)象的setRGB()方法設(shè)置圖片的噪點(diǎn)。
調(diào)用Graphics對(duì)象的setColor()方法、setFont()方法和drawString()方法設(shè)置圖片驗(yàn)證碼。
因?yàn)轵?yàn)證碼的圖片的寬度和高度要根據(jù)網(wǎng)站的風(fēng)格來(lái)確定的,所以字體的大小需要根據(jù)圖片的寬度和高度來(lái)確定,用到了小小的技巧。
package util; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Image; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Random; import javax.imageio.ImageIO; public class Verification { private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"; /** * 生成一個(gè)寬為width, 高為height, 驗(yàn)證碼為code的圖片 * @param width 圖片的寬 * @param height 圖片的高 * @param code 驗(yàn)證碼字符串 * @return 返回圖片驗(yàn)證碼 */ public static BufferedImage getImage(int width, int height, String code){ return getImage(width, height, code, 20); } /** * 生成一個(gè)寬為width, 高為height, 驗(yàn)證碼為code的圖片,圖片中干擾線的條數(shù)為lineCnt * @param width 圖片的寬 * @param height 圖片的高 * @param code 驗(yàn)證碼字符串 * @param lineCnt 干擾線的條數(shù),建議為10條左右,可根據(jù)結(jié)果適當(dāng)調(diào)整 * @return 返回圖片驗(yàn)證碼 */ public static BufferedImage getImage(int width, int height, String code, int lineCnt){ return createImage(width, height, code, lineCnt, 0.01); } /** * 生成一個(gè)寬為width, 高為height, 驗(yàn)證碼為code的圖片,圖片中干擾線的條數(shù)為lineCnt * 噪聲比為noiseRate,即圖片中噪音像素點(diǎn)的百分比 * @param width 圖片的寬 * @param height 圖片的高 * @param code 驗(yàn)證碼字符串 * @param lineCnt 干擾線的條數(shù),建議為10條左右,可根據(jù)結(jié)果適當(dāng)調(diào)整 * @param noiseRate 圖片中噪音像素點(diǎn)占總像素的百分比 * @return 返回圖片驗(yàn)證碼 */ public static BufferedImage getImage(int width, int height, String code, int lineCnt, double noiseRate){ return createImage(width, height, code, lineCnt, noiseRate); } /** * * 生成一個(gè)寬為width, 高為height, 驗(yàn)證碼為code的圖片,圖片中干擾線的條數(shù)為lineCnt * 噪聲比為noiseRate,即圖片中噪音像素點(diǎn)的百分比 * @param width 圖片的寬 * @param height 圖片的高 * @param code 驗(yàn)證碼字符串 * @param lineCnt 干擾線的條數(shù),建議為10條左右,可根據(jù)結(jié)果適當(dāng)調(diào)整 * @param noiseRate 圖片中噪音像素點(diǎn)占總像素的百分比 * @return 返回圖片驗(yàn)證碼 */ private static BufferedImage createImage(int width, int height, String code, int lineCnt, double noiseRate){ int fontWidth = ((int)(width * 0.8)) / code.length(); int fontHeight = (int)(height * 0.7); //為了在任意的width和height下都能生成良好的驗(yàn)證碼, //字體的大小為fontWdith何fontHeight中的小者, int fontSize = Math.min(fontWidth, fontHeight); //drawString時(shí)要用到 int paddingX = (int) (width * 0.1); int paddingY = height - (height - fontSize) / 2; //創(chuàng)建圖像 BufferedImage buffimg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); //獲得畫(huà)筆 Graphics g = buffimg.getGraphics(); //設(shè)置畫(huà)筆的顏色 g.setColor(getRandColor(200, 255)); //然后填充一個(gè)矩形,即設(shè)置背景色 g.fillRect(0, 0, width, height); // 設(shè)置干擾線 for (int i = 0; i < lineCnt; i++) { //隨機(jī)獲取干擾線的起點(diǎn)和終點(diǎn) int xs = (int)(Math.random() * width); int ys = (int)(Math.random() * height); int xe = (int)(Math.random() * width); int ye = (int)(Math.random() * height); g.setColor(getRandColor(1, 255)); g.drawLine(xs, ys, xe, ye); } // 添加噪點(diǎn) int area = (int) (noiseRate * width * height); for(int i=0; i<area; ++i){ int x = (int)(Math.random() * width); int y = (int)(Math.random() * height); buffimg.setRGB(x, y, (int)(Math.random() * 255)); } //設(shè)置字體 Font font = new Font("Ravie", Font.PLAIN, fontSize); g.setFont(font); for(int i=0; i<code.length(); ++i){ String ch = code.substring(i, i+1); g.setColor(getRandColor(1, 199)); g.drawString(ch, paddingX + fontWidth * i, paddingY); } return buffimg; } /** * 獲取隨機(jī)的顏色,r,g,b的取值在L到R之間 * @param L 左區(qū)間 * @param R 右區(qū)間 * @return 返回隨機(jī)顏色值 */ private static Color getRandColor(int L, int R){ if(L > 255) L = 255; if(R > 255) R = 255; if(L < 0) L = 0; if(R < 0) R = 0; int interval = R - L; int r = L + (int)(Math.random() * interval); int g = L + (int)(Math.random() * interval); int b = L + (int)(Math.random() * interval); return new Color(r, g, b); } /** * 隨機(jī)生成若干個(gè)由大小寫(xiě)字母和數(shù)字組成的字符串 * @param len 隨機(jī)生成len個(gè)字符 * @return 返回隨機(jī)生成的若干個(gè)由大小寫(xiě)字母和數(shù)字組成的字符串 */ public static String getRandCode(int len){ String code = ""; for(int i=0; i<len; ++i){ int index = (int)(Math.random() * ALPHABET.length()); code = code + ALPHABET.charAt(index); } return code; } /** * 將圖片轉(zhuǎn)為byte數(shù)組 * @param image 圖片 * @return 返回byte數(shù)組 * @throws IOException */ public static byte[] getByteArray(BufferedImage image) throws IOException{ ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(image, "png", baos); return baos.toByteArray(); //ByteArrayOutputStream 不需要close } }
使用驗(yàn)證碼圖片
在verificationCode.java這個(gè)servlet中調(diào)用上面的類生成驗(yàn)證碼圖片,然后將圖片返回給客戶端。
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); //隨機(jī)生成字符串,并寫(xiě)入session String code = Verification.getRandCode(4); session.setAttribute("verification", code); BufferedImage image = util.Verification.getImage(100,30, code, 5); response.setContentType("image/png"); OutputStream out = response.getOutputStream(); out.write(util.Verification.getByteArray(image)); out.flush(); out.close(); }
在index.jsp中設(shè)置驗(yàn)證碼,用戶點(diǎn)擊驗(yàn)證碼時(shí),調(diào)用js代碼請(qǐng)求服務(wù)器得到新的驗(yàn)證碼。因?yàn)樯厦娴哪莻€(gè)生成驗(yàn)證碼的servlet會(huì)被瀏覽器緩存,所以js代碼中需要給該servlet一個(gè)隨機(jī)的參數(shù),這樣瀏覽器就會(huì)向服務(wù)器發(fā)請(qǐng)求得到新的驗(yàn)證碼,而不是去緩存中讀取。
<%@page import="util.Verification"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> <script type="text/javascript"> function refreshcode(){ document.getElementById("verification").src= "/verificationCode/verificationCode?hehe="+Math.random(); } </script> </head> <body> <form action="<%=request.getContextPath()+"/checkVerification" %>" method="post"> 驗(yàn)證碼:<input type="text" name="submitVerification"> <img id="verification" alt="" title="看不清點(diǎn)擊刷新驗(yàn)證碼" src="<%=request.getContextPath()+"/verificationCode" %>" onclick="refreshcode()"><br> <input type="submit" name="submit" value="提交"> </form> </body> </html>
最后是在checkVerification.java這個(gè)servlet中判斷用戶輸入的驗(yàn)證碼是否正確,為了方便用戶,驗(yàn)證碼一般都設(shè)置成大小寫(xiě)不敏感,所以要先轉(zhuǎn)化為小寫(xiě)字母再比對(duì)。
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); String verification = (String)session.getAttribute("verification"); String submitVerification = request.getParameter("submitVerification"); PrintWriter out = response.getWriter(); if(verification!=null && submitVerification!=null){ if(verification.toLowerCase().equals(submitVerification.toLowerCase())){ out.println("yes!!!"); } else{ out.println("no!!!"); } } else{ out.println("no!!!"); } session.removeAttribute("verification");//防止用戶重復(fù)提交表單 } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); }
最后運(yùn)行的效果圖如下
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。
- 分享J2EE的13種核心技術(shù)
- JDK、J2EE、J2SE、J2ME四個(gè)易混淆概念區(qū)分
- 圖解Eclipse j2ee開(kāi)發(fā)環(huán)境的搭建過(guò)程
- 經(jīng)常聽(tīng)朋友說(shuō)什么J2EE,終于知道點(diǎn)什么是J2EE了,汗一個(gè)
- MyEclipse5.0M1注冊(cè)碼+eclipse3.2[J2EE]
- J2EE 開(kāi)發(fā)購(gòu)物網(wǎng)站 經(jīng)驗(yàn)篇 - 建表
- 實(shí)戰(zhàn) J2EE 開(kāi)發(fā)購(gòu)物網(wǎng)站 - 創(chuàng)建數(shù)據(jù)庫(kù)
- J2ee 高并發(fā)情況下監(jiān)聽(tīng)器實(shí)例詳解
相關(guān)文章
MyBatis使用<foreach>標(biāo)簽報(bào)錯(cuò)問(wèn)題及解決
這篇文章主要介紹了MyBatis使用<foreach>標(biāo)簽報(bào)錯(cuò)問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03基于SpringBoot+vue實(shí)現(xiàn)前后端數(shù)據(jù)加解密
這篇文章主要給大家介紹了基于SpringBoot+vue實(shí)現(xiàn)前后端數(shù)據(jù)加解密,文中有詳細(xì)的示例代碼,具有一定的參考價(jià)值,感興趣的小伙伴可以自己動(dòng)手試一試2023-08-08Java實(shí)現(xiàn)的文件上傳下載工具類完整實(shí)例【上傳文件自動(dòng)命名】
這篇文章主要介紹了Java實(shí)現(xiàn)的文件上傳下載工具類,結(jié)合完整實(shí)例形式分析了java針對(duì)文件上傳下載操作的相關(guān)實(shí)現(xiàn)技巧,并且針對(duì)上傳文件提供了自動(dòng)命名功能以避免文件命名重復(fù),需要的朋友可以參考下2017-11-11java使用Filter實(shí)現(xiàn)自動(dòng)登錄的方法
這篇文章主要為大家詳細(xì)介紹了java使用Filter實(shí)現(xiàn)自動(dòng)登錄的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04mybatis-puls中的resultMap數(shù)據(jù)映射
這篇文章主要介紹了mybatis-puls中的resultMap數(shù)據(jù)映射,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08利用spring-data-redis實(shí)現(xiàn)incr自增的操作
這篇文章主要介紹了利用spring-data-redis實(shí)現(xiàn)incr自增的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11