欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaWeb 实现验证码功能(demo)

程序员文章站 2024-03-08 08:05:51
验证码不用多说,在 web-app 中一般应用于:登录、注册、买某票、秒杀等场景。大家都接触过~可以说是千奇百怪,各式各样。 demo 目标功能 验证码页面输入...

验证码不用多说,在 web-app 中一般应用于:登录、注册、买某票、秒杀等场景。大家都接触过~可以说是千奇百怪,各式各样。

demo 目标功能

  • 验证码页面输入。
  • 页面更换验证码(异步实现)。
  • 后台验证并返回验证结果。

开工

页面:demo1.jsp

<%@ 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?任性呗~哈)

/**
 * 获取 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 代码

<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

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

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 重新设置为该地址(再来一次请求)。

  详细的资料:js在浏览器中解析base64编码图像

        base64图片编码解析及浏览器的兼容性处理

后台验证验证码: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);
 /* 验证码验证 */
 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)

写在最后

  以上就是 javaweb 验证码小 demo 的全部内容啦,最好是把验证提交也搞成异步的,这里就不整了。web 项目中还没尝试过添加验证码功能的小伙伴可以动手搞起来啦!实际项目中利用 jquery 等框架处理 ajax,再配上一个漂亮的前端页面就完美啦。

以上所述是小编给大家介绍的javaweb 实现验证码功能,希望对大家有所帮助