驗證碼不用多說,在 WEB-APP 中一般應用于:登錄、注冊、買某票、秒殺等場景。大家都接觸過~可以說是千奇百怪,各式各樣。
DEMO 目標功能
- 驗證碼頁面輸入。
- 頁面更換驗證碼(異步實現)。
- 后臺驗證并返回驗證結果。
開工
頁面:demo1.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
<%@ page language= "java" import = "java.util.*" pageEncoding= "UTF-8" %> <!DOCTYPE html> <html> <head> <title>驗證示例</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;} /* 后臺返回的驗證信息顯示為紅色 */ </style> </head> <body> <form action= "${pageContext.request.contextPath}/check" method= "post" enctype= "application/x-www-form-urlencoded" > 驗證碼:<input type= "text" name= "code" size= "4" maxlength= "4" id= "code" /> <img id= "code-img" src= "" alt= "驗證碼" style= "display: none;" /> <a href= "javascript:void(0)" rel= "external nofollow" id= "changeCode" >看不清?換一張</a> <br/><br/> <input type= "submit" value= "驗證" /> <span id= "msg" >${msg}</span> </form> </body> </html> |
說明:
"看不清?換一張" 的 href 屬性寫成 javascript:void(0)
是為了防止頁面刷新,這里的更換功能交給 AJAX 異步完成。
JavaScript 工具:util.js(為啥用原生 JS?任性唄~哈)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
/** * 獲取 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; } |
頁面中的 JavaScript 代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<script type= "text/javascript" src= "${pageContext.request.contextPath}/js/util.js" ></script> <script type= "text/javascript" > var xhr = getXHR(); // 獲得 XMLHttpRequest 對象 // 頁面加載時加載驗證碼,但驗證碼初始為隱藏狀態 window.onload=function() { // 為 onreadystatechange 事件注冊回調函數。由于 xhr 為全局變量,所以注冊后就不用管啦 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 ); } // 驗證碼輸入框獲得焦點時,驗證碼狀態更改為顯示 document.getElementById( 'code' ).onfocus=function() { document.getElementById( 'code-img' ).style.display= "inline" ; } // 異步請求,更換驗證碼 document.getElementById( 'changeCode' ).onclick=function() { xhr.open( "GET" , "${pageContext.request.contextPath}/captcha/code" , true ); xhr.send( null ); } </script> |
生成驗證碼的 CaptchaCodeServlet.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
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 { // 生成驗證碼(構造參數分別代表:寬度,高度,字符數,干擾線條數) ValidateCode code = new ValidateCode( 87 , 33 , 4 , 23 ); // 將驗證碼保存到 session 中,用于驗證 request.getSession().setAttribute( "code" , code.getCode()); // 響應返回驗證碼圖片 base64 編碼后的數據給瀏覽器 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
(用起來挺爽的),也就是說簡單的項目不再需要 web.xml
了,但是 Tomcat
需要 7.0+。
其次生成驗證碼我用了一個小工具:ValidateCode.jar。工具十分簡單,不合心意完全可以自己寫。但也就是因為功能太少,所以我又寫了一個 ImageUtil
。我也有打算自己開源一個驗證碼工具出來。
ImageUtil.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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 { /** * 將圖片二進制數據進行 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() {} // 工具類私有化構造方法是常見的做法 } |
說明:
為什么要把圖片二進制數據進行 Base64編碼 呢?因為<img/>
標簽雖然可以直接設置 src
屬性值為${pageContext.request.contextPath}/captcha/code
請求相應的 Servlet 來得到二進制數據直接顯示,但在 AJAX 異步請求中響應返回的是 xhr.responseText
。當把數據直接給 img
標簽的 src
屬性時,用 Chrome-tool
查看只會是一堆二進制當作文本解析的亂碼字符,所以才要多這一步。
或許我作為萌新不知道一些其它的方便技巧。但若不想使用異步,那直接 img src
設置為請求地址將是最簡單的選擇,更換驗證碼無非是監聽事件 img src
重新設置為該地址(再來一次請求)。
后臺驗證驗證碼:CheckServlet.jave
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
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); /* 驗證碼驗證 */ String inputCode = request.getParameter( "code" ); // 獲得 session 中的正確驗證碼 String realCode = (String) request.getSession().getAttribute( "code" ); System.out.println( "input: " +inputCode+ "\nreal: " +realCode); // 用于 Debug if (!(inputCode!= null && realCode!= null && inputCode.equalsIgnoreCase(realCode))) { // 若驗證碼不正確:回到頁面并提示錯誤 request.setAttribute( "msg" , "驗證碼錯誤!請重新輸入" ); request.getRequestDispatcher( "/demo1.jsp" ).forward(request, response); return ; } // 驗證碼正確,響應一句話表示 OK response.getWriter().write( "驗證成功!" ); } @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } |
說明:
doGet() 方法一開始是對中文亂碼進行處理,編碼統一設為 UTF-8。在實際項目中,編碼問題通常交給一個 Filter 完成,達到一勞永逸的效果。
效果
警告!警告!!顏控請速速撤離!!!
寫在最后
以上就是 JavaWeb 驗證碼小 DEMO 的全部內容啦,最好是把驗證提交也搞成異步的,這里就不整了。WEB 項目中還沒嘗試過添加驗證碼功能的小伙伴可以動手搞起來啦!實際項目中利用 JQuery 等框架處理 AJAX,再配上一個漂亮的前端頁面就完美啦。
以上所述是小編給大家介紹的JavaWeb 實現驗證碼功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!
原文鏈接:http://www.jianshu.com/p/9284a31e6ce8