目录
- 开通qq邮箱的stmp
- 实战
- pom.xml
- application.yml
- controller
- service
- 实体类
- 辅助类
 
需要实现一个通过邮箱找回密码的功能
- 正常来说,找回密码的验证码,一般来说,都是通过手机号来找回的居多,那为什么会有通过邮箱找回的方式
- 该说不说,免费的舒服

- 业务的大致流程
开通qq邮箱的stmp

- 点击设置
  
- 点击账号
  
- 正常这里是开启服务,因为我已经开启过,所以显示管理服务
- 会需要手机号发生一段话给某个指定的手机号来做验证,存在发不通的情况(建议换一个号码,指定的手机号,有两个,都试一下)
- 到这一步,会生成一个密码。你可以理解为邮箱的密码
实战
pom.xml
  <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-core</artifactId>
            <version>5.6.5</version>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.1.1</version>
        </dependency>
         <!--邮件-->
        <dependency>
            <groupId>com.sun.mail</groupId>
            <artifactId>javax.mail</artifactId>
            <version>1.6.2</version>
        </dependency>
- javax.mail对应的依赖需要额外导入
application.yml
#邮件配置
email:
  #邮箱账户
  emailAccount:  123@qq.com
  #邮箱密码
  emailPassword: 123
  #发件人名称
  senderName: 发送人名称
  ##发件服务器 stmp的服务协议的服务器
  sendServer: smtp.qq.com
  #发件服务器是否遵循安全协议(0,不是 1是,默认0)
  sendServerIsSSL: 1
  ##发件服务器端口(一般是若sendServerIsSSL = 1,端口则是25,若不是,则为465)
  sendPort: 465
- 只放了关键代码,修改邮箱账号以及邮箱密码(上面开通qq邮箱时,返回的密码)改为自己的
- 注意: 这是qq邮箱的设置版本,如果是163邮箱版本,个别配置需要微调
controller
package com.zyee.iopace.web.controller;
@Api(tags = "用户管理")
@RestController
@RequestMapping("/user")
public class UserController {
  
    @Autowired
    private UserService userService;
    @ApiOperation(value = "通过邮箱发送验证码")
    @GetMapping("/sendEmailCode")
    public ResponseResult sendEmailCode(@RequestParam String email){
        return userService.sendEmailCode(email);
    }
    @ApiOperation(value = "验证邮箱的验证码以及重置密码")
    @PostMapping("/checkEmailCode")
    public ResponseResult checkEmailCode(@RequestBody CheckEmailVo checkEmailVo){
        return userService.checkEmailCode(checkEmailVo);
    }
}
service
    /**
     * 发送邮件code
     */
    public static  final String EMAIL_CODE = "email:code:";
    /**
     * 发送邮件次数
     */
    public static  final String EMAIL_COUNT = "email:count:";
    /**
     * 验证邮箱验证码错误次数
     */
    public static  final String EMAIL_CHECK_COUNT = "email:check:count:";
  @Value("${email.emailAccount}")
    private String emailAccount;
    @Value("${email.emailPassword}")
    private String emailPassword;
    @Value("${email.senderName}")
    private String senderName;
    @Value("${email.sendServer}")
    private String sendServer;
    @Value("${email.sendServerIsSSL}")
    private Integer sendServerIsSSL;
    @Value("${email.sendPort}")
    private Integer sendPort;
 @Override
    public ResponseResult sendEmailCode(String email) {
        if(StringUtils.isEmpty(email)){
            return ResponseResult.FAILURE("邮箱不能为空!");
        }
        User user = getOne(new LambdaQueryWrapper<User>().eq(User::getEmail, email));
        if(Objects.isNull(user)){
            return ResponseResult.FAILURE("请输入正确的邮箱!");
        }
        String key = RedisConstant.EMAIL_COUNT+user.getId();
        if(checkSendLimit(key,5)){
            return ResponseResult.FAILURE("一个小时以内只能发送5次!");
        }
        //产生6位数的随机码
        Random random = new Random();
        int code = random.nextInt(900000) + 10000;
        //发送验证码
        Boolean flag = sendEmailUtil.sendEmailMsg(emailAccount, emailPassword, senderName, sendServer, sendServerIsSSL, sendPort, email,code);
        if(flag){
            String codeKey = RedisConstant.EMAIL_CODE+user.getId();
            //验证码的有效时长为5分钟
            redisUtils.set(codeKey,code,5 * 60);
            // 增加发送次数
            incrementSendCount(key,3600L);
        }else{
            return ResponseResult.FAILURE("发送邮箱验证码失败,请检查邮箱是否合理!");
        }
        return ResponseResult.SUCCESS();
    }
    @Override
    public ResponseResult checkEmailCode(CheckEmailVo checkEmailVo) {
        if(Objects.isNull(checkEmailVo.getCode()) ||
                StringUtils.isEmpty(checkEmailVo.getEmail()) ||
                StringUtils.isEmpty(checkEmailVo.getPwd())){
           return ResponseResult.FAILURE("参数不能为空!");
        }
        //先验证验证码是否正确
        User user = getOne(new LambdaQueryWrapper<User>().eq(User::getEmail, checkEmailVo.getEmail()));
        if(Objects.isNull(user)){
            return ResponseResult.FAILURE("请输入正确的邮箱!");
        }
        //错误次数key
        String checkKey = RedisConstant.EMAIL_CHECK_COUNT+user.getId();
        if(checkSendLimit(checkKey,3)){
            return ResponseResult.FAILURE("5分钟之内错误3次!");
        }
        String codekey = RedisConstant.EMAIL_CODE+user.getId();
        Integer code = redisUtils.getInteger(codekey);
        if(Objects.isNull(code)){
            return ResponseResult.FAILURE("验证码已失效!");
        }else{
            if(code.intValue() != checkEmailVo.getCode().intValue()){
                //错误增加次数
                incrementSendCount(checkKey,5 * 60L);
                return ResponseResult.FAILURE("验证码错误,请重新输入!");
            }
            //验证码正常修改密码
            User updateUser = new User();
            updateUser.setId(user.getId());
            updateUser.setPassword(checkEmailVo.getPwd());
            updateById(updateUser);
        }
        return ResponseResult.SUCCESS();
    }
    /**
     * 验证次数
     * @param key
     * @return
     */
    public boolean checkSendLimit(String key,Integer maxSendCount) {
        Integer sendCount = 0;
        // 最大发送次数限制
        // 获取当前发送次数
        sendCount = redisUtils.getInteger(key);
        if(Objects.isNull(sendCount)){
            sendCount = 0;
        }
        // 超过发送次数限制返回 true,否则返回 false
        return sendCount >= maxSendCount;
    }
    /**
     * 增加验证码发送次数
     * @param key
     * @param expire 过期秒数
     */
    public void incrementSendCount(String key,Long expire) {
        // 获取当前发送次数
        Object countObj = redisUtils.get(key);
        int sendCount = (countObj != null) ? (Integer) countObj : 0;
        // 增加发送次数
        sendCount++;
        if(sendCount != 1){
            expire = redisUtils.getExpire(key);
        }
        // 存储一小时内的发送次数
        redisUtils.set(key, sendCount, expire);
    }
- 三个变量是redis的变量
- 主要是用来控制,发送邮箱验证码时,一个用户1个小时以内只能发送5次
- 输入验证码进行修改密码时,5分钟只能只能错3次,防止有人暴力破解
实体类
package com.zyee.iopace.web.vo.email;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EmailInfoVo {
    /**
     * 邮箱账户
     */
    private String emailAccount;
    /**
     * 邮箱密码
     */
    private String emailPassword;
    /**
     * 发件人名称
     */
    private String senderName;
    /**
     * 发件服务器
     */
    private String sendServer;
    /**
     * 发件服务器是否遵循安全协议(0,不是 1是,默认0)
     */
    private Integer sendServerIsSSL = 0;
    /**
     * 发件服务器端口(一般是若sendServerIsSSL = 1,端口则是25,若不是,则为465)
     */
    private Integer sendPort;
}
辅助类
package com.zyee.iopace.web.utils;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.mail.MailAccount;
import cn.hutool.extra.mail.MailUtil;
import com.zyee.iopace.web.vo.email.EmailInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class SendEmailUtil {
    public static void main(String[] args) {
        String emailAccount = "123@qq.com";
        String emailPassword = "123";
        String senderName = "465";
        String sendServer = "smtp.qq.com";
        Integer sendServerIsSSL = 1;
        Integer sendPort = 465;
        String toAccount = "123@qq.com";
        //产生6位数的随机码
        Random random = new Random();
        int code = random.nextInt(900000) + 10000;
        SendEmailUtil sendEmailUtil = new SendEmailUtil();
        sendEmailUtil.sendEmailMsg(emailAccount, emailPassword, senderName, sendServer,sendServerIsSSL ,sendPort,toAccount,code);
    }
    /**
     * 发送邮箱消息
     * @param emailAccount
     * @param emailPassword
     * @param senderName
     * @param sendServer
     * @param sendServerIsSSL
     * @param sendPort
     * @param code
     */
    public  Boolean sendEmailMsg(String emailAccount,
                                     String emailPassword,
                                     String senderName,
                                     String sendServer,
                                     Integer sendServerIsSSL,
                                     Integer sendPort,
                                     String toAcccount,
                                 Integer code) {
        Boolean flag = false;
        try {
            EmailInfoVo info = new EmailInfoVo();
            info.setEmailAccount(emailAccount);
            info.setEmailPassword(emailPassword);
            info.setSendPort(sendPort);
            //遵循stmp的服务协议的服务器,可以百度,很多的
            info.setSendServer(sendServer);
            info.setSenderName(senderName);
            info.setSendServerIsSSL(sendServerIsSSL);
            MailAccount account = getMailAccount(info);
            String send = MailUtil.send(account, toAcccount, "【大气气候与环境观测网站】您的注册码", "您的验证码是:" + code + ",五分钟有效,请及时完成注册。若不是本人操作请忽略", false);
            log.info("发送验证码 msg={} 验证码={}",toAcccount,code);
            flag = true;
        }catch (Exception e){
            log.info("发送验证码 出现异常msg={}",e.getMessage());
        }
        return flag;
    }
    /**
     * 获取邮箱参数对象
     *
     * @param emailInfo
     * @return
     */
    private static MailAccount getMailAccount(EmailInfoVo emailInfo) {
        MailAccount account = new MailAccount();
        if (ObjectUtil.isNotEmpty(emailInfo.getSenderName())) {
            StringBuilder sb = new StringBuilder();
            sb.append(emailInfo.getSenderName())
                    .append('<')
                    .append(emailInfo.getEmailAccount())
                    .append('>');
            account.setFrom(sb.toString());
        } else {
            account.setFrom(emailInfo.getEmailAccount());
            account.setUser(emailInfo.getEmailAccount());
        }
        account.setPass(emailInfo.getEmailPassword());
        account.setHost(emailInfo.getSendServer());
        account.setPort(emailInfo.getSendPort());
        account.setAuth(true);
        account.setSocketFactoryClass("javax.net.ssl.SSLSocketFactory");
        account.setSocketFactoryFallback(true);
        account.setSocketFactoryPort(emailInfo.getSendPort());
        if (emailInfo.getSendServerIsSSL() == 0) {
            account.setSslEnable(false);
        } else {
            account.setSslEnable(true);
        }
        account.setTimeout(3000);
        return account;
    }
}
- 直接运行main方法,调整成你的邮箱和密码
- toAccount就是你要发送到那个邮箱
  
 -这是成功的效果
在网上找了几个别人做的前台效果图,大家可以参考一下
 
 
 
 



















