springboot+quartz实现定时任务发送邮件demo

项目结构:

 一:实现发送邮件功能

  1:pom.xml文件  
<?xml version="1.0" encoding="UTF-8"?>
<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.path=http://localhost:8080
server.servlet.context-path=/
server.port=8080


spring.mail.host=smtp.qq.com
spring.mail.username=137846575@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
application.yml
  3:Email实体类
import java.io.Serializable;
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;
    }


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

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


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(){}

}
Mailqueue
   6:利用线程池的线程不断去读取队列是否存在Email,然后线程发送邮件
import com.example.quartz.common.entity.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();
                }

            }
        }
    }
}
ConsumeQueue
 7:EmailServiceImpl 
import com.example.quartz.common.entity.Email;
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);
    }
}
EmailServiceImpl
   8:web测试
package com.example.quartz.web;


import com.example.quartz.common.entity.Email;
import com.example.quartz.service.IEmailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/email")
public class textContrller {


    @Autowired
    IEmailService emailService;
    @PostMapping
    public void sendEmail(@RequestBody Email email) throws InterruptedException {
        emailService.pollQueue(email);
    }
}
textContrller
  9:postman测试结果

 

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

这里我只是设置定时任务把邮件放入队列中,quartz的简单应用,没有用过集群什么的。

    1:quartz实体
package com.example.quartz.common.entity;

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;
    }
}
QuartzEntity
 2:MyJob构建
import com.example.quartz.common.entity.Email;
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[]{"137846575@qq.com"});
        email.setContent("测试发送邮件");
        email.setSubject("定时发送邮件demo");
        email.setTemplate("hh.flt");
        Mailqueue.getSingleton().add(email);
    }
}
MyJob
   3:TaskRunner
package com.example.quartz.job;

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
    }
}
TaskRunner
  4:测试每隔5秒钟发送邮件

 

  5:freemarker模板文件
<!doctype html>
<html lang="zh-cmn-Hans">
<head>
    <meta charset="UTF-8">
    <meta name="renderer" content="webkit" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <title>Document</title>
</head>
<body>
    <div class="container"
         style="  800px;
         height: auto;
         margin: 0 auto;
         border: 1px #dddddd solid;
         border-top: 4px #3498db solid;
         font: 14px Microsoft Yahei;
         color: #333;">
        <div class="main" style="padding: 0 15px;">
            <div style="
                 border: 1px #f39d12 dashed;
                 background-color: #fffdf4;
                 margin: 20px 0;
                 border-radius: 6px;">
                <table width="100%" style="border: none">
                    <tr>
                        <td style=" 20%; text-align: center; padding-top: 25px">
                            <img src="${path}/image/dog.png" alt="">
                        </td>
                        <td colspan="2" style="font-size: 18px; line-height: 1.6;padding-top: 30px">
                            <div style="text-indent: 36px; padding-right: 24px">
                                 ${mail.content}
                            </div>
                        </td>
                    </tr>
                </table>
            </div>
        </div>
        <div class="footer" style="margin: auto;
                            padding: 15px 0 15px 15px;
                            background-color: #fafafa;
                            border-top: 1px #ddd solid;
                            color: #333;
                            height: auto;
                            zoom: 1;
                            overflow: auto;">
            <table style=" 100%">
                <tr>
                    <td style=" 60%">
                        <h4 style="font-size: 16px;
                             margin: 10px 0;">
                         大司马迷弟灰灰牛逼哄哄有限公司
                        </h4>
                        <p>
                            公司地址:
                            <b>宇宙银河系泰坦星泰坦星</b>
                        </p>
                        <p>

                        </p>
                        <p>
                            服务热线:
                            <b>
                                <span style="display: inline-block; margin-right: 16px;">17762018584</span>
                            </b>
                        </p>
                    </td>
                    <td style="text-align: right;">
                        <div style=" display: inline-block; 120px ; padding-top: 10px; padding-right: 200px;">
                            <img src="${path}/image/dog.jpg" alt="" style="vertical-align: top">
                        </div>
                    </td>
                </tr>
            </table>
        </div>
    </div>
</body>
</html> 
hh.flt

三:注意事项

导入quartz依赖时导入的是

<!--quartz定时调度依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

  不要导入

<dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.0</version>
        </dependency>

四:参考

https://gitee.com/52itstyle/spring-boot-quartz


原文地址:https://www.cnblogs.com/swqblog/p/13082748.html