SpringBoot - 异步任务、邮件发送、定时任务

一、异步任务

1)什么是异步调用?

异步调用是相对于同步调用而言的,同步调用是指程序按预定顺序一步步执行,每一步必须等到上一步执行完后才能执行,异步调用则无需等待上一步程序执行完即可执行。

2)如何实现异步调用?

多线程,这是很多人第一眼想到的关键词,没错,多线程就是一种实现异步调用的方式。

在非 Spring 目项目中我们要实现异步调用的就是使用多线程方式,可以自己实现 Runable 接口或者集成 Thread 类,或者使用 jdk1.5 以上提供了的 Executors 线程池。

StrngBoot中 则提供了很方便的方式执行异步调用。

3)异步接口的使用场景

耗时比较长,任务比较多的接口。比方说,文件下载,大文件下载比较耗时,这个时候就可以使用异步接口。

4)实例

SpringBoot依赖:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.6.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

@EnableAsync:在Application启动类中添加@EnableAsync注解

@SpringBootApplication
@EnableAsync // 开启异步注解功能
public class Spring09TestApplication {
    public static void main(String[] args) {
        SpringApplication.run(Spring09TestApplication.class, args);
    }
}

@Async:表示这是一个异步的方法。

@Service
public class AsyncService {

    @Async // 表示这是一个异步方法
    public void hello() {
        try {
            Thread.sleep(7000); //睡眠7秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("数据正在处理......");
    }
}

测试:

@RestController
public class AsyncController {

    @Autowired
    AsyncService asyncService;

    @RequestMapping("/hello")
    public String hello(){
        asyncService.hello(); // 停止七秒
        return "OK";
    }
}

测试立刻访问到了,OK。

如果是非异步的话,就会出现令人非常不爽的转圈圈,访问的时候需要等待service的方法在睡眠中醒来才能访问到OK。

二、邮件发送

SpringBoot 实现邮件功能是非常的方便快捷的,因为 SpringBoot 默认有 starter 实现了 Mail 。发送邮件应该是网站的必备功能之一,什么注册验证,忘记密码或者是给用户发送营销信息。最早期的时候我们会使用 JavaMail 相关 api 来写发送邮件的相关代码,后来 spring 推出了 JavaMailSender 更加简化了邮件发送的过程,在之后 springboot 对此进行了封装就有了现在的 spring-boot-starter-mail。

下面就开始使用 SpringBoot 的邮件发送。

1)基础配置

● 引入依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

● 获取邮箱授权码 - 这里使用QQ邮箱

QQ邮箱 -> 设置 -> 账户 -> POP3/SMTP服务:开启服务后会获得QQ的授权码.

● Mail配置文件

host:邮箱服务器地址:这里根据自己的情况填写

- QQ:smtp.qq.com

- sina:smtp.sina.cn

- aliyun:smtp.aliyun.com

- 163:smtp.163.com

spring:
  mail: #邮箱配置
    host: smtp.foxmail.com          # 邮箱服务器地址
    username: cyan9207@foxmail.com  # 邮箱用户名
    password: yslnzsijsxfdbeab      # 授权码
    default-encoding: UTF-8         # 编码格式
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
            required: true

#设置一个邮件发送人
lance:
  mail:
    sender: cyan9207@foxmail.com

2)Conroller测试邮箱发送

package com.cyan.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;

@RestController
public class MailController {

    @Value("${lance.mail.sender}")
    private String sender; // 邮件发送人

    @Autowired
    private JavaMailSender javaMailSender;

    /* *
     * @Description  http://localhost:8080/sendMail
     * @method 发送文本邮件
     */
    @RequestMapping("/sendMail")
    public String sendMail() {

        SimpleMailMessage message = new SimpleMailMessage();
        //邮件发送人
        message.setFrom(sender);
        //邮件接收人
        message.setTo("870919701@qq.com");
        //邮件主题
        message.setSubject("Cyan");
        // 邮件内容
        message.setText("Hello!!!Hello!!!Hello!!!");
        try {
            javaMailSender.send(message);
            System.err.println("简单邮件已经发送");
        } catch (Exception e) {
            System.err.println("发送简单邮件时发生异常!===>" + e.getMessage());
        }
        return "success";
    }

    /* *
     * @Description  http://localhost:8080/sendHtmlMail
     * @method 发送Html邮件
     */
    @RequestMapping("/sendHtmlMail")
    public String testHtmlMail() {

        String content="<html>\n" +
                           "<body>\n" +
                               "<h3>hello world ! 这是一封Html邮件!</h3>\n" +
                           "</body>\n" +
                       "</html>";
        MimeMessage message = javaMailSender.createMimeMessage();

        try {
            // true表示需要创建一个multipart message
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            // 邮件发送人
            helper.setFrom(sender);
            // 邮件接收人
            helper.setTo("870919701@qq.com");
            // 邮件主题
            helper.setSubject("html mail");
            // 邮件内容
            helper.setText(content, true);
            javaMailSender.send(message);
            System.err.println("html邮件发送成功");
        } catch (MessagingException e) {
            System.err.println("发送html邮件时发生异常!" + e);
        }
        return "success";
    }

    /* *
     * @Description  http://localhost:8080/sendFilesMail
     * @method 发送附件邮件
     */
    @RequestMapping("/sendFilesMail")
    public String sendFilesMail() {
        MimeMessage message = javaMailSender.createMimeMessage();
        try {

            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            // 邮件发送人
            helper.setFrom(sender);
            // 邮件接收人
            helper.setTo("870919701@qq.com");
            // 邮件主题
            helper.setSubject("附件邮件");
            // 邮件内容
            helper.setText("这是一封带附件的邮件", true);

            FileSystemResource file = new FileSystemResource(new File("C:\\Users\\ASUS\\Desktop\\JVM.txt"));
            helper.addAttachment(file.getFilename(), file);

            javaMailSender.send(message);
            System.err.println("带附件的邮件已经发送。");
        } catch (MessagingException e) {
            System.err.println("发送带附件的邮件时发生异常! " + e);
        }
        return "success";
    }

    /* *
     * @Description  http://localhost:8080/sendInlineResourceMail
     * @method 发送图片邮件
     */
    @RequestMapping("/sendInlineResourceMail")
    public String sendInlineResourceMail() {
        String Id = "Cyan-";
        String content="<html><body>这是有图片的邮件:<img src=\'cid:" + Id + "\' ></body></html>";
        String imgPath = "C:\\Users\\ASUS\\Pictures\\壁纸\\MK47.jpg";
        MimeMessage message = javaMailSender.createMimeMessage();

        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            // 邮件发送人
            helper.setFrom(sender);
            // 邮件接收人
            helper.setTo("870919701@qq.com");
            // 邮件主题
            helper.setSubject("这是有图片的邮件");
            // 邮件内容
            helper.setText(content, true);

            FileSystemResource res = new FileSystemResource(new File(imgPath));
            helper.addInline(Id, res);

            javaMailSender.send(message);
            System.err.println("嵌入静态资源的邮件已经发送。");
        } catch (MessagingException e) {
            System.err.println("发送嵌入静态资源的邮件时发生异常!" + e);
        }
        return "success";
    }
}
View Code

① 发送简单的文本邮件

@RequestMapping("/sendMail")
public String sendMail() {

    SimpleMailMessage message = new SimpleMailMessage();
    //邮件发送人
    message.setFrom(sender);
    //邮件接收人
    message.setTo("870919701@qq.com");
    //邮件主题
    message.setSubject("Cyan");
    // 邮件内容
    message.setText("Hello!!!Hello!!!Hello!!!");
    try {
        javaMailSender.send(message);
        System.err.println("简单邮件已经发送");
    } catch (Exception e) {
        System.err.println("发送简单邮件时发生异常!===>" + e.getMessage());
    }
    return "success";
}

访问:localhost:8080/sendMail

控制台:

邮箱接收:

② 发送html邮件

@RequestMapping("/sendHtmlMail")
public String testHtmlMail() {

    String content="<html>\n" +
                       "<body>\n" +
                           "<h3>hello world ! 这是一封Html邮件!</h3>\n" +
                       "</body>\n" +
                   "</html>";
    MimeMessage message = javaMailSender.createMimeMessage();

    try {
        // true表示需要创建一个multipart message
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        // 邮件发送人
        helper.setFrom(sender);
        // 邮件接收人
        helper.setTo("870919701@qq.com");
        // 邮件主题
        helper.setSubject("html mail");
        // 邮件内容
        helper.setText(content, true);
        javaMailSender.send(message);
        System.err.println("html邮件发送成功");
    } catch (MessagingException e) {
        System.err.println("发送html邮件时发生异常!" + e);
    }
    return "success";
}

访问:localhost:8080/sendHtmlMail

控制台:

邮箱接收:

③ 发送附件邮件

@RequestMapping("/sendFilesMail")
public String sendFilesMail() {
    MimeMessage message = javaMailSender.createMimeMessage();
    try {

        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        // 邮件发送人
        helper.setFrom(sender);
        // 邮件接收人
        helper.setTo("870919701@qq.com");
        // 邮件主题
        helper.setSubject("附件邮件");
        // 邮件内容
        helper.setText("这是一封带附件的邮件", true);

        FileSystemResource file = new FileSystemResource(new File("C:\\Users\\ASUS\\Desktop\\JVM.txt"));
        helper.addAttachment(file.getFilename(), file);

        javaMailSender.send(message);
        System.err.println("带附件的邮件已经发送。");
    } catch (MessagingException e) {
        System.err.println("发送带附件的邮件时发生异常! " + e);
    }
    return "success";
}

访问:localhost:8080/sendFilesMail

控制台:

邮箱接收:

④ 发送图片邮件

@RequestMapping("/sendInlineResourceMail")
public String sendInlineResourceMail() {
    String Id = "Cyan-";
    String content="<html>" +
                       "<body>这是有图片的邮件:<img src=\'cid:" + Id + "\' ></body>" +
                   "</html>";
    String imgPath = "C:\\Users\\ASUS\\Pictures\\壁纸\\MK47.jpg";
    MimeMessage message = javaMailSender.createMimeMessage();

    try {
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        // 邮件发送人
        helper.setFrom(sender);
        // 邮件接收人
        helper.setTo("870919701@qq.com");
        // 邮件主题
        helper.setSubject("这是有图片的邮件");
        // 邮件内容
        helper.setText(content, true);

        FileSystemResource res = new FileSystemResource(new File(imgPath));
        helper.addInline(Id, res);

        javaMailSender.send(message);
        System.err.println("嵌入静态资源的邮件已经发送。");
    } catch (MessagingException e) {
        System.err.println("发送嵌入静态资源的邮件时发生异常!" + e);
    }
    return "success";
}

访问:localhost:8080/sendInlineResourceMail

控制台:

邮箱接收:

三、定时任务

项目开发中经常需要执行一些定时任务,比如需要在每天凌晨时候,分析一次前一天的日志信息。Spring为我们提供了异步执行任务调度的方式,提供TaskExecutor 、TaskScheduler 接口。

在SpringBoot如何使用呢?

@EnableScheduling:在主方法中开启支持注解的定时任务

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling // 开启定时任务功能
public class Spring09TestApplication {
    public static void main(String[] args) {
        SpringApplication.run(Spring09TestApplication.class, args);
    }
}

@Scheduled:在要定时的方法上增加注解@Scheduled(cron = "秒 分 时 日 月 周几")

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service
public class ScheduledService {

    @Scheduled(cron = "0/2 * * * * ?")  // 每隔2秒执行一次
    public void test(){
        System.err.println(new Date());
    }
}

启动Application测试:每两秒执行一次

Cron表达式

cron计划任务,是任务在约定的时间执行已经计划好的工作。在Linux中,我们经常用到 cron 服务器来完成这项工作。cron服务器可以根据配置文件约定的时间来执行特定的任务。

● * :表示匹配该域的任意值,假如在Minutes域使用*, 即表示每分钟都会触发事件。

● ? :只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用,如果使用表示不管星期几都会触发,实际上并不是这样。

● - :表示范围,例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次

● / :表示起始时间开始触发,然后每隔固定时间触发一次,例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次.

● , :表示列出枚举值值。例如:在Minutes域使用5,20,则意味着在第5和第20分钟分别触发一次。

● L :表示最后,只能出现在DayofWeek和DayofMonth域,如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。

举例:

( 0 0 2 1 * ? * ):表示在每月的1日的凌晨2点调度任务

( 0 15 10 ? * MON-FRI ):表示周一到周五每天上午10:15执行作业

( 0 15 10 ? * 6L 2020-2022 ) :表示2020-2022年的每个月的最后一个星期五上午10:15执行作

( 0 0 10,14,16 * * ? ) :每天上午10点,下午2点,4点

( 0 0/30 9-17 * * ? ) :朝九晚五工作时间内每半小时

( 0 0 12 ? * WED ) :表示每个星期三中午12点

( 0 0 12 * * ? ) :每天中午12点触发

( 0 15 10 * * ? 2020 ) :2020年的每天上午10:15触发

( 0 0/5 14 * * ? ) :在每天下午2点到下午2:55期间的每5分钟触发

( 0 0/5 14,18 * * ? ) :在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发

( 0 0-5 14 * * ? ) :在每天下午2点到下午2:05期间的每1分钟触发

( 0 10,44 14 ? 3 WED ) :每年三月的星期三的下午2:10和2:44触发

( 0 15 10 ? MON-FRI ) :周一至周五的上午10:15触发

( 0 15 10 L * ? ) :每月最后一日的上午10:15触发

( 0 15 10 ? * 6L ) :每月的最后一个星期五上午10:15触发

( 0 15 10 ? * 6L 2020-2022) :2020年至2022年的每月的最后一个星期五上午10:15触发

posted @ 2020-04-17 17:14  ohmok  阅读(344)  评论(0)    收藏  举报