Java使用hutool工具實(shí)現(xiàn)驗(yàn)證碼登錄
1.先說一下流程圖
2.導(dǎo)入工具包
<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="請輸入驗(yàn)證碼" :class="{ 'shake': formErrors.captcha }" maxlength="4" /> <div class="captcha-container"> <img :src="captchaUrl" @click="refreshCaptcha" class="captcha-img" alt="驗(yàn)證碼" @error="handleCaptchaError" /> <button type="button" class="refresh-btn" @click="refreshCaptcha" title="刷新驗(yàn)證碼" > </button> </div> </div> <transition name="fade"> <p v-if="formErrors.captcha" class="error-message">{{ formErrors.captcha }}</p> </transition> </template>
3.2邏輯代碼
前端掛載組件時(shí)發(fā)送請求到后端生成驗(yàn)證碼
@RestController @RequestMapping("/api") public class AuthController { @GetMapping("/captcha") public void generateCaptcha(HttpServletResponse response, HttpSession session) { // 生成驗(yàn)證碼 LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(100, 40); // 將驗(yàn)證碼存入session session.setAttribute("captcha", lineCaptcha.getCode()); try { // 輸出到客戶端 response.setContentType("image/png"); lineCaptcha.write(response.getOutputStream()); } catch (IOException e) { e.printStackTrace(); } }
<img :src="captchaUrl”>動(dòng)態(tài)綁定實(shí)現(xiàn)渲染驗(yàn)證碼,button綁定的是這個(gè)refreshCaptcha事件,所以可以實(shí)現(xiàn)刷新驗(yàn)證碼的操作
const captchaUrl = ref('') // 組件掛載時(shí)加載驗(yàn)證碼 onMounted(() => { refreshCaptcha() }) const refreshCaptcha = () => { // 直接使用API地址,添加時(shí)間戳防止緩存 captchaUrl.value = `${request.defaults.baseURL}/api/captcha?t=${new Date().getTime()}` // 清空驗(yàn)證碼輸入 form.captcha = '' }
然后就是前段提交數(shù)據(jù)到后端做認(rèn)證
const form = reactive({ email: '', password: '', remember: false, captcha: '' }) export function login(data) { return request({ url: '/api/login', method: 'post', data }) } try { // 發(fā)送登錄請求 const res = await login({ username: form.email, password: form.password, captcha: form.captcha, remember: form.remember })
后端接收數(shù)據(jù)進(jìn)行校驗(yàn)
@PostMapping("/login") public Result login(@RequestBody LoginDTO loginDTO, HttpSession session) { // 獲取session中的驗(yàn)證碼 String captcha = (String) session.getAttribute("captcha"); // 校驗(yàn)驗(yàn)證碼 if (!loginDTO.getCaptcha().equalsIgnoreCase(captcha)) { return Result.error("驗(yàn)證碼錯(cuò)誤"); } // TODO: 進(jìn)行登錄邏輯處理 return null; }
4.前端所有代碼
<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 />學(xué)生管理系統(tǒng)</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="請輸入驗(yàn)證碼" :class="{ 'shake': formErrors.captcha }" maxlength="4" /> <div class="captcha-container"> <img :src="captchaUrl" @click="refreshCaptcha" class="captcha-img" alt="驗(yàn)證碼" @error="handleCaptchaError" /> <button type="button" class="refresh-btn" @click="refreshCaptcha" title="刷新驗(yàn)證碼" > <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"> 還沒有賬號(hào)? <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: '' }) // 刷新驗(yàn)證碼 const refreshCaptcha = () => { // 直接使用API地址,添加時(shí)間戳防止緩存 captchaUrl.value = `${request.defaults.baseURL}/api/captcha?t=${new Date().getTime()}` // 清空驗(yàn)證碼輸入 form.captcha = '' } // 處理驗(yàn)證碼加載錯(cuò)誤 const handleCaptchaError = () => { console.error('驗(yàn)證碼圖片加載失敗') // 可以在這里添加重試邏輯或顯示錯(cuò)誤提示 } // 組件掛載時(shí)加載驗(yàn)證碼 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 = '請輸入驗(yàn)證碼' return } // Show loading state isLoading.value = true try { // 發(fā)送登錄請求 const res = await login({ username: form.email, password: form.password, captcha: form.captcha, remember: form.remember }) // 存儲(chǔ) token localStorage.setItem('token', res.data.token) // 登錄成功,跳轉(zhuǎn)到首頁 router.push('/dashboard') } catch (error) { // 根據(jù)錯(cuò)誤類型顯示不同的錯(cuò)誤信息 if (error.code === 400) { formErrors.captcha = '驗(yàn)證碼錯(cuò)誤' await refreshCaptcha() } else if (error.code === 401) { formErrors.password = '用戶名或密碼錯(cuò)誤' 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>
5.后端代碼
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) { // 生成驗(yàn)證碼 LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(100, 40); // 將驗(yàn)證碼存入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中的驗(yàn)證碼 String captcha = (String) session.getAttribute("captcha"); // 校驗(yàn)驗(yàn)證碼 if (!loginDTO.getCaptcha().equalsIgnoreCase(captcha)) { return Result.error("驗(yàn)證碼錯(cuò)誤"); } // TODO: 進(jìn)行登錄邏輯處理 return null; } }
到此這篇關(guān)于Java使用hutool工具實(shí)現(xiàn)驗(yàn)證碼登錄的文章就介紹到這了,更多相關(guān)Java hutool驗(yàn)證碼登錄內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java導(dǎo)出Excel通用工具類實(shí)例代碼
這篇文章主要給大家介紹了關(guān)于Java導(dǎo)出Excel通用工具類的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04Java Spring MVC獲取請求數(shù)據(jù)詳解操作
Spring MVC 是 Spring 提供的一個(gè)基于 MVC 設(shè)計(jì)模式的輕量級(jí) Web 開發(fā)框架,本質(zhì)上相當(dāng)于 Servlet,Spring MVC 角色劃分清晰,分工明細(xì)。由于 Spring MVC 本身就是 Spring 框架的一部分,可以說和 Spring 框架是無縫集成2021-11-11利用Java實(shí)現(xiàn)圖片轉(zhuǎn)化為ASCII圖的示例代碼
本文將詳細(xì)講解如何利用 Java 實(shí)現(xiàn)圖片轉(zhuǎn)化為 ASCII 圖,從項(xiàng)目背景與意義、相關(guān)技術(shù)知識(shí),到系統(tǒng)需求與架構(gòu)設(shè)計(jì),再到詳細(xì)實(shí)現(xiàn)思路、完整代碼和代碼解讀,最后對項(xiàng)目進(jìn)行總結(jié)與展望,需要的朋友可以參考下2025-03-03java構(gòu)建OAuth2授權(quán)服務(wù)器
本文主要介紹了java構(gòu)建OAuth2授權(quán)服務(wù)器,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-07-07SpringBoot開啟虛擬線程的實(shí)現(xiàn)流程
虛擬線程(Virtual?Thread)也稱協(xié)程或纖程,是一種輕量級(jí)的線程實(shí)現(xiàn),與傳統(tǒng)的線程以及操作系統(tǒng)級(jí)別的線程(也稱為平臺(tái)線程)相比,它的創(chuàng)建開銷更小、資源利用率更高,本文給大家介紹了SpringBoot如何開啟虛擬線程,需要的朋友可以參考下2024-06-06超詳細(xì)講解SpringCloud?Commons公共抽象的用法
這篇文章主要介紹了超詳細(xì)講解SpringCloud?Commons公共抽象的用法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04