随机生成验证码的实现+详细诠释

随机生成验证码的实现+详细注释

最近的项目里需要使用到随机验证码,所以昨天认真研读了网上的许多教程,但都无非是千篇一律,不太好懂~~~于是乎博主就做了一回好人,对自己已经投入项目使用的一段代码进行详细的解析说明,让大家更好的理解随机验证码的生成原理!!!

这里给上我的验证码类VerifyCode.java

package com.bob.verifycode;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;

import java.util.Random;

public class VerifyCode {

    private static final char[] CHARS = {//定义随机字符集
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
    };

    private static VerifyCode vCode;

    public static VerifyCode getInstance() {//单例模式获取验证码对象
        if (vCode == null)
            vCode = new VerifyCode();
        return vCode;
    }

//  width="60" height="30"
//          base_padding_left="5"
//          range_padding_left="10"
//          base_padding_top="15"
//          range_padding_top="10"
//          codeLength="4"
//          line_number="3"
//          font_size="20"

    //验证码固定参数,也就是将会用到的几个常量
    private static final int DEFAULT_CODE_LENGTH = 4;//默认的代码长度,也就是会出现4个随机码
    private static final int DEFAULT_FONT_SIZE = 20;//字体大小
    private static final int DEFAULT_LINE_NUMBER = 3;//默认的用于干扰视线直线的条数
    private static final int BASE_PADDING_LEFT = 5, RANGE_PADDING_LEFT = 10, BASE_PADDING_TOP = 15, RANGE_PADDING_TOP = 10;
    /**
     * 上边4个整型数的解释:
     * BASE_PADDING_LEFT,BASE_PADDING_TOP 表示每一个将要画出字符坐标计算的基准
     * RANGE_PADDING_LEFT,RANGE_PADDING_TOP 表示字符坐标x,y的变化范围
     */
    private static final int DEFAULT_WIDTH = 160, DEFAULT_HEIGHT = 30;
    //设置位图宽高,具体的宽高取ImageViewBitMap之间较小的一个,
    // 即就是宽= min{ImageView.Width,Bitmap.Width},高同理
    //注意:当我们需要一个不同尺寸的验证码图片,不仅仅需要修改DEFAULT_WIDTH DEFAULT_HEIGHT,为了显示效果
    //的最佳化,最好将上述的4个坐标值也调整一下,使得我们的验证码能最恰当地占据整个底板

    //将一些常量应用到本类的成员变量上
    //settings decided by the layout xml
    //canvas width and height
    private int width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT;

    //random word space and pading_top
    private int base_padding_left = BASE_PADDING_LEFT, range_padding_left = RANGE_PADDING_LEFT,
            base_padding_top = BASE_PADDING_TOP, range_padding_top = RANGE_PADDING_TOP;

    //number of chars, lines; font size
    private int codeLength = DEFAULT_CODE_LENGTH, line_number = DEFAULT_LINE_NUMBER, font_size = DEFAULT_FONT_SIZE;

    //variables
    private String code;//存储随机生成的随机码序列
    private int padding_left, padding_top;//左边框间距和上边框间距
    private Random random = new Random();//随机数生成器

    public Bitmap createBitmap() {//得到位图对象

        padding_left = 0;//设置位图左内边距离

        Bitmap bp = Bitmap.createBitmap(width, height, Config.ARGB_8888);//创建位图
        /**
         * 位图最后一个设置参数的简介
         * A:透明度
         * R:红色
         * G:绿
         * B:蓝
         * Bitmap.Config ARGB_4444:每个像素占四位,即A=4R=4G=4B=4,那么一个像素点占4+4+4+4=16         * Bitmap.Config ARGB_8888:每个像素占四位,即A=8R=8G=8B=8,那么一个像素点占8+8+8+8=32         * Bitmap.Config RGB_565:每个像素占四位,即R=5G=6B=5,没有透明度,那么一个像素点占5+6+5=16         * Bitmap.Config ALPHA_8:每个像素占四位,只有透明度,没有颜色。
         * 一般情况下我们都是使用的ARGB_8888,由此可知它是最占内存的,因为一个像素占32位,8=1字节,所以一个像素占4字节的内存。假设有一张480x800的图片,如果格式为ARGB_8888,那么将会占用1500KB的内存
         */

        Canvas c = new Canvas(bp);//以创建好的空位图创建画布

        code = createCode();//生成目标字符串

        c.drawColor(Color.WHITE);
        Paint paint = new Paint();//创建画笔
        paint.setTextSize(font_size);//设置画笔的字体大小

        for (int i = 0; i < code.length(); i++) {//画每一个字符
            randomTextStyle(paint);//随机的画笔风格
            randomPadding();//按照约定好的规则生成字符的坐标
            c.drawText(code.charAt(i) + "", padding_left, padding_top, paint);//开始以随机的画笔和坐标画每一个字符
        }

        for (int i = 0; i < line_number; i++) {//画事先设置好数量的几条横线
            drawLine(c, paint);
        }

        c.save(Canvas.ALL_SAVE_FLAG);//保存在画布上的所有操作
        c.restore();
        return bp;//返回画好的位图
    }

    public String getCode() {
        return code;
    }

    private String createCode() {//随机生成随机码
        StringBuilder buffer = new StringBuilder();
        for (int i = 0; i < codeLength; i++) {//codeLength即就是验证码字母个数
            buffer.append(CHARS[random.nextInt(CHARS.length)]);
        }
        return buffer.toString();
    }

    private void drawLine(Canvas canvas, Paint paint) {//自定义的任意方向画横线的方法
        int color = randomColor();
        int startX = random.nextInt(width);
        int startY = random.nextInt(height);
        int stopX = random.nextInt(width);
        int stopY = random.nextInt(height);
        paint.setStrokeWidth(1);//设置画笔粗细
        paint.setColor(color);//颜色
        canvas.drawLine(startX, startY, stopX, stopY, paint);
    }

    private int randomColor() {
        return randomColor(1);
    }//随机生成颜色

    private int randomColor(int rate) {
        int red = random.nextInt(256) / rate;
        int green = random.nextInt(256) / rate;
        int blue = random.nextInt(256) / rate;
        return Color.rgb(red, green, blue);
    }

    private void randomTextStyle(Paint paint) {//随机的字体风格
        int color = randomColor();//颜色
        paint.setColor(color);
        paint.setFakeBoldText(random.nextBoolean());  //粗细;true为粗体,false为非粗体
        float skewX = random.nextInt(11) / 10;
        skewX = random.nextBoolean() ? skewX : -skewX;
        paint.setTextSkewX(skewX); //float类型参数,负数表示右斜,整数左斜
//      paint.setUnderlineText(true); //true为下划线,false为非下划线
//      paint.setStrikeThruText(true); //true为删除线,false为非删除线
    }

    /**
     * 随机定义每一个字符所绘画的坐标,注意:在这里padding_left是具有叠加效果的,
     * 也就是说所画的字符越往后,坐标也就越大,而top永远就是base+range
     */
    private void randomPadding() {
        padding_left += base_padding_left + random.nextInt(range_padding_left);
        padding_top = base_padding_top + random.nextInt(range_padding_top);
    }
}

总结一下:随机验证码的生成无非就是通过一个定义好的字符集(可以是52个大小写字母以及10个数字。当然啦既然作为万国码的unicode,博主今后还会视线对汉字的随机生成以及计算公式的验证码)在一张位图上按照事先规定好的随机规则对随机生成的code进行绘画,当然啦,如果对验证码的验证比较复杂,比如公式计算等等,这个code就非常重要了!!!