验证码实现
网上大都是通过servlet实现的验证码,入下图逻辑:步骤: 1、请求登录页面时随机生成验证码字符串; 2、将生成对验证码字符串存到session中; 3、根据验证码字符串生成验证码图片,然后将验证码图片输出到客户展示; 4、提交登录请求时用户输入的验证码字符串与session中的字符串做比对。
现在很多人都采用Spring mvc,为了更加灵活,解耦servlet,可以写一个验证码制作器:
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Calendar;
import java.util.Random;
public class ValidateCodeMaker {
private int imgWidth = 80; //验证码图片宽度
private int imgHeight = 30; //验证码图片高度
private int charCount = 4; //验证码字符个数
public ValidateCodeMaker() {
}
public ValidateCodeMaker(int imgWidth, int imgHeight, int charCount) {
this.imgWidth = imgWidth;
this.imgHeight = imgHeight;
this.charCount = charCount;
}
//客户端生成验证码图片,并且验证码字符串存session
public void generateValidateCode(HttpSession session,HttpServletResponse response) throws IOException {
String validateCode = randomCode(charCount);
session.setAttribute(Constants.VALIDATE_CODE,validateCode);
session.setAttribute(Constants.VALIDATE_CODE_TIEM, Calendar.getInstance());
// request.getSession().setAttribute("validateCode",validateCode);
BufferedImage image = getCodeImage(validateCode);
response.setContentType("image/jpeg");
OutputStream out = response.getOutputStream();
ImageIO.write(image,"jpeg",out);
}
//用户输入的验证码与session中的验证码字符串对比校验
public static boolean verifyValidateCode(HttpSession session,String checkCode){
String validateCode = (String) session.getAttribute(Constants.VALIDATE_CODE);
Calendar validateCodeTime = (Calendar) session.getAttribute(Constants.VALIDATE_CODE_TIEM);
validateCodeTime.add(Calendar.MINUTE,5); //验证码5分钟有效期
Calendar now = Calendar.getInstance();
if(now.before(validateCodeTime) && validateCode.equals(checkCode.trim().toUpperCase()) ){
session.removeAttribute(Constants.VALIDATE_CODE);
session.removeAttribute(Constants.VALIDATE_CODE_TIEM);
return true;
}
return false;
}
//生成验证码图片
public BufferedImage getCodeImage(String validateCode){
BufferedImage image =
new BufferedImage(imgWidth,imgHeight,BufferedImage.TYPE_INT_RGB); //画布
Graphics g = image.getGraphics(); //画笔
Random r = new Random();
//设置画笔颜色,grb值偏大一些可使背景色偏淡
g.setColor(new Color(r.nextInt(155)+100,r.nextInt(155)+100,r.nextInt(155)+100));
g.fillRect(0, 0, imgWidth, imgHeight); //设置验证码图片背景色
g.setColor(new Color(0, 0, 0));
//Font:参数1->字体类别 参数2->字体样式 参数3->字体size
g.setFont(new Font(null,Font.ITALIC+Font.BOLD,20));
g.drawString(validateCode,10,20); //将字符串画到图片上
//加上一些干扰线
for(int i=0;i<8;i++){
g.drawLine(r.nextInt(80),
r.nextInt(30),
r.nextInt(80),
r.nextInt(30));
}
g.dispose();
return image;
}
//生成随机字符串
public String randomCode(int size){
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
String code = "";
Random r = new Random();
for(int i=0;i<size;i++){
code +=chars.charAt(r.nextInt(chars.length()));
}
return code;
}
}
页面中验证码区域:
<label>验证码:</label>
<input name="checkCode">
<img id="img1" src="${request.contextPath}/requestCheckCode"
onclick="this.src='${request.contextPath}/requestCheckCode?' + Math.random();"/>
<a href="javascript:;"
onclick="document.getElementById('img1').src='${request.contextPath}/requestCheckCode?' + Math.random();">看不清,换一个</a>
客户端请求时,因为IO开销较大,验证码显示会迟与页面的加载,可采用一点小技巧处理这种情况:
比如:客户端请求时,因为验证码图片是异步加载的,可以先隐藏页面的验证码区域,当某一个输入框失去焦点时在将验证码区域显示出来。