大家好,今天给大家带来一个开箱即用的功能:邮箱验证码。 为你的项目增加特色,自然而然就会过答辩!
源码适用于springboot项目,前端是vue。 直接将源码拷贝到你的项目就可以了,无需任何修改!!
实现效果
视频演示
实现步骤
1. 开通QQ邮箱服务器
首先我们需要有一个QQ, 只要能进QQ邮箱即可,用账号密码登录QQ邮箱, 进入邮箱后点击顶部设置
然后切换到账号
拉到下面的POP3/IMAP.... 这一项,开启我们的服务(这里截图是我已经开了)。
然后会获取一段授权码,发邮件代码会用到。
到此你的个人qq邮箱就可以当服务器发邮件了。
2. 后端实现
首先我们需要引入maven, 在项目的目录下的pom.xml 的 <dependencies>节点 添加下面内容:
1234 | <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
到此,前后端实现完毕!!!
用户评论