图片验证码实现的几种方式

一、Google Kaptcha

1、简介

kaptcha 是一个非常实用的验证码生成工具。有了它,你可以生成各种样式的验证码,因为它是可配置的。kaptcha工作的原理是调用 com.google.code.kaptcha.servlet.KaptchaServlet,生成一个图片。同时将生成的验证码字符串放到 HttpSession中。

使用kaptcha可以方便的配置:

  • 验证码的字体
  • 验证码字体的大小
  • 验证码字体的字体颜色
  • 验证码内容的范围(数字,字母,中文汉字!)
  • 验证码图片的大小,边框,边框粗细,边框颜色
  • 验证码的干扰线(可以自己继承com.google.code.kaptcha.NoiseProducer写一个自定义的干扰线)
  • 验证码的样式(鱼眼样式、3D、普通模糊……当然也可以继承com.google.code.kaptcha.GimpyEngine自定义样式)

2、maven依赖


	pro.fessional
    kaptcha
    2.3.3

		com.jhlabs
		filters
		2.0.235

3、验证码配置类



import java.util.Properties;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;

@Component
public class KaptchaConfig {
 
    @Bean
    public DefaultKaptcha getDefaultKaptcha() {
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        // 图片边框
        properties.setProperty("kaptcha.border", "no");
        // 边框颜色
        properties.setProperty("kaptcha.border.color", "black");
        //边框厚度
        properties.setProperty("kaptcha.border.thickness", "1");
        // 图片宽
        properties.setProperty("kaptcha.image.width", "200");
        // 图片高
        properties.setProperty("kaptcha.image.height", "50");
        //图片实现类
        properties.setProperty("kaptcha.producer.impl", "com.google.code.kaptcha.impl.DefaultKaptcha");
        //文本实现类
        properties.setProperty("kaptcha.textproducer.impl", "com.google.code.kaptcha.text.impl.DefaultTextCreator");
        //文本集合,验证码值从此集合中获取
        properties.setProperty("kaptcha.textproducer.char.string", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
        //验证码长度
        properties.setProperty("kaptcha.textproducer.char.length", "4");
        //字体
        properties.setProperty("kaptcha.textproducer.font.names", "宋体");
        //字体颜色
        properties.setProperty("kaptcha.textproducer.font.color", "black");
        //文字间隔
        properties.setProperty("kaptcha.textproducer.char.space", "5");
        //干扰实现类
        properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.DefaultNoise");
        //干扰颜色
        properties.setProperty("kaptcha.noise.color", "blue");
        //干扰图片样式
        properties.setProperty("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.WaterRipple");
        //背景实现类
        properties.setProperty("kaptcha.background.impl", "com.google.code.kaptcha.impl.DefaultBackground");
        //背景颜色渐变,结束颜色
        properties.setProperty("kaptcha.background.clear.to", "white");
        //文字渲染器
        properties.setProperty("kaptcha.word.impl", "com.google.code.kaptcha.text.impl.DefaultWordRenderer");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
 
}

4、接口返回图片验证码

在获取验证码的类中直接引入配置类即可

/**
 * 验证码类:Google Kaptcha
 */
@Autowired
DefaultKaptcha defaultKaptcha;
/**
     * 获取图片验证码
     *
     * @return
     * @throws Exception
     */
    public RspObjectBO verifyCodeGet(VerifyCodeReqBO reqBO) throws Exception {
        RspObjectBO res = new RspObjectBO<>();
        VerifyCodeRspBO data = new VerifyCodeRspBO();
        String verifyId = CommonUtils.getUUID();
        String createText = defaultKaptcha.createText();
        log.info("验证码内容:{}", createText);
        BufferedImage bi = defaultKaptcha.createImage(createText);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        ImageIO.write(bi, "jpeg", stream);
        String verifyCode = Base64.encode(stream.toByteArray());
        stream.flush();
        stream.close();
        RBucket rBucket = redissonClient.getBucket(RedisKeyConstants.VerifyCodeKey + verifyId, StringCodec.INSTANCE);
        if (Objects.nonNull(reqBO.getDev_type()) && reqBO.getDev_type().equals(DeviceTypeEnum.Terminal_WX_Xcx.getType())) {
            rBucket = redissonClient.getBucket(RedisKeyConstants.VerifyCodeKey + reqBO.getDev_type() + verifyId, StringCodec.INSTANCE);
        }
        rBucket.set(createText, 3, TimeUnit.MINUTES);
        data.setVerifyid(verifyId);
        data.setVerifydata(verifyCode);
        res.setData(data);
        return res;
    }

二、自定义实现

import cn.hutool.core.codec.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.Random;

public class RandomValidateCodeUtil {


    private static final String RANDOMCODEKEY = "RANDOMVALIDATECODEKEY";//放到session中的key
    private static final Logger logger = LoggerFactory.getLogger(RandomValidateCodeUtil.class);

    // private String randString = "0123456789";//随机产生只有数字的字符串 private String
    //private String randString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生只有字母的字符串
    private String randString = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生数字与字母组合的字符串

    private int width = 95;// 图片宽
    private int height = 30;// 图片高
    private int lineSize = 40;// 干扰线数量
    private int stringNum = 4;// 随机产生字符数量
    private Random random = new SecureRandom();

    /**
     * 获得字体
     */
    private Font getFont() {
        return new Font("Fixedsys", Font.CENTER_BASELINE, 18);
    }

    /**
     * 获得颜色
     */
    private Color getRandColor(int fc, int bc) {
        if (fc > 255) {
            fc = 255;
        }
        if (bc > 255) {
            bc = 255;
        }
        int r = fc + random.nextInt(bc - fc - 16);
        int g = fc + random.nextInt(bc - fc - 14);
        int b = fc + random.nextInt(bc - fc - 18);
        return new Color(r, g, b);
    }

    /**
     * 生成随机图片 存储到session中
     */
    public void getRandomCode(HttpServletRequest request, HttpServletResponse response) {

        HttpSession session = request.getSession();

        // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);

        // 产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作
        Graphics g = image.getGraphics();

        g.fillRect(0, 0, width, height);//图片大小

        g.setFont(new Font("Times New Roman", Font.ROMAN_BASELINE, 18));//字体大小

        g.setColor(getRandColor(110, 133));//字体颜色

        // 绘制干扰线
        for (int i = 0; i <= lineSize; i++) {
            drawLine(g);
        }

        // 绘制随机字符
        String randomString = "";

        for (int i = 1; i <= stringNum; i++) {
            randomString = drawString(g, randomString, i);
        }
        //将生成的随机字符串保存到session中
        session.removeAttribute(RANDOMCODEKEY);
        session.setAttribute(RANDOMCODEKEY, randomString);
        g.dispose();
        try {
            // 将内存中的图片通过流动形式输出到客户端
            ImageIO.write(image, "JPEG", response.getOutputStream());
        } catch (Exception e) {
            logger.error("将内存中的图片通过流动形式输出到客户端失败>>>> ", e);
        }

    }

    /**
     * 生成随机图片验证码
     */
    private String getRandomCode() throws IOException {
        // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
        // 产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作
        Graphics g = image.getGraphics();
        g.fillRect(0, 0, width, height);//图片大小
        g.setFont(new Font("Times New Roman", Font.ROMAN_BASELINE, 18));//字体大小
        g.setColor(getRandColor(110, 133));//字体颜色
        // 绘制干扰线
        for (int i = 0; i <= lineSize; i++) {
            drawLine(g);
        }
        // 绘制随机字符
        String randomString = "";

        for (int i = 1; i <= stringNum; i++) {
            randomString = drawString(g, randomString, i);
        }
        g.dispose();
        //返回base64图片
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        ImageIO.write(image, "jpeg", stream);
        String verifiCode = Base64.encode(stream.toByteArray());
        stream.flush();
        stream.close();
        return verifiCode;
    }

    /**
     * 绘制字符串
     */
    private String drawString(Graphics g, String randomString, int i) {
        g.setFont(getFont());
        g.setColor(new Color(random.nextInt(101), random.nextInt(111), random
                .nextInt(121)));
        String rand = String.valueOf(getRandomString(random.nextInt(randString
                .length())));
        randomString += rand;
        g.translate(random.nextInt(3), random.nextInt(3));
        g.drawString(rand, 13 * i, 16);
        return randomString;
    }

    /**
     * 绘制干扰线
     */
    private void drawLine(Graphics g) {

        int x = random.nextInt(width);
        int y = random.nextInt(height);

        int xl = random.nextInt(13);
        int yl = random.nextInt(15);

        g.drawLine(x, y, x + xl, y + yl);

    }

    /**
     * 获取随机的字符
     */
    private String getRandomString(int num) {
        return String.valueOf(randString.charAt(num));
    }

    public static void main(String[] args) throws IOException {
        RandomValidateCodeUtil randomValidateCodeUtil = new RandomValidateCodeUtil();
        System.out.println(randomValidateCodeUtil.getRandomCode());
    }
}
    @RequestMapping("getVerifiCode")
    @ResponseBody
    public void getVerifiCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        /*
             1.生成验证码
             2.把验证码上的文本存在session中
             3.把验证码图片发送给客户端
             */
        ImageVerificationCode ivc = new ImageVerificationCode();     //用我们的验证码类,生成验证码类对象
        BufferedImage image = ivc.getImage();  //获取验证码
        request.getSession().setAttribute("text", ivc.getText()); //将验证码的文本存在session中
        ivc.output(image, response.getOutputStream());//将验证码图片响应给客户端
    }

 三、Hutool工具类实现

1、Hutool工具简介

        Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。

Hutool中的工具方法来自每个用户的精雕细琢,它涵盖了Java开发底层代码中的方方面面,它既是大型项目开发中解决小问题的利器,也是小型项目中的效率担当;

Hutool是项目中“util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug。

2、引入maven依赖


    com.xiaoleilu
    hutool-all
    3.2.3

3、验证码功能介绍

验证码功能位于cn.hutool.captcha包中,核心接口为ICaptcha,此接口定义了以下方法:
●createCode 创建验证码,实现类需同时生成随机验证码字符串和验证码图片
●getCode 获取验证码的文字内容
●verify 验证验证码是否正确,建议忽略大小写
●write 将验证码写出到目标流中
其中write方法只有一个OutputStream,ICaptcha实现类可以根据这个方法封装写出到文件等方法。AbstractCaptcha为一个ICaptcha抽象实现类,此类实现了验证码文本生成、非大小写敏感的验证、写出到流和文件等方法,通过继承此抽象类只需实现createImage方法定义图形生成规则即可。
LineCaptcha线段干扰的验证码

//定义图形验证码的长和宽
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100);

//图形验证码写出,可以写出到文件,也可以写出到流
lineCaptcha.write("d:/line.png");
//输出code
Console.log(lineCaptcha.getCode());
//验证图形验证码的有效性,返回boolean值
lineCaptcha.verify("1234");

//重新生成验证码
lineCaptcha.createCode();
lineCaptcha.write("d:/line.png");
//新的验证码
Console.log(lineCaptcha.getCode());
//验证图形验证码的有效性,返回boolean值
lineCaptcha.verify("1234");

CircleCaptcha圆圈干扰验证码

//定义图形验证码的长、宽、验证码字符数、干扰元素个数

CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 20);

//CircleCaptcha captcha = new CircleCaptcha(200, 100, 4, 20);

//图形验证码写出,可以写出到文件,也可以写出到流

captcha.write("d:/circle.png");

//验证图形验证码的有效性,返回boolean值

captcha.verify("1234");

ShearCaptcha扭曲干扰验证码

//定义图形验证码的长、宽、验证码字符数、干扰线宽度

ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(200, 100, 4, 4);

//ShearCaptcha captcha = new ShearCaptcha(200, 100, 4, 4);

//图形验证码写出,可以写出到文件,也可以写出到流

captcha.write("d:/shear.png");

//验证图形验证码的有效性,返回boolean值

captcha.verify("1234");

自定义验证码
        有时候标准的验证码不满足要求,比如我们希望使用纯字母的验证码、纯数字的验证码、加减乘除的验证码,此时我们就要自定义CodeGenerator

// 自定义纯数字的验证码(随机4位数字,可重复)
RandomGenerator randomGenerator = new RandomGenerator("0123456789", 4);
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100);
lineCaptcha.setGenerator(randomGenerator);
// 重新生成code
lineCaptcha.createCode();
ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(200, 45, 4, 4);
// 自定义验证码内容为四则运算方式
captcha.setGenerator(new MathGenerator());
// 重新生成code
captcha.createCode();

你可能感兴趣的:(java,spring,java)