一、概要

开发Web应用时,多数应用都具备任务调度功能。常见的任务包括异步任务、定时任务和发邮件任务。

我们以数据库报表为例看看任务调度如何帮助改善系统设计。报表可能是错综复杂的,用户可能需要很长时间找到需要的报表数据,此时,我们可以在这个报表应用中添加异步任务减少用户等待时间,从而提高用户体验;除此之外,还可以在报表应用中添加定时任务和邮件任务,以便用户可以安排在任何他们需要的时间定时生成报表,并在Email中发送。

二、异步任务

1.无返回值异步任务调用

a.Spring Boot 项目创建

选择Web模块中的Web依赖

b.编写异步调用方法

创建一个业务实现类MyAsyncService,并创建模拟发送短信验证码的方法

@Service

public class MyAsyncService {

@Async

public void sendSMS() throws Exception {

System.out.println("调用短信验证码业务方法...");

Long startTime = System.currentTimeMillis();

Thread.sleep(5000);

Long endTime = System.currentTimeMillis();

System.out.println("短信业务执行完成耗时:" + (endTime - startTime));

}

c.开启基于注解的异步任务支持

@EnableAsync

@SpringBootApplication

public class SpringMissionApplication {

public static void main(String[] args) {

SpringApplication.run(SpringMissionApplication.class, args);

}

}

d.编写控制层业务调用方法

创建一个调用异步方法的实现类MyAsyncController, 并创建模拟发送短信验证码的处理方法

@Controller

public class MyAsyncController {

@Autowired

private MyAsyncService myService;

@GetMapping("/sendSMS")

@ResponseBody

public String sendSMS() throws Exception {

Long startTime = System.currentTimeMillis();

myService.sendSMS();

Long endTime = System.currentTimeMillis();

System.out.println("主流程耗时: " + (endTime - startTime));

return "success";

}

e.异步任务效果测试

访问 http://localhost:8080/sendSMS

注意:上述异步方法是没有返回值的,这样主流程在执行异步方法时不会阻塞,而是继续向下执行主流程程序,直接向页面响应结果,而调用的异步方法会作为一个子线程单独执行,直到异步方法执行完成。

2.有返回值异步任务调用

a.编写异步调用方法

在MyAsyncService业务处理类中,添加两个模拟有返回值的异步任务业务处理方法

@Async

public Future<Integer> processA() throws Exception {

System.out.println("开始分析并统计业务A数据...");

Long startTime = System.currentTimeMillis();

Thread.sleep(4000);

int count=123456;

Long endTime = System.currentTimeMillis();

System.out.println("业务A数据统计耗时:" + (endTime - startTime));

return new AsyncResult<Integer>(count);

}

@Async

public Future<Integer> processB() throws Exception {

System.out.println("开始分析并统计业务B数据...");

Long startTime = System.currentTimeMillis();

Thread.sleep(5000);

int count=654321;

Long endTime = System.currentTimeMillis();

System.out.println("业务B数据统计耗时:" + (endTime - startTime));

return new AsyncResult<Integer>(count);

}

b.编写控制层业务调用方法

在MyAsyncController业务处理类中,编写业务数据分析统计的请求处理方法

@GetMapping("/statistics")

public String statistics() throws Exception {

Long startTime = System.currentTimeMillis();

Future<Integer> futureA = myService.processA();

Future<Integer> futureB = myService.processB();

int total = futureA.get() + futureB.get();

System.out.println("异步任务数据统计汇总结果: "+total);

Long endTime = System.currentTimeMillis();

System.out.println("主流程耗时: "+(endTime-startTime));

return "success";}

c.异步任务效果测试

访问http://localhost:8080/statistics

注意:上述异步方法是有返回值的,这样主流程在执行异步方法时会有短暂阻塞,需要等待并获取异步方法的返回结果,而调用的两个异步方法会作为两个子线程并行执行,直到异步方法执行完成并返回结果,这样主流程会在最后一个异步方法返回结果后跳出阻塞状态。

三、定时任务

1.介绍

Springboot不仅继承spring的scheduling tasks实现定时任务,而且更好地支持注解方式的定时任务。

相关注解:

@EnableScheduling

@Scheduled

2.定时任务实现

a.编写定时任务业务处理方法

新建一个定时任务管理的业务处理类ScheduledTaskService,并在该类中编写对应的定时任务处理方法。

使用@Scheduled注解声明了三个定时任务方法,这三个方法定制的执行规则基本相同,

都是每隔1分钟重复执行一次定时任务,在使用fixedDelay属性的方法scheduledTaskAfterSleep()中,

使用Thread.sleep(10000)模拟该定时任务处理耗时为10秒钟。

@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 scheduledTaskImmediately() {

System.out.println(String.format("fixedRate第%s次执行,当前时间为:%s",

count1++, dateFormat.format(new Date())));

}

@Scheduled(fixedDelay = 60000)

public void scheduledTaskAfterSleep() throws InterruptedException {

System.out.println(String.format("fixedDelay第%s次执行,当前时间为:%s",

count2++, dateFormat.format(new Date())));

Thread.sleep(10000);

}

@Scheduled(cron = "0 * * * * *")

public void scheduledTaskCron(){

System.out.println(String.format("cron第%s次执行,当前时间为:%s",

count3++, dateFormat.format(new Date())));

}

}

b.开启基于注解的定时任务支持

@EnableScheduling

@EnableAsync

@SpringBootApplication

public class SpringMissionApplication {

c.定时任务效果测试

结论:配置@Scheduled注解的fixedRate和fixedDelay属性的定时方法会立即执行一次,配置cron属性的定时方法会在整数分钟时间点首次执行;

接着,配置fixedRate和cron属性的方法会每隔1分钟重复执行一次定时任务,

而配置fixedDelay属性的方法是在上一次方法执行完成后再相隔1分钟重复执行一次定时任务。

四、邮件任务

1.发送纯文本邮件

a.添加邮件服务的依赖启动器

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-mail</artifactId>

</dependency>

当添加上述依赖后,Spring Boot自动配置的邮件服务会生效,在邮件发送任务时,可以直接使用Spring框架提供的JavaMailSender接口或者它的实现类JavaMailSenderImpl邮件发送。

b.添加邮件服务配置

# 发件人:以qq邮箱服务器作为例子,其他的类似

spring.mail.host=smtp.qq.com

spring.mail.port=587

# 配置个人QQ账户和密码(密码是加密后的授权码,授权码会变)

spring.mail.username=2127269781@qq.com

spring.mail.password=ijdjokspcbnzfbfa

spring.mail.default-encoding=UTF-8

# 邮件服务超时时间配置

spring.mail.properties.mail.smtp.connectiontimeout=5000

spring.mail.properties.mail.smtp.timeout=3000

spring.mail.properties.mail.smtp.writetimeout=5000

c.定制邮件发送服务

新建一个邮件发送任务管理的业务处理类SendEmailService,编写了一个发送纯文本邮件的sendSimpleEmail()方法,在该方法中通过SimpleMailMessage类定制了邮件信息的发件人地址(From)、收件人地址(To)、邮件标题(Subject)和邮件内容(Text),最后使用JavaMailSenderImpl的send()方法实现纯文本邮件发送。

@Service

public class SendEmailService {

@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

SimpleMailMessage message = new SimpleMailMessage();

message.setFrom(from);

message.setTo(to);

message.setSubject(subject);

message.setText(text);

try {

// 发送邮件

mailSender.send(message);

System.out.println("纯文本邮件发送成功");

} catch (MailException e) {

System.out.println("纯文本邮件发送失败 "+e.getMessage());

e.printStackTrace();

}

}

d.纯文本邮件发送效果测试

先定制了纯文本邮件发送方法所需要的参数(示例中定制了给自己邮箱发送邮件),然后调用业务方法实现了纯文本邮件发送。

@SpringBootTest

class SpringMissionApplicationTests {

@Autowired

private SendEmailService sendEmailService;

@Test

public void sendSimpleMailTest() {

String to="2127269781@qq.com";

String subject="【纯文本邮件】标题";

String text="Spring Boot纯文本邮件发送内容测试.....";

sendEmailService.sendSimpleEmail(to,subject,text);

}

注释掉//@EnableScheduling,直接启动单元测试方法sendSimpleMailTest(),

2.发送带附件和图片的邮件

a.定制邮件发送服务

打开之前创建的邮件发送任务的业务处理类SendEmailService,在该类中编写一个发送带附件和图片邮件的业务方法sendComplexEmail() ,该方法需要接收的参数除了基本的发送信息外,还包括静态资源唯一标识、静态资源路径和附件路径。

/**

* 发送复杂邮件(包括静态资源和附件)

* @param to           收件人地址

* @param subject      邮件标题

* @param text         邮件内容

* @param filePath     附件地址

* @param rscId        静态资源唯一标识

* @param rscPath      静态资源地址

*/

public void sendComplexEmail(String to,String subject,String text,String filePath,String rscId,String rscPath){

// 定制复杂邮件信息MimeMessage

MimeMessage message = mailSender.createMimeMessage();

try {

// 使用MimeMessageHelper帮助类,并设置multipart多部件使用为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.getMessage());

e.printStackTrace();

}

}

b.邮件发送效果测试

在项目测试类中添加一个方法调用带附件和图片的复杂邮件发送的方法实现邮件发送效果测试,根据前面定义的复杂邮件发送业务方法定制了各种参数。其中,在定义邮件内容时使用了Html标签编辑邮件内容,并内嵌了一个标识为rscId的图片,并为邮件指定了携带的附件路径。在邮件发送之前,务必保证指定路径下存放有对应的静态资源和附件文件。

@Test

public void sendComplexEmailTest() {

String to="2127269781@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="F:\\email\\newyear.jpg";

String filePath="F:\\email\\元旦放假注意事项.docx";

// 发送复杂邮件

sendEmailService.sendComplexEmail(to,subject,text.toString(),filePath,rscId,rscPath);

}

c.执行测试方法

3.发送模板邮件

a.添加Thymeleaf模板引擎依赖启动器

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-thymeleaf</artifactId>

</dependency>

b.定制模板邮件

在templates文件夹下新建emailTemplate_vercode.html

<!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>&nbsp;先生/女士,您好:</div>

<P style="text-indent: 2em">您的新用户验证码为<span th:text="${code}"

style="color: cornflowerblue">123456</span>,请妥善保管。</P>

</body></html>

c.定制邮件发送服务

在业务处理类SendEmailService中编写一个发送Html模板邮件的业务方法,sendTemplateEmail()方法主要用于处理Html内容(包括Thymeleaf邮件模板)的邮件发送,在定制Html模板邮件信息时,使用了MimeMessageHelper类对邮件信息进行封装处理。

/**

* 发送模板邮件

* @param to       收件人地址

* @param subject  邮件标题

* @param content  邮件内容

*/

public void sendTemplateEmail(String to, String subject, String content) {

MimeMessage message = mailSender.createMimeMessage();

try {

// 使用MimeMessageHelper帮助类,并设置multipart多部件使用为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.getMessage());

e.printStackTrace();

}

}

d.模板邮件发送效果测试

在项目测试类中添加一个方法调用前面编写的Html模板邮件发送方法测试邮件发送效果,先使用@Autowired注解引入了Thymeleaf提供的模板引擎解析器TemplateEngine,然后定制了模板邮件发送所需的参数。

@Autowired

private TemplateEngine templateEngine;

@Test

public void sendTemplateEmailTest() {

String to="2127269781@qq.com";

String subject="【模板邮件】标题";

// 使用模板邮件定制邮件正文内容

Context context = new Context();

context.setVariable("username", "石头");

context.setVariable("code", "456123");

// 使用TemplateEngine设置要处理的模板页面

String emailContent = templateEngine.process("emailTemplate_vercode", context);

// 发送模板邮件

sendEmailService.sendTemplateEmail(to,subject,emailContent);

}

做测试时关闭定时任务,控制台看得清楚点,不关闭也没事

9-Springboot任务管理相关推荐

  1. java定时任务管理_基于SpringBoot+layui秒级定时任务管理:JTimer for JAVA项目

    一.JTimer for JAVA简介 1.项目介绍 JTimer for JAVA是基于SpringBoot+layui秒级定时任务管理,取代crontab.其PHP版本 https ://gite ...

  2. springboot 集成xxl-job 定时任务管理平台

    项目集成xxl-job https://github.com/nlxs0511/springmybatisplus.git 项目集成邮件      https://github.com/nlxs051 ...

  3. flowable工作流_【程序源代码】Springboot开源工作流开发框架

    关键字:springboot 工作流框架 管理系统  框架 正文 | 内容 01 - [介绍] zjmzxfzhl 是基于 SpringBoot + Spring Security OAuth2(Sh ...

  4. 基于SpringBoot和Vue的分布式爬虫系统(JavaWeb)

    前言 本期案例分享,学长给大家上点干货,手把手带你开发一个分布式爬虫系统.通过这个项目,你将学习到下面几点: 架构设计.如果设计一个通用的爬虫系统?一个系统支持爬取所有的网站. 分布式开发经验.分布式 ...

  5. SpringBoot基础重难点

    来源:SpringBoot基础重难点 - liangxiaolong - 博客园 1.SpringBoot 1.1 概念 Spring Boot是构建所有基于Spring的应用程序的起点.Spring ...

  6. 学习笔记之-Activiti7工作流引擎,概述,环境搭建,类关系图,使用Activiti BPMN visualizer,流程变量,组任务 网关,Activiti整合Spring SpringBoot

    本篇学习笔记是观看黑马程序员Activiti7视频而得 Activiti7 一.工作流介绍 1.1 概念 工作流(Workflow),就是通过计算机对业务流程自动化执行管理.它主要解决的是" ...

  7. SpringBoot shedlock MongoDb锁配置

    配置mongo的表进行锁任务管理 maven依赖包 <dependency><groupId>net.javacrumbs.shedlock</groupId>&l ...

  8. Jeecg-Boot 1.0 版本发布,基于SpringBoot+Mybatis+AntDesign快速开发平台

    基于SpringBoot+Mybatis+AntDesign企业级快速开发平台 引言:      Jeecg-Boot 一款基于代码生成器的J2EE快速开发框架!  采用前后端分离技术: Spring ...

  9. SpringBoot教程

    springboot思维导图 前置知识: java基础,javaweb,maven,spring,mybatis 参考: <深入浅出Spring Boot2.x> 哔哩哔哩的黑马程序员 1 ...

最新文章

  1. SpringMVC实现文件的上传和下载
  2. 价值为王,市场需要降温
  3. Linux下的tar归档及解压缩功能详解
  4. python 标准差内数据概率怎么求_Python-统计概率
  5. 状态码202_至少 10 个 HTTP 状态码
  6. spring5.x cxf3.4.x 服务端和客户端 非maven版本
  7. 案例演示Python二维列表与Java二维数组
  8. win10一直正在检查更新_听说每个新时代的网民,都被win10迫害过
  9. 使用 Responsive Elements 快速构建响应式网站
  10. LuaForUnity7.1:Lua“类与对象”
  11. The remote system refused the connection.
  12. dict.txt(上一个程序的文件)
  13. [IOI2009]Regions
  14. (2017多校训练第四场)HDU - 6078 Wavel Sequence dp
  15. 服务器问题网站拔毛,网站被百度拔毛的经验分析
  16. IOS不兼容超出部分省略号 且页面显示不起作用 行数限定无作用
  17. selenium 更新 chromedriver 驱动
  18. python酷炫图形代码_牛批了,1 行 Python 代码就可实现炫酷可视化
  19. java如何将mp4写入光盘_iOS - 读取/写入mp4视频的XMP元数据
  20. awk】1-awk基础篇(又名UNIX.Shell.awk)

热门文章

  1. 【java】Java 8 - 移除Permgen 使用元空间
  2. 【java】基于JWT的token身份认证方案
  3. 【Flink】Flink 报错 Writing records to streamload failed
  4. 【Flink】Flink 部分算子是 FinishSHED 不做checnpoint
  5. 【java】java 一个线程占用多少内存
  6. 【java】JVM Attach机制实现与jstack使用(jvm参数DisableAttachMechanism)
  7. 【Linux】Linux 守护进程的启动方法
  8. 【Kafka】kafka 0.10.0 版本低级消费 API
  9. Maven : Log4j2 could not find a logging implementation
  10. 【Flink】Flink TimeServer 之 timerService().registerProcessingTimeTimer