JavaWeb 實(shí)現(xiàn)驗(yàn)證碼功能(demo)
驗(yàn)證碼不用多說,在 WEB-APP 中一般應(yīng)用于:登錄、注冊(cè)、買某票、秒殺等場(chǎng)景。大家都接觸過~可以說是千奇百怪,各式各樣。
DEMO 目標(biāo)功能
- 驗(yàn)證碼頁(yè)面輸入。
- 頁(yè)面更換驗(yàn)證碼(異步實(shí)現(xiàn))。
- 后臺(tái)驗(yàn)證并返回驗(yàn)證結(jié)果。
開工
頁(yè)面:demo1.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <title>驗(yàn)證示例</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <style type="text/css"> img { width: 87px; height: 33px; border: 1px solid gray; } #msg {color: red;} /* 后臺(tái)返回的驗(yàn)證信息顯示為紅色 */ </style> </head> <body> <form action="${pageContext.request.contextPath}/check" method="post" enctype="application/x-www-form-urlencoded"> 驗(yàn)證碼:<input type="text" name="code" size="4" maxlength="4" id="code" /> <img id="code-img" src="" alt="驗(yàn)證碼" style="display: none;"/> <a href="javascript:void(0)" rel="external nofollow" id="changeCode">看不清?換一張</a> <br/><br/> <input type="submit" value="驗(yàn)證"/> <span id="msg">${msg}</span> </form> </body> </html>
說明:
"看不清?換一張" 的 href 屬性寫成 javascript:void(0)
是為了防止頁(yè)面刷新,這里的更換功能交給 AJAX 異步完成。
JavaScript 工具:util.js(為啥用原生 JS?任性唄~哈)
/** * 獲取 XMLHttpRequest Object * @returns XMLHttpRequest Object */ function getXHR() { var xmlHttp; try { // Firefox, Opera 8.0+, Safari xmlHttp = new XMLHttpRequest(); } catch (e) { // Internet Explorer try { xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { alert("Sorry, 您的瀏覽器不支持 AJAX!"); return false; } } } return xmlHttp; }
頁(yè)面中的 JavaScript 代碼
<script type="text/javascript" src="${pageContext.request.contextPath}/js/util.js"></script> <script type="text/javascript"> var xhr = getXHR(); // 獲得 XMLHttpRequest 對(duì)象 // 頁(yè)面加載時(shí)加載驗(yàn)證碼,但驗(yàn)證碼初始為隱藏狀態(tài) window.onload=function() { // 為 onreadystatechange 事件注冊(cè)回調(diào)函數(shù)。由于 xhr 為全局變量,所以注冊(cè)后就不用管啦 xhr.onreadystatechange=function() { if(xhr.readyState==4 && xhr.status==200) { document.getElementById('code-img').src="data:image/png;base64,"+xhr.responseText; } } xhr.open("GET","${pageContext.request.contextPath}/captcha/code",true); xhr.send(null); } // 驗(yàn)證碼輸入框獲得焦點(diǎn)時(shí),驗(yàn)證碼狀態(tài)更改為顯示 document.getElementById('code').onfocus=function() { document.getElementById('code-img').style.display="inline"; } // 異步請(qǐng)求,更換驗(yàn)證碼 document.getElementById('changeCode').onclick=function() { xhr.open("GET","${pageContext.request.contextPath}/captcha/code",true); xhr.send(null); } </script>
生成驗(yàn)證碼的 CaptchaCodeServlet.java
package com.leo.web.captcha; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.leo.util.ImageUtil; import cn.dsna.util.images.ValidateCode; @WebServlet("/captcha/code") public class CaptchaCodeServlet extends HttpServlet { private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 生成驗(yàn)證碼(構(gòu)造參數(shù)分別代表:寬度,高度,字符數(shù),干擾線條數(shù)) ValidateCode code = new ValidateCode(87, 33, 4, 23); // 將驗(yàn)證碼保存到 session 中,用于驗(yàn)證 request.getSession().setAttribute("code", code.getCode()); // 響應(yīng)返回驗(yàn)證碼圖片 base64 編碼后的數(shù)據(jù)給瀏覽器 response.getWriter().write(ImageUtil.encodeImg2Base64(code.getBuffImg(), "png")); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
說明:
這里使用了 Servlet3.0
的新特性-用注解配置 url-pattern
(用起來挺爽的),也就是說簡(jiǎn)單的項(xiàng)目不再需要 web.xml
了,但是 Tomcat
需要 7.0+。
其次生成驗(yàn)證碼我用了一個(gè)小工具:ValidateCode.jar。工具十分簡(jiǎn)單,不合心意完全可以自己寫。但也就是因?yàn)楣δ芴?,所以我又寫了一個(gè) ImageUtil
。我也有打算自己開源一個(gè)驗(yàn)證碼工具出來。
ImageUtil.java
package com.leo.util; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import javax.imageio.ImageIO; import sun.misc.BASE64Encoder; public class ImageUtil { /** * 將圖片二進(jìn)制數(shù)據(jù)進(jìn)行 base64 編碼 * @param bufImg * @return base64 編碼后的字符串 */ public static String encodeImg2Base64(BufferedImage bufImg, String formatName) { ByteArrayOutputStream outputStream = null; try { outputStream = new ByteArrayOutputStream(); ImageIO.write(bufImg, formatName, outputStream); } catch (IOException e) { throw new RuntimeException("Base64 編碼失??!"+e.getMessage()); } BASE64Encoder encoder = new BASE64Encoder(); return encoder.encode(outputStream.toByteArray()); } private ImageUtil() {} // 工具類私有化構(gòu)造方法是常見的做法 }
說明:
為什么要把圖片二進(jìn)制數(shù)據(jù)進(jìn)行 Base64編碼 呢?因?yàn)?code><img/>標(biāo)簽雖然可以直接設(shè)置 src
屬性值為${pageContext.request.contextPath}/captcha/code
請(qǐng)求相應(yīng)的 Servlet 來得到二進(jìn)制數(shù)據(jù)直接顯示,但在 AJAX 異步請(qǐng)求中響應(yīng)返回的是 xhr.responseText
。當(dāng)把數(shù)據(jù)直接給 img
標(biāo)簽的 src
屬性時(shí),用 Chrome-tool
查看只會(huì)是一堆二進(jìn)制當(dāng)作文本解析的亂碼字符,所以才要多這一步。
或許我作為萌新不知道一些其它的方便技巧。但若不想使用異步,那直接 img src
設(shè)置為請(qǐng)求地址將是最簡(jiǎn)單的選擇,更換驗(yàn)證碼無非是監(jiān)聽事件 img src
重新設(shè)置為該地址(再來一次請(qǐng)求)。
詳細(xì)的資料:JS在瀏覽器中解析Base64編碼圖像
后臺(tái)驗(yàn)證驗(yàn)證碼:CheckServlet.jave
package com.leo.web.controller; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/check") public class CheckServlet extends HttpServlet { private static final long serialVersionUID = -6588625852621588221L; @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String encoding = "UTF-8"; request.setCharacterEncoding(encoding); response.setContentType("text/html;charset="+encoding); /* 驗(yàn)證碼驗(yàn)證 */ String inputCode = request.getParameter("code"); // 獲得 session 中的正確驗(yàn)證碼 String realCode = (String) request.getSession().getAttribute("code"); System.out.println("input: "+inputCode+"\nreal: "+realCode); // 用于 Debug if(!(inputCode!=null && realCode!=null && inputCode.equalsIgnoreCase(realCode))) { // 若驗(yàn)證碼不正確:回到頁(yè)面并提示錯(cuò)誤 request.setAttribute("msg", "驗(yàn)證碼錯(cuò)誤!請(qǐng)重新輸入"); request.getRequestDispatcher("/demo1.jsp").forward(request, response); return; } // 驗(yàn)證碼正確,響應(yīng)一句話表示 OK response.getWriter().write("驗(yàn)證成功!"); } @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
說明:
doGet() 方法一開始是對(duì)中文亂碼進(jìn)行處理,編碼統(tǒng)一設(shè)為 UTF-8。在實(shí)際項(xiàng)目中,編碼問題通常交給一個(gè) Filter 完成,達(dá)到一勞永逸的效果。
效果
警告!警告??!顏控請(qǐng)速速撤離!?。?/p>
寫在最后
以上就是 JavaWeb 驗(yàn)證碼小 DEMO 的全部?jī)?nèi)容啦,最好是把驗(yàn)證提交也搞成異步的,這里就不整了。WEB 項(xiàng)目中還沒嘗試過添加驗(yàn)證碼功能的小伙伴可以動(dòng)手搞起來啦!實(shí)際項(xiàng)目中利用 JQuery 等框架處理 AJAX,再配上一個(gè)漂亮的前端頁(yè)面就完美啦。
以上所述是小編給大家介紹的JavaWeb 實(shí)現(xiàn)驗(yàn)證碼功能,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
Java數(shù)據(jù)結(jié)構(gòu)之線段樹中的懶操作詳解
對(duì)于線段樹,若要求對(duì)區(qū)間中的所有點(diǎn)都進(jìn)行更新,可以引入懶操作。懶操作包括區(qū)間更新和區(qū)間查詢操作。本文將通過一個(gè)示例和大家詳細(xì)聊聊線段樹中的懶操作,需要的可以參考一下2022-10-10java中LinkedBlockingQueue與ArrayBlockingQueue的異同
這篇文章主要介紹了java中LinkedBlockingQueue與ArrayBlockingQueue的異同,需要的朋友可以參考下2016-08-08使用Sentinel實(shí)現(xiàn)流控和服務(wù)降級(jí)的代碼示例
Sentinel是面向分布式、多語言異構(gòu)化服務(wù)架構(gòu)的流量治理組件,本文將詳細(xì)為大家介紹如何使用Sentinel實(shí)現(xiàn)流控和服務(wù)降級(jí),文中有相關(guān)的代碼示例,需要的朋友可以參考下2023-05-05Java中實(shí)現(xiàn)文件上傳下載的三種解決方案(推薦)
這篇文章主要介紹了Java中實(shí)現(xiàn)文件上傳下載的三種解決方案的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07如何實(shí)現(xiàn)springboot中controller之間的相互調(diào)用
這篇文章主要介紹了實(shí)現(xiàn)springboot中controller之間的相互調(diào)用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06Springboot實(shí)現(xiàn)給前端返回一個(gè)tree結(jié)構(gòu)方法
這篇文章主要介紹了SpringBoot返回給前端一個(gè)tree結(jié)構(gòu)的實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07Mybatis一對(duì)多和多對(duì)一處理的深入講解
Mybatis可以通過關(guān)聯(lián)查詢實(shí)現(xiàn),關(guān)聯(lián)查詢是幾個(gè)表聯(lián)合查詢,只查詢一次,通過在resultMap里面的association,collection節(jié)點(diǎn)配置一對(duì)一,一對(duì)多的類就可以完成,這篇文章主要給大家介紹了關(guān)于Mybatis一對(duì)多和多對(duì)一處理的相關(guān)資料,需要的朋友可以參考下2021-09-09Spring?Boot?教程之創(chuàng)建項(xiàng)目的三種方式
這篇文章主要分享了Spring?Boot?教程之創(chuàng)建項(xiàng)目的三種方式,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-05-05