Java项目中发送邮箱验证码及有效时长(超详细)

    最近做一个社区项目,发现很多地方都需要校验是否为用户本人,然后做了个邮箱验证分享给大家,当然也可以采用手机验证码。思想和邮箱验证码是类似的,只需要稍作修改。废话不多说直接上代码。

1.导入邮箱依赖

     我这里是基于spring boot下的maven项目,导入pom依赖。用的是springboot2.2.2版本。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

2.有关application.yaml配置

    #邮件发送
spring:
   mail:
    username:XXXX@qq.com
    #邮箱授权码,百度一下很简单
    password: 授权码
    host: smtp.qq.com
    default-encoding: utf-8
    #开启加密验证
    properties:
      mail:
        smtp:
          ssl:
            enable: ture

3.创建一个工具类生成验证码

/**
 * @Description TODO:邮箱验证码,采用SecureRandom真随机数
 * @Author 郁郁201
 * @Date 2020-01-20 17:03
 * @Version 1.0
 */
public class VerCodeGenerateUtil {
//邮箱字符串提取,去除了容易混淆的几个字符比如0,o~
    private static final String SYMBOLS = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
    private static final Random RANDOM = new SecureRandom();
    /**
     * 生成4位随机验证码
     * @return 返回4位验证码
     */
    public static String getVerCode() {
        char[] nonceChars = new char[4];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }
}

4.发送邮件验证码

     创建ScheduledExecutorService线程池(该线程池,将计时和多线程结合一起,perfect),以便于多用户获取验证码放入session并计时。ReslutTypeDto为返回前端的数据类型,VisitorStatusEmun为枚举类型,存放多种结果操作,下面附有注释,可自行替换。

    //创建线程池对象
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
	//这个是我用户Service实现类可以自行替换
    @Autowired
    UserServiceImpl userServiceImpl;
    //这个是邮件类,必须要导入哦
    @Autowired
    JavaMailSenderImpl mailSender;

@GetMapping("/reg/sendEmail")
@ResponseBody
public ReslutTypeDto sendEmail(String email,HttpServletRequest request){
    HttpSession session = request.getSession();
    //验证码
    String verCode = VerCodeGenerateUtil.getVerCode();
    //发送时间 --这里自己写了一个时间类,格式转换,用于邮件发送
    String time = DateUtils.date2String(new Date(), "yyyy-MM-dd hh:mm:ss");
    Map<String,String> map = new HashMap<>();
    map.put("code",verCode);
    map.put("email",email);
    //验证码和邮箱,一起放入session中
    session.setAttribute("verCode",map);
    Map<String,String> codeMap = (Map<String,String>) session.getAttribute("verCode");
    //创建计时线程池,到时间自动移除验证码
    try {
        scheduledExecutorService.schedule(new Thread(()->{
            if(email.equals(codeMap.get("email"))){
                session.removeAttribute("verCode");
            }
        }), 5*60, TimeUnit.SECONDS);
    } catch (Exception e) {
        e.printStackTrace();
    }
    //一下为发送邮件部分
    MimeMessage mimeMessage = null;
    MimeMessageHelper helper = null;
    try {
        //发送复杂的邮件
        mimeMessage = mailSender.createMimeMessage();
        //组装
        helper= new MimeMessageHelper(mimeMessage, true);
        //邮件标题
        helper.setSubject("【Share社区】 注册账号验证码");
        //因为设置了邮件格式所以html标签有点多,后面的ture为支持识别html标签
        //想要不一样的邮件格式,百度搜索一个html编译器,自我定制。
        helper.setText("<h3>\n" +
                "\t<span style=\"font-size:16px;\">亲爱的用户:</span> \n" +
                "</h3>\n" +
                "<p>\n" +
                "\t<span style=\"font-size:14px;\">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style=\"font-size:14px;\">&nbsp; <span style=\"font-size:16px;\">&nbsp;&nbsp;您好!您正在进行邮箱验证,本次请求的验证码为:<span style=\"font-size:24px;color:#FFE500;\"> "+verCode+"</span>,本验证码5分钟内有效,请在5分钟内完成验证。(请勿泄露此验证码)如非本人操作,请忽略该邮件。(这是一封自动发送的邮件,请不要直接回复)</span></span>\n" +
                "</p>\n" +
                "<p style=\"text-align:right;\">\n" +
                "\t<span style=\"background-color:#FFFFFF;font-size:16px;color:#000000;\"><span style=\"color:#000000;font-size:16px;background-color:#FFFFFF;\"><span class=\"token string\" style=\"font-family:&quot;font-size:16px;color:#000000;line-height:normal !important;background-color:#FFFFFF;\">Share社区</span></span></span> \n" +
                "</p>\n" +
                "<p style=\"text-align:right;\">\n" +
                "\t<span style=\"background-color:#FFFFFF;font-size:14px;\"><span style=\"color:#FF9900;font-size:18px;\"><span class=\"token string\" style=\"font-family:&quot;font-size:16px;color:#000000;line-height:normal !important;\"><span style=\"font-size:16px;color:#000000;background-color:#FFFFFF;\">"+time+"</span><span style=\"font-size:18px;color:#000000;background-color:#FFFFFF;\"></span></span></span></span> \n" +
                "</p>",true);
        //收件人
        helper.setTo(email);
        //发送方
        helper.setFrom(我的邮箱);
        try {
        //发送邮件
            mailSender.send(mimeMessage);
        } catch (MailException e) {
        //邮箱是无效的,或者发送失败
                return new ReslutTypeDto(VisitorStatusEmun.Email_Invalid);
        }
    } catch (MessagingException e) {
        //发送失败--服务器繁忙
        return new ReslutTypeDto(VisitorStatusEmun.Server_Busy);
    }
    //发送验证码成功
    return new ReslutTypeDto(VisitorStatusEmun.Send_Email_Captcha_OK);
}

5.接收并使用邮件验证码

     最后一步注册时使用验证码,获取了前端三个参数,邮箱(username),密码,验证码(vercode)。

//这里我采用的是email作为username
 @PostMapping("/reg")
 @ResponseBody
    public ReslutTypeDto reg(String username,
                      String password,
                      String verCode,
                      HttpServletRequest httpServletRequest){
        HttpSession session = httpServletRequest.getSession();
        Map<String,String> codeMap = (Map<String,String>)session.getAttribute("verCode");
        String code = null;
        String email = null;
        try {
            code = codeMap.get("code");
            email = codeMap.get("email");
        } catch (Exception e) {
            //验证码过期,或未找到  ---验证码无效
            return new ReslutTypeDto(VisitorStatusEmun.Email_Captcha_Invalid);
        }
        //验证码判断
        if (!verCode.toUpperCase().equals(code) || !username.equals(email)) {
            return new ReslutTypeDto(VisitorStatusEmun.Email_Captcha_Fail);
        }
        //验证码使用完后session删除
        session.removeAttribute("verCode");
        User user = userServiceImpl.findUserByName(username);
        //用户名是否可用
        if (user!=null){
        //返回,该用户)(username)已被注册过
            return new ReslutTypeDto(VisitorStatusEmun.Account_Registered);
        }
        //数据库插入数据
        Integer integer = userServiceImpl.addUser(username, password);
        //是否插入数据成功
        if (integer==null||!integer.equals(1)){
        //返回注册失败
            return new ReslutTypeDto(VisitorStatusEmun.Register_Fail);
        }
       //返回注册成功
        return new ReslutTypeDto(VisitorStatusEmun.Register_OK);
    }

6.效果展示

在这里插入图片描述

7.思想总结

     验证码运用在项目中的还是挺简单的(需要全套源码评论区留邮箱哦),主要掌握核心思想,就是验证码的存放,移除。我这采用的session存放,当然大家也可已采用其他方式。以上就是发送邮箱验证码全过程了,如有纰漏还请多多指教~

发布了9 篇原创文章 · 获赞 5 · 访问量 1145

猜你喜欢

转载自blog.csdn.net/weixin_44200984/article/details/104056378