登录和注册页面 - 验证码功能的实现

2023-11-07

目录

1. 生成验证码

2. 将本地验证码发布成 URL

3. 后端返回验证码的 URL 给前端

4. 前端将用户输入的验证码传给后端

5. 后端验证验证码


1. 生成验证码

使用hutool 工具生成验证码.

1.1 添加 hutool 验证码依赖

<!--  验证码 -->
<dependency>
	<groupId>cn.hutool</groupId>
	<artifactId>hutool-all</artifactId>
	<version>5.8.16</version>
</dependency>

1.2 创建验证码的控制器 

@RestController
public class CaptchaController {
    @Value("${imagepath}")
    private String imagepath; // 验证码的本地路径

    @RequestMapping("/getcaptcha")
    public Object getCaptcha1(){
        // 1.生成验证码到本地
        //定义图形验证码的长和宽 (这个验证码的大小需要和自己前端的验证码的大小匹配)
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(128, 50);
        String uuid = UUID.randomUUID().toString().replace("-","");
        // 图形验证码写出,可以写出到文件,也可以写出到流
        lineCaptcha.write(imagepath + uuid + ".png");

        return AjaxResult.success(imagepath+uuid+".png");
    }
}

application.propertities 中添加验证码保存路径 (末尾一定要带斜杆)

# 验证码保存路径
imagepath=D:/image/

【注意】

  • 如果项目中配置了拦截器, 那么一定要记得再拦截规则中给验证码的路由放行!!
  • 使用 UUID 每次生成不同地址的验证码

 1.3 前端关键代码

<div class="row" style="margin-bottom: 20px;">
    <span>验证码</span>
    <input id="checkCode" style="width: 66px;">&nbsp;&nbsp;
    <img onclick="loadCode()" id="codeimg" src=""
            style="height: 50px;width: 128px;">
</div>

浏览器直接访问接口 : 127.0.0.1:8080/getcaptcha 

再查看本地路径也确实生成了对应的验证码 : 

 

2. 将本地验证码发布成 URL

2.1 配置映射图片路径

@Configuration
public class AppConfig implements WebMvcConfigurer {

    @Value("${imagepath}")
    private String imagepath;

    /**
     * 映射图片路径
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/image/**")
                .addResourceLocations("file:" + imagepath + "/");
    }
}

使用网络路径 /image/** 映射到本地验证码路径, 注意 "file:" + imagepath + "/"  这最后可能要加上一个斜杆才能生效. (因人而异)

2.2 使用映射后的网络路径访问验证码

浏览器输入: 127.0.0.1:8080/image/b1306474838b4b0e9f8a6ac7606567cb.png

成功访问到了!!

3. 后端返回验证码的 URL 给前端

后端不仅要返回验证码给前端, 还需要返回一个 "验证码的 key" 给前端.

后端返回验证码的 URL 给前端可以理解, 前端需要展示给用户看; 

那么验证码的 key 是啥呢 ???

后端需要将验证码存储 redis, 因为验证码在某一时间内可以生成很多, 而用户输入的正确与否, 需要在后端进行判断, 后端进行判断时, 就得把生成的验证码存储 redis (快), 而存储 redis 我们可以借着前面的 UUID , 把 UUID 作为 key, 验证码作为 value 去存储. 然后再将 key 去传给前端, 前端就可以带着输入的验证码和 key 一起传给后端, 后端就可以拿着 key 去查 redis 得到一个验证码, 然后与前端传过来的作比较即可.

3.1 完善后端 CaptchaController.java 代码

@RestController
public class CaptchaController {
    @Value("${imagepath}")
    private String imagepath; // 验证码的本地路径

    @Resource
    private RedisTemplate redisTemplate; // 将存储验证码的 key - uuid

    @RequestMapping("/getcaptcha")
    public Object getCaptcha(){
        // 1.生成验证码到本地
        //定义图形验证码的长和宽 (这个验证码的大小需要和自己前端的验证码的大小匹配)
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(128, 50);
        String uuid = UUID.randomUUID().toString().replace("-","");
        // 图形验证码写出,可以写出到文件,也可以写出到流
        lineCaptcha.write(imagepath+uuid+".png");
        // 验证码的网络地址
        String url = "/image/"+uuid+".png";
        // 将验证码存储到 redis
        redisTemplate.opsForValue().set(uuid,lineCaptcha.getCode());
        HashMap<String,String> result = new HashMap<>();
        result.put("codeurl",url);
        result.put("codekey",uuid);
        return AjaxResult.success(result);
    }
}

4. 前端将用户输入的验证码传给后端

4.1 前端加载验证码

<script>
    // 验证码key
    var codeKey = "";

    // 获取并显示验证码
    function loadCode() {
        jQuery.ajax({
            url: "/getcaptcha",
            type: "GET",
            data: {},
            success: function (res) {
                if (res.code = 200 && res.data != null && res.data != "") {
                    // 获取验证码成功
                    codeKey = res.data.codekey;
                    jQuery("#codeimg").attr("src", res.data.codeurl);
                }
            }
        });
    }
    loadCode();
</script>

效果图  

 4.2 前端将验证码和 key 传给后端

jQuery.ajax({
    url:"/user/reg",
    type:"post",
    data:{
        username:username.val(),
        password:password.val(),
        checkCode:checkCode.val(),
        codeKey:codeKey
    },
    success:function(body) {
        if(body.code==200 && body.data!=null) {
            alert("恭喜,注册成功!");
            if(confirm("是否要去登录页面 ?")) {
                location.href = "login.html";
            }
        } else if(body.code == -1) {
            alert("抱歉, 注册失败, 请重新注册! " + body.msg);
        } else {
            alert("该用户名已被使用, 请重新输入!");
        }
    }
});

5. 后端验证验证码

5.1 注册功能中验证验证码

@RequestMapping("/reg")
public Object reg(UserInfoVo userInfoVo) {
    // 1. 非空效验
    // 省去具体代码....

    // 2.检查验证码是否正确
    String redisCodeValue = 
        (String) redisTemplate.opsForValue().get(userInfoVo.getCodeKey());
    if(!StringUtils.hasLength(redisCodeValue) ||
            !redisCodeValue.equals(userInfoVo.getCheckCode())) {
        // 验证码不正确
        return AjaxResult.fail(-1, "验证码错误!");
    }
    // .....
    // .... 其他业务逻辑
    return AjaxResult.success(result);
}

登录功能的后端验证验证码其实是一样的方法, 照猫画虎即可~


此处的验证码功能是针对之前的博客 - SSM - 博客系统 来做的一个扩展功能, 有兴趣的可以去实现一下~~

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

登录和注册页面 - 验证码功能的实现 的相关文章

  • 设计模式-状态模式(State)

    文章目录 前言 状态模式的核心概念 状态模式的用途 示例 状态模式的Java实现 状态模式优缺点 总结 前言 当我们需要在对象的生命周期中管理不同状态时 状态模式 State Pattern 是一种有用的设计模式 在这篇博客中 我们将介绍状
  • Spring框架(三)Spring注解和获取Bean对象详解

    目录 一 什么是基于Java的Spring注解配置 具体注解的例子 二 更好的将Bean存储在Spring中 1 前置工作 在配置文件中设置Bean根路径 2 添加注解存储Bean对象 2 1 Controller 控制器存储 2 2 Se
  • SpringBootWeb登录认证

    登录服务端的核心逻辑就是 接收前端请求传递的 用户名 和 密码 然后再根据用户名和密码查询用户信息 如果用户信息存在 则说明用户输入的用户名和密码正确 如果查询到的用户不存在 则说明用户输入的用户名和密码错误 统一拦截 可以使用两种技术实现
  • SpringBoot统一功能处理

    目录 SpringMVC统一处理的三种方式 1 基于SpringMVC的配置类扩展 1 添加路径前缀 2 添加拦截器 2 统一的响应数据格式封装 3 统一异常处理 基于SpringAOP已经实现统一功能增强 但如果希望对Controller
  • Spring 的创建和使用

    目录 一 创建 Spring项目 二 存储 Bean 对象到Spring中 1 添加Spring配置文件 2 创建一个 Bean 对象 3 将 Bean 存储到 Spring 容器中 三 从 Spring 中获取并使用 Bean 对象 1
  • 21 个简洁的 JavaScript单行代码技巧

    JavaScript 发展至今已经变得越来越强大 且广泛用于前端和后端开发 作为一名前端程序员 不断的学习精进技巧 了解JS的最新发展也是非常必要的 而简洁的一行代码示例就是很好的方法 今天 我们有 21 个JavaScript单行代码技巧
  • 设计模式学习(五):State状态模式

    目录 一 什么是State模式 二 State模式示例程序 2 1 伪代码 2 1 1 不使用State模式的伪代码 2 1 2 使用State模式的伪代码 2 2 各个类之间的关系 2 3 State接口 2 4 DayState类 2
  • MyBatis 查询数据库

    目录 1 什么是 MyBatis 2 MyBatis 环境搭建 2 1 创建数据库和表 2 2 添加 MyBatis 框架支持 2 3 配置数据库连接和MyBatis 2 4 添加代码 2 4 1 添加实体类 2 4 2 添加 mapper
  • 设计模式_19 状态模式(含 UML图 和 C++代码)

    设计模式 19 状态模式 19 状态模式 19 1 概念 19 2 结构 19 3 实现 19 3 1 UML图 19 3 2 代码 19 3 3 测试结果 19 4 优缺点 19 4 1 优点 19 4 2 缺点 19 5 使用场景 re
  • 【计算机基础知识9】前端设计模式与常见类型

    目录 一 前言 二 设计模式的基本概念和原则 三 创建型设计模式 四 结构型设计模式 五 行为型设计模式 六 MVC和MVVM框架中的设计模式 七 实际应用案例分析 一 前言 在软件开发领域 设计模式是一种解决常见问题的最佳实践 它可以帮助
  • 登录和注册页面 - 验证码功能的实现

    目录 1 生成验证码 2 将本地验证码发布成 URL 3 后端返回验证码的 URL 给前端 4 前端将用户输入的验证码传给后端 5 后端验证验证码 1 生成验证码 使用hutool 工具生成验证码 1 1 添加 hutool 验证码依赖
  • springboot封装响应实体

    前言 首先什么是响应实体 正常我们的后端都是接收前端 然后把请求需要的数据返回给前端 而这个返回的数据就是我们的响应实体 那么 为什么我们需要进行封装响应实体呢 第一点 最明显的就是 为了人机友好交互 如果单单只是把返回的数据给到前端 有数
  • vue3对echarts的二次封装之按需加载

    欢迎点击领取 前端面试题进阶指南 前端登顶之巅 最全面的前端知识点梳理总结 分享一个使用比较久的 效果展示 1 echarts是我们后台系统中最常用的数据统计图形展示 外界对它的二次封装也不计层数 2 在业务代码内每次的初始dom和绑定se
  • 设计模式【15】——状态模式(State模式)

    文章目录 前言 一 状态模式 State模式 二 具体源码 1 State h 2 State cpp 3 Context h 4 Context cpp 5 main cpp 三 运行结果 总结 前言 每个人 事物在不同的状态下会有不同表
  • SpringMVC 框架详解

    目录 1 什么是 Spring MVC 1 1 什么是MVC 1 2 MVC 和 Spring MVC 的关系 2 第一个SpringMVC程序 2 1 RequestMapping 注解 2 2 ResponseBody 注解 2 3 g
  • 【TS第三讲】完善TS开发环境

    文章目录 写在前面 ts node nodemon nodemon文件类型 nodemon文件范围 写在最后 写在前面 探索TypeScript世界 驭Vue3 Ts潮流 开启前端之旅 欢迎来到前端技术的精彩世界 无论你是刚刚踏入编程大门的
  • 【面试题】前端开发中如何高效渲染大数据量?

    前端面试题库 面试必备 推荐 地址 前端面试题库 国庆头像 国庆爱国 程序员头像 总有一款适合你 在日常工作中 较少的能遇到一次性往页面中插入大量数据的场景 数栈的离线开发 以下简称离线 产品中 就有类似的场景 本文将分享一个实际场景中的前
  • 【设计模式】用Java实现状态模式

    一 状态模式介绍与使用场景 状态模式是一种行为设计模式 它允许对象在内部状态发生改变时改变其行为 该模式将对象的行为包装在不同的状态类中 使得对象的行为可以根据其当前状态动态改变 状态模式通常由以下几个角色组成 环境类 Context 环境
  • MyBatis-Plus 的基础增删改查

    目录 1 简介 2 准备工作 3 MyBatis Plus 实现增删改查 1 MyBatis Plus 简介 MyBatis Plus 简称 MP 是 MyBatis 的增强工具 在 MyBatis 的基础上只做增强不做改变 为简化开发 提
  • 行为型模式-状态模式

    package per mjn pattern state after 环境角色类 public class Context 定义对应状态对象的常量 public final static OpeningState OPENING STAT

随机推荐

  • 表格行与列边框样式处理的原理分析及实战应用

    欢迎大家前往腾讯云社区 获取更多腾讯海量技术实践干货哦 作者 韩宇波 导语 table之间的边框存在共用问题 自然而然就存在冲突 既然存在冲突 那么就势必涉及到最后渲染哪一个样式的问题 本文就主要研究当冲突产生时 如何让浏览器按照自己意愿渲
  • 新的开始----

    种一棵树最好的时间就是现在 为什么记录博客呢 因为记不住 如何学 怎么学习编程 利用能利用的时间 学上不会的 补上会了不熟的 攻克看了还是模棱两可的 博客模板 总分总 WWH
  • Qt中QT_BEGIN_NAMESPACE和QT_END_NAMESPACE的作用

    在Qt中 我们经常会看到 QT BEGIN NAMESPACE class QAction class QMenu class QPlainTextEdit QT END NAMESPACE 这样的方式表达方式 这样做有什么意义呢 只要深入
  • 【华为OD统一考试B卷

    华为OD统一考试A卷 B卷 新题库说明 2023年5月份 华为官方已经将的 2022 0223Q 1 2 3 4 统一修改为OD统一考试 A卷 和OD统一考试 B卷 你收到的链接上面会标注A卷还是B卷 请注意 根据反馈 目前大部分收到的都是
  • 函数变更记录表 function_change

    函数变更记录表 datamart function change 表结构 CREATE TABLE datamart function change function name character varying 200 函数名 new p
  • Linux巡检脚本

    linux巡检脚本 转自 http myit icu index php archives 1634 待测试 bin bash Author Dean Date 2021 11 25 E mail deanmr qq com bin bas
  • Application tried to present modally an active controller

    控制器模态到另一个控制器发生了错误 报错是Application 试图模态到一个活跃的控制器中 第一次模态的时候不会出现问题 第二次发生了问题 也就是说明了第二次模态的视图是活跃状态 没有销毁 查找代码 发现了问题 第一次模态之后 控制器不
  • json-server常见问题

    json server搭建本地测试服务器 mock数据 模拟后台数据 现在基本上都是前后端分离 前端是前端工程师 后端属于后端工程师 但是前后端交互是个必不可少的环节 一般用Ajax进行交互 还需要一些实验数据来支撑 就需要模拟数据 1 v
  • Android第二讲笔记(约束布局ConstraintLayout)

    目录 为什么要使用约束布局ConstraintLayout 约束布局基本属性 约束布局简单使用方法 示例 示例一 仿QQ消息 示例二 仿微信登陆界面 示例三 仿QQ音乐界面 补充 写在最后 ScrollView 滚动布局 示例一 纵向滚动
  • 实测C++变量长度、最小值、最大值

    说明 基本的内置变量类型 bool char wchar t int float double 类型修饰符 signed unsigned short long 环境 win7x64 VS2015 Debugx86 测试结果 补充 doub
  • [1190]如何解决Chrome无法访问ftp的问题

    在最新一次Chrome更新中彻底抛弃ftp协议了 之前可以在搜索栏搜索chrome flags 并将Enable support for ftp Urls设置为Enabled才能访问ftp 但是在Chrome96中直接将修改选项剔除了 这代
  • 珠心算测验-NOIP2014普及t1

    题目描述 珠心算是一种通过在脑中模拟算盘变化来完成快速运算的一种计算技术 珠心算训练 既能够开发智力 又能够为日常生活带来很多便利 因而在很多学校得到普及 某学校的珠心算老师采用一种快速考察珠心算加法能力的测验方法 他随机生成一个正整数集合
  • SpringBoot 项目在Linux服务器上启动、停止脚本(详细)

    SpringBoot 项目在Linux服务器上启动 停止脚本详细 创建脚本 在jar包目录 创建脚本 实际项目只需要修改包名 1 进入可编辑 执行代码 vim xxxxxx sh xxxxxx就是你自己创建的脚本名称 写好后 按下回车后 进
  • C语言

    这篇文章主要和大家分享三种基础的排序算法 冒泡排序 选择排序 快速排序 一 排序问题 1 冒泡排序 冒泡排序的主要思想是通过两两相邻的元素进行比较 通过元素的大小决定是否交换 一趟冒泡排序的结果是一定有一个最大数会排到最后一个元素 因此对n
  • Python中requests包的安装

    在使用pycharm开发的时候 我们经常需要导入一些包 但是这些包 我们事先并没有安装 一个显著的现象就是我们在pycharm中导入一个包时 系统提示不存在 那就是我们没有安装这个包 举一个例子 我在使用pycharm时 需要导入一个req
  • c++ typeid使用

    今天用了下c typeid这个操作符记录一下 class parent void getdata virtual void deal class son public parent int main parent pa new son po
  • How do you install Typecho in Docker and mount hosting server's Mysql service

    Fist of all I presume that you have already installed Docker and Portainer and works smoothly All CLI procdures are base
  • Ubuntu安装GCC 3.4

    Ubuntu安装GCC 3 4 一 背景 二 安装 三 总结 一 背景 因最近学习hit os编译linux 0 11版本内核 需要使用到gcc 3 4 故此记录 二 安装 下载deb包 wget http old releases ubu
  • 如何运用bat脚本批量 重命名/复制 文件

    在平时运维的时候 最繁琐的就是要每个月写运维记录的文档如excel表格 一个月30日要产生30个文件 拷30个运维记录文档的模版再进行重命名实在太麻烦了 所以想到copy模版之后可以用脚本来对文件进行重命名自己想要的效果 首先给出效果图 下
  • 登录和注册页面 - 验证码功能的实现

    目录 1 生成验证码 2 将本地验证码发布成 URL 3 后端返回验证码的 URL 给前端 4 前端将用户输入的验证码传给后端 5 后端验证验证码 1 生成验证码 使用hutool 工具生成验证码 1 1 添加 hutool 验证码依赖