验证码:验证码(CAPTCHA)是“Completely Automated Public Turing test to tell Computers and Humans Apart”(全自动区分计算机和人类的图灵测试)的缩写,是一种区分用户是计算机还是人的公共全自动程序。可以防止:恶意破解密码、刷票、论坛灌水,有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试,实际上用验证码是现在很多网站通行的方式,我们利用比较简易的方式实现了这个功能。这个问题可以由计算机生成并评判,但是必须只有人类才能解答。由于计算机无法解答CAPTCHA的问题,所以回答出问题的用户就可以被认为是人类。
上面这段文字就是对验证码的定义,相关定义见百度词条:验证码
在初学JavaWeb的过程中,想学习关于验证码的知识。随着技术的进步,各种类型的验证码层出不穷,常见的验证码有:短信验证码、数字验证码、中文汉字验证码、图形验证码、混合验证码等等类型。编者作为JavaWeb的一个初学者,将在此博客中记录最简单的验证码方式,4位数字验证码。去哦是验证码的原理是非常简单的,使用Java生成一张固定比例的图片,在通过随机产生4位数字放在图片上,后再给图片一些干扰线,最后将图片输出在网页上即可。并且在此过程中产生的随机数需要放在一个session中,后面需要在这个session中获取验证码内容并且用来验证前端提交的验证码。话不多说,我们先来看如何实现的。
第一步:新建一个Java类,本例命名为Vcode.java 。此类的作用是生成验证码,代码如下:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;
import javax.imageio.ImageIO;
public class Vcode {
private int w = 70;
private int h = 35;
private Random r = new Random();
// {"宋体", "华文楷体", "黑体", "华文新魏", "华文隶书", "微软雅黑", "楷体_GB2312"}
private String[] fontNames = {"宋体", "华文楷体", "黑体", "微软雅黑", "楷体_GB2312"};
private String codes = "23456789abcdefghjkmnopqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ";
private Color bgColor = new Color(255, 255, 255);
private String text ;
private Color randomColor () {
int red = r.nextInt(150);
int green = r.nextInt(150);
int blue = r.nextInt(150);
return new Color(red, green, blue);
}
private Font randomFont () {
int index = r.nextInt(fontNames.length);
String fontName = fontNames[index];
int style = r.nextInt(4);
int size = r.nextInt(5) + 24;
return new Font(fontName, style, size);
}
private void drawLine (BufferedImage image) {
int num = 3;
Graphics2D g2 = (Graphics2D)image.getGraphics();
for(int i = 0; i < num; i++) {
int x1 = r.nextInt(w);
int y1 = r.nextInt(h);
int x2 = r.nextInt(w);
int y2 = r.nextInt(h);
g2.setStroke(new BasicStroke(1.5F));
g2.setColor(Color.BLUE);
g2.drawLine(x1, y1, x2, y2);
}
}
private char randomChar () {
int index = r.nextInt(codes.length());
return codes.charAt(index);
}
private BufferedImage createImage () {
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = (Graphics2D)image.getGraphics();
g2.setColor(this.bgColor);
g2.fillRect(0, 0, w, h);
return image;
}
public BufferedImage getImage () {
BufferedImage image = createImage();
Graphics2D g2 = (Graphics2D)image.getGraphics();
StringBuilder sb = new StringBuilder();
// 向图片中画4个字符
for(int i = 0; i < 4; i++) {
String s = randomChar() + "";
sb.append(s);
float x = i * 1.0F * w / 4;
g2.setFont(randomFont());
g2.setColor(randomColor());
g2.drawString(s, x, h-5);
}
this.text = sb.toString();
drawLine(image);
return image;
}
public String getText () {
return text;
}
public static void output (BufferedImage image, OutputStream out)
throws IOException {
ImageIO.write(image, "JPEG", out);
}
}
第二步:新建一个servlet,本例命名为VcodeServlet,此servlet的作用是:前端页面需要生成验证码的地方请求该servlet。代码如下:
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Vcode vc = new Vcode();
BufferedImage image = vc.getImage();// 获取一次性验证码图片
// 该方法必须在getImage()方法之后来调用
Vcode.output(image, response.getOutputStream());// 把图片写到指定流中
// 把文本保存到session中,为LoginServlet验证做准备
request.getSession().setAttribute("vCode", vc.getText());
}
第三步:在index.jsp中的body元素中添加以下代码:
<form action="">
验证码:<input type="text" name = "yzm"><br>
<img alt="验证码" src="servlet/VcodeServlet"><br>
<input type="submit" value="提交">
</form>
第四步:发布服务器,测试结果如下:
综上所述,验证码的基本功能就已经实现了。现在接下来需要考虑的问题是:
1,如何实现验证码的换一张功能;
2,在输入框中失去焦点验证索输入的验证码是否正确;
3,后台校验验证码
为解决问题一和二,这里需要采用js来实现验证。本例中采用jquery来实现验证码的换一张和失去焦点验证。
验证码实现换一张功能:此时在index.jsp中的body元素中代码如下:
<form action="">
验证码:<input type="text" name = "yzm"><br>
<img alt="验证码" id = "imgVerifyCode" src="servlet/VcodeServlet"><br>
<a href = "javascript:_hyz()">换一张</a><br>
<input type="submit" value="提交">
</form>
引入相对应的jqery库,书写实现换一张的js代码,如下:
<script type="text/javascript" src = "/vcode/js/jquery-1.5.1.js"></script>
<script type="text/javascript">
function _hyz() {
/*
* 1. 获取<img>元素
* 2. 重新设置它的src
* 3. 使用毫秒来添加参数
*/
$("#imgVerifyCode").attr("src", "servlet/VcodeServlet?a=" + new Date().getTime());
}
</script>
此时发布服务器访问结果会出现如下结果:
点击换一张出现如下结果:
至此换一张的功能实现。
实现验证码的异步校验,即请求服务器验证输入框中的验证码是否和图片上的验证码正确,需要以下几步:
1.新建一个VerifyCodeServlet类,此类用来验证输入框中所填验证码和图片中的验证码是否完全一致,代码如下:
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String yzm = request.getParameter("yzm");
String vcode = (String) request.getSession().getAttribute("vCode");
boolean result = yzm.equalsIgnoreCase(vcode);
PrintWriter out = response.getWriter();
out.print(result);
}
2.此时在index.jsp中的body元素中代码如下:
<form action="">
验证码:<input type="text" id="verifycode" οnblur="checkVerifyCcode()" name = "yzm"><br>
<img alt="验证码" id = "imgVerifyCode" src="servlet/VcodeServlet"><br>
<a href = "javascript:_hyz()">换一张</a><br>
<input type="submit" value="提交">
</form>
3.在javascript中代码如下:
<script type="text/javascript">
function _hyz() {
/*
* 1. 获取<img>元素
* 2. 重新设置它的src
* 3. 使用毫秒来添加参数
*/
$("#imgVerifyCode").attr("src", "servlet/VcodeServlet?a=" + new Date().getTime());
}
function checkVerifyCcode(){
var id = "verifycode";
var value = $("#"+id).val();
/*
*1.非空校验
*/
if(!value){
alert("验证码不能为空!");
}
/*
*2.长度校验
*/
if(value.length != 4){
alert("错误的验证码!");
}
/*
*3.ajax异步验证
*/
$.ajax({
url:"servlet/VerifyCodeServlet",//要请求的servlet
data:{yzm:value},
type:"POST",
dataType:"json",
async:false,//是否异步请求,如果是异步,那么不会等服务器返回,我们这个函数就向下运行了。
cache:false,
success:function(result){
//alert(result);
if(!result){
alert("验证码错误!");
}
}
});
}
</script>
4.发布服务器,重新访问项目:并按照相应情况测试。编者的测试结果完全正确,测试图如下。
测试结果错误的图
测试结果正确的图
总结:在编者实现这个案例的过程中遇到了诸多问题都逐一解决了,本例中还存在一个问题:在js验证的时候本例是直接弹出一个警告框,实际例子中需要对本案例进行适当的修改。另外生成验证码的方式有很多种,需要读者自己去选择适合自己的。如今各大网络巨头也已经给出了相应的验证码方式,如网易等。欢迎读者提出新的想法和批评指正文章中不足的地方。严谨求学是编者的一个心愿。
最后附上本案例的源码:http://download.csdn.net/download/rong_gong/10247856