简单的验证码实现

344 阅读2分钟

一、实现思路

  1. 使用BufferedImage用于在内存中存储生成的验证码图片
  2. 使用Graphics来进行验证码图片的绘制
  3. 最后通过ImageIO将生成的图片进行输出

二、实现代码


import javax.imageio.ImageIO;
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 java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

/**
 * 验证码工具类
 */
@WebServlet("/cta")
public class CaptcahCode extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        CaptcahCode.drawImage(resp);
    }

    /**
     * 验证码的生成方法
     * @param response
     * @return
     */
    public static void drawImage(HttpServletResponse response) {

        //1、使用stringbuilder类,对字符串进行处理。不用String,因为其赋值后不能改变。
        StringBuilder builder = new StringBuilder();
        //2、产生随机数,长度为4
        for (int i = 0; i < 4; i++) {
            builder.append(randomChar());
        }
        Random random = new Random();
        String  code = builder.toString();
        //3、定义图片的宽度和高度,使用BufferedImage对象。
        int width = 120;
        int height = 25;

        BufferedImage bi = new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR);
        //4、获取Graphics2D 绘制对象,开始绘制验证码
        Graphics2D g = bi.createGraphics();
        //6、定义字体的颜色
        Color color = new Color(0,0,0);
        // 设置字体(定义文字的字体和大小)
        //Font font1 = getFont(fontHeight);
        Font font = new Font("Fixedsys", Font.BOLD, 20);
        g.setFont(font);
        //设置颜色
        g.setColor(color);
        //设置背景
        g.setBackground(new Color(226,226,240   ));
        //开始绘制对象
        g.clearRect(0,0,width,height);
        //绘制形状,获取矩形对象
        FontRenderContext context = g.getFontRenderContext();
        Rectangle2D bounds = font.getStringBounds(code,context);
        //计算文件的坐标和间距
        double x = (width - bounds.getWidth())/2;
        double y = (height- bounds.getHeight())/2;
        double ascent = bounds.getY();
        double baseY = y - ascent;
        //干扰线
        for (int i = 0; i < 20; i++) {
           int xs = random.nextInt(width);
           int ys = random.nextInt(height);
           int xe = xs + random.nextInt(width);
           int ye = ys + random.nextInt(height);
           g.setColor(getRandColor(1, 255));
           g.drawLine(xs, ys, xe, ye);
           }
        // 添加噪点
        float yawpRate = 0.01f;
        int area = (int) (yawpRate * width * height);
        for (int i = 0; i < area; i++) {
            int xz = random.nextInt(width);
            int yz = random.nextInt(height);

            bi.setRGB(xz, yz, random.nextInt(255));
        }
        g.drawString(code,(int)x,(int)baseY);
        //结束绘制
        g.dispose();

        try {
            ImageIO.write(bi,"jpg",response.getOutputStream());
            //刷新响应流
            response.flushBuffer();
        } catch (IOException e) {
            e.printStackTrace();
        }
//        return code;

    }

    /**
     * 此方法用于用户产生随机字母和数字
     * @return
     */
    private static char randomChar(){
        // 1、定义验证需要的字母和数字
        String str = "ZXCVBNMASDFGHJKLQWERTYUIOP0123456789";
        //2、定义随机对象
        Random random = new Random();
        //3、返回随机字符
        return  str.charAt(random.nextInt(str.length()));

    }
    /**
     * 得到随机颜色
     * @param fc
     * @param bc
     * @return
     */
    private static Color getRandColor(int fc, int bc) {
        Random random = new Random();
        if (fc > 255){
            fc = 255;
        }
        if (bc > 255){
            bc = 255;
        }
        int r = fc + random.nextInt(bc - fc);
        int g = fc + random.nextInt(bc - fc);
        int b = fc + random.nextInt(bc - fc);
        return new Color(r, g, b);
    }
    /**
     * 产生随机字体
     */
    private Font getFont(int size) {
        Random random = new Random();
        Font[] font = new Font[5];
        font[0] = new Font("Ravie", Font.PLAIN, size);
        font[1] = new Font("Antique Olive Compact", Font.PLAIN, size);
        font[2] = new Font("Fixedsys", Font.PLAIN, size);
        font[3] = new Font("Wide Latin", Font.PLAIN, size);
        font[4] = new Font("Gill Sans Ultra Bold", Font.PLAIN, size);
        return font[random.nextInt(5)];
    }


}

三、结果展示

YDDK`D58V_Q@VL_2_VL_NVD.png

四、总结

生成的验证码添加比较简单线条等干扰因素,比较容易识别。在实际的项目中可采用其他的第三方验证码库来生成验证码。