SpringBoot后端生成漂亮美观的验证码图片

该博客主要展示了如何创建一个验证码工具类,包括生成随机字符串、绘制干扰线、添加噪点等功能,用于生成复杂的图片验证码。此外,还配置了图片消息转换器,以便在Controller中返回验证码图片,并在页面上显示。最后,提供了前端页面部分代码和验证码图片的切换功能。
摘要由CSDN通过智能技术生成

1.定义一个验证码工具类CaptchaUtil

package com.zzq.ams.util;

import com.zzq.ams.model.CaptchaImage;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.*;
import java.util.List;

/**
 * @author zzq
 * @project ams-simple
 * @description 验证码工具
 * @date 2021/3/4 22:47
 */
public class CaptchaUtil {
    private static final Random random = new Random();
    private static final int imgWidth = 412;  //图片宽度
    private static final int imgHeight = 150;  //图片高度
    private static final int fontSize = 70;  //字体大小
    private static final int fontSizeFloat = 10;  //字体大小浮动值
    private static final int lineCount = 10;  //线条数量
    private static final float noiseRage = 0.05f;  //噪声率
    private static final int charSpace = 15;  //验证码字符间距
    private static final int frontColor = 220;  //前景色RGB值
    private static final int frontColorFloat = 20;  //前景色浮动值
    private static final int backColor = 100;   //背景色RGB值
    private static final int backColorFloat = 20;  //背景色浮动值
    private static final int minCodeLen = 4;  //最短验证码字符数
    private static final int maxCodeLen = 5;  //最长验证码字符数
    private static final Character[] charArr;  //验证码基础字符数组
    private static final String[] fontNameArr;  //字体名称数组

    static {
        //默认字体
        List<String> fontNames = new ArrayList<>();
        fontNames.add("Cambria");
        fontNames.add("Arial");
        fontNames.add("Comic Sans MS");
        fontNames.add("Consolas");
        fontNames.add("Lucida Console");
        fontNames.add("Microsoft YaHei UI");
        fontNames.add("Segoe Print");
        //集合转数组
        fontNameArr = new String[fontNames.size()];
        fontNames.toArray(fontNameArr);

        //基础字符数组[0-9a-zA-Z]
        charArr = new Character[62];
        int i = 0;
        for (char j = '0'; j <= '9'; j++) {
            charArr[i++] = j;
        }
        for (char j = 'a'; j <= 'z'; j++) {
            charArr[i++] = j;
        }
        for (char j = 'A'; j <= 'Z'; j++) {
            charArr[i++] = j;
        }
        //数组转集合
        List<Character> characterList = Arrays.asList(charArr);
        //集合洗牌
        Collections.shuffle(characterList);
        //集合转数组
        characterList.toArray(charArr);
    }

    /**
     * 获取验证码
     *
     * @return 图片验证码
     */
    public static CaptchaImage getCaptchaImage() {
        BufferedImage image = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_BGR);
        Graphics graph = image.getGraphics();
        //设置背景
        graph.setColor(getRandColor(frontColor, frontColorFloat));  //背景色
        graph.fillRect(0, 0, imgWidth, imgHeight);  //填充矩形尺寸
        //设置字体
        Font font = getRandFont(fontSize, fontSizeFloat);
        graph.setFont(font);
        //绘制干扰线
        drawRandLine(graph, lineCount, imgWidth, imgHeight);
        //添加噪点
        addNoisePoint(image, noiseRage, imgWidth, imgHeight);
        //绘制字符
        String code = getRandChars(minCodeLen, maxCodeLen);
        drawCaptcha(graph, code);
        return CaptchaImage.of(code, image);
    }

    /**
     * 绘制验证码
     *
     * @param graph   图像
     * @param captcha 验证码
     */
    private static void drawCaptcha(Graphics graph, String captcha) {
        char[] charArr = captcha.toCharArray();
        for (int i = 0; i < charArr.length; i++) {
            Font font = getRandFont(fontSize, fontSizeFloat);
            int bottom = imgHeight - font.getSize();  //底部距离
            graph.setColor(getRandColor(backColor, backColorFloat));
            graph.drawString(String.valueOf(charArr[i]), i * font.getSize() + charSpace, bottom);
        }
    }

    /**
     * 添加图片噪点
     *
     * @param image     图片
     * @param noiseRate 噪声率
     */
    private static void addNoisePoint(BufferedImage image, float noiseRate, int imgWidth, int imgHeight) {
        int area = (int) (noiseRate * imgWidth * imgHeight);
        for (int i = 0; i < area; i++) {
            int x = random.nextInt(imgWidth);
            int y = random.nextInt(imgHeight);
            int rgb = random.nextInt(256);
            image.setRGB(x, y, rgb);
        }
    }

    /**
     * 绘制随机线条
     *
     * @param graph     图像
     * @param lineCount 线条数
     * @param imgWidth  图片宽度
     * @param imgHeight 图片高度
     */
    private static void drawRandLine(Graphics graph, int lineCount, int imgWidth, int imgHeight) {
        for (int i = 0; i < lineCount; i++) {
            int x1 = random.nextInt(imgWidth);
            int y1 = random.nextInt(imgHeight);
            int x2 = random.nextInt(imgWidth);
            int y2 = random.nextInt(imgHeight);
            graph.setColor(getRandColor(50, 30));
            graph.drawLine(x1, y1, x2, y2);
        }
    }

    /**
     * 生成随机字体
     *
     * @param size       字体最小size
     * @param floatValue 浮动值
     * @return 字体对象
     */
    private static Font getRandFont(int size, int floatValue) {
        int minFontSize = size - floatValue;
        int maxFontSize = size + floatValue;
        String fontName = fontNameArr[random.nextInt(fontNameArr.length)];
        int fontStyle = random.nextInt(3);
        int fontSize = random.nextInt(maxFontSize - minFontSize + 1) + minFontSize;
        return new Font(fontName, fontStyle, fontSize);
    }

    /**
     * 生成随机颜色
     *
     * @param rgbVal   颜色基本值
     * @param floatVal 浮动值
     * @return 颜色对象
     */
    private static Color getRandColor(int rgbVal, int floatVal) {
        if (rgbVal > 255) {
            rgbVal = 255;
        }

        int min = rgbVal - floatVal;
        if (min < 0) {
            min = 0;
        }

        int max = rgbVal + floatVal;
        if (max > 255) {
            max = 255;
        }

        int r = random.nextInt(max - min + 1) + min;
        int g = random.nextInt(max - min + 1) + min;
        int b = random.nextInt(max - min + 1) + min;
        return new Color(r, g, b);
    }

    /**
     * 生成随机字符串
     *
     * @param minLen 最小长度
     * @param maxLen 最大长度
     * @return 字符串
     */
    private static String getRandChars(int minLen, int maxLen) {
        int len = random.nextInt(maxLen - minLen + 1) + minLen;
        char[] randCharArr = new char[len];
        for (int j = 0; j < len; j++) {
            randCharArr[j] = charArr[random.nextInt(62)];  //26*2+10
        }
        return String.valueOf(randCharArr);
    }
}

2.配置图片消息转换器

/**
 * @author zzq
 * @project ams-simple
 * @description mvc配置
 * @date 2021/3/4 1:00
 */

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        //注册图片消息转换器
        converters.add(new BufferedImageHttpMessageConverter());
    }
}

3.Controller代码

@RequestMapping("/login")
@Controller
public class LoginController extends BaseController {
    @RequestMapping(value = "/captcha", produces = MediaType.IMAGE_JPEG_VALUE)
    @ResponseBody
    public BufferedImage captcha(HttpServletResponse response) {
        //获取验证码图片
        CaptchaImage captchaImage = CaptchaUtil.getCaptchaImage();
        //获取验证码
        String code = captchaImage.getCode();
        System.err.println(code);
        //通知浏览器不缓存
        response.setHeader("cache-control","no-store");
        return captchaImage.getImage();
    }
}

4.页面部分代码

    <div class="layui-form-item">
        <label class="layui-icon layui-icon-vercode" for="captcha"></label>
        <input type="text" id="captcha" name="captcha" lay-verify="required|captcha" placeholder="图形验证码"
               autocomplete="off" class="layui-input verification captcha" value="xszg">
        <div class="captcha-img">
            <img id="captchaPic" src="">
        </div>
    </div>
  	//JS:点击切换验证码图片
    $("#captchaPic").click(function () {
        $(this).attr("src", "/login/captcha");
    });

5.几张效果图

在这里插入图片描述
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值