小工具知识网

当前位置: 首页 > 行业知识 > Java 验证码生成的两种方式【开箱即用】

行业知识

Java 验证码生成的两种方式【开箱即用】

2026-11-06 18:09:52 来源:互联网转载

小伙伴们好,���迎关注,一起学习,无限进步

()

文章目录

    • 通用公共配置
      • 公共依赖
      • 配置 `application.yml` 文件
      • 公共常量
      • Redis 序列化配置
      • Redis 工具类
      • 通用返回结果封装
      • 方法一:Graphics2D 画图实现
        • 1、验证码工具类
        • 2、Controller 控制层
        • 方法二:kaptcha 依赖实现
          • 1、验证码配置
          • 2、验证码文本生成器
          • 3、测试正码生成

            通用公共配置

            公共依赖

            SpringBoot项目

                org.springframework.boot    spring-boot-starter-data-redis    org.apache.commons    commons-pool2    com.github.penggle    kaptcha    2.3.2

            配置 application.yml 文件

            spring:  # redis 配置  redis:    # 地址    host: localhost    # 端口,默认为6379    port: 6379    # 数据库索引    database: 0    # 密码    password:    # 连接超时时间    timeout: 10s    lettuce:      pool:        # 连接池中的最小空闲连接        min-idle: 0        # 连接池中的最大空闲连接        max-idle: 8        # 连接池的最大数据库连接数        max-active: 8        # #连接池最大阻塞等待时间(使用负值表示没有限制)        max-wait: -1ms

            公共常量

            /** * 公共常量 */public class ConstantCode {    /**     * 系统缓存常量     */    public static final String KAPTCHA_KEY = "ss:kaptcha";    public static final Long REDIS_EXP_TIME = 60 * 60L;    public static final Long KAPTCHA_EXP_TIME = 60 * 3L;    /**     * 验证码宽高常量     */    public static final Integer WIDTH = 200;    public static final Integer HEIGHT = 55;    /**     * 图片后缀名称     */    public static final String IMG_JPG = "jpg";    public static final String IMG_PNG = "png";    public static final String IMG_JPEG = "jpeg";}

            Redis 序列化配置

            import com.fasterxml.jackson.annotation.JsonAutoDetect;import com.fasterxml.jackson.annotation.PropertyAccessor;import com.fasterxml.jackson.databind.ObjectMapper;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.connection.RedisConnectionFactory;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;import org.springframework.data.redis.serializer.StringRedisSerializer;@Configurationpublic class RedisConfig {        @Bean    @SuppressWarnings("all")    public RedisTemplate redisTemplate(RedisConnectionFactory factory) {        // 为了自己开发方便,一般直接使用         RedisTemplate template = new RedisTemplate();        template.setConnectionFactory(factory);        // Json序列化配置        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);        ObjectMapper om = new ObjectMapper();        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);        jackson2JsonRedisSerializer.setObjectMapper(om);        // String 的序列化        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();        // key采用String的序列化方式        template.setKeySerializer(stringRedisSerializer);        // hash的key也采用String的序列化方式        template.setHashKeySerializer(stringRedisSerializer);        // value序列化方式采用jackson        template.setValueSerializer(jackson2JsonRedisSerializer);        // hash的value序列化方式采用jackson        template.setHashValueSerializer(jackson2JsonRedisSerializer);        template.afterPropertiesSet();        return template;    }}

            Redis 工具类

            import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.ValueOperations;import org.springframework.stereotype.Component;import org.springframework.util.CollectionUtils;import java.util.Collection;import java.util.concurrent.TimeUnit;/** * Redis工具类 */@Component@SuppressWarnings("all")public class RedisUtils {    /**     * 日志对象     */    private static Logger logger = LoggerFactory.getLogger(RedisUtils.class);    @Autowired    private RedisTemplate redisTemplate;    /**     * 缓存基本的对象,Integer、String、实体类等     *     * @param key      缓存的键值     * @param value    缓存的值     * @param timeout  时间     * @param timeUnit 时间颗粒度     */    public  void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);    }    /**     * 获得缓存的基本对象。     *     * @param key 缓存键值     * @return 缓存键值对应的数据     */    public  T getCacheObject(final String key) {        ValueOperations operation = redisTemplate.opsForValue();        return operation.get(key);    }    /**     * 获得缓存的基本对象列表     *     * @param pattern 字符串前缀     * @return 对象列表     */    public Collection keys(final String pattern) {        return redisTemplate.keys(pattern);    }    /**     * 删除集合对象     *     * @param collection 多个对象     * @return     */    public long deleteObject(final Collection collection) {        return redisTemplate.delete(collection);    }    /**     * 指定缓存失效时间     *     * @param key  键     * @param time 时间(秒)     * @return     */    public boolean expire(String key, long time) {        try {            if (time > 0) {                redisTemplate.expire(key, time, TimeUnit.SECONDS);            }            return true;        } catch (Exception e) {            logger.error("RedisUtils expire(String key,long time) failure." + e.getMessage());            return false;        }    }    /**     * 根据key 获取过期时间     *     * @param key 键 不能为null     * @return 时间(秒) 返回0代表为永久有效     */    public long getExpire(String key) {        return redisTemplate.getExpire(key, TimeUnit.SECONDS);    }    /**     * 判断key是否存在     *     * @param key 键     * @return true 存在 false不存在     */    public boolean hasKey(String key) {        try {            return redisTemplate.hasKey(key);        } catch (Exception e) {            logger.error("RedisUtils hasKey(String key) failure." + e.getMessage());            return false;        }    }    /**     * 删除缓存     *     * @param key 可以传一个值 或多个     */    public void del(String... key) {        if (key != null && key.length > 0) {            if (key.length == 1) {                redisTemplate.delete(key[0]);            } else {                redisTemplate.delete(CollectionUtils.arrayToList(key));            }        }    }    //============================String=============================    /**     * 普通缓存获取     *     * @param key 键     * @return 值     */    public Object get(String key) {        return key == null ? null : redisTemplate.opsForValue().get(key);    }    /**     * 普通缓存放入     *     * @param key   键     * @param value 值     * @return true成功 false失败     */    public boolean set(String key, Object value) {        try {            redisTemplate.opsForValue().set(key, value);            return true;        } catch (Exception e) {            logger.error("RedisUtils set(String key,Object value) failure." + e.getMessage());            return false;        }    }    /**     * 普通缓存放入并设置时间     *     * @param key   键     * @param value 值     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期     * @return true成功 false 失败     */    public boolean set(String key, Object value, long time) {        try {            if (time > 0) {                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);            } else {                set(key, value);            }            return true;        } catch (Exception e) {            logger.error("RedisUtils set(String key,Object value,long time) failure." + e.getMessage());            return false;        }    }}

            通用返回结果封装

            import org.springframework.http.HttpStatus;import org.springframework.util.StringUtils;import java.util.HashMap;/** * 操作消息提醒 */public class Result extends HashMap {    private static final long serialVersionUID = 1L;    /**     * 状态码     */    public static final String CODE_TAG = "code";    /**     * 返回内容     */    public static final String MSG_TAG = "msg";    /**     * 数据对象     */    public static final String DATA_TAG = "data";    /**     * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。     */    public Result() {    }    /**     * 初始化一个新创建的 AjaxResult 对象     *     * @param code 状态码     * @param msg  返回内容     */    public Result(int code, String msg) {        super.put(CODE_TAG, code);        super.put(MSG_TAG, msg);    }    /**     * 初始化一个新创建的 AjaxResult 对象     *     * @param code 状态码     * @param msg  返回内容     * @param data 数据对象     */    public Result(int code, String msg, Object data) {        super.put(CODE_TAG, code);        super.put(MSG_TAG, msg);        if (!StringUtils.isEmpty(data)) {            super.put(DATA_TAG, data);        }    }    /**     * 返回成功消息     *     * @return 成功消息     */    public static Result success() {        return Result.success("操作成功");    }    /**     * 返回成功数据     *     * @return 成功消息     */    public static Result success(Object data) {        return Result.success("操作成功", data);    }    /**     * 返回成功消息     *     * @param msg 返回内容     * @return 成功消息     */    public static Result success(String msg) {        return Result.success(msg, null);    }    /**     * 返回成功消息     *     * @param msg  返回内容     * @param data 数据对象     * @return 成功消息     */    public static Result success(String msg, Object data) {        return new Result(HttpStatus.OK.value(), msg, data);    }    /**     * 返回错误消息     *     * @return     */    public static Result error() {        return Result.error("操作失败");    }    /**     * 返回错误消息     *     * @param msg 返回内容     * @return 警告消息     */    public static Result error(String msg) {        return Result.error(msg, null);    }    /**     * 返回错误消息     *     * @param msg  返回内容     * @param data 数据对象     * @return 警告消息     */    public static Result error(String msg, Object data) {        return new Result(HttpStatus.INTERNAL_SERVER_ERROR.value(), msg, data);    }    /**     * 返回错误消息     *     * @param code 状态码     * @param msg  返回内容     * @return 警告消息     */    public static Result error(int code, String msg) {        return new Result(code, msg, null);    }    /**     * 方便链式调用     *     * @param key   键     * @param value 值     * @return 数据对象     */    @Override    public Result put(String key, Object value) {        super.put(key, value);        return this;    }}

            方法一:Graphics2D 画图实现

            使用 jdk 画图 Graphics2D 生成验证码

            ()

            1、验证码工具类

            import java.awt.*;import java.awt.image.BufferedImage;import java.util.Random;/** * 验证码工具类 */public class VerifyCodeUtils {    /**     * 传入BufferedImage对象,并将生成好的验证码保存到BufferedImage中     */    public static String drawRandomText(BufferedImage bufferedImage, int width, int height) {        Graphics2D graphics = (Graphics2D) bufferedImage.getGraphics();        // 验证码背景色        graphics.setColor(new Color(255, 255, 255));        // 填充线条背景        graphics.fillRect(0, 0, width, height);        graphics.setFont(new Font("宋体,楷体,微软雅黑", Font.BOLD, 35));        // 数字和字母的组合        String baseNumLetter = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";        StringBuilder builder = new StringBuilder();        // 旋转原点的 x 坐标        int x = 40;        String ch;        Random random = new Random();        for (int i = 0; i  

            2、Controller 控制层

            import org.springframework.beans.factory.annotation.Autowired;import org.springframework.util.FastByteArrayOutputStream;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import javax.imageio.ImageIO;import javax.servlet.ServletOutputStream;import javax.servlet.http.HttpServletResponse;import java.awt.image.BufferedImage;import java.io.IOException;import java.util.Base64;import java.util.UUID;@RestControllerpublic class VerificationController {    @Autowired    private RedisUtils redisUtils;    /**     * 验证码生成工具,返回图片信息     * 适合学习练手使用,redis 呢能存在一个     * @param response     * @throws IOException     */    @GetMapping("/getImageCode")    public void getImageCode(HttpServletResponse response) throws IOException {        // 禁止缓存        response.setDateHeader("Expires", 0);        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");        response.addHeader("Cache-Control", "post-check=0, pre-check=0");        response.setHeader("Pragma", "no-cache");        // 设置响应格式为png图片        response.setContentType("image/png");        // 生成图片验证码        BufferedImage image = new BufferedImage(ConstantCode.WIDTH, ConstantCode.HEIGHT, BufferedImage.TYPE_INT_RGB);        String randomText = VerifyCodeUtils.drawRandomText(image, ConstantCode.WIDTH, ConstantCode.HEIGHT);        // 存入redis        redisUtils.set(ConstantCode.KAPTCHA_KEY, randomText, ConstantCode.KAPTCHA_EXP_TIME);        ServletOutputStream out = response.getOutputStream();        ImageIO.write(image, ConstantCode.IMG_JPG, out);        out.flush();        out.close();    }    /**     * 验证码 Base64     * 可生成多个     * @return     */    @GetMapping("/getCaptchaInfo")    public Result getCaptchaInfo() {        Result success = Result.success();        // 生成图片验证码        BufferedImage image = new BufferedImage(ConstantCode.WIDTH, ConstantCode.HEIGHT, BufferedImage.TYPE_INT_RGB);        String uuid = UUID.randomUUID().toString().replace("-", "");        // 验证码key        String verifyKey = ConstantCode.KAPTCHA_KEY + uuid;        String randomText = VerifyCodeUtils.drawRandomText(image, ConstantCode.WIDTH, ConstantCode.HEIGHT);        // 存入redis        redisUtils.set(verifyKey, randomText, ConstantCode.KAPTCHA_EXP_TIME);        // 转换流信息写出        FastByteArrayOutputStream os = new FastByteArrayOutputStream();        try {            ImageIO.write(image, "jpg", os);        } catch (IOException e) {            return Result.error(e.getMessage());        }        success.put("uuid", uuid);        success.put("img", Base64.getEncoder().encodeToString(os.toByteArray()));        return success;    }}

            方法二:kaptcha 依赖实现

            1、验证码配置

            import com.google.code.kaptcha.impl.DefaultKaptcha;import com.google.code.kaptcha.util.Config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import java.util.Properties;import static com.google.code.kaptcha.Constants.*;/** * 验证码配置 */@Configurationpublic class CaptchaConfig {    @Bean(name = "captchaProducer")    public DefaultKaptcha getKaptchaBean() {        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();        Properties properties = new Properties();        // 是否有边框 默认为true 我们可以自己设置yes,no        properties.setProperty(KAPTCHA_BORDER, "yes");        // 验证码文本字符颜色 默认为Color.BLACK        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");        // 验证码图片宽度 默认为200        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");        // 验证码图片高度 默认为50        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");        // 验证码文本字符大小 默认为40        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");        // KAPTCHA_SESSION_KEY        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");        // 验证码文本字符长度 默认为5        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");        // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");        // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");        Config config = new Config(properties);        defaultKaptcha.setConfig(config);        return defaultKaptcha;    }    @Bean(name = "captchaProducerMath")    public DefaultKaptcha getKaptchaBeanMath() {        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();        Properties properties = new Properties();        // 是否有边框 默认为true 我们可以自己设置yes,no        properties.setProperty(KAPTCHA_BORDER, "yes");        // 边框颜色 默认为Color.BLACK        properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");        // 验证码文本字符颜色 默认为Color.BLACK        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");        // 验证码图片宽度 默认为200        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");        // 验证码图片高度 默认为50        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");        // 验证码文本字符大小 默认为40        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");        // KAPTCHA_SESSION_KEY        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");        // 验证码文本生成器 注意:KaptchaTextCreator的路径        properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.test.demo.KaptchaTextCreator");        // 验证码文本字符间距 默认为2        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");        // 验证码文本字符长度 默认为5        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");        // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");        // 验证码噪点颜色 默认为Color.BLACK        properties.setProperty(KAPTCHA_NOISE_COLOR, "white");        // 干扰实现类        properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");        // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");        Config config = new Config(properties);        defaultKaptcha.setConfig(config);        return defaultKaptcha;    }}

            2、验证码文本生成器

            import com.google.code.kaptcha.text.impl.DefaultTextCreator;import java.util.Random;/** * 验证码文本生成器 */public class KaptchaTextCreator extends DefaultTextCreator {    private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");    @Override    public String getText() {        Integer result = 0;        Random random = new Random();        int x = random.nextInt(10);        int y = random.nextInt(10);        StringBuilder suChinese = new StringBuilder();        int randomoperands = (int) Math.round(Math.random() * 2);        if (randomoperands == 0) {            result = x * y;            suChinese.append(CNUMBERS[x]);            suChinese.append("*");            suChinese.append(CNUMBERS[y]);        } else if (randomoperands == 1) {            if (!(x == 0) && y % x == 0) {                result = y / x;                suChinese.append(CNUMBERS[y]);                suChinese.append("/");                suChinese.append(CNUMBERS[x]);            } else {                result = x + y;                suChinese.append(CNUMBERS[x]);                suChinese.append("+");                suChinese.append(CNUMBERS[y]);            }        } else if (randomoperands == 2) {            if (x >= y) {                result = x - y;                suChinese.append(CNUMBERS[x]);                suChinese.append("-");                suChinese.append(CNUMBERS[y]);            } else {                result = y - x;                suChinese.append(CNUMBERS[y]);                suChinese.append("-");                suChinese.append(CNUMBERS[x]);            }        } else {            result = x + y;            suChinese.append(CNUMBERS[x]);            suChinese.append("+");            suChinese.append(CNUMBERS[y]);        }        suChinese.append("=?@" + result);        return suChinese.toString();    }}

            3、测试正码生成

            import com.google.code.kaptcha.Producer;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.util.FastByteArrayOutputStream;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;import javax.imageio.ImageIO;import java.awt.image.BufferedImage;import java.io.IOException;import java.util.Base64;import java.util.UUID;/** * 验证码操作处理 */@RestControllerpublic class CaptchaController {    @Resource(name = "captchaProducer")    private Producer captchaProducer;    @Resource(name = "captchaProducerMath")    private Producer captchaProducerMath;    @Autowired    private RedisUtils redisUtils;    /**     * 文本验证码     *     * @return     */    @GetMapping("/captchaCharImage")    public Result getCharCode() {        Result ajax = Result.success();        // 生成验证码        String capText = captchaProducerMath.createText();        String capStr = capText.substring(0, capText.lastIndexOf("@"));        String code = capText.substring(capText.lastIndexOf("@") + 1);        BufferedImage image = captchaProducerMath.createImage(capStr);        // 保存验证码信息        String uuid = UUID.randomUUID().toString().replace("-", "");        String verifyKey = ConstantCode.KAPTCHA_KEY + uuid;        redisUtils.set(verifyKey, code, ConstantCode.KAPTCHA_EXP_TIME);        // 转换流信息写出        FastByteArrayOutputStream os = new FastByteArrayOutputStream();        try {            ImageIO.write(image, "jpg", os);        } catch (IOException e) {            return Result.error(e.getMessage());        }        ajax.put("uuid", uuid);        ajax.put("img", Base64.getEncoder().encodeToString(os.toByteArray()));        return ajax;    }    /**     * 生成验证码     */    @GetMapping("/captchaMathImage")    public Result getMathCode() {        Result ajax = Result.success();        // 生成验证码        String capText = captchaProducer.createText();        BufferedImage image = captchaProducerMath.createImage(capText);        // 保存验证码信息        String uuid = UUID.randomUUID().toString().replace("-", "");        String verifyKey = ConstantCode.KAPTCHA_KEY + uuid;        redisUtils.set(verifyKey, capText, ConstantCode.KAPTCHA_EXP_TIME);        // 转换流信息写出        FastByteArrayOutputStream os = new FastByteArrayOutputStream();        try {            ImageIO.write(image, "jpg", os);        } catch (IOException e) {            return Result.error(e.getMessage());        }        ajax.put("uuid", uuid);        ajax.put("img", Base64.getEncoder().encodeToString(os.toByteArray()));        return ajax;    }}

上一篇:轻松下载琴谱链接的详细步骤教程

下一篇:宝塔面板模板定制秘籍,轻松修改,打造吸引眼球的模板改动指南