java web验证码实现

时间:2022-12-30 19:06:35

验证码实现

网上大都是通过servlet实现的验证码,入下图逻辑: java web验证码实现
步骤: 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开销较大,验证码显示会迟与页面的加载,可采用一点小技巧处理这种情况:

比如:客户端请求时,因为验证码图片是异步加载的,可以先隐藏页面的验证码区域,当某一个输入框失去焦点时在将验证码区域显示出来。