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

news2024/12/26 18:15:24

效果

在这里插入图片描述

实现思路

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

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

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

简单验证码

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

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、添加依赖

<dependency>
	<groupId>cn.hutool</groupId>
	<artifactId>hutool-all</artifactId>
	<version>5.7.16</version>
</dependency>

2、写一个控制器

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 "验证码错误,请重试!";
        }
    }
}
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

<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>

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
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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2046874.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Qt 学习第六天:页面布局

如何设计页面&#xff1f; 有个类似沙盒模式的玩法&#xff0c;Qt Widget Designer可以更好的帮助我们设计页面 点击.ui文件进入 右上方可以看到四种常见的布局&#xff1a; 四种布局 &#xff08;一&#xff09;水平布局horizontalLayout&#xff1a;QHBoxLayout H 是 hori…

c++实现B树(上)

哈喽啊&#xff01;好久不见&#xff0c;甚是想念&#xff01;失踪人口要回归了&#xff0c;时隔一个多月小吉我终于要更新blog了&#x1f389;。在停更的一个多月中&#xff0c;小吉也有在好好学习提升自己&#xff0c;立志给大家呈现好文章。  现在让我们进入正题吧&#xf…

初识C++:开启C++之旅

目录 1.C的第一个程序 2.namesapce命名空间域 2.1namespace的意义 2.2.2namespace的定义 2.3命名空间的使用 3.C输入/输出 4.缺省参数 5.函数重载 6.引用 6.1引用的特性 6.2引用的使用 1.C的第一个程序 c版本&#xff1a; #include<iostream>using std::cout…

kali安装wechart

前言&#xff1a; 突发奇想想在kali安装个wechart&#xff0c;试了下网上的很多&#xff0c;玩坏了一个虚拟机算是找到了一个不错的方法&#xff0c;这里记录下&#xff0c;防迷路 基础配置&#xff1a; 首先修改源&#xff1a; vim /etc/apt/sources.list 注释默认配置&…

EasyCVR视频汇聚平台:打造全栈视频监控系统的基石,解锁可视化管理与高效运维

随着科技的飞速发展&#xff0c;视频监控已成为现代社会不可或缺的一部分&#xff0c;广泛应用于社区、公共场所、工业领域等多个场景。EasyCVR视频汇聚平台&#xff0c;作为一款高性能的视频汇聚管理平台&#xff0c;凭借其强大的视频处理、汇聚与融合能力&#xff0c;在构建全…

centos8 安装zookeeper

1&#xff1a;下载 zookeeper官网 解压&#xff1a;tar -zxvf apache-zookeeper-3.6.3.tar.gz 修改自己想要的文件目录 mv apache-zookeeper-3.6.3 zookeeper_3.6.3 备份一下 配置文件 cp zoo_sample.cfg zoo.cfg vim zoo.cfg 编辑日志文件和端口号

nginx实战演练

目录 一.Nginx架构和安装&#xff08;未完待续&#xff09; <1>.Nginx概述 <2>.Nginx架构和进程 <3>.Nginx模块 <4>.Nginx安装(编译安装) 二.Nginx基础配置 <1>.关闭debug <2>.将nginx软件添加到环境变量 <3>.开机自启动脚…

EmguCV学习笔记 VB.Net 2.5 Mat类、Matrix类和Image类的相互转换

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV学习笔记目录 Vb.net EmguCV学习笔记目录 C# 笔者的博客网址&#xff1a;VB.Net-CSDN博客 教程相关说明以及如何获得pdf教…

基于Vue的MES生产制造执行系统

TOC springboot307基于Vue的MES生产制造执行系统 第1章 绪论 1.1 选题动因 到现在为止&#xff0c;互联网已经进入了千家万户&#xff0c;最普通的平民百姓也有属于自己的智能设备&#xff0c;计算机各种技术的储备也是相当的丰富&#xff0c;并且实现也是没有难度&#xf…

VSCode配置ssh免密连接远程服务器

我配置了免密设置(Windows利用ssh免密码登录Linux)&#xff0c;git bash已经能够正常连接了&#xff0c;但是vscode还是不行&#xff0c;很奇怪。 VSCode报错信息&#xff1a; [17:55:50.360] SSH Resolver called for "ssh-remote106.52.2.19", attempt 5, (Recon…

《机器学习》——运用OpenCV库中的KNN算法进行图像识别

文章目录 KNN算法的简单介绍下载OpenCV库实验内容实验结果完整代码自己手写数字传入模型中测试 KNN算法的简单介绍 一、KNN算法的基本要素 K值的选择&#xff1a;K值代表选择与新测试样本距离最近的前K个训练样本数&#xff0c;通常K是不大于20的整数。K值的选择对算法结果有重…

电压检测之比较电路

设计这款电路主要是本人在锂电池充电电路中挖了一个坑&#xff0c;对电源显示芯片的数据手册内容撰写不够详细的不好感受&#xff0c;所以自己根据比较电路的思想设计出了电压检测并反馈的电路&#xff0c;亦在提供一种电压检测的思想不需要借助ADC采集&#xff0c;在电路硬件上…

基于hive的海鲜交易数据分析系统设计与实现【hadoop、Flask、某东爬虫、sqoop、flume、mysql、hdfs】商品可换

文章目录 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍研究背景国内外研究现状研究目的研究意义 关键技术理论介绍数据采集及预处理数据采集字段介绍数据预处理hadoop集群搭建及实现过程hive建表hive大数据分析 可视化展示店铺维度画像分…

AR 眼镜之-开关机定制-实现方案

目录 &#x1f4c2; 前言 AR 眼镜系统版本 开关机定制 1. &#x1f531; 技术方案 1.1 技术方案概述 1.2 实现方案 1&#xff09;开机 Logo 2&#xff09;开机音效 3&#xff09;开机动画 4&#xff09;关机动画 5&#xff09;关机弹窗 2. &#x1f4a0; 开机 Logo…

C++笔试题汇总

C笔试题汇总记录 一、概述二、概念分类1. 结构体1. C 和 C 中 struct 有什么区别&#xff1f;2. C中的 struct 和 class 有什么区别&#xff1f; 2. 类相关1. 类的大小1. 空类的大小2. 一般非空类大小3. 有虚函数类4. 有虚函数类的继承5. 只有虚函数6. 静态数据成员 2. C的三大…

【分享】格力手机色界G0245D 刷REC、root、 救砖、第三方rom教程和资源

开门见山 帮别人弄了一台 格力G0245D&#xff0c;把找到的资源和教程分享一下 教程 这个写的很详细了格力手机色界G0245D-Root-最简指南 不过教程里刷rec这一步漏了加上电源键&#xff0c;加上就行了。 附加参考&#xff1a;格力手机2刷机 格力手机二代刷机 GREE G0215D刷机…

C++ 特殊类设计以及单例模式

目录 1 不能被拷贝 2 只能在堆上创建对象 3 只能在栈上创建对象 4 禁止在堆上创建对象 5 不能被继承的类 6 单例类 特殊类就是一些有特殊需求的类。 1 不能被拷贝 要设计一个防拷贝的类&#xff0c;C98之前我们只需要将拷贝构造以及拷贝赋值设为私有&#xff0c;同时只声明…

在HFSS中对曲线等结构进行分割(Split)

在HFSS中对曲线进行分割 我们往往需要把DXF等其他类型文件导入HFSS进行分析&#xff0c;但是有时需要对某一个曲线单独进行分割成两段修改。 如果是使用HFSS绘制的曲线&#xff0c;我们修改起来非常方便&#xff0c;修改参数即可。但是如果是导入的曲线&#xff0c;则需要使用…

代码随想录训练营 Day31打卡 贪心算法 part05 56. 合并区间 738. 单调递增的数字 968. 监控二叉树

代码随想录训练营 Day31打卡 贪心算法 part05 一、 力扣56. 合并区间 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中…

【JavaEE】JVM 内存区域划分,以及 Java 垃圾回收机制引用计数器,可达性分析等

目录 1. JVM执行流程 2. JVM运行时数据区 2.1 堆 2.2 Java虚拟机栈(线程私有) 2.3本地方法栈(线程私有) 2.4 程序计数器 2.5 元数据区 3. JVM的类加载机制 1) 加载 2) 验证 3) 准备 4) 解析 5) 初始化 双亲委派模型 4. java垃圾回收 4.1 死亡对象判断方法 a) …