工具类:实现生成验证码的功能,和实现生成随机数的功能
public class MailUtils {
// 发送邮件验证码
public static void sendTestMail(String email, String code) throws MessagingException {
// 1.创建Properties 类用于记录邮箱的一些属性
Properties pros = new Properties();
// 1.1 表示SMTP发送邮件,必须进行身份验证
pros.put("mail.smtp.auth", "true");
// 1.2 此处填写SMTP服务器
pros.put("mail.smtp.host", "smtp.qq.com");
// 1.3 端口号,QQ邮箱端口587
pros.put("mail.smtp.port", "587");
// 1.4 此处填写,写信人的账号
pros.put("mail.user", "写信人的QQ号(因为我们是自己操作,可以填写自己的)");
// 1.5 此处填写16位STMP口令 为QQ邮箱授权码
pros.put("mail.password", "QQ邮箱授权码(在QQ邮箱里面操作弄出来的)");
// 2.构建授权信息,用于进行SMTP进行身份验证 Authenticator(身份验证器)
Authenticator authenticator = new Authenticator() {
protected javax.mail.PasswordAuthentication getPasswordAuthentication() {
// 2.1 用户名
String userName = pros.getProperty("mail.user");
// 2.2 16位STMP口令
String password = pros.getProperty("mail.password");
return new javax.mail.PasswordAuthentication(userName, password);
}
};
// 3.使用环境属性和授权信息,创建邮件会话
Session mailSession = Session.getInstance(pros, authenticator);
// 4.创建邮件消息对象
MimeMessage message = new MimeMessage(mailSession);
// 4.1 设置发件人
InternetAddress from = new InternetAddress(pros.getProperty("mail.user"));
message.setFrom(from);
// 4.2 设置收件人
InternetAddress to = new InternetAddress(email);
message.setRecipient(Message.RecipientType.TO, to);
// 4.3 设置邮件标题
message.setSubject("【AT瑞吉外卖】邮箱登录验证码");
// 4.4 设置邮件的正文
message.setContent("尊敬的AT用户:您好!\r\n您的登录验证码为:" + code + "(有效期为一分钟,请勿告知他人)", "text/html;charset=UTF-8");
// 5.最后,发送邮件
Transport.send(message);
}
// 获取六位随机验证码
public static String getCode() {
// 由于数字 1 、 0 和字母 O 、l 有时分不清楚,所以,没有数字 1 、 0
String[] beforeShuffle = {"2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F",
"G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a",
"b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
"w", "x", "y", "z"};
// 将数组转换成集合
List<String> list = Arrays.asList(beforeShuffle);
// 打乱集合顺序,以达到随机的效果
Collections.shuffle(list);
// 创建StringBuilder,不是线程安全的,但是速度比StringBuffer更快
StringBuilder sb = new StringBuilder();
// 将集合转变成StringBuilder字符串
for (String s : list) {
sb.append(s);
}
// 返回sb字符串中第10~17位的5位验证码,这个区间其实随便设的
return sb.substring(10, 16);
}
}
UserController:
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
@Autowired
private UserService userService;
// 发送邮箱验证码
@PostMapping("/sendMsg")
public R<String> sendMsg(@RequestBody User user, HttpSession session) throws MessagingException {
if (userService.sendMsg(user, session)) {
return R.success("验证码发送成功");
}
return R.error("验证码发送失败");
}
// 移动端用户登录登录
@PostMapping("/login")
public R<User> login(@RequestBody Map<String, String> map, HttpSession session) {
User user = userService.login(map, session);
return R.success(user);
}
}
userService:
public interface UserService extends IService<User> {
// 发送邮箱验证码
Boolean sendMsg(User user, HttpSession session) throws MessagingException;
// 移动端用户登录
User login(Map<String, String> map, HttpSession session);
}
userServiceImpl:
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
// 发送邮箱验证码
@Override
public Boolean sendMsg(User user, HttpSession session) throws MessagingException {
// 1.获取前端传来的用户邮箱
String email = user.getEmail();
// 2.如果邮箱不为空才进行下一步操作
if (!email.isEmpty()) {
// 2.1 随机生成六位数验证码
String code = MailUtils.getCode();
// 2.2 发送验证码邮件
MailUtils.sendTestMail(email, code);
// 2.3 把获得的验证码存入session保存作用域,方便后面拿出来比对(code,就是上面生成的6位随机数验证码,这里的email仅仅是一个存在session域中的名字
session.setAttribute(email, code);
// 启动多线程来限定验证码的时效性
new Thread(() -> {
try {
// 验证码的有效时长
Thread.sleep(60000L);
// 更换新验证码
session.setAttribute(email, MailUtils.getCode());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
return true;
}
return false;
}
// 移动端用户登录登录
@Override
public User login(Map<String, String> map, HttpSession session) {
// 获取前端传送来的用户邮箱
String email = map.get("email");
// 获取前端传送来的验证码
String code = map.get("code");
// 验证邮箱和验证码是否为空,如果为空则直接登录失败
if (email.isEmpty() || code.isEmpty()) {
throw new CustomException("邮箱或验证码不能为空");
}
// 如果邮箱和验证码不为空,前往调用数据层查询数据库有无该用户
// 获取之前存在session保存作用域中的正确验证码
String trueCode = (String) session.getAttribute(email);
// 比对用户输入的验证码和真实验证码,错了直接登录失败
if (!code.equals(trueCode)) {
throw new CustomException("验证码错误");
}
// 验证码匹配,开始调用数据库查询
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
lqw.eq(User::getEmail, email);
User user = this.getOne(lqw);
// 如果数据库中没有该用户,就是新用户,要添加新用户
if (user == null) {
// 添加新用户
user = new User();
user.setEmail(email);
this.save(user);
}
// 最后把这个登录用户存到session保存作用域中,表示已登录,让拦截器放行
session.setAttribute("user", user.getId());
return user;
}
}