从零开始,SpringBoot+Redis+MySQL搭建个人博客(五)-----添加注册功能并依托Redis实现邮箱限时验证注册

目录

 

一、前言

二、添加前端界面

三、邮件发送工具

1.引入java.mail

2.邮箱开启POP3/SMTP/IMAP

3.设置相关参数

4.EmailUtil.java类

 5.测试

四、注册功能

五、总结


一、前言

在十三大神的博客界面的基础上,我又加上了GayHub上的一个My Login界面,很漂亮有兴趣的朋友可以自己去GayHub上搜索或者在本文末尾我的GitHub中查找。其实本来不打算添加这些登录注册功能的,毕竟也没啥人来看我的博客,但是又觉得既然做了,那就把所有的内容都做好才能行,所以趁今天加班把这个完成

二、添加前端界面

将下载好的代码放到自己创建好的文件夹,把css文件和一些图片放到对应的文件夹中,我习惯将html文件改为jsp文件

代码放完后要记住修改一些代码中的路径,否则会造成找不到css或者图标素材之类的问题

也有可能发生经过路径跳转后,相对路径错误的问题,所以我们这里统一改成绝对路径

现在以index.jsp为例

修改controller,测试界面

界面正常

三、邮件发送工具

1.引入java.mail

        <!-- javax.mail -->
        <dependency>
            <groupId>com.sun.mail</groupId>
            <artifactId>javax.mail</artifactId>
            <version>1.6.0</version>
        </dependency>

2.邮箱开启POP3/SMTP/IMAP

 

 开启SMTP功能会要求设置同行码,记录下来,下一步会用到

3.设置相关参数

新建config.properties,将相关参数写入

mail.smtp.auth=true
#mail.transport.protocol=smtp
mail.send.charset=UTF-8
mail.smtp.port=465
#mail.is.ssl=true
mail.host=smtp.163.com
[email protected]
#授权码
mail.auth.password=wy********
mail.smtp.timeout=5000

4.EmailUtil.java类

新建EmailUtil.java类,并导入邮箱参数

package cn.yzstu.common.utils.email;

import cn.yzstu.common.utils.Configration;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;

/**
 * \* Created with IntelliJ IDEA.
 * \* User: Baldwin
 * \* E_Mail: [email protected] || [email protected]
 * \* Date: 2019/12/16
 * \* Time: 16:22
 * \* To change this template use File | Settings | File Templates.
 * \* Description:
 * \
 */
public class EmailUtil {

    // 发件人的 邮箱 和 密码(替换为自己的邮箱和密码)
    // PS: 某些邮箱服务器为了增加邮箱本身密码的安全性,给 SMTP 客户端设置了独立密码(有的邮箱称为“授权码”),
    // 对于开启了独立密码的邮箱, 这里的邮箱密码必需使用这个独立密码(授权码)。
    public static String myEmailAccount = Configration.getInstance("config").getValue("mail.auth.name");

    public static String myEmailPassword = Configration.getInstance("config").getValue("mail.auth.password");

    // 发件人邮箱的 SMTP 服务器地址, 必须准确, 不同邮件服务器地址不同, 一般(只是一般, 绝非绝对)格式为: smtp.xxx.com
    // 网易163邮箱的 SMTP 服务器地址为: smtp.163.com
    public static String myEmailSMTPHost = Configration.getInstance("config").getValue("mail.host");
    //端口
    public static int myEmailSMTPPort = Integer.valueOf(Configration.getInstance("config").getValue("mail.smtp.port"));
    //chartset
    public static String myEmailCharset = Configration.getInstance("config").getValue("mail.send.charset");



    /**
     * spring方式发送
     *
     * @param content
     * @param addr
     */
    private void sendByAdds(String content, String title, String addr[]) {
        // 创建邮件发送服务器
        JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
        mailSender.setHost(myEmailSMTPHost);
        mailSender.setPort(myEmailSMTPPort);
        mailSender.setUsername(myEmailAccount);
        mailSender.setPassword(myEmailPassword);
        mailSender.setDefaultEncoding(myEmailCharset);
        // 加认证机制
        Properties javaMailProperties = new Properties();
        javaMailProperties.setProperty("mail.smtp.auth", "true");// 开启认证
        javaMailProperties.setProperty("mail.debug", "true");// 启用调试
        javaMailProperties.setProperty("mail.smtp.timeout", "1000");// 设置链接超时
        javaMailProperties.setProperty("mail.smtp.port", Integer.toString(myEmailSMTPPort));// 设置端口
        javaMailProperties.setProperty("mail.smtp.socketFactory.port", Integer.toString(myEmailSMTPPort));// 设置ssl端口
        javaMailProperties.setProperty("mail.smtp.socketFactory.fallback", "false");
        javaMailProperties.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");

        mailSender.setJavaMailProperties(javaMailProperties);
        // 创建邮件内容
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(myEmailAccount);

        for (int i = 0; i < addr.length; i++) {
            String email = addr[i];
            message.setTo(email);
            message.setSubject(title);
            message.setText(content);
            // 发送邮件
            mailSender.send(message);
        }

    }

    public static void sendEmail(String content, String title, String addr[]) {
        // 配置发送邮件的环境属性
        final Properties props = new Properties();
        // 表示SMTP发送邮件,需要进行身份验证
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.host", myEmailSMTPHost);
        // 如果使用ssl,则去掉使用25端口的配置,进行如下配置,
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        props.put("mail.smtp.socketFactory.port", "465");
        props.put("mail.smtp.port", "465");
        // 发件人的账号
        props.put("mail.user", myEmailAccount);
        // 访问SMTP服务时需要提供的密码
        props.put("mail.password", myEmailPassword);
        // 构建授权信息,用于进行SMTP进行身份验证
        Authenticator authenticator = new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                // 用户名、密码
                String userName = props.getProperty("mail.user");
                String password = props.getProperty("mail.password");
                return new PasswordAuthentication(userName, password);
            }
        };
        // 使用环境属性和授权信息,创建邮件会话
        Session mailSession = Session.getInstance(props, authenticator);
        // mailSession.setDebug(true);
        // 创建邮件消息
        MimeMessage message = new MimeMessage(mailSession);
        try {

            for (int j = 0; j < addr.length; j++) {
                // 设置发件人
                InternetAddress from = new InternetAddress(myEmailAccount);
                message.setFrom(from);
                // Address[] a = new Address[1];
                // a[0] = new InternetAddress("***");
                // message.setReplyTo(a);
                // 设置收件人
                InternetAddress to = new InternetAddress(addr[j]);
                message.setRecipient(MimeMessage.RecipientType.TO, to);
                // 设置邮件标题
                message.setSubject(title);
                // 设置邮件的内容体
                message.setContent(content, "text/html;charset=UTF-8");
                // 发送邮件
                Transport.send(message);
            }

        } catch (MessagingException e) {
            e.printStackTrace();
            // 在这里处理message内容, 格式是固定的
            System.out.println(e.getMessage());
        }
    }

    public static void main(String[] args) {
        String content = "用户密码:123455";

        EmailUtil emailUtil = new EmailUtil();
        emailUtil.sendEmail(content, "我是测试title", new String[]{"[email protected]"});
    }
}

 5.测试

这里在EmaiUtil.java中写一个main函数来测试,直接运行main函数

邮箱接收到邮件

四、注册功能

引用大佬的前端模板,做一下小小的修改,添加了几个需要填入的参数

点击Create One进入注册界面

输入完成后点击Register会请求/user/regist.action,这个请求地址是写在UserController.java里的,我们来看下相关的代码

    @RequestMapping(value = "/regist.action")
    public ModelAndView userRegist(HttpServletRequest request) {

        ModelAndView mv = new ModelAndView();

        String userEmail = request.getParameter("email");

        //6位随机验证码
        String emailVerifyCode = RandomUtil.getRandomString(6);
        //发送验证码
        try {
            EmailUtil.sendEmail(Constants.EMAIL_VERIFY_CONTANTS_PREFIX + emailVerifyCode + Constants.EMAIL_VERIFY_CONTANTS_SUFFIX, Constants.EMAIL_VERIFY_TITLE, userEmail);
        } catch (SendFailedException e) {//捕获错误的邮箱格式或其他原因导致的异常
            request.setAttribute("msg", "发送验证码失败,请检查邮箱格式或稍后重新发送!");
            mv.setViewName("forward:/login/register.jsp");
        }

        //String emailVerfyKey = userEmail ;
        //验证码存入redis,设置三分钟内过期,等待验证
        //打算把验证码设置成一天只能发一次,防止邮件攻击
        redisUtil.set(userEmail, emailVerifyCode, 180);

        //请求转发到验证界面
        mv.setViewName("forward:/login/verify.jsp");
        return mv;
    }

我们这里做了四件事:生成验证码、验证码发送、验证码存入Redis(key=email),转发请求到验证页面

 

虽然我能保证这个邮箱验证功能没啥问题,但是这个验证码不是我邮件收到的,而是我从Redis库里拿到的,原因是坑爹的网易云邮箱禁止了我这种穷逼程序员用他的STMP服务,第一次发送邮件的时候我收到了网站发来的邮件,但是第一次过后我就再也收不到了,这是这个原因导致我这篇文章晚了两天才发布,这两天一直在尝试找一个免费使用的STMP服务商,但大多数比较坑,现在准备自己搭建一个邮箱服务器

我们用的request请求转发,但是我们需要在verify.jsp让user自己输入验证码,输入验证码再请求服务器时,注册时的参数都丢失了,所以我们需要在verify.jsp中将参数隐性的放到request里,如下

<form method="POST" class="my-login-validation" novalidate="" action="/user/emailVerify.action">

                            <input type="hidden" id="nickName" name="nickName" value="<%=request.getParameter("nickName")%>">
                            <input type="hidden" id="password" name="password" value="<%=request.getParameter("password")%>">
                            <input type="hidden" id="name" name="name" value="<%=request.getParameter("name")%>">
                            <input type="hidden" id="email" name="email" value="<%=request.getParameter("email")%>">
                            <input type="hidden" id="phone" name="phone" value="<%=request.getParameter("phone")%>">
                            <input type="hidden" id="detail" name="detail" value="<%=request.getParameter("detail")%>">

                            <div class="form-group">
                                <label for="emailVerify">Email Verify Code</label>
                                <input id="emailVerify" type="text" class="form-control" name="emailVerify"
                                       required
                                       data-eye>
                                <div class="invalid-feedback">
                                    Password is required
                                </div>
                            </div>

                            <div class="form-group m-0">
                                <button type="submit" class="btn btn-primary btn-block">
                                    Register
                                </button>
                            </div>
                            <div class="mt-4 text-center">
                                Already have an account? <a href="<%=basePath%>login/index.jsp">Login</a>
                            </div>
                        </form>

在form标签中加入几个type为hidden的input标签,将上一个请求的参数写入request,然后请求/user/emailVerify.action,相关代码如下

/**
     * @param request
     * @return
     */
    @RequestMapping(value = "/emailVerify.action")
    public ModelAndView sendMail(HttpServletRequest request) {

        ModelAndView mv = new ModelAndView();

        Map<String, String[]> paramMap = RequestUtil.getRequestParamMap(request);

        String userMail = paramMap.containsKey("email") ? paramMap.get("email")[0] : "nothing";
        String verifyCode = (String) redisUtil.get(userMail);
        if (null == verifyCode) {//验证码不存在===》失效
            request.setAttribute("msg", "验证码失效,请重新发送!");
            mv.setViewName("forward:/login/register.jsp");
            return mv;
        }

        String userCode = paramMap.get("emailVerify")[0];
        if (!verifyCode.equalsIgnoreCase(userCode)) {
            request.setAttribute("msg", "验证码错误,请重新输入!");
            mv.setViewName("forward:/login/register.jsp");
            return mv;
        }

        User user = new User(paramMap);
        int target = userService.insert(user);

        mv.setViewName("forward:/login/index.jsp");

        return mv;
    }

在这个接口里,我们做了四件事:验证验证码是否失效、验证验证码、OK则写入数据库(注册已完成)、跳转到登录界面

有朋友或许注意到了,我将request的param封装在了一个map里,这样是为了容易进行一些判定操作,我也不知道这样是否合适,如果有懂这个的朋友,还请指点一下

五、总结

其实这个功能不算麻烦,设计思路也很近简单,但是拖了两天才发出来,就是因为STMP服务那个问题,一开始完全没有想到是服务商的问题,找了很久自己代码的毛病,但是第一次发送其实是成功的,所以困扰了很久,后来是在网上看到了一篇抱怨网易邮箱的文章才忽然想明白的。

总之,垃圾网易、毁我青春(滑稽脸)

æ们穷鬼æ¯è¿æ ·çå¦

上一篇:从零开始,SpringBoot+Redis+MySQL搭建个人博客(四)-----利用互联网工具一天内快速完成一套博客前端界面

下一篇:从零开始,SpringBoot+Redis+MySQL搭建个人博客(六)-----添加登录功能并实现访问网址即跳转主页

项目地址:https://github.com/DikeyWang/BaldwinBlog

发布了45 篇原创文章 · 获赞 113 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/shouchenchuan5253/article/details/103564346