博客邮件提醒功能的实现

作者:ChenZhen

博客地址:https://www.chenzhen.space/

版权:本文为博主 ChenZhen 的原创文章,本文版权归作者所有,转载请附上原文出处链接及本声明。

如果对你有帮助,请给一个小小的star⭐


邮件提醒功能:当你收到某个人的回复时,会给你发送一封提醒邮件,并展示回复的内容。
在这里插入图片描述

我觉得对于一个博客,邮件回复的功能是必不可少的,能让你及时的回复别人的评论,还能让我更方便的和网上的人对线

其实这个功能还是蛮好实现的,我们先演示怎么用java发送一封简单的邮件

1.开启POP3/SMTP服务

以QQ邮箱为例:

进入设置
在这里插入图片描述

在下方开启POP3/SMTP服务,此处已开启
在这里插入图片描述

经过身份认证过后,会获得一串授权码,请务必保存下来

在这里插入图片描述

2.引入spring-boot-starter-mail 依赖

由于Spring推出了关于Mail的JavaMailSender类,基于该类Spring Boot又对其进行了进一步封装,从而实现了轻松发送邮件的集成。而且JavaMailSender类提供了强大的邮件发送能力,支持各种类型的邮件发送。

<!--        邮件发送功能 启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>

3.yaml文件配置

spring:
  mail:
    host: smtp.qq.com  # 配置 smtp 服务器地址
    port: 25  # smtp 服务器端口
    username: xxxxx #配置你的邮箱地址
    password: xxxxx #配置申请到的授权码
    protocol: smtp #协议
    thymeleaf-html: mail  #设置要解析发送的html模板

4.测试发送普通邮件

配置完后,我们来测试发送一封普通的邮件

  • 在这里有两个关键的对象,JavaMailSender负责发送邮件,SimpleMailMessage负责构建邮件内容对象,我们使用这两个对象来发送邮件。

由于Spring Boot的starter模块提供了自动化配置,在引入了spring-boot-starter-mail依赖之后,会根据配置文件中的内容去创建JavaMailSender实例并交给spring管理,因此我们可以直接在需要使用的地方直接@Autowired来引入 JavaMailSender 邮件发送对象

注意:使用@Autowired注解的类必须交由spring管理,即加上@Component注解

在这里插入图片描述

使用SimpleMailMessage对象来构建一封邮件

@Test
        public void test5(){
    
    
            //构建邮件内容对象
            SimpleMailMessage msg = new SimpleMailMessage();
            //邮件发送者
            msg.setFrom("[email protected]");
            //邮件接收者
            msg.setTo("[email protected]");
            //邮件主题
            msg.setSubject("测试邮件主题");
            //邮件正文
            msg.setText("测试邮件内容");
            //邮件发送时间
            msg.setSentDate(new Date());
            //邮件发送
            javaMailSender.send(msg);

        }

运行测试方法,需要等待一会便能收到

在这里插入图片描述

在这里插入图片描述

5.发送静态邮件模板

上面演示了如何发送普通邮件,接下来我们要实现发送一封静态邮件模板,就像开头的实例一样

这里我们使用Thymeleaf作为模板

引入Thymeleaf启动器

<!--Thymeleaf 静态模板jar包-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

自定义静态模板

这里可以自己自定义好看的邮件模板,这里我就简单的测试一下

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"><head>
    <meta charset="UTF-8">
    <title>Thymeleaf邮件模板</title>
</head>
<body>
<p>这是一封Thymeleaf邮件模板</p>
<table border="1">
    <tr>
        <td>姓名</td>
        <td th:text="${name}"></td>
    </tr>
    <tr>
        <td>年龄</td>
        <td th:text="${age}"></td>
    </tr>

</table>
<div style="color: red;">这是一封Thymeleaf邮件模板</div>
</body>
</html>

将该html文件放到templates目录下,这是springboot放置模板文件的默认路径

在这里插入图片描述

运行测试方法

  • 这里使用MimeMessageHelper来构建邮件,利用Context对象可以设置模板里面的Thymeleaf表达式的值
  • 调用springTemplateEngine的process方法来解析模板,第一个参数为模板文件的名字
 @Test
        public void test4() throws MessagingException {
    
    
            MimeMessage msg = javaMailSender.createMimeMessage();//构建邮件
            MimeMessageHelper helper = new MimeMessageHelper(msg, true);//设置可选文本或添加内联元素或附件,

            helper.setFrom("[email protected]");//发件人
            helper.setSentDate(new Date());//发送日期
            helper.setSubject("这是测试主题(thymeleaf)");//发送主题
            helper.setTo("[email protected]");//收件人

            Context context = new Context();//构建上下文环境
            context.setVariable("name","高级工程师");
            context.setVariable("age", 19);

            String process = springTemplateEngine.process("table", context);//将模板解析成静态字符串
            helper.setText(process,true);//内容是否设置成html,true代表是


            javaMailSender.send(msg);//发送
        }

成功收到

在这里插入图片描述

在这里插入图片描述

  • 现在我们将一些操作进行封装,做成一个工具类,并且新建一个Mail对象来简化发送的过程,完成博客的邮件提醒功能。

Mail类

package com.chenzhen.blog.pojo;

import java.util.Date;

/**
 * @author ChenZhen
 * @Description
 * @create 2022/9/27 11:52
 * @QQ 1583296383
 * @WeXin(WeChat) ShockChen7
 */
public class Mail {
    
    

    //发件人邮箱账号(固定为我自己 即博主本人)
    private String sendMailAccount;
    //收件人邮箱账号
    private String acceptMailAccount;
    //收件人姓名
    private String name;
    //收件人评论的内容
    private String comment;
    //回复收件人的 回复者的姓名
    private String respondent;
    //回复者的回复内容
    private String reply;
    //评论发生的地方链接(回复者是在哪里回复收件人的)
    private String address;
    //邮件主题
    private String theme;
    //发送时间
    private Date sendTime = new Date();

    public Mail() {
    
    
    }

    public Mail(String sendMailAccount, String acceptMailAccount, String name, String comment, String respondent, String reply, String address, String theme) {
    
    
        this.sendMailAccount = sendMailAccount;
        this.acceptMailAccount = acceptMailAccount;
        this.name = name;
        this.comment = comment;
        this.respondent = respondent;
        this.reply = reply;
        this.address = address;
        this.theme = theme;
    }


    public String getAddress() {
    
    
        return address;
    }

    public void setAddress(String address) {
    
    
        this.address = address;
    }

    public String getSendMailAccount() {
    
    
        return sendMailAccount;
    }

    public void setSendMailAccount(String sendMailAccount) {
    
    
        this.sendMailAccount = sendMailAccount;
    }

    public String getAcceptMailAccount() {
    
    
        return acceptMailAccount;
    }

    public void setAcceptMailAccount(String acceptMailAccount) {
    
    
        this.acceptMailAccount = acceptMailAccount;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public String getComment() {
    
    
        return comment;
    }

    public void setComment(String comment) {
    
    
        this.comment = comment;
    }

    public String getRespondent() {
    
    
        return respondent;
    }

    public void setRespondent(String respondent) {
    
    
        this.respondent = respondent;
    }

    public String getReply() {
    
    
        return reply;
    }

    public void setReply(String reply) {
    
    
        this.reply = reply;
    }

    public String getTheme() {
    
    
        return theme;
    }

    public void setTheme(String theme) {
    
    
        this.theme = theme;
    }

    public Date getSendTime() {
    
    
        return sendTime;
    }

    public void setSendTime(Date sendTime) {
    
    
        this.sendTime = sendTime;
    }
}

邮件工具类MailUtil

  • 有一个地方需要额外注意,发送提醒邮件的功能是在用户进行评论后的操作,但是邮件的发送过程需要花一段时间,会造成用户点了评论发送按钮之后很久才得到反馈,为了解决这个问题,我们需要运用到多线程思想。
  • 我们将发送邮件的方法sendThymeleafEmail()加上@Async注解,将该方法标记为一个异步方法,这样在执行该方法的时候springboot会为我们开辟一个另外的线程来运行邮件的发送功能。这样不会造成线程的堵塞
package com.chenzhen.blog.util;

import com.chenzhen.blog.pojo.Mail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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.context.Context;
import org.thymeleaf.spring5.SpringTemplateEngine;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;


/**
 * @author ChenZhen
 * @Description
 * @create 2022/9/27 11:59
 * @QQ 1583296383
 * @WeXin(WeChat) ShockChen7
 */
@Component
public class MailUtil {
    
    

    @Autowired
    private JavaMailSender javaMailSender;//引入 JavaMailSender 邮件发送对象 来实现发送邮件的功能

    @Autowired
    private SpringTemplateEngine springTemplateEngine;//Spring 模板引擎

    @Value("${spring.mail.username}") //从yaml配置文件中获取
    private String from; //发送方邮箱地址

    @Value("${spring.mail.thymeleaf-html}")//从yaml配置文件中获取
    private String html;


    /**
     * 发送 thymeleaf 页面邮件
     */
    @Async("asyncThreadPoolTaskExecutor")  //设置为一个异步方法
    public void sendThymeleafEmail(Mail mail) throws MessagingException {
    
    


        MimeMessage msg = javaMailSender.createMimeMessage();//构建邮件
        MimeMessageHelper helper = new MimeMessageHelper(msg, true);//构建邮件收发信息。


            helper.setFrom(from);//发件人(默认固定为自己)
            helper.setSentDate(mail.getSendTime());//发送日期
            helper.setSubject(mail.getTheme());//发送主题


            Context context = new Context();//将mail中的值设置进context交由模板引擎渲染
//            WebContext context = new WebContext(request, response, request.getServletContext(), request.getLocale());

            context.setVariable("name",mail.getName());
            context.setVariable("theme", mail.getTheme());
            context.setVariable("comment", mail.getComment());
            context.setVariable("respondent", mail.getRespondent());
            context.setVariable("reply", mail.getReply());
            context.setVariable("address", mail.getAddress());

            String process = springTemplateEngine.process(html, context);
            helper.setText(process,true);//内容是否设置成html,true代表是
            helper.setTo(mail.getAcceptMailAccount());//收件人
            javaMailSender.send(msg);//发送

        }
    }

自定义线程池配置类

  • @Async后的属性参数值是指定使用哪个线程池,这里我们自己配置一个线程池来让Async指定
package com.chenzhen.blog;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author ChenZhen
 * @Description 自定义线程池
 * @create 2022/9/28 18:31
 * @QQ 1583296383
 * @WeXin(WeChat) ShockChen7
 */
@Configuration
public class AsyncPoolConfig {
    
    

    @Bean(name = "asyncThreadPoolTaskExecutor")
    public ThreadPoolTaskExecutor asyncThreadPoolTaskExecutor(){
    
    
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(20);
        executor.setMaxPoolSize(200);
        executor.setQueueCapacity(25);
        executor.setKeepAliveSeconds(200);
        executor.setThreadNamePrefix("asyncThread");
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);

        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        return executor;
    }

}

在Service层添加发送邮件功能

对用户进行判断:

  • 如果是游客评论则会通知管理员,如果是管理员自己发的评论则不需要通知自己
  • 如果是回复别人的评论,则都进行邮件通知
    在这里插入图片描述
public void sendMail(User user, Message message) throws MessagingException {
    
    


        if (user!=null){
    
    
            //如果是管理员发的评论
            if (message.getParentMessage().getId()==null || message.getParentMessage()==null){
    
    
                //如果是根评论
                //不需要发给自己邮件
                return;
            }else {
    
    
                //如果不是根评论,则给[我回复的对象]发一封提醒邮件
                Message parentMessage = messageMapper.selectById(message.getParentMessage().getId());//获取父评论
                Mail mail = new Mail(null, parentMessage.getEmail(), parentMessage.getNickname(), parentMessage.getContent(),
                        message.getNickname(), message.getContent(),
                        "/message", "您在《ChenZhen的客栈-留言板》中的评论有了新的回复!");

                mailUtil.sendThymeleafEmail(mail);
            }
        }else {
    
    
            //如果不是管理员发的评论
            if (message.getParentMessage().getId()==null || message.getParentMessage()==null){
    
    
                //如果是根评论
                //发给我自己,提醒有人在留言板留言了
                Mail mail = new Mail(null, "[email protected]", "ChenZhen", null,
                        message.getNickname(), message.getContent(),
                        "/message","在《ChenZhen的客栈-留言板》中有了新的留言!");

                mailUtil.sendThymeleafEmail(mail);

            }else{
    
    
                //如果不是根评论
                //给回复者[回复的对象]发一份提醒邮件
                Message parentMessage = messageMapper.selectById(message.getParentMessage().getId());//获取父评论
                Mail mail = new Mail(null,parentMessage.getEmail(),parentMessage.getNickname(),
                        parentMessage.getContent(),message.getNickname(),message.getContent(),
                        "/message","您在《ChenZhen的客栈-留言板》中的评论有了新的回复!");

                mailUtil.sendThymeleafEmail(mail);

            }

        }
    }

在保持到数据库后,调用Service层的方法,异步地给用户发送提醒邮件

在这里插入图片描述

  • 自此邮件提醒功能就完成了!

猜你喜欢

转载自blog.csdn.net/ShockChen7/article/details/127230812
今日推荐