• 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- 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- 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秒的等待时间

    (欲知后事如何,请听下回分解)

    或者用你们的赞和鼓励来加快我写文章的步伐叭

    参考:Spring Boot发送邮件详解 https://www.iteye.com/blog/xieke90-2428892

    转载请注明出处

  • 相关阅读:
    Shiro-身份验证
    ORA-12514: TNS: no listener 解决方案
    Oracle创建用户、角色、授权、建表
    ORA-28547:connection to server failed, probable Oracle Net admin error错误,解决方法
    Python学习笔记
    Python学习笔记
    Python学习笔记
    winrm service
    C#动态编译并执行代码
    TypeScript的4种编译方式
  • 原文地址:https://www.cnblogs.com/mmimo/p/13234969.html
Copyright © 2020-2023  润新知