项目结构:
一:实现发送邮件功能
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>
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
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; } }
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

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(){} }
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(); } } } } }
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); } }
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); } }
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; } }
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); } }
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 } }
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>
三:注意事项
导入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>