发送邮箱验证码功能实现

This commit is contained in:
YuNan 2024-11-06 18:47:00 +08:00
parent 1b7bf095dc
commit fdb2b98a98
10 changed files with 124 additions and 162 deletions

View File

@ -1,24 +1,24 @@
package com.yunan.controller;
import com.yunan.constant.ResponseCode;
import com.yunan.dto.ApiResponse;
import com.yunan.response.ApiResponse;
import com.yunan.dto.LoginDTO;
import com.yunan.dto.RegisterDTO;
import com.yunan.entity.Mail;
import com.yunan.pojo.User;
import com.yunan.service.AuthService;
import com.yunan.service.EmailService;
import com.yunan.util.VerificationCodeUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.validation.Valid;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -52,9 +52,10 @@ public class AuthController {
*/
@PostMapping("/register")
@ApiOperation("用户注册")
public ResponseEntity<User> register(@RequestBody RegisterDTO registerDTO) {
// return authService.register(registerDTO);
return null;
public ResponseEntity<Object> register(@RequestBody @Valid RegisterDTO registerDTO) throws MessagingException, UnsupportedEncodingException {
//获取发送的验证码
String rightCode = emailCodeMap.get(registerDTO.getEmail());
return authService.register(registerDTO, rightCode);
}
// 存储已发送的验证码
@ -62,23 +63,24 @@ public class AuthController {
/**
* 发送验证码
* @param mail
* @param registerDTO
* @return {@link ApiResponse }<{@link String }>
* @throws MessagingException
*/
@PostMapping("/sendEmail")
@ApiOperation("邮箱验证码")
public ApiResponse<String> sendEmail(@RequestBody Mail mail) throws MessagingException {
public ApiResponse<String> sendEmail(@RequestBody @Valid RegisterDTO registerDTO) throws MessagingException {
// 生成验证码
String code = VerificationCodeUtils.generateCode(6);
// 发送邮件
String subject = "注册验证码";
String content = "尊敬的用户,您的验证码为:" + code;
emailService.sendMail(mail.email, subject, content);
emailService.sendMail(registerDTO.getEmail(), subject, content);
// 保存验证码
emailCodeMap.put(mail.email, code);
emailCodeMap.put(registerDTO.getEmail(), code);
return new ApiResponse<>(ResponseCode.SUCCESS,"验证码已发送");
}

View File

@ -1,12 +0,0 @@
package com.yunan.entity;
import lombok.Data;
@Data
public class Mail {
public String email;
public String username;
public String password;
}

View File

@ -0,0 +1,24 @@
package com.yunan.handler;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class GlobalExceptionHandler {
// 捕获所有的校验异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Object> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
for (FieldError error : ex.getBindingResult().getFieldErrors()) {
errors.put(error.getField(), error.getDefaultMessage());
}
return ResponseEntity.badRequest().body(errors);
}
}

View File

@ -7,7 +7,5 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface AuthMapper extends BaseMapper<User> {
void insertUser(RegisterDTO registerDTO);
User findUserByEmail(String email);
}

View File

@ -1,4 +1,4 @@
package com.yunan.dto;
package com.yunan.response;
public class ApiResponse<T> {

View File

@ -0,0 +1,48 @@
package com.yunan.response;
// ErrorResponse.java
public class ErrorResponse {
private String message; // 错误消息
private int code; // 错误代码 (可选)
private long timestamp; // 错误发生的时间戳 (可选)
// 构造方法
public ErrorResponse(String message) {
this.message = message;
this.timestamp = System.currentTimeMillis(); // 当前时间戳
this.code = 400; // 默认为 400 错误代码
}
// 构造方法带自定义错误码
public ErrorResponse(String message, int code) {
this.message = message;
this.code = code;
this.timestamp = System.currentTimeMillis();
}
// Getter Setter
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
}

View File

@ -1,17 +1,15 @@
package com.yunan.service;
import com.yunan.dto.ApiResponse;
import com.yunan.dto.RegisterDTO;
import com.yunan.entity.Mail;
import com.yunan.pojo.User;
import org.springframework.http.ResponseEntity;
import javax.mail.MessagingException;
import javax.mail.internet.AddressException;
import java.io.UnsupportedEncodingException;
public interface AuthService {
User register(RegisterDTO registerDTO) throws AddressException, UnsupportedEncodingException;
ResponseEntity<Object> register(RegisterDTO registerDTO, String rightCode) throws UnsupportedEncodingException, AddressException, MessagingException;
}

View File

@ -1,43 +1,14 @@
package com.yunan.service;
import com.yunan.dto.ApiResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
@Service
public class EmailService {
@Autowired
private JavaMailSender mailSender;
public interface EmailService {
@Value("${spring.mail.username}")
private String from;
/**
* 发送邮件
*
* @param to 收件人邮箱
* @param subject 邮件主题
* @param content 邮件内容
*/
public void sendMail(String to, String subject, String content) throws MessagingException {
// 创建邮件消息
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, true);
// 发送邮件
mailSender.send(message);
}
void sendMail(String email, String subject, String content) throws MessagingException;
}

View File

@ -1,27 +1,17 @@
package com.yunan.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yunan.constant.ResponseCode;
import com.yunan.dto.ApiResponse;
import com.yunan.dto.RegisterDTO;
import com.yunan.mapper.AuthMapper;
import com.yunan.pojo.User;
import com.yunan.response.ErrorResponse;
import com.yunan.service.AuthService;
import com.yunan.util.VerificationCodeUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;
import javax.annotation.Resource;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeUtility;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.TimeUnit;
@Service
@ -30,95 +20,39 @@ public class AuthServiceImpl implements AuthService {
private AuthMapper authMapper;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private JavaMailSender mailSender;
/**
* 发送邮箱验证码
*
* @param email
* @return {@link String }
*/
public String sendEmail(@PathVariable String email) throws UnsupportedEncodingException, AddressException {
String key = "msg_" + email;
ValueOperations valueOperations = stringRedisTemplate.opsForValue();
String already_have = (String) valueOperations.get(key);
if (already_have == null) {
// 随机生成一个6位数字型的字符串
String code = "123456";
// 邮件对象
SimpleMailMessage message = new SimpleMailMessage();
message.setSubject("医院小程序邮箱验证码");
message.setText("尊敬的用户您好!\n\n感谢您使用XX医院。\n\n尊敬的: " + email + "您的校验验证码为: " + code + ",有效期2分钟请不要把验证码信息泄露给其他人,如非本人请勿操作");
message.setTo(email);
// 对方看到的发送人
message.setFrom(new InternetAddress(MimeUtility.encodeText("医院官方") + "<2774668116@qq.com>").toString());
//发送邮件
mailSender.send(message);
valueOperations.set(key, code, 5L, TimeUnit.MINUTES);
return code;
} else {
return already_have;
}
}
/**
* 验证码验证是否正确
* @param email
* @param code
* @return {@link Integer }
*/
public Integer verifyCode(String email, String code) {
int result = 1;
ValueOperations valueOperations = stringRedisTemplate.opsForValue();
String msgKey = "msg_" + email;
Object value = valueOperations.get(msgKey);
if(value == null){
result = -1;
}else if(!code.equals(value)) {
result = 0;
}
// 如果验证码正确则删除从redis
if(result == 1){
stringRedisTemplate.delete(msgKey);
}
/*
1 验证码正确
0 验证码错误
-1 验证码过期
*/
return result;
}
@Override
public User register(RegisterDTO registerDTO) throws AddressException, UnsupportedEncodingException {
String code = sendEmail(registerDTO.getEmail());
Integer result = verifyCode(registerDTO.getEmail(), registerDTO.getCode());
public ResponseEntity<Object> register(RegisterDTO registerDTO, String rightCode) {
//处理registerDTO对数据为空的逻辑
// 验证验证码的正确性
if(registerDTO.getCode() == rightCode){
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
if(result == 1){
queryWrapper.eq(User::getUsername, registerDTO.getUsername());
Long l = authMapper.selectCount(queryWrapper);
if(l == 0){
// 插入用户到数据库
authMapper.insertUser(registerDTO);
// emailServiceImpl.sendEmail(registerDTO.getEmail(), "注册确认", "请点击以下链接进行确认...");
if(authMapper.selectOne(queryWrapper) != null) {
return ResponseEntity
.status(HttpStatus.CONFLICT)
.body(new ErrorResponse("用户名已存在!!!"));
}
User user = new User();
user.setUsername(registerDTO.getUsername());
user.setPassword(registerDTO.getPassword());
user.setEmai(registerDTO.getEmail());
boolean isSaved = authMapper.insert(user) > 0;
if (isSaved) {
return ResponseEntity
.status(HttpStatus.OK)
.body("注册成功!");
} else {
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("数据库存储失败,请稍后重试");
}
} else{
// 如果验证码为空或者与正确的验证码不匹配返回错误信息
return ResponseEntity
.status(HttpStatus.BAD_REQUEST) // 设置 HTTP 状态码为 400
.body(new ErrorResponse("验证码不正确或已过期")); // 返回自定义的错误消息
}
// 返回注册成功的用户对象可根据需求返回具体的 User 对象
// LambdaQueryWrapper<User> queryWrapperByEmail = new LambdaQueryWrapper<>();
// queryWrapperByEmail.eq(User::getEmai, registerDTO.getEmail());
return authMapper.findUserByEmail(registerDTO.getEmail()); // 假设有这个方法来查询用户
}else{
throw new RuntimeException("用户存在,请重新输入");
}
} else if (result == -1) { // 验证码过期
throw new RuntimeException("验证码已过期,请重新获取"); // 或者定义自定义异常
} else { // 验证码错误
throw new RuntimeException("验证码错误,请检查后重试"); // 或者定义自定义异常
}
}
}

View File

@ -1 +0,0 @@
spring.application.name=YuNan-demo