在开发Web应用时,多数应用都具备任务调度的功能,常见的任务包括异步任务,定时任务和邮件服务。
异步任务
Web应用开发中,大多数都是通过同步方式完成数据交互的,但是当我们在处理与第三方系统交互的时候,容易造成响应迟缓的问题,为了解决这个问题,我们大部分时候会采用多线程的方式来面对,除了多线程之外,我们还可以使用异步任务的方式来完美解决这个问题。
异步任务根据处理方式的不同可以分为无返回值异步调用和有返回值异步调用。
无返回值异步调用
业务层代码
/**
* 无返回值的异步调用
* @throws InterruptedException
*/
@Async//表明该方法是一个异步方法
public void sendMSM() throws InterruptedException {
System.out.println("调用短信方法....");
long startTime = System.currentTimeMillis();
Thread.sleep(5000);
long endTime = System.currentTimeMillis();
System.out.println("短信方法完成,耗时:"+(endTime-startTime));
}
使用异步调用需要在项目引导类上开启异步任务的支持
@SpringBootApplication
@EnableAsync//开启异步任务的支持
public class Chapter09Application {
public static void main(String[] args) {
SpringApplication.run(Chapter09Application.class, args);
}
}
控制层代码
@Autowired
private MyAsycService myAsycService;
@RequestMapping("test")
public String test() throws InterruptedException {
long startTime = System.currentTimeMillis();
myAsycService.sendMSM();
long endTime = System.currentTimeMillis();
System.out.println("主线程耗时:"+(endTime-startTime));
return "ok";
}
有返回值异步调用
业务层代码
/**
* 有返回值的异步调用
*/
@Async
public Future<Integer> processonA() throws InterruptedException {
long start = System.currentTimeMillis();
Thread.sleep(4000);
//模拟一个计算结果
int count=1506;
long end = System.currentTimeMillis();
System.out.println("业务A耗时:"+(end-start));
return new AsyncResult<Integer>(count);
}
@Async
public Future<Integer> processonB() throws InterruptedException {
long start = System.currentTimeMillis();
Thread.sleep(4000);
//模拟一个计算结果
int count=1798;
long end = System.currentTimeMillis();
System.out.println("业务B耗时:"+(end-start));
return new AsyncResult<Integer>(count);
}
控制层代码
@Autowired
private MyAsycService myAsycService;
@RequestMapping("statistics")
public String statistics()throws Exception{
long start = System.currentTimeMillis();
Future<Integer> fa = myAsycService.processonA();
Future<Integer> fb = myAsycService.processonB();
int total = fa.get() + fb.get();
System.out.println("异步调用的结果为:"+total);
long end = System.currentTimeMillis();
System.out.println("主线程耗时:"+(end-start));
return "ok";
}
这里对控制层进行访问需要等待业务层返回结果之后才会响应页面,这就是有返回值异步调用。
定时任务
使用定时任务需要在项目引导类上开启定时任务的支持
@SpringBootApplication
@EnableAsync//开启异步任务的支持
@EnableScheduling//开启定时任务的支持
public class Chapter09Application {
public static void main(String[] args) {
SpringApplication.run(Chapter09Application.class, args);
}
}
业务层代码
@Service
public class ScheduledTaskService {
private static final SimpleDateFormat dateFormat =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private Integer count1=1;
private Integer count2=1;
private Integer count3=1;
@Scheduled(fixedRate = 60000)//一分钟执行一次
public void test1(){
System.out.println(String.format("定时任务fixeRate第%s次执行,当前时间为:%s",count1++,dateFormat.format(new Date())));
}
@Scheduled(fixedDelay = 60000)//表示上一次任务执行完成之后,在指定时间后执行下一次任务
public void test2() throws InterruptedException {
System.out.println(String.format("定时任务fixeDelay第%s次执行,当前时间为:%s",count2++,dateFormat.format(new Date())));
Thread.sleep(10000);
}
@Scheduled(cron ="0 * * * * *" )//定制任务触发的时间
public void test3() {
System.out.println(String.format("定时任务cron第%s次执行,当前时间为:%s",count3++,dateFormat.format(new Date())));
}
}
邮箱服务
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
使用邮箱服务需要在application.properties中配置相关的配置信息
#发件人的主机及qq邮箱端口号
spring.mail.host=smtp.qq.com
spring.mail.port=587
#发件人的账户密码
spring.mail.username=1106774637@qq.com
spring.mail.password=ljjmmefhpmtijjbfgwr
spring.mail.default-encoding=utf-8
#设置超市服务
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=5000
spring.mail.properties.mail.smtp.writetimeout=5000
注意这里的密码需要在发件人的邮箱的设置中开启相关的设置之后获得密码
1、纯文本邮箱服务
业务层代码
@Autowired
private JavaMailSenderImpl mailSender;
@Value("${spring.mail.username}")
private String from;
/**
* 测试纯文本邮件发送
* @param to
* @param subject
* @param text
*/
public void sendSimpleEmail(String to,String subject,String text){
SimpleMailMessage mailMessage=new SimpleMailMessage();
mailMessage.setFrom(from);
mailMessage.setTo(to);
mailMessage.setSubject(subject);
mailMessage.setText(text);
try{
mailSender.send(mailMessage);
System.out.println("纯文本邮件发送成功");
}catch (Exception e){
System.out.println("纯文本邮件发送失败");
e.printStackTrace();
}
}
测试代码
@Autowired
private SendEmailService sendEmailService;
@Test
public void setSendEmailTest(){
String to="1106774637@qq.com";
String subject="【纯文本邮件】标题";
String text="Spring boot 纯文本邮件测试";
sendEmailService.sendSimpleEmail(to,subject,text);
}
2、带图片和附件的邮箱服务
业务层代码
/**
* 测试复邮件发送
*/
public void sendComplexEmail(String to,String subject,String text,String filePath,String rscId,String rscPath){
//定制复杂邮件信息MimeMessage
MimeMessage message=mailSender.createMimeMessage();
try{
//使用MimeMessageHelper帮助类并设置multpart多部件使用为true
MimeMessageHelper helper=new MimeMessageHelper(message,true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(text,true);
//设置邮件静态资源
FileSystemResource res=new FileSystemResource(new File(rscPath));
helper.addInline(rscId,res);
//设置邮件附件
FileSystemResource file=new FileSystemResource(new File(filePath));
String fileName=filePath.substring(filePath.lastIndexOf(File.separator));
helper.addAttachment(fileName,file);
//发送邮件
mailSender.send(message);
System.out.println("复杂邮件发送成功");
} catch (MessagingException e) {
System.out.println("复杂邮件发送失败");
e.printStackTrace();
}
}
测试代码
@Autowired
private SendEmailService sendEmailService;
@Test
public void sendComplexEmail(){
String to="1106774637@qq.com";
String subject="【复杂邮件】标题";
//定制邮件内容
StringBuilder text=new StringBuilder();
text.append("<html><head></head>");
text.append("<body><h1>祝你国庆快乐!</h1>");
//cid为固定写法,rscId自定义的资源唯一标识
String rscId="img001";
text.append("<img src='cid:"+rscId+"'/></body>");
text.append("</html>");
//指定静态资源文件的路径和附件的路径
String rscPath="C:\\Users\\SDL\\Desktop\\test.jpg";
String filePath="C:\\Users\\SDL\\Desktop\\text.txt";
//发送复杂邮件
sendEmailService.sendComplexEmail(to,subject,text.toString(),filePath,rscId,rscPath);
}
3、模板邮箱服务
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
业务层代码
/**
* 测试模板邮件发送
*
*/
public void sendTemplateEmail(String to,String subject,String content){
MimeMessage message=mailSender.createMimeMessage();
try{
//使用MimeMessageHelper帮助类并设置multpart多部件使用为true
MimeMessageHelper helper=new MimeMessageHelper(message,true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content,true);
//发送邮件
mailSender.send(message);
System.out.println("模板邮件发送成功!");
} catch (MessagingException e) {
System.out.println("模板邮件发送失败");
e.printStackTrace();
}
}
测试代码
/**
*测试发送模板邮件
*/
@Autowired
private SendEmailService sendEmailService;
@Autowired
private TemplateEngine templateEngine;
@Test
public void sendTemplateEmail(){
String to="1106774637@qq.com";
String subject="【模板邮件】标题";
//使用模板定制邮件正文内容
Context context=new Context();
context.setVariable("username","张三");
context.setVariable("code","489");
//使用TemplateEngline设置要处理的模板 页面
String emailTemplate = templateEngine.process("emailTemplate", context);
//发送模板邮件
sendEmailService.sendTemplateEmail(to,subject,emailTemplate);
}
模板页面
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>用户验证码</title>
</head>
<body>
<div><span th:text="${username}">XXX</span> 先生/女士,您好: </div>
<p style="text-indent: 2em">您的用户验证码为<span th:text="${code}" style="color: cornflowerblue">123456</span>,请妥善保管。></p>
</body>
</html>