springboot实现发送邮件

153 阅读3分钟

这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战」。

springboot实现发送邮件demo

1:pom.xml文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example.quartz</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- freemarker模版 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>

        <dependency>
            <groupId>net.sourceforge.nekohtml</groupId>
            <artifactId>nekohtml</artifactId>
        </dependency>
        <!-- email -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib</artifactId>
            <version>2.4</version>
            <classifier>jdk15</classifier><!--指定jdk版本-->
        </dependency>
        <!--quartz定时调度依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>


    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

pom.xml
2:配置文件
server.servlet.context-path=/
server.port=8080


spring.mail.host=smtp.qq.com
spring.mail.username=xxx@qq.com
#授权码需要填写自己的
spring.mail.password=xxx
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.smtp.starttls.enable=true
spring.mail.properties.smtp.starttls.required = true
spring.mail.default-encoding=UTF-8
#使用freemarker模板发送
#放置模板的位置
spring.freemarker.template-loader-path=classpath:/static/template/
spring.freemarker.suffix=.flt
spring.freemarker.enabled=true
spring.freemarker.cache=false
spring.freemarker.charset=UTF-8
spring.freemarker.content-type=text/html
spring.freemarker.allow-request-override=false
spring.freemarker.check-template-location=true
spring.freemarker.expose-request-attributes=false
spring.freemarker.expose-session-attributes= false
spring.freemarker.expose-spring-macro-helpers=false

 3:Email实体类
import java.util.Arrays;
import java.util.HashMap;

public class Email  implements Serializable {

    private static final long serialVersionUID = 1L;
    private String[] email; //接受方邮箱
    private String subject; //主题
    private String content; //内容
    private String template; //模板



    public Email() {
        super();
    }

    public Email(String[] email, String subject, String content, String template) {
        this.email = email;
        this.subject = subject;
        this.content = content;
        this.template = template;

    }

    public String[] getEmail() {
        return email;
    }

    public void setEmail(String[] email) {
        this.email = email;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getTemplate() {
        return template;
    }

    public void setTemplate(String template) {
        this.template = template;
    }


}
 4:IEmailService接口
import javax.mail.MessagingException;

public interface IEmailService {
    public void send(Email email) throws MessagingException;//发送邮件
    public void pollQueue(Email email) throws InterruptedException;//把邮件放入队列中
}
   5:利用BlockingQueue保存Email


import com.example.quartz.common.entity.Email;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 保存邮件的队列
 * 设计为单例模式
 */
public class Mailqueue {

    public static final int QUEUE_SIZE = 100;

    public static BlockingQueue<Email> queue = new LinkedBlockingQueue<>(QUEUE_SIZE);

    public volatile static Mailqueue mailqueue ;

    /*
     *使用DCL模式
     */
    public static Mailqueue getSingleton()
    {
        if(mailqueue == null)
        {
            synchronized (Mailqueue.class)
            {
                if(mailqueue == null)
                {
                    mailqueue = new Mailqueue();
                }
            }
        }

        return mailqueue;
    }
    //入队
    public void add(Email email) throws InterruptedException {
        queue.put(email);
    }
    //出队
    public Email poll() throws InterruptedException {
        return queue.take();
    }
    //队列大小
    public int size()
    {
        return queue.size();
    }

    private Mailqueue(){}

}
  6:利用线程池的线程不断去读取队列是否存在Email,然后线程发送邮件
import com.example.quartz.service.IEmailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.mail.MessagingException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 消费队列
 *
 */


@Component
public class ConsumeQueue {
    @Autowired
    IEmailService emailService;

    @PostConstruct
    public  void start()
    {
        ExecutorService pool = Executors.newFixedThreadPool(2);//固定两个线程的线程池
        pool.submit(new task()); //提交任务
    }
    class task implements  Runnable{

        @Override
        public void run() {
            System.out.println("等待接受任务");
            while(true)
            {
                Email email = null;
                try {
                    email = Mailqueue.getSingleton().poll();
                    System.out.println("接受到邮件");
                    if(email != null)
                    {
                            emailService.send(email);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (MessagingException e) {
                    e.printStackTrace();
                }

            }
        }
    }
}

 7:EmailServiceImpl
import com.example.quartz.common.queue.Mailqueue;
import com.example.quartz.service.IEmailService;
import freemarker.core.ParseException;
import freemarker.template.*;
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.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;


@Service
public class EmailServiceImpl implements IEmailService {


    @Autowired
    JavaMailSender mailSender;//用于发送邮件
    @Autowired
    Configuration configuration;//freemarker
    @Value("${spring.mail.username}")
    public String USER_NAME;//发送者
    @Value("${server.path}")
    public String PATH; //模板中的图片等静态资源路径

    /**
     * 把邮件放进队列中
     * @param email
     */
    @Override
    public void send(Email email)  {
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = null;
        try {
            helper = new MimeMessageHelper(message, true);
            helper.setFrom(USER_NAME,"通过模板发送邮件");
            helper.setTo(email.getEmail());//发送给谁
            helper.setSubject(email.getSubject());//主题
            Map<String, Object> model = new HashMap<>();
            model.put("mail",email);
            model.put("path",PATH);
            Template template = configuration.getTemplate(email.getTemplate());//获得模板
            String msg = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
            helper.setText(msg,true);
            mailSender.send(message);//正式发送邮件
        } catch (MessagingException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (MalformedTemplateNameException e) {
            e.printStackTrace();
        } catch (TemplateNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }


    }

    @Override
    public void pollQueue(Email email) throws InterruptedException {
        Mailqueue.getSingleton().add(email);
    }
}

利用quartz实现定时发送邮件功能

  1:quartz实体

public class QuartzEntity {

    private String jobName;//任务名称
    private String jobGroup;//任务分组
    private String description;//任务描述
    private String jobClassName;//执行类
    private String jobMethodName;//执行方法
    private String cronExpression;//执行时间
    private String triggerName;//执行时间
    private String triggerState;//任务状态

    public String getJobName() {
        return jobName;
    }

    public void setJobName(String jobName) {
        this.jobName = jobName;
    }

    public String getJobGroup() {
        return jobGroup;
    }

    public void setJobGroup(String jobGroup) {
        this.jobGroup = jobGroup;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getJobClassName() {
        return jobClassName;
    }

    public void setJobClassName(String jobClassName) {
        this.jobClassName = jobClassName;
    }

    public String getJobMethodName() {
        return jobMethodName;
    }

    public void setJobMethodName(String jobMethodName) {
        this.jobMethodName = jobMethodName;
    }

    public String getCronExpression() {
        return cronExpression;
    }

    public void setCronExpression(String cronExpression) {
        this.cronExpression = cronExpression;
    }

    public String getTriggerName() {
        return triggerName;
    }

    public void setTriggerName(String triggerName) {
        this.triggerName = triggerName;
    }

    public String getTriggerState() {
        return triggerState;
    }

    public void setTriggerState(String triggerState) {
        this.triggerState = triggerState;
    }
}

 2:MyJob构建
import com.example.quartz.common.queue.Mailqueue;
import org.quartz.*;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

@DisallowConcurrentExecution
public class MyJob implements Job , Serializable {

    private static final long serialVersionUID = 1L;


    @Override
    public void execute(JobExecutionContext context){
        JobDetail jobDetail = context.getJobDetail();
        JobDataMap dataMap = jobDetail.getJobDataMap();
        /**
         * 获取任务中保存的方法名字,动态调用方法
         */
        String methodName = dataMap.getString("jobMethodName");
        try {
            MyJob job = new MyJob();
            Method method = job.getClass().getMethod(methodName);
            method.invoke(job);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    public  void test1() throws InterruptedException {
        System.out.println("执行任务");
            //往邮件队列中放入邮件
        Email email = new Email();
        email.setEmail(new String[]{"xxx@qq.com"});
        email.setContent("测试发送邮件");
        email.setSubject("定时发送邮件demo");
        email.setTemplate("hh.flt");
        Mailqueue.getSingleton().add(email);
    }
}
 3:TaskRunner

import com.example.quartz.common.entity.QuartzEntity;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
/**
 * 初始化任务
 */
@Component
public class TaskRunner  implements ApplicationRunner {

    private final static Logger LOGGER = LoggerFactory.getLogger(TaskRunner.class);

    @Autowired
    private Scheduler scheduler;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        //初始化任务测试发送邮件
        QuartzEntity quartz = new QuartzEntity();
        quartz.setJobName("测试一下");
        quartz.setJobGroup("test");
        quartz.setDescription("测试定时任务发送邮件");
        quartz.setJobClassName("com.example.quartz.job.MyJob");
        quartz.setCronExpression("*/5 * * * * ?"); //每隔5秒发送邮件
        quartz.setJobMethodName("test1"); //具体的需要执行的定时任务逻辑方法名
        Class cls = Class.forName(quartz.getJobClassName());
        cls.newInstance();
        //构建job
        JobDetail job = JobBuilder.newJob(cls).withIdentity(quartz.getJobName(), quartz.getJobGroup())
                .withDescription(quartz.getDescription()).build();
        job.getJobDataMap().put("jobMethodName","test1");
        //触发的时间点
        CronScheduleBuilder cronSchedule = CronScheduleBuilder.cronSchedule(quartz.getCronExpression());
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(quartz.getJobName(), quartz.getJobGroup())
                .startNow().withSchedule(cronSchedule).build();
        scheduler.scheduleJob(job,trigger); //将job和trigger交给scheduler
    }
}