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


    一、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依赖

    1. <dependency>
    2. <groupId>pro.fessionalgroupId>
    3. <artifactId>kaptchaartifactId>
    4. <version>2.3.3version>
    5. dependency>
    1. <dependency>
    2. <groupId>com.jhlabsgroupId>
    3. <artifactId>filtersartifactId>
    4. <version>2.0.235version>
    5. dependency>

    3、验证码配置类

    1. import java.util.Properties;
    2. import org.springframework.context.annotation.Bean;
    3. import org.springframework.stereotype.Component;
    4. import com.google.code.kaptcha.impl.DefaultKaptcha;
    5. import com.google.code.kaptcha.util.Config;
    6. @Component
    7. public class KaptchaConfig {
    8. @Bean
    9. public DefaultKaptcha getDefaultKaptcha() {
    10. DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
    11. Properties properties = new Properties();
    12. // 图片边框
    13. properties.setProperty("kaptcha.border", "no");
    14. // 边框颜色
    15. properties.setProperty("kaptcha.border.color", "black");
    16. //边框厚度
    17. properties.setProperty("kaptcha.border.thickness", "1");
    18. // 图片宽
    19. properties.setProperty("kaptcha.image.width", "200");
    20. // 图片高
    21. properties.setProperty("kaptcha.image.height", "50");
    22. //图片实现类
    23. properties.setProperty("kaptcha.producer.impl", "com.google.code.kaptcha.impl.DefaultKaptcha");
    24. //文本实现类
    25. properties.setProperty("kaptcha.textproducer.impl", "com.google.code.kaptcha.text.impl.DefaultTextCreator");
    26. //文本集合,验证码值从此集合中获取
    27. properties.setProperty("kaptcha.textproducer.char.string", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    28. //验证码长度
    29. properties.setProperty("kaptcha.textproducer.char.length", "4");
    30. //字体
    31. properties.setProperty("kaptcha.textproducer.font.names", "宋体");
    32. //字体颜色
    33. properties.setProperty("kaptcha.textproducer.font.color", "black");
    34. //文字间隔
    35. properties.setProperty("kaptcha.textproducer.char.space", "5");
    36. //干扰实现类
    37. properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.DefaultNoise");
    38. //干扰颜色
    39. properties.setProperty("kaptcha.noise.color", "blue");
    40. //干扰图片样式
    41. properties.setProperty("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.WaterRipple");
    42. //背景实现类
    43. properties.setProperty("kaptcha.background.impl", "com.google.code.kaptcha.impl.DefaultBackground");
    44. //背景颜色渐变,结束颜色
    45. properties.setProperty("kaptcha.background.clear.to", "white");
    46. //文字渲染器
    47. properties.setProperty("kaptcha.word.impl", "com.google.code.kaptcha.text.impl.DefaultWordRenderer");
    48. Config config = new Config(properties);
    49. defaultKaptcha.setConfig(config);
    50. return defaultKaptcha;
    51. }
    52. }

    4、接口返回图片验证码

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

    /**
     * 验证码类:Google Kaptcha
     */
    @Autowired
    DefaultKaptcha defaultKaptcha;
    1. /**
    2. * 获取图片验证码
    3. *
    4. * @return
    5. * @throws Exception
    6. */
    7. public RspObjectBO verifyCodeGet(VerifyCodeReqBO reqBO) throws Exception {
    8. RspObjectBO res = new RspObjectBO<>();
    9. VerifyCodeRspBO data = new VerifyCodeRspBO();
    10. String verifyId = CommonUtils.getUUID();
    11. String createText = defaultKaptcha.createText();
    12. log.info("验证码内容:{}", createText);
    13. BufferedImage bi = defaultKaptcha.createImage(createText);
    14. ByteArrayOutputStream stream = new ByteArrayOutputStream();
    15. ImageIO.write(bi, "jpeg", stream);
    16. String verifyCode = Base64.encode(stream.toByteArray());
    17. stream.flush();
    18. stream.close();
    19. RBucket rBucket = redissonClient.getBucket(RedisKeyConstants.VerifyCodeKey + verifyId, StringCodec.INSTANCE);
    20. if (Objects.nonNull(reqBO.getDev_type()) && reqBO.getDev_type().equals(DeviceTypeEnum.Terminal_WX_Xcx.getType())) {
    21. rBucket = redissonClient.getBucket(RedisKeyConstants.VerifyCodeKey + reqBO.getDev_type() + verifyId, StringCodec.INSTANCE);
    22. }
    23. rBucket.set(createText, 3, TimeUnit.MINUTES);
    24. data.setVerifyid(verifyId);
    25. data.setVerifydata(verifyCode);
    26. res.setData(data);
    27. return res;
    28. }

    二、自定义实现

    1. import cn.hutool.core.codec.Base64;
    2. import org.slf4j.Logger;
    3. import org.slf4j.LoggerFactory;
    4. import javax.imageio.ImageIO;
    5. import javax.servlet.http.HttpServletRequest;
    6. import javax.servlet.http.HttpServletResponse;
    7. import javax.servlet.http.HttpSession;
    8. import java.awt.*;
    9. import java.awt.image.BufferedImage;
    10. import java.io.ByteArrayOutputStream;
    11. import java.io.IOException;
    12. import java.security.SecureRandom;
    13. import java.util.Random;
    14. public class RandomValidateCodeUtil {
    15. private static final String RANDOMCODEKEY = "RANDOMVALIDATECODEKEY";//放到session中的key
    16. private static final Logger logger = LoggerFactory.getLogger(RandomValidateCodeUtil.class);
    17. // private String randString = "0123456789";//随机产生只有数字的字符串 private String
    18. //private String randString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生只有字母的字符串
    19. private String randString = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生数字与字母组合的字符串
    20. private int width = 95;// 图片宽
    21. private int height = 30;// 图片高
    22. private int lineSize = 40;// 干扰线数量
    23. private int stringNum = 4;// 随机产生字符数量
    24. private Random random = new SecureRandom();
    25. /**
    26. * 获得字体
    27. */
    28. private Font getFont() {
    29. return new Font("Fixedsys", Font.CENTER_BASELINE, 18);
    30. }
    31. /**
    32. * 获得颜色
    33. */
    34. private Color getRandColor(int fc, int bc) {
    35. if (fc > 255) {
    36. fc = 255;
    37. }
    38. if (bc > 255) {
    39. bc = 255;
    40. }
    41. int r = fc + random.nextInt(bc - fc - 16);
    42. int g = fc + random.nextInt(bc - fc - 14);
    43. int b = fc + random.nextInt(bc - fc - 18);
    44. return new Color(r, g, b);
    45. }
    46. /**
    47. * 生成随机图片 存储到session中
    48. */
    49. public void getRandomCode(HttpServletRequest request, HttpServletResponse response) {
    50. HttpSession session = request.getSession();
    51. // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
    52. BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
    53. // 产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作
    54. Graphics g = image.getGraphics();
    55. g.fillRect(0, 0, width, height);//图片大小
    56. g.setFont(new Font("Times New Roman", Font.ROMAN_BASELINE, 18));//字体大小
    57. g.setColor(getRandColor(110, 133));//字体颜色
    58. // 绘制干扰线
    59. for (int i = 0; i <= lineSize; i++) {
    60. drawLine(g);
    61. }
    62. // 绘制随机字符
    63. String randomString = "";
    64. for (int i = 1; i <= stringNum; i++) {
    65. randomString = drawString(g, randomString, i);
    66. }
    67. //将生成的随机字符串保存到session中
    68. session.removeAttribute(RANDOMCODEKEY);
    69. session.setAttribute(RANDOMCODEKEY, randomString);
    70. g.dispose();
    71. try {
    72. // 将内存中的图片通过流动形式输出到客户端
    73. ImageIO.write(image, "JPEG", response.getOutputStream());
    74. } catch (Exception e) {
    75. logger.error("将内存中的图片通过流动形式输出到客户端失败>>>> ", e);
    76. }
    77. }
    78. /**
    79. * 生成随机图片验证码
    80. */
    81. private String getRandomCode() throws IOException {
    82. // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
    83. BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
    84. // 产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作
    85. Graphics g = image.getGraphics();
    86. g.fillRect(0, 0, width, height);//图片大小
    87. g.setFont(new Font("Times New Roman", Font.ROMAN_BASELINE, 18));//字体大小
    88. g.setColor(getRandColor(110, 133));//字体颜色
    89. // 绘制干扰线
    90. for (int i = 0; i <= lineSize; i++) {
    91. drawLine(g);
    92. }
    93. // 绘制随机字符
    94. String randomString = "";
    95. for (int i = 1; i <= stringNum; i++) {
    96. randomString = drawString(g, randomString, i);
    97. }
    98. g.dispose();
    99. //返回base64图片
    100. ByteArrayOutputStream stream = new ByteArrayOutputStream();
    101. ImageIO.write(image, "jpeg", stream);
    102. String verifiCode = Base64.encode(stream.toByteArray());
    103. stream.flush();
    104. stream.close();
    105. return verifiCode;
    106. }
    107. /**
    108. * 绘制字符串
    109. */
    110. private String drawString(Graphics g, String randomString, int i) {
    111. g.setFont(getFont());
    112. g.setColor(new Color(random.nextInt(101), random.nextInt(111), random
    113. .nextInt(121)));
    114. String rand = String.valueOf(getRandomString(random.nextInt(randString
    115. .length())));
    116. randomString += rand;
    117. g.translate(random.nextInt(3), random.nextInt(3));
    118. g.drawString(rand, 13 * i, 16);
    119. return randomString;
    120. }
    121. /**
    122. * 绘制干扰线
    123. */
    124. private void drawLine(Graphics g) {
    125. int x = random.nextInt(width);
    126. int y = random.nextInt(height);
    127. int xl = random.nextInt(13);
    128. int yl = random.nextInt(15);
    129. g.drawLine(x, y, x + xl, y + yl);
    130. }
    131. /**
    132. * 获取随机的字符
    133. */
    134. private String getRandomString(int num) {
    135. return String.valueOf(randString.charAt(num));
    136. }
    137. public static void main(String[] args) throws IOException {
    138. RandomValidateCodeUtil randomValidateCodeUtil = new RandomValidateCodeUtil();
    139. System.out.println(randomValidateCodeUtil.getRandomCode());
    140. }
    141. }
    1. @RequestMapping("getVerifiCode")
    2. @ResponseBody
    3. public void getVerifiCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
    4. /*
    5. 1.生成验证码
    6. 2.把验证码上的文本存在session中
    7. 3.把验证码图片发送给客户端
    8. */
    9. ImageVerificationCode ivc = new ImageVerificationCode(); //用我们的验证码类,生成验证码类对象
    10. BufferedImage image = ivc.getImage(); //获取验证码
    11. request.getSession().setAttribute("text", ivc.getText()); //将验证码的文本存在session中
    12. ivc.output(image, response.getOutputStream());//将验证码图片响应给客户端
    13. }

     三、Hutool工具类实现

    1、Hutool工具简介

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

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

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

    2、引入maven依赖

    1. <dependency>
    2. <groupId>com.xiaoleilugroupId>
    3. <artifactId>hutool-allartifactId>
    4. <version>3.2.3version>
    5. dependency>

    3、验证码功能介绍

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

    1. //定义图形验证码的长和宽
    2. LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100);
    3. //图形验证码写出,可以写出到文件,也可以写出到流
    4. lineCaptcha.write("d:/line.png");
    5. //输出code
    6. Console.log(lineCaptcha.getCode());
    7. //验证图形验证码的有效性,返回boolean值
    8. lineCaptcha.verify("1234");
    9. //重新生成验证码
    10. lineCaptcha.createCode();
    11. lineCaptcha.write("d:/line.png");
    12. //新的验证码
    13. Console.log(lineCaptcha.getCode());
    14. //验证图形验证码的有效性,返回boolean值
    15. lineCaptcha.verify("1234");

    CircleCaptcha圆圈干扰验证码

    1. //定义图形验证码的长、宽、验证码字符数、干扰元素个数
    2. CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 20);
    3. //CircleCaptcha captcha = new CircleCaptcha(200, 100, 4, 20);
    4. //图形验证码写出,可以写出到文件,也可以写出到流
    5. captcha.write("d:/circle.png");
    6. //验证图形验证码的有效性,返回boolean值
    7. captcha.verify("1234");

    ShearCaptcha扭曲干扰验证码

    1. //定义图形验证码的长、宽、验证码字符数、干扰线宽度
    2. ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(200, 100, 4, 4);
    3. //ShearCaptcha captcha = new ShearCaptcha(200, 100, 4, 4);
    4. //图形验证码写出,可以写出到文件,也可以写出到流
    5. captcha.write("d:/shear.png");
    6. //验证图形验证码的有效性,返回boolean值
    7. captcha.verify("1234");

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

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

  • 相关阅读:
    猿创征文 | JavaScript函数柯里化
    基于ssm+jsp框架实现的学生选课信息管理系统【源码+数据库】
    springcloudalibaba和nacos版本对应关系
    MySQL数据库中,在读已提交和可重复读这两个不同事务隔离级别下幻读的区别
    高等数学教材重难点题型总结(六)定积分的应用
    十五、Java中I/O流
    <scope>compile</scope>在dependency中有什么用?
    YAPI介绍及Docker Compose部署指南
    mysql 用户控制命令
    Linux centos7配置JDK环境
  • 原文地址:https://blog.csdn.net/xrq1995/article/details/126405524