Java Web項(xiàng)目中驗(yàn)證碼功能的制作攻略
一、前言
在表單頁面中使用驗(yàn)證碼的好處在于有效防止用戶惡意提交表單,或者使用外掛非法攻擊系統(tǒng)。
二、準(zhǔn)備條件
1、一個(gè)普通的web項(xiàng)目 webProject;
2、一個(gè)web服務(wù)器 Tomcat。
三、實(shí)現(xiàn)思路:
1、自定義一個(gè)servlet VerifyCodeServlet 畫一個(gè)包含驗(yàn)證字符的驗(yàn)證碼圖片,這里的圖片需要使用Graphics2D手動(dòng)去畫;
2、在具體頁面使用img標(biāo)簽的src引用這個(gè)servlet即可顯示servlet;
3、因?yàn)楫媹D的時(shí)候把驗(yàn)證碼信息放入了session,所以提交表單后可以根據(jù)session中保存的值和用戶輸入的code做比較,驗(yàn)證輸入是否正確。
網(wǎng)上大都是通過servlet實(shí)現(xiàn)的驗(yàn)證碼,入下圖邏輯:
步驟:
1、請(qǐng)求登錄頁面時(shí)隨機(jī)生成驗(yàn)證碼字符串;
2、將生成對(duì)驗(yàn)證碼字符串存到session中;
3、根據(jù)驗(yàn)證碼字符串生成驗(yàn)證碼圖片,然后將驗(yàn)證碼圖片輸出到客戶展示;
4、提交登錄請(qǐng)求時(shí)用戶輸入的驗(yàn)證碼字符串與session中的字符串做比對(duì)。
四、具體代碼如下:
package com.servlet; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.util.Random; import javax.imageio.ImageIO; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * 產(chǎn)生驗(yàn)證碼圖片的servlet * @author Administrator * */ public class VerifyCodeServlet extends HttpServlet { private static final long serialVersionUID = -5051097528828603895L; /** * 驗(yàn)證碼圖片的寬度。 */ private int width = 100; /** * 驗(yàn)證碼圖片的高度。 */ private int height = 30; /** * 驗(yàn)證碼字符個(gè)數(shù) */ private int codeCount = 4; /** * 字體高度 */ private int fontHeight; /** * 第一個(gè)字符的x軸值,因?yàn)楹竺娴淖址鴺?biāo)依次遞增,所以它們的x軸值是codeX的倍數(shù) */ private int codeX; /** * codeY ,驗(yàn)證字符的y軸值,因?yàn)椴⑿兴灾狄粯? */ private int codeY; /** * codeSequence 表示字符允許出現(xiàn)的序列值 */ char[] codeSequence = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; /** * 初始化驗(yàn)證圖片屬性 */ public void init() throws ServletException { // 從web.xml中獲取初始信息 // 寬度 String strWidth = this.getInitParameter("width"); // 高度 String strHeight = this.getInitParameter("height"); // 字符個(gè)數(shù) String strCodeCount = this.getInitParameter("codeCount"); // 將配置的信息轉(zhuǎn)換成數(shù)值 try { if (strWidth != null && strWidth.length() != 0) { width = Integer.parseInt(strWidth); } if (strHeight != null && strHeight.length() != 0) { height = Integer.parseInt(strHeight); } if (strCodeCount != null && strCodeCount.length() != 0) { codeCount = Integer.parseInt(strCodeCount); } } catch (NumberFormatException e) { e.printStackTrace(); } //width-4 除去左右多余的位置,使驗(yàn)證碼更加集中顯示,減得越多越集中。 //codeCount+1 //等比分配顯示的寬度,包括左右兩邊的空格 codeX = (width-4) / (codeCount+1); //height - 10 集中顯示驗(yàn)證碼 fontHeight = height - 10; codeY = height - 7; } /** * @param request * @param response * @throws ServletException * @throws java.io.IOException */ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException { // 定義圖像buffer BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D gd = buffImg.createGraphics(); // 創(chuàng)建一個(gè)隨機(jī)數(shù)生成器類 Random random = new Random(); // 將圖像填充為白色 gd.setColor(Color.LIGHT_GRAY); gd.fillRect(0, 0, width, height); // 創(chuàng)建字體,字體的大小應(yīng)該根據(jù)圖片的高度來定。 Font font = new Font("Fixedsys", Font.PLAIN, fontHeight); // 設(shè)置字體。 gd.setFont(font); // 畫邊框。 gd.setColor(Color.BLACK); gd.drawRect(0, 0, width - 1, height - 1); // 隨機(jī)產(chǎn)生160條干擾線,使圖象中的認(rèn)證碼不易被其它程序探測(cè)到。 gd.setColor(Color.gray); for (int i = 0; i < 16; i++) { int x = random.nextInt(width); int y = random.nextInt(height); int xl = random.nextInt(12); int yl = random.nextInt(12); gd.drawLine(x, y, x + xl, y + yl); } // randomCode用于保存隨機(jī)產(chǎn)生的驗(yàn)證碼,以便用戶登錄后進(jìn)行驗(yàn)證。 StringBuffer randomCode = new StringBuffer(); int red = 0, green = 0, blue = 0; // 隨機(jī)產(chǎn)生codeCount數(shù)字的驗(yàn)證碼。 for (int i = 0; i < codeCount; i++) { // 得到隨機(jī)產(chǎn)生的驗(yàn)證碼數(shù)字。 String strRand = String.valueOf(codeSequence[random.nextInt(36)]); // 產(chǎn)生隨機(jī)的顏色分量來構(gòu)造顏色值,這樣輸出的每位數(shù)字的顏色值都將不同。 red = random.nextInt(255); green = random.nextInt(255); blue = random.nextInt(255); // 用隨機(jī)產(chǎn)生的顏色將驗(yàn)證碼繪制到圖像中。 gd.setColor(new Color(red,green,blue)); gd.drawString(strRand, (i + 1) * codeX, codeY); // 將產(chǎn)生的四個(gè)隨機(jī)數(shù)組合在一起。 randomCode.append(strRand); } // 將四位數(shù)字的驗(yàn)證碼保存到Session中。 HttpSession session = request.getSession(); session.setAttribute("validateCode", randomCode.toString()); // 禁止圖像緩存。 response.setHeader("Pragma", "no-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); response.setContentType("image/jpeg"); // 將圖像輸出到Servlet輸出流中。 ServletOutputStream sos = response.getOutputStream(); ImageIO.write(buffImg, "jpeg", sos); sos.close(); } }
然后在web.xml中配置下這個(gè)生成驗(yàn)證碼的servlet,具體如下:
<servlet> <servlet-name>VerifyCodeServlet</servlet-name> <servlet-class>com.servlet.VerifyCodeServlet</servlet-class> <init-param> <param-name>width</param-name> <param-value>120</param-value> </init-param> <init-param> <param-name>height</param-name> <param-value>32</param-value> </init-param> <init-param> <param-name>codeCount</param-name> <param-value>4</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>VerifyCodeServlet</servlet-name> <url-pattern>/VerifyCodeServlet</url-pattern> </servlet-mapping>
啟動(dòng)服務(wù)器,在瀏覽器地址欄輸入:http://localhost:8080/webProject/VerifyCodeServlet
查看顯示效果,具體如下:
1、 每次刷新驗(yàn)證碼都有變化,這是因?yàn)閟ervlet設(shè)置了禁用瀏覽器緩存。
2、這里發(fā)現(xiàn)一個(gè)問題:如果使用火狐瀏覽器,VerifyCodeServlet中重寫的serviice方法被執(zhí)行了兩次,換成重寫doGet方法或者doPost方法也是一樣, 并且其他瀏覽器都不見該情況,后來發(fā)現(xiàn)如果是通過頁面引用該servlet就調(diào)用正常了。
然后就可以在頁面中引用該驗(yàn)證碼了,具體代碼如下:
<%@ 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=ISO-8859-1"> <title>Insert title here</title> </head> <body> <div> <% String inputCode = request.getParameter("inputCode"); String verifyCode = (String)session.getAttribute("validateCode"); if(inputCode!=null && verifyCode!=null){ out.print("真正的驗(yàn)證碼:" + verifyCode + "<br/>" + "用戶輸入的驗(yàn)證碼:" + inputCode + "<br/>"); inputCode = inputCode.toUpperCase();//不區(qū)分大小寫 out.print("比較驗(yàn)證碼證明用戶輸入 " + (inputCode.equals(verifyCode)?"正確":"錯(cuò)誤") + "!"); } %> <form action="index.jsp"> 驗(yàn)證碼:<input name="inputCode" value=""/> <img src="VerifyCodeServlet" align="middle" title="看不清,請(qǐng)點(diǎn)我" onclick="javascript:refresh(this);" onmouseover="mouseover(this)"/><br/> <input name="submit" type="submit" value="提交"/> </form> </div> <script> function refresh(obj){ obj.src = "VerifyCodeServlet?" + Math.random(); } function mouseover(obj){ obj.style.cursor = "pointer"; } </script> </body> </html>
上面代碼通過表單提交驗(yàn)證碼到當(dāng)前jsp,驗(yàn)證用戶輸入的驗(yàn)證碼是否正確,運(yùn)行的具體效果如下:
1、輸入正確的驗(yàn)證碼
2、輸入錯(cuò)誤的驗(yàn)證碼
- Java Web開發(fā)之圖形驗(yàn)證碼的生成與使用方法
- Java web含驗(yàn)證碼及權(quán)限登錄實(shí)例代碼
- JavaWeb 實(shí)現(xiàn)驗(yàn)證碼功能(demo)
- javaweb登錄驗(yàn)證碼的實(shí)現(xiàn)方法
- Java Web開發(fā)過程中登陸模塊的驗(yàn)證碼的實(shí)現(xiàn)方式總結(jié)
- java web中圖片驗(yàn)證碼功能的簡(jiǎn)單實(shí)現(xiàn)方法
- Javaweb開發(fā)中通過Servlet生成驗(yàn)證碼圖片
- javaWeb使用驗(yàn)證碼實(shí)現(xiàn)簡(jiǎn)單登錄
- java web開發(fā)之servlet圖形驗(yàn)證碼功能的實(shí)現(xiàn)
- javaweb servlet生成簡(jiǎn)單驗(yàn)證碼
相關(guān)文章
java編寫的簡(jiǎn)單移動(dòng)方塊小游戲代碼
這篇文章主要介紹了java編寫的簡(jiǎn)單移動(dòng)方塊小游戲代碼,涉及Java簡(jiǎn)單圖形繪制與事件響應(yīng)的相關(guān)技巧,需要的朋友可以參考下2015-12-12feign調(diào)用第三方接口,編碼定義GBK,響應(yīng)中文亂碼處理方式
這篇文章主要介紹了feign調(diào)用第三方接口,編碼定義GBK,響應(yīng)中文亂碼處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01詳解Spring Boot中使用Flyway來管理數(shù)據(jù)庫版本
這篇文章主要介紹了詳解Spring Boot中使用Flyway來管理數(shù)據(jù)庫版本,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-01-01詳解JavaScript中的函數(shù)聲明和函數(shù)表達(dá)式
這篇文章主要介紹了詳解JavaScript中的函數(shù)聲明和函數(shù)表達(dá)式,是JS入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-08-08Java字符串拼接的五種方法及性能比較分析(從執(zhí)行100次到90萬次)
字符串拼接一般使用“+”,但是“+”不能滿足大批量數(shù)據(jù)的處理,Java中有以下五種方法處理字符串拼接及性能比較分析,感興趣的可以了解一下2021-12-12詳解mybatis #{}和${}的區(qū)別、傳參、基本語法
這篇文章主要介紹了mybatis #{}和${}的區(qū)別、傳參、基本語法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07