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

相关推荐
Scott9999HH7 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔7 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社8 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海8 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖9 小时前
JDK 26 新特性详解
java·开发语言
马优晨10 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区12 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大12 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai13 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说13 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json