首页 > 技术文章 > 验证码

Spirit612 2015-05-14 21:20 原文

大家在登录账号时经常会遇到验证码,输入验证码来识别人和机器是防止恶意软件盗取账号密码的最好方式,

验证码的Java代码,我在这里总结两种方式。

 

一、自定义方法:

package yanzhengma;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.Random;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

/**
 * 绘制验证码图像
 *
 * @author Spirit桥
 *
 */
public class YzmColor {

    // 图像宽度
    private int width = 200;
    // 图像高度
    private int height = 80;
    // 验证码字符长度
    private int length = 6;
    // 随机生成验证码基础字符串
    private final String azAZ19 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

    /**
     * 获取验证码图像
     *
     * @return 验证码图像
     */
    public BufferedImage getCaptchaImage() {
        // 创建图像缓冲区
        BufferedImage img = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        // 获取图像上下文(画笔)
        Graphics gp = img.getGraphics();
        // 设置图像背景色,填充背景矩形
        gp.setColor(Color.WHITE);//白色
        /*public abstract void fillRect(int x, y,int width, int height);
        x - 要填充矩形的 x 坐标。
        y - 要填充矩形的 y 坐标。
        width - 要填充矩形的宽度。
        height - 要填充矩形的高度。*/
        gp.fillRect(0, 0, width, height);
        /* 生成随机验证码 */
        int len = azAZ19.length(); // 基础字符串长度
        gp.setFont(new Font("楷体", Font.BOLD, 30)); // 设置验证码字体,效果及大小(楷体,加粗,30px)
        // 循环生成验证码各字符
        Random rand = new Random();
        for (int i = 0; i < length; i++) {
            // 随机生成验证码中单个字符
            String randStr = String.valueOf(azAZ19.charAt(rand
                    .nextInt(len)));
            // 绘制单个字符宽度
            int width = this.width / this.length;
            // 绘制当前字符原点
            int x = width * i;
            int y = this.height / 2 + rand.nextInt(this.height / 5);
            /* 将该字符画到图像中 */
            drawString(gp, x, y, randStr);
        }
        // 画干扰线
        drawLine(gp, 10);
        // 释放图像上下文(画笔)
        gp.dispose();
        return img;
    }

    /**
     * 画验证码字符串中单个字符
     *
     * @param gp
     *            图像上下文
     * @param width
     *            字符所占宽度
     * @param height
     *            字符所占高度
     * @param str
     *            待绘制字符串
     */
    private void drawString(Graphics gp, int width, int height, String str) {
        Random rand = new Random();
        // 随机生成字符旋转角度(-30~30度)
        int degree = rand.nextInt(60);
        if (degree > 30)
            degree = 30 - degree;
        // 设置字体颜色
        gp.setColor(getRandomColor(0, 200));//字体颜色稍深色一点
        // 转换 Graphics2D
        Graphics2D g2 = (Graphics2D) gp.create();
        // 平移原点到图形环境的中心 ,就是将字符串移动到某一个位置
        g2.translate(width + rand.nextInt(5), height + rand.nextInt(5));
        // 旋转文本
        g2.rotate(degree * Math.PI / 180);
        // 画文本,这里的画笔已经具有了上次指定的一个位置,所以这里指定的是一个相对位置
        g2.drawString(str, 0, 0);
    }

    /**
     * 画随机干扰线
     *
     * @param g
     *            画笔(图像上下文)
     * @param count
     *            干扰线条数
     */
    private void drawLine(Graphics gp, int count) {
        Random rand = new Random();
        // 循环绘制每条干扰线
        for (int i = 0; i < count; i++) {
            // 设置线条随机颜色
            gp.setColor(getRandomColor(0, 255));
            // 生成随机线条起点终点坐标点
            int y1 = rand.nextInt(this.height);
            int y2 = rand.nextInt(this.height);
            // 画线条
            gp.drawLine(0, y1, 200, y2);
        }
    }

    /**
     * 获取随机颜色
     *
     * @param minimum
     *            颜色下限值
     * @param maximum
     *            颜色上限值(0—255)
     * @return 随机颜色对象
     */
    private Color getRandomColor(int minimum, int maximum) {
        /*
         * 转换最大值和最小值
         * */
        if (minimum > maximum) {
            int tmp = minimum;
            minimum = maximum;
            maximum = tmp;
        }
        /*
         * 更改超出rgb色彩值范围的值
         *
         * */
        if (maximum > 255){
            maximum = 255;
            }
        if (minimum < 0){
            minimum = 0;
            }
/*
 * 随机生成rgb的值(0—(maximum - minimum)范围)
 * */
        int r = minimum + (int) (Math.random() * (maximum - minimum));
        int g = minimum + (int) (Math.random() * (maximum - minimum));
        int b = minimum + (int) (Math.random() * (maximum - minimum));
        return new Color(r, g, b);
    }

    public static void main(String[] args) {
        YzmColor xyc = new YzmColor();
        JFrame frame = new JFrame("验证码");
        frame.setSize(300, 200);//设置窗体大小
        frame.setLocationRelativeTo(null);//大小不可更改
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//按关闭时的状态
        //显示图像
        JLabel lbl = new JLabel(new ImageIcon(xyc.getCaptchaImage()));
        frame.add(lbl);//将lbl加入窗体中
        frame.setVisible(true);//显示窗口
    }
}

效果(因线条与颜色随机,所以每次效果不同,若要四个字符的,将上面的legnth改为4即可)

 

二、重写paint方法(效果与上述一样)

package canvas;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.Random;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class drawYanzm extends JFrame {
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    // 图像宽度
    private int width = 200;
    // 图像高度
    private int height = 80;
    // 验证码字符长度
    private int length = 6;
    // 随机生成验证码基础字符串
    private final String azAZ19 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

    public drawYanzm(){
        setTitle("验证码");
        setSize(300,200);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
@Override
public void paint(Graphics g) {
    //super.paint(g);
    BufferedImage img=new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    // 获取图像上下文(画笔)
    Graphics gp = img.getGraphics();
    // 设置图像背景色,填充背景矩形
    gp.setColor(Color.WHITE);//白色
    gp.fillRect(0, 0, width, height);
    /* 生成随机验证码 */
    int len = azAZ19.length(); // 基础字符串长度
    gp.setFont(new Font("楷体", Font.BOLD, 30)); // 设置验证码字体,效果及大小(楷体,加粗,30px)
    // 循环生成验证码各字符
    Random rand = new Random();
    for (int i = 0; i < length; i++) {
        // 随机生成验证码中单个字符
        String randStr = String.valueOf(azAZ19.charAt(rand
                .nextInt(len)));
        // 绘制单个字符宽度
        int width = this.width / this.length;
        // 绘制当前字符原点
        int x = width * i;
        int y = this.height / 2 + rand.nextInt(this.height / 5);
        /* 将该字符画到图像中 */
        drawString(gp, x, y, randStr);
    }
    // 画干扰线
    drawLine(gp, 10);
    JLabel lbl = new JLabel(new ImageIcon(img));
    this.add(lbl);//将lbl加入窗体中
   // 释放图像上下文(画笔)
    gp.dispose();
    
}

private void drawString(Graphics gp, int width, int height, String str){
    Random rand = new Random();
    // 随机生成字符旋转角度(-30~30度)
    int degree = rand.nextInt(60);
    if (degree > 30)
        degree = 30 - degree;
    // 设置字体颜色
    gp.setColor(randomColor(120));//字体颜色稍深色一点
    // 转换 Graphics2D
    Graphics2D g2 = (Graphics2D) gp.create();
    // 平移原点到图形环境的中心 ,就是将字符串移动到某一个位置
    g2.translate(width + rand.nextInt(5), height + rand.nextInt(5));
    // 旋转文本
    g2.rotate(degree * Math.PI / 180);
    // 画文本,这里的画笔已经具有了上次指定的一个位置,所以这里指定的是一个相对位置
    g2.drawString(str, 0, 0);
}
private void drawLine(Graphics gp, int count){
    Random rand = new Random();
    // 循环绘制每条干扰线
    for (int i = 0; i < count; i++) {
        // 设置线条随机颜色
        gp.setColor(randomColor(255));
        // 生成随机线条起点终点坐标点
        int y1 = rand.nextInt(this.height);
        int y2 = rand.nextInt(this.height);
        // 画线条
        gp.drawLine(0, y1, 200, y2);
    }
}

    private Color randomColor(int max){
        if(max<0||max>255){
            max=255;
        }
        int r=(int)(Math.random()*max);
        int g=(int)(Math.random()*max);
        int b=(int)(Math.random()*max);
        return new Color(r,g,b);        
    }
    public static void main(String[] args) {
        new drawYanzm().setVisible(true);
    }
    
}

推荐阅读