一、概述

login01
如上图,在登录页面上,除了输入用户名和密码之外,有时候需要输入验证码,那么验证的功能可以怎么实现呢?

二、实现过程

1、工具类

public class CaptchaUtil {

    /** 验证码源 */
    public static final String CAPTHCHA_CODES = "23456789adcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ";
    /** 验证码位数 */
    public static final Integer CAPTCHA_SIZE = 4;

    private static Random random = new Random();

    /**
     * 使用系统默认字符源生成验证码
     *
     * @param captchaSize  验证码长度
     * @return 验证码
     */
    public static String generateCaptcha(int captchaSize) {
        return generateCaptcha(captchaSize, CAPTHCHA_CODES);
    }

    /**
     * 使用指定源生成验证码
     *
     * @param captchaSize   验证码长度
     * @param sources  验证码字符源
     * @return 验证码
     */
    public static String generateCaptcha(int captchaSize, String sources) {
        if (sources == null || sources.length() == 0) {
            sources = CAPTHCHA_CODES;
        }
        int codesLen = sources.length();
        Random rand = new Random(System.currentTimeMillis());

        StringBuilder captcha = new StringBuilder(captchaSize);
        for (int i = 0; i < captchaSize; i++) {
            captcha.append(sources.charAt(rand.nextInt(codesLen - 1)));
        }
        return captcha.toString();
    }

    /**
     * 输出随机验证码图片流,并返回验证码值
     *
     * @param w 宽度
     * @param h 高度
     * @param os 输出流
     * @param captchaSize 验证码长度
     * @return
     * @throws IOException
     */
    public static String outputCaptchaImage(int w, int h, OutputStream os, int captchaSize) throws IOException {
        String captcha = generateCaptcha(captchaSize);
        outputImage(w, h, os, captcha);
        return captcha;
    }

    /**
     * 输出指定验证码图片流
     *
     * @param w 宽度
     * @param h 高度
     * @param os 输出流
     * @param captcha 验证码
     * @throws IOException
     */
    public static void outputImage(int w, int h, OutputStream os, String captcha) throws IOException {
        BufferedImage image = generateBufferedImage(w, h, captcha);
        ImageIO.write(image, "jpg", os);
    }

    public static BufferedImage generateBufferedImage(int w, int h, String code) {
        BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = image.createGraphics();
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // 设置背景色
        g2.setColor(getRandColor(200, 250));
        g2.fillRect(0, 0, w, h);

        // 设置线条的颜色
        g2.setColor(getRandColor(160, 200));
        for (int i = 0; i < 10; i++) {
            int x = random.nextInt(w - 1);
            int y = random.nextInt(h - 1);
            int xl = random.nextInt(6) + 1;
            int yl = random.nextInt(12) + 1;
            // 绘制干扰线
            g2.drawLine(x, y, x + xl + 40, y + yl + 20);
        }

        // 添加噪点
        float yawpRate = 0.02f; // 噪声率
        int area = (int) (yawpRate * w * h);
        for (int i = 0; i < area; i++) {
            int x = random.nextInt(w);
            int y = random.nextInt(h);
            int rgb = getRandomIntColor();
            image.setRGB(x, y, rgb);
        }

        // 设置验证码
        g2.setColor(getRandColor(100, 160));
        int fontSize = h - 4;
        Font font = new Font("Algerian", Font.ITALIC, fontSize);
        g2.setFont(font);
        char[] chars = code.toCharArray();
        int length = code.length();
        for (int i = 0; i < length; i++) {
            AffineTransform affine = new AffineTransform();
            affine.setToRotation(Math.PI / 4 * random.nextDouble() * (random.nextBoolean() ? 1 : -1),
                    (w / length) * i + fontSize / 2, h / 2);
            g2.setTransform(affine);
            g2.drawChars(chars, i, 1, ((w - 10) / length) * i + 5, h / 2 + fontSize / 2 - 5);
        }
        g2.dispose();

        return image;
    }

    private static Color getRandColor(int fc, int bc) {
        if (fc > 255) {
            fc = 255;
        }

        if (bc > 255) {
            bc = 255;
        }

        int r = fc + random.nextInt(bc - fc);
        int g = fc + random.nextInt(bc - fc);
        int b = fc + random.nextInt(bc - fc);
        return new Color(r, g, b);
    }

    private static int getRandomIntColor() {
        int[] rgb = getRandomRgb();
        int color = 0;
        for (int c : rgb) {
            color = color << 8;
            color = color | c;
        }
        return color;
    }

    private static int[] getRandomRgb() {
        int[] rgb = new int[3];
        for (int i = 0; i < 3; i++) {
            rgb[i] = random.nextInt(255);
        }
        return rgb;
    }

}

2、服务端控制器调用方式

@ApiOperation(value = "生成验证码")
@GetMapping("/generateCaptcha")
public void generateCaptcha(HttpServletResponse response) {
    try {
        OutputStream os = response.getOutputStream();
        response.setContentType("image/jpg");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "No-cache");
        String captcha = CaptchaUtil.outputCaptchaImage(100, 30, os, CaptchaUtil.CAPTCHA_SIZE);

        SessionUtil.getSession();
        SessionUtil.setCaptcha(captcha);

        os.flush();
    } catch (IOException e) {
        LOGGER.error("produce imageVerifyCode failed!");
        LOGGER.error(e.getMessage(), e);
    }
}

#3、前端页面调用方式

<div id="validatePanel" class="item" style="width: 137px;">
    <input type="text" name="captcha" placeholder="请输入验证码" maxlength="4">
    <img id="refreshCaptcha" class="validateImg"  src="/common/generateCaptcha" >
</div>

打赏
支付宝 微信
上一篇 下一篇