使用Springboot异步发送模板邮件完成注册功能

目录

1、使用Springboot发送模板邮件并测试

1、添加依赖

2、配置application.properties

3、编写HTML邮件模板

4、编写发送邮件工具类

5、测试

2、在用户使用邮箱注册业务中----使用多线程异步发送账户激活邮件

1、配置线程池

2、在邮件工具类发送邮件的方法上添加@Async注解

3、实现邮箱注册功能

3.1 点击注册,将邮箱和密码发送给后端

3.2、后端处理请求,将结果封装到AjaxResult中返回

 4、实现邮箱激活功能

4.1、点击邮件里的激活链接,跳转到激活页面

4.2、后端激活用户接口,操作数据库修改state为1

3、邮箱注册激活完整流程

1、进入注册页面,点击注册

2、进入邮箱,查看邮件

3、点击邮件中的链接去完成用户激活

4、激活成功,跳转到登录界面:


1、使用Springboot发送模板邮件并测试

1、添加依赖

<!--mail-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!--thymeleaf-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

2、配置application.properties

需要获取邮箱授权码,这里我就不详细讲了

# 设置邮箱主机(服务商)
spring.mail.host=smtp.qq.com
# 设置用户名
spring.mail.username=xxx@qq.com
# 设置密码,该处的密码是QQ邮箱开启SMTP的授权码而非QQ密码
spring.mail.password=xxx
# 设置编码
spring.mail.default-encoding=UTF-8
#发件人

# 必须进行授权认证,它的目的就是阻止他人任意乱发邮件
spring.mail.properties.mail.smtp.auth=true

#SMTP加密方式:连接到一个TLS保护连接
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true

# JavaMailSender 配置
spring.mail.port=465
#SSL 配置
spring.mail.protocol=smtp
spring.mail.properties.mail.smtp.ssl.enable=true
spring.mail.properties.mail.smtp.socketFactory.port=465
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory

3、编写HTML邮件模板

        将该模板页面放在resources下的templates目录下:registerTemplate.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <title>激活邮件</title>
    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: Arial, Helvetica, sans-serif;
        }

        body {
            background-color: #ECECEC;
        }

        .container {
            width: 800px;
            margin: 50px auto;
        }

        .header {
            height: 80px;
            background-color: #49bcff;
            border-top-left-radius: 5px;
            border-top-right-radius: 5px;
            padding-left: 30px;
        }

        .header h2 {
            padding-top: 25px;
            color: white;
        }

        .content {
            background-color: #fff;
            padding-left: 30px;
            padding-bottom: 30px;
            border-bottom: 1px solid #ccc;
        }

        .content h2 {
            padding-top: 20px;
            padding-bottom: 20px;
        }

        .content p {
            padding-top: 10px;
        }

        .footer {
            background-color: #fff;
            border-bottom-left-radius: 5px;
            border-bottom-right-radius: 5px;
            padding: 35px;
        }

        .footer p {
            color: #747474;
            padding-top: 10px;
        }
    </style>
</head>

<body>
<div class="container">
    <div class="header">
        <h1>欢迎加入宠物之家!</h1>
    </div>
    <div class="content">
        <h2>亲爱的用户,您好!</h2>
        <p>您的邮箱:<b><span th:text="${email}"></span></b></p>
        <p>您的激活码:<b><span th:text="${code}"></span></b></p>
        <p>您注册时的日期:<b><span th:text="${createTime}"></span></b></p>
        <P><b>请在10分钟内完成激活:<a href="http://127.0.0.1:8083/activation.html">点我激活</a></b></P>
        <p></p>
        <p>当您在使用本网站时,务必要遵守法律法规</p>
        <p>如果您有什么疑问可以联系管理员,Email: <b>r1624603357@126.com</b></p>
    </div>
    <div class="footer">
        <p>此为系统邮件,请勿回复</p>
        <p>请保管好您的信息,避免被他人盗用</p>
        <p>©Rk</p>
    </div>
</div>
</body>
</html>

4、编写发送邮件工具类

package com.rk.pethome.basic.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import javax.mail.internet.MimeMessage;
import java.util.Map;

@Component
public class SendMailUtil {
    //发件人
    private String sender="1624603357@qq.com";
    @Autowired
     JavaMailSender javaMailSender;
    @Autowired
     TemplateEngine templateEngine;

    /**
     * 发送邮件
     * @param receiver 收件人
     * @param subject  邮件标题
     * @param emailTemplate HTML模板
     * @param dataMap  模板中的数据
     * @throws Exception
     */
    @Async//异步发送注解
    public void sendTemplateMail(String receiver, String subject, String emailTemplate, Map<String, Object> dataMap) throws Exception {
        //给模板引擎提供变量
        Context context = new Context();
        //设置传入模板页面的值   从dataMap中获取
        for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
            context.setVariable(entry.getKey(), entry.getValue());//例如:context.setVariable("code",123)
        }
        //emailTemplate是你要发送的模板,我这里用的是Thymeleaf  emailTemplate="registerTemplate"
        String templateContent = templateEngine.process(emailTemplate, context);

        //准备发送邮件
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        //设置发件人
        helper.setFrom(sender);
        //设置收件人
        helper.setTo(receiver);
        //设置标题
        helper.setSubject(subject);
        //设置内容
        helper.setText(templateContent, true);
        javaMailSender.send(message);
    }
}

5、测试

package com.rk.pethome.mail;
import com.rk.pethome.basic.util.SendMailUtil;
import com.rk.pethome.basic.util.StrUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.mail.internet.MimeMessage;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class MailSenderTest {

    @Autowired
    private SendMailUtil mailUtil;

    //收件人
    private final String receiver = "1624603357@qq.com";

    @Test
    public void testTemplateMail(){
        //发送邮件
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
        String subject = "宠物之家--用户注册";
        String emailTemplate = "registerTemplate";
        String code = StrUtils.getRandomString(5);
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("email", receiver);
        dataMap.put("code", code);
        dataMap.put("createTime", sdf.format(new Date()));
        try {
            mailUtil.sendTemplateMail(receiver, subject, emailTemplate, dataMap);
            System.out.println("发送完成");
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
    }

}

2、在用户使用邮箱注册业务中----使用多线程异步发送账户激活邮件

1、配置线程池

package com.rk.pethome.basic.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@Configuration
@EnableAsync  // 启用异步任务
public class AsyncConfiguration {
    // 声明一个线程池(并指定线程池的名字)
    @Bean("taskExecutor")
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程数5:线程池创建时候初始化的线程数
        executor.setCorePoolSize(5);
        //最大线程数5:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
        executor.setMaxPoolSize(5);
        //缓冲队列500:用来缓冲执行任务的队列
        executor.setQueueCapacity(500);
        //允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
        executor.setKeepAliveSeconds(60);
        //线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
        executor.setThreadNamePrefix("DailyAsync-");
        executor.initialize();
        return executor;
    }
}

2、在邮件工具类发送邮件的方法上添加@Async注解

3、实现邮箱注册功能

3.1 点击注册,将邮箱和密码发送给后端

             //通过邮箱注册用户
            emilReg(){
                //获取参数
                let para = Object.assign({}, this.user);
                //发送请求
                this.$http.post("/user/registerByEmial",para).then((res)=>{
                    console.debug(res);
                    console.debug(para);
                    let {success,msg}=res.data;
                    if(!success)//如果失败
                     {
                        this.errorMsg=msg;
                    }else{
                        //清空错误信息
                        this.errorMsg="";
                        //location.href="login.html";
                    }
                });
            },

3.2、后端处理请求,将结果封装到AjaxResult中返回

AjaxResult:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class AjaxResult {
    private Boolean success=true;
    private String msg;
    //返回到前端的结果值
    private Object result;

    public AjaxResult(Boolean success,String msg)
    {
        this.success=success;
        this.msg=msg;
    }

    public AjaxResult setResult(Object result){
        this.result=result;
        return this;
    }
}

Controller层:

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private IUserService userService;


    /**
     * 通过邮箱进行注册
     * @param userDot
     * @return
     */
    @PostMapping("/registerByEmial")
    public AjaxResult registerByEmial(@RequestBody UserDot userDot){
        try {
            System.out.println(userDot);
            return userService.registerEmail(userDot);
        } catch (Exception e) {
            e.printStackTrace();
            return new AjaxResult(false,"注册失败");
        }
    }
}

Service层:

        1、首先判断密码是否输入并且两次密码输入是否一致,在此之前已经进行异步的判断其是否已经注册,所以这里就不用判断邮箱。

        2、将注册的邮箱和密码保存到数据库中,邮箱同时也是用户名

        3、异步(多线程)的发送激活邮件,如果不是异步,发送邮件大概需要6s左右,极大降低用户的使用体验,点击注册后之间卡了6s---还以为是网络出现问题 

        注意:发送邮件的方法上也要使用  @Async注解   这样才能异步执行

        4、发送模板邮件的testTemplateMail方法中,会生成激活码,将该激活码存储在redis服务器上


@Service
public class IUserServiceImpl extends BaseServiceImpl<User> implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private SendMailUtil mailUtil;


    /**
     * 通过邮箱进行注册
     * @param userDot
     * @return
     */
    @Override
    public AjaxResult registerEmail(UserDot userDot){
        try {
            //判断密码是否输入
            if(StringUtils.isBlank(userDot.getPassword())||StringUtils.isBlank(userDot.getConfirmPassword()))
                return new AjaxResult(false,"请输入密码");
            //如果两次面不相等
            if(!userDot.getPassword().equals(userDot.getConfirmPassword()))
                return new AjaxResult(false,"两次密码不一致");

            //保存对象
            User user=new User();
            user.setUsername(userDot.getEmail());
            user.setEmail(userDot.getEmail());
            user.setCreatetime(new Date());
            user.setState(0);//手机验证通过后已激活

            //给用户密码进行盐值加密
            user.setPassword(MD5Utils.encrypByMd5(userDot.getPassword()));
            //保存用户
            userMapper.saveUser(user);
            //给刚注册好的用户发送邮件
            testTemplateMail(user.getEmail());
            return new AjaxResult(false,"邮件已发送至邮箱,请在10分钟内完成激活!");
        } catch (Exception e){
            e.printStackTrace();
            return new AjaxResult(false,"注册失败!");
        }
    }

    /**
     * 发送邮件
     * @param receiver 收件人
     */
    @Async
    public void testTemplateMail(String receiver){
        //发送邮件
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
        String subject = "宠物之家--用户注册";
        String emailTemplate = "registerTemplate";
        //获取激活码
        String code = StrUtils.getRandomString(5);
        //将激活码存入redis服务器
        //设置有效期10分钟  key值为:Action+邮箱 value值为:验证码
        RedisUtils.INSTANCE.set("Action:"+receiver,code,10*60);
        System.out.println("key:"+"Action:"+receiver+"   value:"+code);
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("email", receiver);
        dataMap.put("code", code);
        dataMap.put("createTime", sdf.format(new Date()));
        try {
            mailUtil.sendTemplateMail(receiver, subject, emailTemplate, dataMap);
            System.out.println("发送完成");
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
    }
}

Mapper层:

    /**
     * 保存用户
     * @param user
     */
    void saveUser(User user);

Mapper.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.rk.pethome.user.mapper.UserMapper">
    <!--保存用户-->
    <insert id="saveUser" parameterType="user">
        insert into t_user(username,email,phone, password, state, createtime)
        VALUES (#{username},#{email},#{phone},#{password},#{state},#{createtime})
    </insert>
</mapper>

        此时用户state属性为0,用户是未激活的状态 我们需要去邮箱点击激活按钮后完成激活操作才能登陆。

 4、实现邮箱激活功能

4.1、点击邮件里的激活链接,跳转到激活页面

     userActivation(){
                let para={"email":this.email,"code":this.code};
                this.$http.post("/user/userAction",para).then((res)=> {
                    let {success,msg}=res.data;
                    if(!success)//如果激活  //打印失败信息
                    {
                        this.errorMsg=msg;
                    }else{
                        //清空错误信息
                        this.errorMsg="";
                        //完成激活,跳转到登录页面
                        location.href="login.html";
                    }
                })
            },

4.2、后端激活用户接口,操作数据库修改state为1

Controller层:

 /**
     * 通过邮箱或者手机号登陆
     * @return
     */
    @PostMapping("/userAction")
    public AjaxResult activation(@RequestBody HashMap<String,String> para){
        try {
            System.out.println(para.get("code"));
            String email=para.get("email");
            String code = para.get("code");
            return userService.activation(email,code);
        } catch (Exception e) {
            e.printStackTrace();
            return new AjaxResult(false, e.getMessage());
        }
    }

Service层:

        1、判断输入的值是否为空

        2、接收传递过来的email,通过Action+email来过去该用户的激活码,code为用户输入的激活码。

        3、通过Action+email从redis服务器上能否获取值来判断:用户名是否输入正确或者激活码是否过期。如果不为空与用户输入的值进行对比。相等则说明激活码正确。

        4、通过email修改用户的state为1。表示该用户已激活,此时移除redis服务器上的激活码   

    /**
     * 用户激活
     *
     * @param email 邮箱
     * @param code  激活码
     * @return
     */
    @Override
    public AjaxResult activation(String email, String code) {
        //判断输入是否为空
        if(StringUtils.isBlank(email)||StringUtils.isBlank(code)){
            return new AjaxResult(false,"请输入邮箱和激活码!!");
        }
        //校验激活码是否正常
        //从redis服务器中获取code值,如果code值为空,说明激活码错误或者已过期!
        String s = RedisUtils.INSTANCE.get("Action:" + email);//redis服务器上获取的激活码
        System.out.println("redis服务器上获取的激活码为:"+s);
        if(s==null)
            return new AjaxResult(false,"邮箱错误或者激活码已过期!!");
        //激活码是否正确
        if(!code.equals(s))//不正确
        {
            return new AjaxResult(false,"激活码错误!!");
        }

        //激活后从redis服务器上移除
        RedisUtils.INSTANCE.del("Action:" + email);

        //修改用户状态为1    说明用户已经激活
        userMapper.updateState(email);

        return new AjaxResult();
    }

Mapper层:

    /**
     * 激活用户
     * @param email
     */
    void updateState(String email);

Mapper.xml:

    <!--修改用户为激活状态-->
    <update id="updateState">
        update t_user set state=1 where email=#{email}
    </update>

3、邮箱注册激活完整流程

1、进入注册页面,点击注册

2、进入邮箱,查看邮件

查看redis服务器上的key :

查看数据库中注册的用户:

3、点击邮件中的链接去完成用户激活

输入错误的激活码:

输入正确的激活码:

4、激活成功,跳转到登录界面:

 查看数据库中的用户

查看redis服务器上的激活码:

  • 2
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Rk..

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值