公众号merlinsea
发送邮件的过程
1、添加依赖,说明:添加完依赖以后记得刷新dependency,防止没有及时更新
!--发送邮件--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
2、在application.xml中配置邮件信息(和application同级)
说明:对应的邮件服务器如网易邮箱要开启POP3 / SMTP服务
mail: host: smtp.163.com #发送邮件服务器 username: merlinssea@163.com #发送邮件的邮箱地址 password: PIJCHLGOSQAPDVFN #客户端授权码,不是邮箱密码,网易的是自己设置的 from: merlinssea@163.com # 发送邮件的地址,和上面username一致 properties.mail.smtp.starttls.enable: true properties.mail.smtp.starttls.required: true properties.mail.smtp.ssl.enable: true default-encoding: utf-8
3、编写业务类MailServicceImpl
@Service @Slf4j public class MailServiceImpl implements MailService { /** * springboot 提供的一个发送邮件的简单抽象,直接注入即可 */ @Autowired private JavaMailSender mailSender; /** * 从application.yml中读取 merlinssea@163.com */ @Value("${spring.mail.from}") private String from; /** * 发送邮件 * @param to 收件人 * @param subject 主题 * @param content 内容 */ @Override public void sendMail(String to, String subject, String content) { //创建一个邮箱消息对象 SimpleMailMessage message = new SimpleMailMessage(); //配置邮箱发送人 message.setFrom(from); //邮件的收件人 message.setTo(to); //邮件的主题 message.setSubject(subject); //邮件的内容 message.setText(content); mailSender.send(message); log.info("邮件发送成功:{}",message.toString()); } }
4、编写NotifyServiceImpl类,只负责发送邮件验证码,如果上一次发送的验证码在60s内,那么就是重复发送,拒绝本次发送。方法:value拼接时间戳
@Service @Slf4j public class NotifyServiceImpl implements NotifyService { @Autowired private MailService mailService; @Autowired private RedisTemplate redisTemplate; /** * 验证码的标题 */ private static final String SUBJECT= "lianglin 验证码"; /** * 验证码的内容 */ private static final String CONTENT= "您的验证码是%s,有效时间是60秒"; /** * 如果用户重复发送验证码,那么先判别之前60s没是否发送过验证码,发送过则拒绝发送,否则发送 * 方法:在把验证码存入redis之前拼接时间戳 即:code_时间戳 * @param sendCodeEnum * @param to * @return */ @Override public JsonData sendCode(SendCodeEnum sendCodeEnum, String to) { String cacheKey = String.format(CacheKey.CHECK_CODE_KEY,sendCodeEnum.name(),to); String cacheValue = (String) redisTemplate.opsForValue().get(cacheKey); //如果不为空,则判断是否60秒内重复发送 if(StringUtils.isNotBlank(cacheValue)){ long ttl = Long.parseLong(cacheValue.split("_")[1]); //当前时间戳-验证码发送时间戳,如果小于60秒,则不给重复发送 if(CommonUtil.getCurrentTimestamp() - ttl < 1000*60){ log.info("重复发送验证码,时间间隔:{} 秒",(CommonUtil.getCurrentTimestamp()-ttl)/1000); return JsonData.buildResult(BizCodeEnum.CODE_LIMITED); } } String code = CommonUtil.getRandomCode(6); //通过对value拼接时间戳的f方法,可以避免在小范围时间内重复发送 String value = code+"_"+CommonUtil.getCurrentTimestamp(); if(CheckUtil.isEmail(to)){ /** * 这里的code是自己生成的,和之前的图形验证码无关,只有图形验证码通过了,才会调用这个验证码 */ //后续这个code验证码还得存redis中 mailService.sendMail(to,SUBJECT, String.format(CONTENT, value)); return JsonData.buildSuccess(); }else if(CheckUtil.isPhone(to)){ //手机号发送手机验证码 //TODO } return JsonData.buildResult(BizCodeEnum.CODE_TO_ERROR); } }
3、编写NotifyController对外api接口[通过第一步可以提高被薅羊毛的成本]
1、先匹配用户发来的图形验证码和redis中存的图形验证码是否一致
2、再调用发送邮件验证码服务
/** * 发送邮箱验证码 * 1、首先匹配图形验证码是否正常 * 2、再发送邮箱验证码 * * @param to 接收方邮箱 * @param captcha 接收方输入的图形验证码 * @param request * @return */ @ApiOperation("获取邮件注册验证码") @GetMapping("send_code") public JsonData sendRegisterCode(@RequestParam(value = "to", required = true) String to, @RequestParam(value = "captcha", required = true) String captcha, HttpServletRequest request) { String cacheKey = getCaptchaKey(request);//根据用户的request获取缓存key String cacheCaptcha = redisTemplate.opsForValue().get(cacheKey); if (captcha != null && cacheCaptcha != null && captcha.equalsIgnoreCase(cacheCaptcha)) { //图形验证码通过,发送邮件 redisTemplate.delete(cacheKey); JsonData jsonData = notifyService.sendCode(SendCodeEnum.USER_REGISTER, to); return jsonData; } else { //图形验证码没通过 return JsonData.buildResult(BizCodeEnum.CODE_CAPTCHA_ERROR); } }