文字图片验证码源码,教程分享

目录导航

一. 验证码前篇

1.1 概述

  • 验证码(CAPTCHA)是“Completely Automated Public Turing test to tell Computers and Humans Apart”(全自动区分计算机和人类的图灵测试)的缩写,是一种区分用户是计算机还是人的公共全自动程序。可以防止:恶意破解密码、刷票、论坛灌水,有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试,实际上用验证码是现在很多网站通行的方式,我们利用比较简易的方式实现了这个功能。这个问题可以由计算机生成并评判,但是必须只有人类才能解答。由于计算机无法解答CAPTCHA的问题,所以回答出问题的用户就可以被认为是人类

1.2 效果图图示:

  • 在这里插入图片描述

1.3 完成的图示:

在这里插入图片描述

1.4 说明

此项目为某大神(已找不到出处)的作品,为帮助大家,从而添加更细致的注释,更清楚的讲解,更快的入门使用;

二. 关键代码

2.1 工具类

package com.liutao.util;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Random;

/**
 * 验证码工具类
 *
 * @author: LIUTAO
 * @Description:
 * @Date: Created in 10:57 2018/6/25
 * @Modified By:
 */
public class VerifyCodeUtil {
    private static int width = 60;  //验证码宽度
    private static int height = 20;  //验证码高度
    private static int codeCount = 4;  //验证码字符个数
    private static int fontHeight;  //字体高度

    /**
     * 初始化图片属性
     */
    public static void init() {
        String strWidth ="800";
        String strHeight ="300";
        String strCodeCount = "4";
        // 将配置的信息转换成数值
        try {
            if (strWidth != null && strWidth.length() != 0) {
                width = Integer.parseInt(strWidth);
            }
            if (strHeight != null && strHeight.length() != 0) {
                height = Integer.parseInt(strHeight);
            }
            if (strCodeCount != null && strCodeCount.length() != 0) {
                codeCount = Integer.parseInt(strCodeCount);
            }
        } catch (NumberFormatException e) {
        }
        fontHeight = height/2;
    }


    /**
     * 获取验证码图片
     * @return
     * @throws IOException
     */
    public static byte[] getVerifyImg() throws IOException {
        init();
        Random random = new Random();

        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics graphic = image.getGraphics();

        graphic.setColor(Color.getColor("F8F8F8"));
        graphic.fillRect(0, 0, width, height);

        Color[] colors = new Color[] { Color.BLUE, Color.GRAY, Color.GREEN, Color.RED, Color.BLACK, Color.ORANGE,
                Color.CYAN };
        // 在 "画板"上生成干扰线条 ( 50 是线条个数)
        for (int i = 0; i < 50; i++) {
            graphic.setColor(colors[random.nextInt(colors.length)]);
            final int x = random.nextInt(width);
            final int y = random.nextInt(height);
            final int w = random.nextInt(20);
            final int h = random.nextInt(20);
            final int signA = random.nextBoolean() ? 1 : -1;
            final int signB = random.nextBoolean() ? 1 : -1;
            graphic.drawLine(x, y, x + w * signA, y + h * signB);
        }

        // 在 "画板"上绘制字母
        graphic.setFont(new Font("Comic Sans MS", Font.BOLD, fontHeight));
        for (int i = 0; i < codeCount; i++) {
            final int temp = random.nextInt(26) + 97;
            String s = String.valueOf((char) temp);
            System.out.println(s);
            graphic.setColor(colors[random.nextInt(colors.length)]);
            graphic.drawString(s, i * (width / 6), height - (height / 3));
        }
        graphic.dispose();

        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(image, "png", os);
        byte b[] = os.toByteArray();
        return b;
    }
}

2.2 测试类

package com.liutao.util;

import javax.imageio.stream.FileImageOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

/**
 * @program: test2
 * @author: 暗余
 * @create: 2019/3/8-9:38
 **/

public class test2 {
    public static void main(String[] args) {
        OutputStream outputStream=null;
        try {
            byte[] verifyImg=VerifyCodeUtil.getVerifyImg();
            FileImageOutputStream imageOutput=new FileImageOutputStream(new File("D://image3.jpg"));
            imageOutput.write(verifyImg, 0, verifyImg.length);//将byte写入硬盘
            imageOutput.close();
        } catch (Exception e) {
        }
    }
}

2.3 说明:

  • 工具类
  • 测试类
  • 放好后导入相关引用
  • 直接运行即可
  • 后续放demo文件

三. 验证码升级

3.1 概述:

  • 前面的验证码太过于清晰,且只能为字母,这次加上了大小写字母以及数字,并且进行了模糊,不容易被机器识别:

3.2 效果图:

在这里插入图片描述

3.3 代码:

package com.cdmtc.util;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Random;

/**
 * 验证码工具类
 *
 * @author: LIUTAO
 * @Description:
 * @Date: Created in 10:57 2018/6/25
 * @Modified By:
 */
public class VerifyCodeUtils {
    private final static int width = 800;  //验证码宽度
    private final static int height = 300;  //验证码高度
    private final static int codeCount = 4;  //验证码字符个数
    private final static int fontHeight=150;  //字体高度
    private static String verifyVariable;
    public static String getVerifyVariable() {
        return verifyVariable;
    }
    /**
     * 获取验证码图片
     */
    public static byte[] getVerifyImg() throws IOException {
        //定义装验证码的String

        StringBuilder verifyVariableBuilder = new StringBuilder();

        Random random = new Random();

        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics graphic = image.getGraphics();

        graphic.setColor(Color.getColor("F8F8F8"));
        graphic.fillRect(0, 0, width, height);

        Color[] colors = new Color[] { Color.BLUE, Color.GRAY, Color.GREEN, Color.RED, Color.BLACK, Color.ORANGE,
                Color.CYAN };
        // 在 "画板"上生成干扰线条 ( 50 是线条个数)
        for (int i = 0; i < (int)(300*Math.random()+200); i++) {
            graphic.setColor(colors[random.nextInt(colors.length)]);
            final int x = random.nextInt(width);
            final int y = random.nextInt(height);
            final int w = random.nextInt(20);
            final int h = random.nextInt(20);
            final int signA = random.nextBoolean() ? 1 : -1;
            final int signB = random.nextBoolean() ? 1 : -1;
            int[] data=new int[]{x,y,20,0,-10};
            graphic.drawLine(data[(int)(Math.random()*5)],data[(int)(Math.random()*5)] , x + w * signA, y + h * signB);
        }


        String str="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";
        String[] split = str.split("、");
        // 在 "画板"上绘制字母
        graphic.setFont(new Font("Comic Sans MS", Font.BOLD, fontHeight));
        for (int i = 0; i < codeCount; i++) {
            String s = split[(int) (Math.random() * split.length)];
            System.out.println(s);
            //将四位验证码字母组合为String
            verifyVariableBuilder.append(s);
            graphic.setColor(colors[random.nextInt(colors.length)]);
            graphic.drawString(s, i * (width / 4), height - (height / 3));
        }
        graphic.dispose();

        verifyVariable=verifyVariableBuilder.toString();

        //打印显示
        System.out.println("验证码答案:"+verifyVariable);


        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(image, "png", os);
        return os.toByteArray();
    }

}

四. 验证码再升级:运算验证码

4.1 效果图:

在这里插入图片描述

4.2 工具类改造后的如下:

package com.cdmtc.util;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.List;

/**
 * 验证码工具类
 *
 * @author: zhanglei
 * @Description:
 * @Date: Created in 10:57 2018/6/25
 * @Modified By:
 */
public class VerifyCodeUtilOfMath {
    private final static int width = 800;  //验证码宽度
    private final static int height = 300;  //验证码高度
    private final static int codeCount = 5;  //验证码字符个数
    private final static int fontHeight = 150;  //字体高度
    private static String verifyVariable;
    private static int firstNum;        //第一位数字

    public static String getVerifyVariable() {
        return verifyVariable;
    }

    /**
     * 获取验证码图片
     */
    public static byte[] getVerifyImg() throws IOException {
        //定义装验证码的String

        StringBuilder verifyVariableBuilder = new StringBuilder();

        Random random = new Random();

        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics graphic = image.getGraphics();

        graphic.setColor(Color.getColor("F8F8F8"));
        graphic.fillRect(0, 0, width, height);

        Color[] colors = new Color[]{Color.BLUE, Color.GRAY, Color.GREEN, Color.RED, Color.BLACK, Color.ORANGE,
                Color.CYAN};
        // 在 "画板"上生成干扰线条 ( 50 是线条个数)
        for (int i = 0; i < (int) (300 * Math.random() + 200); i++) {
            graphic.setColor(colors[random.nextInt(colors.length)]);
            final int x = random.nextInt(width);
            final int y = random.nextInt(height);
            final int w = random.nextInt(20);
            final int h = random.nextInt(20);
            final int signA = random.nextBoolean() ? 1 : -1;
            final int signB = random.nextBoolean() ? 1 : -1;
            int[] data = new int[]{x, y, 20, 0, -10};
            graphic.drawLine(data[(int) (Math.random() * 5)], data[(int) (Math.random() * 5)], x + w * signA, y + h * signB);
        }

        //定义运算符号
        List list = new ArrayList();
//        Collections.addAll(list, "+", "-", "X", "÷");
        Collections.addAll(list,"÷");
        String yunsuan = (String) list.get((int) (Math.random() * list.size()));
        // 在 "画板"上绘制字母
        graphic.setFont(new Font("Comic Sans MS", Font.BOLD, fontHeight));

        if (yunsuan.equals("÷")) {
            Map<Integer, Integer> map = new HashMap<Integer, Integer>();
            map.put(3, 1);
            map.put(2, 1);
            map.put(6, 3);
            map.put(4, 4);
            map.put(8, 4);
            map.put(10, 2);
            map.put(9, 3);
            map.put(12, 2);
            map.put(15,5);
            map.put(14,2);
            map.put(16,8);
            map.put(18,6);
            map.put(20,4);
            map.put(21,7);
            List<Integer> list1 = new ArrayList<Integer>();
            Collections.addAll(list1, 3, 2, 6, 4, 8, 10, 9, 12,15,14,16,18,20,21);
            int numRandom = getNumRandom(0,9);
            int key = list1.get(numRandom);
            Integer value = map.get(key);

            //将四位验证码字母组合为String
            verifyVariableBuilder.append(key + "÷" + value);      //添加进答案
            graphic.setColor(colors[random.nextInt(colors.length)]);
            graphic.drawString(key + "", 0 * (width / 6), height - (height / (9 / 2)));
            graphic.setColor(colors[random.nextInt(colors.length)]);
            graphic.drawString("÷", 1 * (width / 6), height - (height / (9 / 2)));
            graphic.setColor(colors[random.nextInt(colors.length)]);
            graphic.drawString(value+"", 2 * (width / 6), height - (height / (9 / 2)));
            graphic.setColor(colors[random.nextInt(colors.length)]);
            graphic.drawString("=", 3 * (width / 6), height - (height / (9 / 2)));
            graphic.setColor(colors[random.nextInt(colors.length)]);
            graphic.drawString("?", 4 * (width / 6), height - (height / (9 / 2)));
        } else {
            // 加减乘
            for (int i = 0; i < codeCount; i++) {
                if (i == 1) {         //运算符号
                    verifyVariableBuilder.append(yunsuan);      //添加进答案
                    graphic.setColor(colors[random.nextInt(colors.length)]);
                    graphic.drawString(yunsuan + "", i * (width / 6), height - (height / (9 / 2)));
                }
                if (i == 3) {
                    graphic.setColor(colors[random.nextInt(colors.length)]);// = 号
                    graphic.drawString("=", i * (width / 6), height - (height / (9 / 2)));
                }
                if (i == 4) {
                    graphic.setColor(colors[random.nextInt(colors.length)]);   // ? 号
                    graphic.drawString("?", i * (width / 6), height - (height / (9 / 2)));
                }
                if (i == 0 || i == 2) {
                    if (yunsuan.equals("-")) {
                        if (i == 0) {
                            setNumVerify(verifyVariableBuilder, graphic, i, 5, 15, colors[random.nextInt(colors.length)]);
                        } else {
                            setNumVerify(verifyVariableBuilder, graphic, i, 0, firstNum, colors[random.nextInt(colors.length)]);
                        }
                    } else {
                        setNumVerify(verifyVariableBuilder, graphic, i, 1, 9, colors[random.nextInt(colors.length)]);
                    }
                }
            }
        }
        graphic.dispose();
        verifyVariable = verifyVariableBuilder.toString();
        //打印显示
        System.out.println("验证码答案:" + verifyVariable);
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(image, "png", os);
        return os.toByteArray();
    }

    private static void setNumVerify(StringBuilder verifyVariableBuilder, Graphics graphic, int i, int i2, int i3, Color color) {
        int s = getNumRandom(i2, i3);
        System.out.println(s);
        //将四位验证码字母组合为String
        verifyVariableBuilder.append(s);      //添加进答案
        graphic.setColor(color);
        graphic.drawString(s + "", i * (width / 6), height - (height / (9 / 2)));
        if (i == 0) {
            firstNum = s;
        }
    }


    private static int getNumRandom(int min, int max) {
        return (int) (Math.random() * (max + 1 - min) + min);   //产生10-20任意随机整数
    }
}

4.3 验证码测试类如下:

    @Test
    public void test23424() throws Exception {
        byte[] verifyImg = VerifyCodeUtilOfMath.getVerifyImg();
        FileImageOutputStream imageOutput = new FileImageOutputStream(new File("C:\\Users\\13262\\Desktop\\验证码.png"));//打开输入流
        imageOutput.write(verifyImg, 0, verifyImg.length);//将byte写入硬盘
        String verifyVariable = VerifyCodeUtilOfMath.getVerifyVariable();
        System.out.println("我是答案:" + verifyVariable);
        int verifyNum = 0;
        if (verifyVariable.contains("÷")) {
            String[] split = verifyVariable.split("÷");
            verifyNum = Integer.valueOf(split[0]) / Integer.valueOf(split[1]);
        }
        if (verifyVariable.contains("+")) {
            String[] split = verifyVariable.split("\\+");
            verifyNum = Integer.valueOf(split[0])+Integer.valueOf(split[1]);
        }
        if (verifyVariable.contains("-")){
            String[] split = verifyVariable.split("-");
            verifyNum = Integer.valueOf(split[0])-Integer.valueOf(split[1]);
        }
        if (verifyVariable.contains("X")){
            String[] split=verifyVariable.split("X");
            verifyNum = Integer.valueOf(split[0])*Integer.valueOf(split[1]);
        }

        System.out.println("运算答案为:"+verifyNum);
        imageOutput.close();
    }
    ~~~
    > 引入SpringBootTest依赖,在Test包下创建类,使用@SpringBoot(启动类.class)@RunWith(SpringRunner.class)注解即可使用此测试类,也可以直接写到自己的代码里面;
    ~~~
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暗余

码字来之不易,您的鼓励我的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值