springboot注册功能中邮箱验证的实现
我们放假啦,前几天疯狂复习,现在又可以再次投入到代码中啦,这是我的第一篇博客园博客耶嘻嘻,希望大家喜欢!(本人也只是个大二的小白一枚,一同进步和成长叭)
废话不多说,我们要实现的功能是:注册时对用户输入的邮箱进行验证,包括 ①邮箱存不存在和 ②邮箱是否是用户的邮箱 两个验证
我们分为前端和后端来实现:
前期准备
1. pom.xml文件中引入相关的依赖(发送邮箱用的依赖):
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
2. 引入相关js和css文件:
① 邮箱验证要使用到的jquery.cookie.js:(作用后面会讲哈)
下载地址:http://plugins.jquery.com/cookie/
下载完后放到相应的文件夹里,譬如我是这样放的:
② me.css文件(不引入也可以哟,这只是让页面显示在中间,并不影响功能)
1 .m-container-small { 2 max-width: 60em !important; 3 margin: auto !important; 4 } 5 .m-padded-tb-massive { 6 padding-top: 5em !important; 7 padding-bottom: 5em !important; 8 }
基本的前端(继续完善的前端在下一篇,敬请期待)
1. html代码:(注意要修改一下js文件的相对路径,改成你自己的【第76行】)
(引入了css的小伙伴同时要改一下me.css的相对路径哈【第9行】)
1 <!DOCTYPE html> 2 <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width,initial-scale=1.0"> 6 <title>博客游客注册</title> 7 8 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css"> 9 <link rel="stylesheet" href="../../static/css/me.css"> 10 </head> 11 <body> 12 <br><br><br> 13 <div class="m-container-small m-padded-tb-massive" style="max-width: 30em !important;"> 14 <div class="ui container"> 15 <div class="ui middle aligned center aligned grid"> 16 17 <div class="column"> 18 <div class="ui negative message" th:unless="${#strings.isEmpty(message)}"> 19 <i class="close icon"></i> 20 <div class="header"> 21 校验失败 22 </div> 23 <p th:text="${message}"></p> 24 </div> 25 <h2 class="ui teal image header"> 26 <div class="content"> 27 游客注册 28 </div> 29 </h2> 30 <form class="ui large form" method="post" action="#" th:action="@{/tourist/register}"> 31 <div class="ui segment"> 32 <div class="field"> 33 <div class="ui left icon input"> 34 <i class="user icon"></i> 35 <input type="text" id="username" name="username" placeholder="用户名" 36 onchange="isUsernameUnique(this)"> 37 </div> 38 </div> 39 <div class="field"> 40 <div class="ui left icon input"> 41 <i class="lock icon"></i> 42 <input type="password" name="password" placeholder="密码"> 43 </div> 44 </div> 45 <div class="field"> 46 <div class="ui left icon input"> 47 <i class="mail icon"></i> 48 <input type="text" name="email" id="email" placeholder="邮箱"> 49 <input type="button" id="getcode" class="ui grey label" value="获取验证码"> 50 </div> 51 52 </div> 53 <div class="code field" style="display:none" > 54 <div class="ui left icon input"> 55 <i class="check square outline icon"></i> 56 <input type="text" name="identify" id="identify" placeholder="验证码"> 57 </div> 58 </div> 59 <button class="ui fluid large teal submit button" id="register-btn">注 册</button> 60 </div> 61 <div id="isRepeat"></div> 62 <div class="ui error mini message"></div> 63 64 </form> 65 66 67 </div> 68 69 </div> 70 71 </div> 72 </div> 73 74 75 <script src="https://code.jquery.com/jquery-3.1.1.min.js" crossorigin="anonymous"></script> 76 <script type="text/javascript" src="../../static/js/jquery.cookie.js" ></script> 77 <script src="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.js"></script> 78 </body> 79 </html>
2. 界面展示
现在我们已经拥有一个静态页面啦,接下来的工作是让它动起来
1. 在用户点击“获取验证码”的时候,判断邮箱位置是否为空,若为空,则不作任何操作
代码如下:
1 $('#getcode').click(function(){ 2 3 //判断邮箱位置是否为空 4 var email = $("#email").val(); 5 if(email==""){ 6 return; 7 } 8 9 });
2. 不为空的时候我们就要把用户的邮箱发给后端,让后端进行邮箱的存在性检查以及发送
这时候要用到的技术是ajax:
$.ajax({ //url路径 url: "http://localhost:8080/tourist/sendEmail", //data请求数据 data: {"email": email}, //dataType json type: "post", //回调函数 success: function (data) { //回调函数 data 返回流 if (data == "failure") { alert("发送失败"); } else if (data=="false"){ alert("目标邮箱不存在,请检查你的邮箱是否正确"); } // else{ // } } });
合并上面两个代码,结果如下:
$('#getcode').click(function(){ //发送验证码 var email = $("#email").val(); if(email==""){ return; } alert("验证码已发送,请及时查看你的邮箱"); $(".code").toggle(); //ajax实现后台邮箱的发送 $.ajax({ //url路径 url: "http://localhost:8080/tourist/sendEmail", //data请求数据 data: {"email": email}, //dataType json type: "post", //回调函数 success: function (data) { //回调函数 data 返回流 if (data == "failure") { alert("发送失败"); } else if (data=="false"){ alert("目标邮箱不存在,请检查你的邮箱是否正确"); } // else{ // } } }); });
最基本的前端已经完成啦,我们现在来看后端:
后端的实现
1. controller的命名与位置:
①名字你可以随便起,我起的是RegisterController
②位置我是新建了一个web文件夹,然后在web文件夹下新建了一个子文件夹tourist,在这个文件夹中放着我的控制器
(由于这是我博客系统的一部分功能,所以里面有很多很多代码,我码掉了,如果大家喜欢我的文章,我就会继续分享一些实用的有关博客的功能唷)
2. html代码:
(我命名为register.html,并且放在了templates文件里的子文件tourist下
)
//import com.lrm.util.MD5Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.mail.MailSendException; import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import javax.servlet.http.HttpSession; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.HashMap; import java.util.Map; import java.util.Random; @Controller @RequestMapping("/tourist") public class RegisterController { @Autowired private UserService userService; private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Value("${mail.fromMail.sender}") private String sender;// 发送者 @Autowired private JavaMailSender javaMailSender; private Map<String, Object> resultMap = new HashMap<>(); @GetMapping("/register") public String register() { return "tourist/register"; } @RequestMapping("/sendEmail") //转换json数据 @ResponseBody @ResponseBody public String sendEmail(String email) { SimpleMailMessage message = new SimpleMailMessage(); String code = VerifyCode(6); //随机数生成6位验证码 message.setFrom(sender); message.setTo(email); message.setSubject("博客系统");// 标题 message.setText("【博客系统】你的验证码为:"+code+",有效时间为5分钟(若不是本人操作,可忽略该条邮件)");// 内容 try { javaMailSender.send(message); logger.info("文本邮件发送成功!"); saveCode(code); return "success"; }catch (MailSendException e){ logger.error("目标邮箱不存在"); return "false"; } catch (Exception e) { logger.error("文本邮件发送异常!", e); return "failure"; } } private String VerifyCode(int n){ Random r = new Random(); StringBuffer sb =new StringBuffer(); for(int i = 0;i < n;i ++){ int ran1 = r.nextInt(10); sb.append(String.valueOf(ran1)); } // System.out.println(sb); return sb.toString(); } //保存验证码和时间 private void saveCode(String code){ SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss"); Calendar c = Calendar.getInstance(); c.add(Calendar.MINUTE, 5); String currentTime = sf.format(c.getTime());// 生成5分钟后时间,用户校验是否过期 String hash = MD5Utils.code(code);//生成MD5值 resultMap.put("hash", hash); resultMap.put("tamp", currentTime); } }
思路:先随机生成一串验证码,然后通过邮箱发送给用户输入的邮箱号,通过捕获异常来判断用户输入的邮箱是否存在
用到的小技术:里面用到了MD5加密,即生成验证码时,将验证码和发送时间通过加密技术进行加密,然后保存到Map对象中(用于后面与用户输入的验证码及时间相比对,来判断用户验证码输入是否正确,以及验证码是否过期)
所以这里我们还需要引入一下MD5加密工具(或者你可以使用springboot自带的加密功能,具体的可自行查阅)
MD5Utils的代码如下:
import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5Utils { /** * MD5加密类 * * @param str 要加密的字符串 * @return 加密后的字符串 */ public static String code(String str) { try { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(str.getBytes()); byte[] byteDigest = md.digest(); int i; StringBuffer buf = new StringBuffer(""); for (int offset = 0; offset < byteDigest.length; offset++) { i = byteDigest[offset]; if (i < 0) i += 256; if (i < 16) buf.append("0"); buf.append(Integer.toHexString(i)); } //32位加密 return buf.toString(); // 16位的加密 //return buf.toString().substring(8, 24); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return null; } } public static void main(String[] args) { System.out.println(code("123")); } }
(这个引入之后就可以在上面的controller报错的地方引入相应的包啦(*^▽^*)【报错的地方就是因为这个包没引入】)
这样发送验证码的前后端我们基本都写好啦,是不是跃跃欲试呢,哈哈
放心,你马上就可以开始运行了,我们还差最后一个工作,就是配置我们的application.properties
##根据自己的情况填写 ##邮箱服务器地址 ##QQ smtp.qq.com ##sina smtp.sina.cn ##aliyun smtp.aliyun.com ##163 smtp.163.com spring.mail.host=smtp.qq.com ##邮箱用户名 spring.mail.username=362517658@qq.com ##邮箱密码(注意:QQ邮箱应该使用授权码) spring.mail.password=******** ##编码格式 spring.mail.default-encoding=UTF-8 ##发送邮件地址 mail.fromMail.sender=362517658@qq.com ##接收邮件地址 mail.fromMail.receiver=362517658@qq.com
注意!!里面的邮箱密码,不是你的qq密码,而是邮箱里的授权码,不明白的可看下获取授权码步骤:
① 点击设置
② 选择“账户”
③ 下拉到图中所示位置,选择前两个任意一个打开就行(我这里已经打开,没有打开的小伙伴上面会有“打开”按钮的选择),根据它的指引最后可以获得一串16位的授权码,这个授权码就是我们要的
哒啦啦啦,回到正题:现在让我们来测试一下吧!
①点击“获取验证码”,跳出验证码框
② 输入一个不存在的邮箱号
(这里的“59秒后可重新获取”是我们后面要实现的功能,大家这里显示的还是“获取验证码”哈)
③ 填写正确的邮箱地址
成功收到邮箱啦嘻嘻
发送邮箱验证码我们已经成功实现,现在我们要验证一下用户输入的验证码是否和我们发送的一样(你就快要完成啦,坚持就是胜利!!!!)
这里是点击“注册”时,我们进行邮箱验证码的判断
前端我们是已经加过表单的跳转位置了,
所以我们现在就来做相应的后端:
直接上后端代码:(加在controller(我们的后端代码)里)
@PostMapping("/register") public String login(@RequestParam String username, @RequestParam String password, @RequestParam String email, @RequestParam String identify,RedirectAttributes attributes, User user) { if (resultMap.size() ==0){ return "tourist/register"; } //判断验证码是否正确 String requestHash = resultMap.get("hash").toString(); String tamp = resultMap.get("tamp").toString(); SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");//当前时间 Calendar c = Calendar.getInstance(); String currentTime = sf.format(c.getTime()); if (tamp.compareTo(currentTime) > 0) { String hash = MD5Utils.code(identify);//生成MD5值 if (hash.equalsIgnoreCase(requestHash)){ //校验成功 attributes.addFlashAttribute("m", "恭喜!现在,你可以登录你的用户名。"); return "redirect:/tourist"; }else { //验证码不正确,校验失败 System.out.println("2"); attributes.addFlashAttribute("message", "验证码输入不正确"); return "redirect:/tourist/register"; } } else { // 超时 System.out.println("3"); attributes.addFlashAttribute("message", "验证码已过期"); return "redirect:/tourist/register"; } }
思路:判断此时时间与上次存的验证码的生成时间之差是否大于五分钟,若大于,则提示超时;若没有大于,再将用户输入的验证码进行加密,接着判断用户输入的验证码与最先保存的验证码是否一致(这里也可以通过验证码的解密,然后将解密后的验证码和用户输入的直接比对)
为了更方便地看出结果,我们再加个login界面,位置和register.html一样
html代码:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"> <head > <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <title>博客用户登录</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css"> </head> <body> <br><br><br> <div class="m-container-small m-padded-tb-massive" style="max-width: 30em !important;"> <div class="ui success message" th:unless="${#strings.isEmpty(m)}"> <i class="close icon"></i> <div class="header"> 你注册成功! </div> <p th:text="${m}">现在,你可以登录你的用户名。</p> </div> <div class="ui container"> <div class="ui middle aligned center aligned grid"> <div class="column"> <h2 class="ui teal image header"> <div class="content"> 用户登录 </div> </h2> </div> </div> </div> </div> <script src="https://code.jquery.com/jquery-3.1.1.min.js" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.js"></script> //消息提示关闭初始化 $('.message .close') .on('click', function () { $(this) .closest('.message') .transition('fade'); }); </script> </body> </html>
现在又到了激动人心的测试环节,大家开始躁起来吧!
(具体演示忽略)
完善功能:用户60秒才能重新发送邮箱,这样可以避免某些坏心眼的孩子一直不断地发送邮箱(哈哈虽然目的不只是这个),当然每次测试的时候我们也多了个60秒的等待时间
(欲知后事如何,请听下回分解)
☞ 下篇文章:springboot中邮箱验证按钮实现60秒后可重新获取(防止刷新)以及防重复发送
或者用你们的赞和鼓励来加快我写文章的步伐叭
参考:Spring Boot发送邮件详解 https://www.iteye.com/blog/xieke90-2428892
转载请注明出处