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

 

转载请注明出处

posted @ 2020-07-04 15:11  工程小白菜  阅读(7143)  评论(9编辑  收藏  举报