使用Java得hutool工具实现验证码登录

使用Java的hutool工具实现验证码登录

1.先说一下流程图

在这里插入图片描述

2.导入工具包

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

3.流程梳理

3.1前端模版代码

<template>
          <form @submit.prevent="handleSubmit">
            <div class="input-group">
              <div class="captcha-wrapper">
                <input
                  v-model="form.captcha"
                  type="text"
                  placeholder="请输入验证码"
                  :class="{ 'shake': formErrors.captcha }"
                  maxlength="4"
                />
                <div class="captcha-container">
                  <img 
                    :src="captchaUrl" 
                    @click="refreshCaptcha"
                    class="captcha-img"
                    alt="验证码"
                    @error="handleCaptchaError"
                  />
                  <button 
                    type="button" 
                    class="refresh-btn"
                    @click="refreshCaptcha"
                    title="刷新验证码"
                  >
                  </button>
                </div>
              </div>
              <transition name="fade">
                <p v-if="formErrors.captcha" class="error-message">{{ formErrors.captcha }}</p>
              </transition> 
</template>

3.2逻辑代码

  1. 前端挂载组件时发送请求到后端生成验证码

    @RestController
    @RequestMapping("/api")
    public class AuthController {
        @GetMapping("/captcha")
        public void generateCaptcha(HttpServletResponse response, HttpSession session) {
            // 生成验证码
            LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(100, 40);
            // 将验证码存入session
            session.setAttribute("captcha", lineCaptcha.getCode());
    
            try {
                // 输出到客户端
                response.setContentType("image/png");
                lineCaptcha.write(response.getOutputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
  2. , <img :src="captchaUrl”>动态绑定实现渲染验证码,button绑定的是这个refreshCaptcha事件,所以可以实现刷新验证码的操作

    const captchaUrl = ref('')
    // 组件挂载时加载验证码
    onMounted(() => {
      refreshCaptcha()
    })
    const refreshCaptcha = () => {
      // 直接使用API地址,添加时间戳防止缓存
      captchaUrl.value = `${request.defaults.baseURL}/api/captcha?t=${new Date().getTime()}`
      // 清空验证码输入
      form.captcha = ''
    }
    
  3. 然后就是前段提交数据到后端做认证

    const form = reactive({
      email: '',
      password: '',
      remember: false,
      captcha: ''
    })
    export function login(data) {
      return request({
        url: '/api/login',
        method: 'post',
        data
      })
    }
     try {
        // 发送登录请求
        const res = await login({
          username: form.email,
          password: form.password,
          captcha: form.captcha,
          remember: form.remember
        })
    
  4. 后端接收数据进行校验

       @PostMapping("/login")
        public Result login(@RequestBody LoginDTO loginDTO, HttpSession session) {
            // 获取session中的验证码
            String captcha = (String) session.getAttribute("captcha");
            // 校验验证码
            if (!loginDTO.getCaptcha().equalsIgnoreCase(captcha)) {
                return Result.error("验证码错误");
            }
            // TODO: 进行登录逻辑处理
            return null;
        }
    

前端所有代码

<template>
  <div class="login-page">
    <div class="login-container">
      <!-- Left side with rocket -->
      <div class="left-side">
        <div class="logo-container">
          <h1 class="logo">七禾页话</h1>
        </div>
        
        <div class="hero-text">
          <h2>欢迎使用<br />学生管理系统</h2>
          <p>让工作更高效!</p>
        </div>

        <!-- Animated rocket -->
        <div class="rocket-container">
          <div class="rocket" :class="{ 'rocket-hover': isRocketHovering }">
            <div class="rocket-body">
              <div class="rocket-main"></div>
              <div class="rocket-base"></div>
              <div class="rocket-side-left"></div>
              <div class="rocket-side-right"></div>
            </div>
          </div>
          
          <!-- Animated clouds -->
          <div class="clouds">
            <div v-for="i in 3" :key="i" 
                 class="cloud"
                 :class="`cloud-${i}`"
                 :style="`--delay: ${i * 2}s`">
            </div>
          </div>
        </div>
      </div>

      <!-- Right side with form -->
      <div class="right-side">
        <div class="form-container">
          <h2>用户登录</h2>
          
          <form @submit.prevent="handleSubmit">
            <div class="input-group">
              <input
                v-model="form.email"
                type="email"
                placeholder="请输入用户名"
                :class="{ 'shake': formErrors.email }"
              />
              <transition name="fade">
                <p v-if="formErrors.email" class="error-message">{{ formErrors.email }}</p>
              </transition>
            </div>

            <div class="input-group">
              <input
                v-model="form.password"
                type="password"
                placeholder="请输入密码"
                :class="{ 'shake': formErrors.password }"
              />
              <transition name="fade">
                <p v-if="formErrors.password" class="error-message">{{ formErrors.password }}</p>
              </transition>
            </div>

            <div class="input-group">
              <div class="captcha-wrapper">
                <input
                  v-model="form.captcha"
                  type="text"
                  placeholder="请输入验证码"
                  :class="{ 'shake': formErrors.captcha }"
                  maxlength="4"
                />
                <div class="captcha-container">
                  <img 
                    :src="captchaUrl" 
                    @click="refreshCaptcha"
                    class="captcha-img"
                    alt="验证码"
                    @error="handleCaptchaError"
                  />
                  <button 
                    type="button" 
                    class="refresh-btn"
                    @click="refreshCaptcha"
                    title="刷新验证码"
                  >
                    <svg viewBox="0 0 24 24" class="refresh-icon">
                      <path d="M17.65 6.35A7.958 7.958 0 0012 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08A5.99 5.99 0 0112 18c-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z" fill="currentColor"/>
                    </svg>
                  </button>
                </div>
              </div>
              <transition name="fade">
                <p v-if="formErrors.captcha" class="error-message">{{ formErrors.captcha }}</p>
              </transition>
            </div>

            <div class="remember-me">
              <input
                v-model="form.remember"
                type="checkbox"
                id="remember"
              />
              <label for="remember">记住我</label>
            </div>

            <button
              type="submit"
              :class="{ 'loading': isLoading }"
              :disabled="isLoading"
            >
              <span v-if="!isLoading">登 录</span>
              <span v-else class="loading-text">
                <svg class="spinner" viewBox="0 0 50 50">
                  <circle class="path" cx="25" cy="25" r="20" fill="none" stroke-width="5"></circle>
                </svg>
                登录中...
              </span>
            </button>
          </form>

          <div class="auth-links">
            <p class="forgot-password">
              <a href="#">忘记密码?</a>
            </p>
            <p class="register-link">
              还没有账号? <router-link to="/register" class="text-primary">立即注册</router-link>
            </p>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
import { login, getCaptcha } from '@/api/auth'
import request from '@/utils/request'

const router = useRouter()
const isRocketHovering = ref(true)
const isLoading = ref(false)
const captchaUrl = ref('')

const form = reactive({
  email: '',
  password: '',
  remember: false,
  captcha: ''
})

const formErrors = reactive({
  email: '',
  password: '',
  captcha: ''
})

// 刷新验证码
const refreshCaptcha = () => {
  // 直接使用API地址,添加时间戳防止缓存
  captchaUrl.value = `${request.defaults.baseURL}/api/captcha?t=${new Date().getTime()}`
  // 清空验证码输入
  form.captcha = ''
}

// 处理验证码加载错误
const handleCaptchaError = () => {
  console.error('验证码图片加载失败')
  // 可以在这里添加重试逻辑或显示错误提示
}

// 组件挂载时加载验证码
onMounted(() => {
  refreshCaptcha()
})

const handleSubmit = async () => {
  // Reset errors
  formErrors.email = ''
  formErrors.password = ''
  formErrors.captcha = ''

  // Validate
  if (!form.email) {
    formErrors.email = '请输入用户名'
    return
  }
  if (!form.password) {
    formErrors.password = '请输入密码'
    return
  }
  if (!form.captcha) {
    formErrors.captcha = '请输入验证码'
    return
  }

  // Show loading state
  isLoading.value = true

  try {
    // 发送登录请求
    const res = await login({
      username: form.email,
      password: form.password,
      captcha: form.captcha,
      remember: form.remember
    })

    // 存储 token
    localStorage.setItem('token', res.data.token)
    
    // 登录成功,跳转到首页
    router.push('/dashboard')
  } catch (error) {
    // 根据错误类型显示不同的错误信息
    if (error.code === 400) {
      formErrors.captcha = '验证码错误'
      await refreshCaptcha()
    } else if (error.code === 401) {
      formErrors.password = '用户名或密码错误'
      await refreshCaptcha()
    } else {
      console.error('登录失败:', error)
      formErrors.password = error.message || '登录失败,请稍后重试'
      await refreshCaptcha()
    }
  } finally {
    // Reset loading state
    isLoading.value = false
  }
}

// Start rocket hover animation
setInterval(() => {
  isRocketHovering.value = !isRocketHovering.value
}, 2000)
</script>

后端代码

package com.qiheyehua.vuespringboot2.controller;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import com.qiheyehua.vuespringboot2.domain.dto.LoginDTO;
import com.qiheyehua.vuespringboot2.utils.Result;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;

/**
 * @author 七禾页话
 * @date 2024/12/16 18:57
 **/
@RestController
@RequestMapping("/api")
public class AuthController {
    @GetMapping("/captcha")
    public void generateCaptcha(HttpServletResponse response, HttpSession session) {
        // 生成验证码
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(100, 40);
        // 将验证码存入session
        session.setAttribute("captcha", lineCaptcha.getCode());

        try {
            // 输出到客户端
            response.setContentType("image/png");
            lineCaptcha.write(response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @PostMapping("/login")
    public Result login(@RequestBody LoginDTO loginDTO, HttpSession session) {
        // 获取session中的验证码
        String captcha = (String) session.getAttribute("captcha");
        // 校验验证码
        if (!loginDTO.getCaptcha().equalsIgnoreCase(captcha)) {
            return Result.error("验证码错误");
        }
        // TODO: 进行登录逻辑处理
        return null;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java中Map接口的实现类

一、介绍 Map接口常用的实现类有HashMap和TreeMap。HashMap是基于哈希表的Map接口的实现&#xff0c;HashMap类实现的Map集合添加和删除映射关系效率更高。HashMap通过哈希码对其内部的映射关系进行快速查找。TreepMap中的映射关系存在一定的顺序&#xff0c;如果希望Map集合中…

讯飞智文丨一键生成WordPPT

在当今数字化办公的浪潮中,Word和PPT已经成为职场人士日常工作的标配工具。然而,面对繁琐的内容编辑和格式调整任务,如何提升效率成了每个人的追求。而讯飞智文,一款结合人工智能技术的文字处理与演示文稿工具,正逐渐成为用户的得力助手。本文将详细介绍讯飞智文的功能特点…

Dot Foods EDI 需求分析及对接流程

Dot Foods 是一家美国领先的食品和非食品产品的中间批发分销商&#xff0c;主要为食品服务、零售和分销行业的客户提供服务&#xff0c;是北美大型食品中间分销商之一。Dot Foods &#xff08;以下简称 Dot&#xff09;的业务模式是通过整合多个供应商的产品&#xff0c;为客户…

感知机及python实现

感知机&#xff08;Perceptron&#xff09;是神经网络的基本构件之一&#xff0c;最初由Frank Rosenblatt在1957年提出。感知机是一种二分类的线性分类器&#xff0c;通过一个简单的线性函数将输入数据分类到两种类别之一。 基本原理 感知机的工作原理如下&#xff1a; 输入&…

信号滤波分析-低通分析(Matlab)

Matlab低通滤波 信号滤波分析-低通分析&#xff08;Matlab&#xff09; 【标价是仅源码的价格】 【有课程设计答辩PPT和设计文档报告】 需要或感兴趣可以随时联系博主哦&#xff0c;常在线秒回&#xff01; 低通滤波分析方案的设计包括&#xff1a; 1.信号生成原理 2.低通滤波…

ChatGPT客户端安装教程(附下载链接)

用惯了各类AI的我们发现每天打开网页还挺不习惯和麻烦&#xff0c;突然发现客户端上架了&#xff0c;懂摸鱼的人都知道这里面的道行有多深&#xff0c;话不多说&#xff0c;开整&#xff01; 以下是ChatGPT客户端的详细安装教程&#xff0c;适用于Windows和Mac系统&#xff1a…

影像组学+病理组学+深度学习人工智能应用

影像组学 基础学习内容&#xff1a; 特征提取&#xff1a;使用pyradiomics进行形状、纹理、小波变换等特征提取。特征筛选&#xff1a;应用ICC、相关系数、mRMR、Lasso等方法。建模&#xff1a;使用LR、SVM、RF、XGBoost、LightGBM等机器学习算法。模型评估&#xff1a;通过A…

蓝桥杯新年题解 | 第15届蓝桥杯迎新篇

蓝桥杯新年题解 | 第15届蓝桥杯迎新篇 2024年的蓝桥杯即将拉开序幕&#xff01;对于许多编程爱好者来说&#xff0c;这不仅是一次展示自我能力的舞台&#xff0c;更是一次学习和成长的机会。作为一名大一新生的小蓝&#xff0c;对蓝桥杯充满了期待&#xff0c;但面对初次参赛的…

Laplace-Beltrami 拉普拉斯-贝尔特拉米算子

Laplace-Beltrami 拉普拉斯-贝尔特拉米算子 Laplace-Beltrami算子是定义在黎曼流形上的一个二阶微分算子&#xff0c;它在微分几何和偏微分方程中都有重要的应用。在计算机图形学和几何处理中&#xff0c;Laplace-Beltrami算子通常用于网格处理&#xff0c;特别是在网格平滑、…

ISP算法之坏点校正DPC(二):Verilog硬件实现与仿真

DPC的算法讲解和MATLAB仿真参考上一节&#xff1a; ISP算法之坏点校正DPC(一)&#xff1a;MATLAB仿真验证-CSDN博客 本节讲解Verilog的硬件实现与仿真 行缓存设计 DPC算法是基于窗口邻域的像素级别算法&#xff0c;因此需要对实时到来的视频流进行行缓存&#xff0c;行缓存…

clearvoice 语音降噪、语音分离库

参看: https://github.com/modelscope/ClearerVoice-Studio/tree/main ClearVoice 提供了一个统一的推理平台,用于语音增强、语音分离以及视听目标说话人提取。 代码参看: https://github.com/modelscope/ClearerVoice-Studio/tree/main/clearvoice https://github.com/mode…

Linux(网络协议和管理)

后面也会持续更新&#xff0c;学到新东西会在其中补充。 建议按顺序食用&#xff0c;欢迎批评或者交流&#xff01; 缺什么东西欢迎评论&#xff01;我都会及时修改的&#xff01; 在这里真的很感谢这位老师的教学视频让迷茫的我找到了很好的学习视频 王晓春老师的个人空间…

代理 IP 行业现状与未来趋势分析

随着互联网的飞速发展&#xff0c;代理 IP 行业在近年来逐渐兴起并成为网络技术领域中一个备受关注的细分行业。它在数据采集、网络营销、隐私保护等多个方面发挥着重要作用&#xff0c;其行业现状与未来发展趋势值得深入探讨。 目前&#xff0c;代理 IP 行业呈现出以下几个显著…

[Java] 使用 VSCode 来开发 Java

目录 前言Java 环境怎么看自己是否已经配置完成&#xff1f;安装 JDK安装 Maven 环境修改 Maven 依赖源 完善 VS Code配置插件配置 Maven配置 Maven Settings配置 Maven 可执行文件地址 前言 由于使用 VSCode 编码已经成为习惯&#xff0c;并且它确实相对其他的 IDE 较为轻量化…

【热力学与工程流体力学】流体静力学实验,雷诺实验,沿程阻力实验,丘里流量计流量系数测定,局部阻力系数的测定,稳态平板法测定材料的导热系数λ

关注作者了解更多 我的其他CSDN专栏 过程控制系统 工程测试技术 虚拟仪器技术 可编程控制器 工业现场总线 数字图像处理 智能控制 传感器技术 嵌入式系统 复变函数与积分变换 单片机原理 线性代数 大学物理 热工与工程流体力学 数字信号处理 光电融合集成电路…

基于单片机的无绳跳绳设计

基于单片机设计了一款无绳跳绳&#xff0c;采用传感器代替了绳子的摆动&#xff0c;从而实现了模拟跳绳的功能。其研究的方法是&#xff1a;以单片机作为这次设计的核心&#xff0c;它的外围包含有传感器模块、按键模块、显示模块、语音播报模块及电源模块等。本设计采用STM32芯…

暂停一下,给Next.js项目配置一下ESLint(Next+tailwind项目)

前提 之前开自己的GitHub项目&#xff0c;想着不是团队项目&#xff0c;偷懒没有配置eslint&#xff0c;后面发现还是不行。eslint的存在可以帮助我们规范代码格式&#xff0c;同时 ctrl s保存立即调整代码格式是真的很爽。 除此之外&#xff0c;团队使用eslint也是好处颇多…

音频进阶学习八——傅里叶变换的介绍

文章目录 前言一、傅里叶变换1.傅里叶变换的发展2.常见的傅里叶变换3.频域 二、欧拉公式1.实数、虚数、复数2.对虚数和复数的理解3.复平面4.复数和三角函数5.复数的运算6.欧拉公式 三、积分运算1.定积分2.不定积分3.基本的积分公式4.积分规则线性替换法分部积分法 5.定积分计算…

Mac m2电脑上安装单机Hadoop(伪集群)

1. 引言 本教程旨在介绍在Mac 电脑上安装Hadoop 2. 前提条件 2.1 安装JDK Mac电脑上安装Hadoop&#xff0c;必须首先安装JDK&#xff0c;并配置环境变量&#xff08;此处不做详细描述&#xff09; 2.2 配置ssh环境 关闭防火墙 在Mac下配置ssh环境&#xff0c;防止后面启…

【记录49】vue2 vue-office在线预览 docx、pdf、excel文档

vue2 在线预览 docx、pdf、excel文档 docx npm install vue-office/docx vue-demi0.14.6 指定版本 npm install vue-office/docx vue-demi <template><VueOfficeDocx :src"pdf" style"height: 100vh;" rendere"rendereHandler" error&…