springboot+vue实现邮箱验证码
大家好,今天给大家带来一个开箱即用的功能:邮箱验证码。 为你的项目增加特色,自然而然就会过答辩!
源码适用于springboot项目,前端是vue。 直接将源码拷贝到你的项目就可以了,无需任何修改!!
实现效果

视频演示
https://githubs.xyz/show/c4f5e2a2-6bf9-4d77-b1ab-6f256a491357.mp4
实现步骤
1. 开通QQ邮箱服务器
首先我们需要有一个QQ, 只要能进QQ邮箱即可,用账号密码登录QQ邮箱, 进入邮箱后点击顶部设置

然后切换到账号

拉到下面的POP3/IMAP.... 这一项,开启我们的服务(这里截图是我已经开了)。

然后会获取一段授权码,发邮件代码会用到。

到此你的个人qq邮箱就可以当服务器发邮件了。
2. 后端实现
首先我们需要引入maven, 在项目的目录下的pom.xml 的 <dependencies>节点 添加下面内容:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
环境配置
spring: mail: host: smtp.qq.com username: 你的邮箱(3571289092@qq.com) password: 你的授权码(上面生成的) properties.mail.smtp: auth: true starttls: enable: true required: true
获取邮箱验证码接口和注册接口代码:
@RestController @RequestMapping("/reg") public class RegisterController { @Autowired Emails emails; @PostMapping("get-code") public V getCode(@RequestBody User user) { if (StringUtils.isEmpty(user.getEmail())) { return V.err("邮箱为空"); } if (!emails.isValidEmail(user.getEmail())) { return V.err("邮箱格式错误"); } // 这里可以从数据库中根据邮箱查询用户,如果数据存在, 提示 该邮箱已经被注册 // 发送邮箱验证码 String code = emails.send(user); // 验证码 存入缓存 emails.putCache(user.getEmail(), code); System.out.println("用户获取邮箱验证码 : " + user.getEmail() + " , code:" + code); return V.ok(); } @PostMapping("register") public V register(@RequestBody User user) { if (StringUtils.isEmpty(user.getEmail()) || !emails.isValidEmail(user.getEmail()) || StringUtils.isEmpty(user.getCode())) { return V.err("参数错误"); } // 从缓存中判断验证码 if (!emails.getCache(user.getEmail()).equals(user.getCode().trim())) { return V.err("邮箱验证码错误"); } System.out.println("验证码验证成功,开始注册"); // 下面为验证码正确 // 进行你的注册逻辑 return V.ok() ; } }
Emails 类是我封装的一个邮箱工具类, 支持 发送邮箱,邮箱验证码校验,邮箱校验 等功能。
项目的前后端整体源码我已经整理清楚,移步获取:
gitcode典康姆/hadluo2/func_code.git
3. 后端实现
注册页面代码:
<template> <div class="register-container"> <h2>用户注册</h2> <div class="register-form"> <div class="form-item"> <label>邮箱:</label> <input type="email" v-model="email" placeholder="请输入邮箱"> </div> <div class="form-item verification-code"> <label>验证码:</label> <input type="text" v-model="verificationCode" placeholder="请输入验证码"> <button @click="sendVerificationCode" :disabled="cooldown > 0"> {{ cooldown > 0 ? `${cooldown}秒后重试` : '获取验证码' }} </button> </div> <div class="form-item"> <label>密码:</label> <input type="password" v-model="password" placeholder="请输入密码"> </div> <button class="register-btn" @click="handleRegister">注册</button> </div> </div> </template> <script> import { getCode, register } from '@/api/registerApi' import { ElMessage } from 'element-plus' export default { name: 'Register', data() { return { email: '3571289092@qq.com', verificationCode: '', password: '', cooldown: 0 } }, methods: { async sendVerificationCode() { if (!this.email) { ElMessage.warning('请输入邮箱地址'); return; } try { await getCode(this.email); this.startCooldown(); ElMessage.success('验证码已发送,请查收邮件'); } catch (error) { ElMessage.error('发送验证码失败'); } }, startCooldown() { this.cooldown = 60; const timer = setInterval(() => { this.cooldown--; if (this.cooldown <= 0) { clearInterval(timer); } }, 1000); }, async handleRegister() { if (!this.email || !this.verificationCode || !this.password) { ElMessage.warning('请填写完整信息'); return; } try { await register({ email: this.email, code: this.verificationCode, password: this.password }); ElMessage.success('注册成功'); this.$router.push('/login'); } catch (error) { console.log(error); } } } } </script> <style scoped> .register-container { max-width: 500px; margin: 50px auto; padding: 20px; } .register-form { background: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); } .form-item { margin-bottom: 20px; } .form-item label { display: block; margin-bottom: 8px; } .form-item input { width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; } .verification-code { display: flex; gap: 10px; } .verification-code input { flex: 1; } .verification-code button { padding: 8px 15px; background: #409EFF; color: white; border: none; border-radius: 4px; cursor: pointer; } .verification-code button:disabled { background: #a0cfff; cursor: not-allowed; } .register-btn { width: 100%; padding: 12px; background: #409EFF; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; } .register-btn:hover { background: #66b1ff; } </style>
registerApi.js代码:
import request from '@/utils/requests' // 获取验证码 export function getCode(email) { return request({ url: '/reg/get-code', method: 'post', data: { email } }) } // 添加广告 export function register(data) { return request({ url: '/reg/register', method: 'post', data }) }
requets.js代码:
import axios from 'axios' import { ElMessage } from 'element-plus' const service = axios.create({ baseURL: '/api', timeout: 5000 }) // 请求拦截器 service.interceptors.request.use( config => { // 在请求发送之前做一些处理,比如添加token const token = localStorage.getItem('token') if (token) { config.headers['Authorization'] = `Bearer ${token}` } return config }, error => { console.log(error) return Promise.reject(error) } ) // 响应拦截器 service.interceptors.response.use( response => { const res = response.data // 这里可以根据后端的响应结构进行调整 if (res.code === 0) { return res.data } else { ElMessage.error(res.msg || '请求失败') return Promise.reject(new Error(res.msg || '请求失败')) } }, error => { console.log('err' + error) ElMessage.error(error.message || '请求失败') return Promise.reject(error) } ) // 封装GET请求 export function get(url, params) { return service({ url, method: 'get', params }) } // 封装POST请求 export function post(url, data) { return service({ url, method: 'post', data }) } // 封装PUT请求 export function put(url, data) { return service({ url, method: 'put', data }) } // 封装DELETE请求 export function del(url, params) { return service({ url, method: 'delete', params }) } export default service
到此,前后端实现完毕!!!

浙公网安备 33010602011771号