java:实现简单的验证码功能

效果

实现思路

验证码图片的url由后端的一个Controller生成,前端请求这个Controller接口的时候根据当前时间生成一个uuid,并把这个uuid在前端使用localStorage缓存起来,下一次还是从缓存中获取。

Controller生成验证码之后,把前端传过来的uuid通过redis缓存起来,这里分两次缓存

  • 缓存uuid
  • 以uuid为key,缓存验证码

这样,当点击登录按钮将数据提交到后台登录接口时,会从redis中获取uuid,然后通过这个uuid去获取验证码,和前端用户输入的验证码进行比较。

简单验证码

生成随机字符(如数字、字母)的字符串,并将这些字符绘制到一张图片上,最后输出这张图片。

java 复制代码
import javax.imageio.ImageIO;  
import java.awt.*;  
import java.awt.image.BufferedImage;  
import java.io.File;  
import java.io.IOException;  
import java.util.Random;  
  
public class CaptchaGenerator {  
  
    private static final int WIDTH = 100;  
    private static final int HEIGHT = 40;  
    private static final Random RANDOM = new Random();  
  
    public static void main(String[] args) {  
        // 生成验证码文本  
        String captchaText = generateCaptchaText(6);  
        // 生成验证码图片  
        File outputFile = new File("captcha.png");  
        generateCaptchaImage(captchaText, outputFile);  
        System.out.println("Captcha generated: " + captchaText);  
    }  
  
    private static String generateCaptchaText(int length) {  
        StringBuilder sb = new StringBuilder(length);  
        for (int i = 0; i < length; i++) {  
            // 随机选择字符类型  
            int type = RANDOM.nextInt(3);  
            if (type == 0) { // 数字  
                sb.append(RANDOM.nextInt(10));  
            } else if (type == 1) { // 小写字母  
                sb.append((char) ('a' + RANDOM.nextInt(26)));  
            } else { // 大写字母  
                sb.append((char) ('A' + RANDOM.nextInt(26)));  
            }  
        }  
        return sb.toString();  
    }  
  
    private static void generateCaptchaImage(String captchaText, File outputFile) {  
        BufferedImage bufferedImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);  
        Graphics2D g2d = bufferedImage.createGraphics();  
  
        // 设置背景色  
        g2d.setColor(Color.WHITE);  
        g2d.fillRect(0, 0, WIDTH, HEIGHT);  
  
        // 设置字体  
        Font font = new Font("Arial", Font.BOLD, 24);  
        g2d.setFont(font);  
  
        // 绘制验证码文本  
        g2d.setColor(Color.BLACK);  
        FontMetrics fontMetrics = g2d.getFontMetrics();  
        int x = (WIDTH - fontMetrics.stringWidth(captchaText)) / 2;  
        int y = ((HEIGHT - fontMetrics.getHeight()) / 2) + fontMetrics.getAscent();  
        g2d.drawString(captchaText, x, y);  
  
        // 释放资源  
        g2d.dispose();  
  
        // 输出图片  
        try {  
            ImageIO.write(bufferedImage, "png", outputFile);  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
}

工具包

  • Hutool:是一个多功能的工具包,其中有验证码的功能hutool-captcha
  • easy-captcha:专注验证码

Hutool demo

1、添加依赖

xml 复制代码
<dependency>
	<groupId>cn.hutool</groupId>
	<artifactId>hutool-all</artifactId>
	<version>5.7.16</version>
</dependency>

2、写一个控制器

java 复制代码
package com.zhangyu.controller;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.json.JSONObject;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@RestController
public class CaptchaController {

    @GetMapping("/captcha")
    public Map captcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 生成验证码图片  
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100, 4, 4);
        // 获取验证码图片上的文字
        String captchaText = lineCaptcha.getCode();
        // 将验证码文字放入session,键名为  CAPTCHA_KEY
        request.getSession().setAttribute("CAPTCHA_KEY", captchaText);
        System.out.println("文字是" + captchaText);

        // 输出图片  
        BufferedImage image = lineCaptcha.getImage();
        // 图片转base64
        String base = ImageToBase64.convertImageToBase64(image);
        System.out.println("base文字是" + base);

        // 组装数据
        Map resultMap = new HashMap();
        resultMap.put("code", captchaText);
        resultMap.put("img", "data:image/png;base64," + base);
        return resultMap;
    }

    @PostMapping("/submit")
    public String submit(HttpServletRequest request, @RequestBody JSONObject jsonObject) {
        String captcha = jsonObject.getStr("captcha");
        String sessionCaptcha = (String) request.getSession().getAttribute("CAPTCHA_KEY");
        if (captcha.equalsIgnoreCase(sessionCaptcha)) {
            return "验证码正确!";
        } else {
            return "验证码错误,请重试!";
        }
    }
}
java 复制代码
package com.zhangyu.controller;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Base64;
import java.io.IOException;

public class ImageToBase64 {
    public static String convertImageToBase64(BufferedImage image) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(image, "png", baos); // 可以改为需要的图片格式,如"jpg"
        byte[] imageBytes = baos.toByteArray();
        return Base64.getEncoder().encodeToString(imageBytes);
    }
}

3、前端测试

这里我用vue写了一个简单的demo

js 复制代码
<template>
  <div class="home">
    <img :src="imgUrl" @click="getCaptchaImg()" alt="captcha" title="点击刷新">
    <input type="text" name="captcha" placeholder="输入验证码" v-model="text">
    <button type="submit" @click="submitCaptcha()">提交</button>
  </div>
</template>

<script>
import baseApi from '@/api/base'
export default {
  name: 'HomeView',
  data () {
    return {
      imgUrl: '',
      text: ''
    }
  },
  methods: {
    async getCaptchaImg() {
      const res = await baseApi.getCaptchaImg()
      this.imgUrl = res.img
    },
    async submitCaptcha() {
      const params = {
        captcha: this.text,
      }
      const res = await baseApi.submitCaptcha(params)
    }
  },
  async mounted () {
    this.getCaptchaImg()
  }
}
</script>
js 复制代码
import ajax from '@/libs/ajax'

const baseApi = {
  getCaptchaImg: () => ajax.request({
    url: '/captcha',
    method: 'get'
  }),
  submitCaptcha: (data) => ajax.request({
    url: '/submit',
    method: 'post',
    data
  })
}
export default baseApi
js 复制代码
devServer: {
  port: 9001,
  open: false,
  // 配置跨域请求头,解决开发环境的跨域问题
  headers: {
    'Access-Control-Allow-Origin': '*',
  },
  proxy: 'http://192.168.18.21:9090/'
},

4、效果

总结

这里只是用Hutool工具包做了一个demo,easy-captcha我就不展示了也差不多。

真实的场景是返回给前端base64图片和一个uuid,并不是我这里展示的图片文字,然后提交的时候前端把uuid和输入内容传递给后端,由于我这里只是demo所以没有牵扯uuid

相关推荐
欧阳枫落2 分钟前
python 2小时学会八股文-数据结构
开发语言·数据结构·python
何曾参静谧10 分钟前
「QT」文件类 之 QTextStream 文本流类
开发语言·qt
monkey_meng13 分钟前
【Rust类型驱动开发 Type Driven Development】
开发语言·后端·rust
落落落sss22 分钟前
MQ集群
java·服务器·开发语言·后端·elasticsearch·adb·ruby
我救我自己22 分钟前
UE5运行时创建slate窗口
java·服务器·ue5
2401_8532757342 分钟前
ArrayList 源码分析
java·开发语言
zyx没烦恼42 分钟前
【STL】set,multiset,map,multimap的介绍以及使用
开发语言·c++
lb363636363642 分钟前
整数储存形式(c基础)
c语言·开发语言
feifeikon1 小时前
Python Day5 进阶语法(列表表达式/三元/断言/with-as/异常捕获/字符串方法/lambda函数
开发语言·python
爪哇学长1 小时前
SQL 注入详解:原理、危害与防范措施
xml·java·数据库·sql·oracle