SpringBoot3任务处理

目录

1.异步任务

无返回值异步任务

效果

有返回值异步任务

效果

2.定时任务

效果

3.邮件任务

获取授权码

加入依赖

配置文件

纯文本邮件

效果

复杂邮件

效果

 

1.异步任务

@Async注释:

SpringBoot中的异步调用,可以写在类上或方法上,异步调用只是发送调用的指定,调用者无需等待被调用的方法完全执行完毕,而是继续执行下面流程。

@EnableAsync:

SpringBoot启动类开启异步支持。

无返回值异步任务

为了释放主线程

实现类

/**
 * 无返回值异步任务
 */
@Service
//异步任务注释
@Async
public class TimeService {
    public void sendSMS() {
        System.out.println("发短信启动-----------------");
        long l = System.currentTimeMillis();
        //模拟发动短信过程
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        long l1 = System.currentTimeMillis();
        System.out.println("短信业务耗时" + (l1 - l));

    }
}

控制层

/**
     * 无返回值异步任务
     * 为了释放主线程
     *
     * @return
     */
    @Autowired
    TimeService timeService;

    @RequestMapping("/text1")
    public String SendSMS() {
        System.out.println("主程序启动-----------------");
        long timeMillis = System.currentTimeMillis();
        //异步任务
        timeService.sendSMS();
        long timeMillis1 = System.currentTimeMillis();
        System.out.println("主线程耗时" + (timeMillis1 - timeMillis));
        return "主流程已完成,已释放";
    }

效果

使用前:

cb6da98355454dd9972ebbd1eca9ef5f.png

主线程需要等待子线程完成后才结束。

使用后:

9385d47107f743a0a49b13d451e54543.png

8bb76472853a4706ab3da65ad269f817.png

主线程已经进行完毕,子线程还在继续。

有返回值异步任务

AsyncResult类:封装异步任务上的异步操作的结果

Future类:表示一个可能还没有完成的异步任务的结果

Future的主要方法:

get()方法可以当任务结束后返回一个结果,如果调用时,工作还没有结束,则会阻塞线程,直到任务执行完毕

get(long timeout,TimeUnit unit)做多等待timeout的时间就会返回结果

cancel(boolean mayInterruptIfRunning)方法可以用来停止一个任务,如果任务可以停止(通过mayInterruptIfRunning来进行判断),则可以返回true,如果任务已经完成或者已经停止,或者这个任务无法停止,则会返回false.

isDone()方法判断当前方法是否完成

isCancel()方法判断当前方法是否取消

实现类

此时@Async注解写在方法上,表示4个线程同时进行,主线程需要四个线程返回值的和

/**
 * 有返回值异步任务
 */
@Service
public class MyAsyncService {
    //异步任务注释
    @Async
    //Future<Integer>只能在这里和@Async配合使用
    public Future<Integer> processA() {
        System.out.println("开始分析并统计业务A数据...");
        Long startTime = System.currentTimeMillis();
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        int count = 123;
        Long endTime = System.currentTimeMillis();
        System.out.println("业务A数据统计耗时:" + (endTime - startTime));
        //封装在AsyncResult结果集中
        return new AsyncResult<Integer>(count);
    }

    @Async
    //Future<Integer>只能在这里和@Async配合使用
    public Future<Integer> processB() {
        System.out.println("开始分析并统计业务B数据...");
        Long startTime = System.currentTimeMillis();
        try {
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        int count = 456;
        Long endTime = System.currentTimeMillis();
        System.out.println("业务B数据统计耗时:" + (endTime - startTime));
        //封装在AsyncResult结果集中
        return new AsyncResult<Integer>(count);
    }

    @Async
    //Future<Integer>只能在这里和@Async配合使用
    public Future<Integer> processC() {
        System.out.println("开始分析并统计业务C数据...");
        Long startTime = System.currentTimeMillis();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        int count = 789;
        Long endTime = System.currentTimeMillis();
        System.out.println("业务C数据统计耗时:" + (endTime - startTime));
        //封装在AsyncResult结果集中
        return new AsyncResult<Integer>(count);
    }

    @Async
    //Future<Integer>只能在这里和@Async配合使用
    public Future<Integer> processD() {
        System.out.println("开始分析并统计业务D数据...");
        Long startTime = System.currentTimeMillis();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        int count = 963;
        Long endTime = System.currentTimeMillis();
        System.out.println("业务D数据统计耗时:" + (endTime - startTime));
        //封装在AsyncResult结果集中
        return new AsyncResult<Integer>(count);
    }
}

控制层

/**
     * 有返回值异步任务
     * 是为了释放完成任务的子线程
     * @return
     */
    @Autowired
    MyAsyncService myAsyncService;
    @RequestMapping("/text2")
    public String statistics() throws ExecutionException, InterruptedException {
        Long startTime = System.currentTimeMillis();
        Future<Integer> futureA = myAsyncService.processA();
        Future<Integer> futureB = myAsyncService.processB();
        Future<Integer> futureC = myAsyncService.processC();
        Future<Integer> futureD = myAsyncService.processD();
        int total = futureA.get() + futureB.get()+ futureC.get()+ futureD.get();
        System.out.println("异步任务数据统计汇总结果:" + total);
        Long endTime = System.currentTimeMillis();
        System.out.println("主流程耗时:" + (endTime - startTime));
        return "子线程已完成,已释放主流程已完成";
    }

效果

9cf4da02c0414602b39c39c1f6e28572.png

ab323156ed564874a8122d64e28bbbe0.png

此时,线程完成自己的任务后即可释放。

2.定时任务

@EnableScheduling:

启用了Spring的任务调度功能,在配置类上使用,开启计划任务的支持

@Scheduled:

写在发放上,来声明这是一个任务,包括 cron,fixDelay,fixRate 等类型。无需调用,系统识别到注解会自动调用。

fixRate --按时间频率执行,控制方法执行的间隔时间,是以上一次方法执行完开始算起,如上一次方法执行阻塞住了,那么直到上一次执行完,并间隔给定的时间后,执行下一次。

fixDelay--延迟时间,按照一定的速率执行,是从上一次方法执行开始的时间算起,如果上一次方法阻塞住了,下一次也是不会执行,但是在阻塞这段时间内累计应该执行的次数,当不再阻塞时,一下子把这些全部执行掉,而后再按照固定速率继续执行

cron--固定时间

是否必填

值以及范围

通配符

0-59

, - * /

0-59

, - * /

0-23

, - * /

1-31

, - * ? / L W

1-12 或 JAN-DEC

, - * /

1-7 或 SUN-SAT

, - * ? / L #

1970-2099

, - * /

* :通配,语义相当于… 比如第五个位置的 *就表示每月都会执行(相当于1-12)

? :忽略,语义相当于不管… 比如第六个位置的?就表示不管当前是周几就会执行。至于为什么会有这种用法,我觉得应该是因为它和其他的字符可能会冲突。如果用*的话表示周一到周日都会执行,此时其他语义就不明确了,所以如果用不上星期的话一般给它用一个?表示 not care。

/ :间隔,语义相当于每隔 比如例2中的第三个位置的2/5就表示从2点开始每隔五小时

- :区间,语义相当于到…的每… 比如例2中的第二个位置的15-20就表示第15分钟到20分钟之间的每分钟

, :枚举,语义相当于和… 比如例2中的第一个位置的15,20,40就表示第15秒、20秒和40秒

L :最后(last),语义相当于最后一个 比如例2中的第四个位置的L就表示最后一天

W :工作日,字面意思,就是工作日 比如例3中的第四个位置的15W表示15号附近最近的工作日,如果15号刚好是工作日那就15号触发,如果15号是周六那就14号触发,如果15号是周日那就16号触发。前面不带数字就是所有匹配的工作日。

'L'和 'W'可以一组合使用。如果在日字段上设置"LW",则表示在本月的最后一个工作日触发(一般指发工资)

# :周定位,语义相当于每月的第几个周几 比如例4中的第六个位置的2#3就表示第三个周一。

周字段的设置,若使用英文字母是不区分大小写的 MON 与mon相同。

效果

 

@Scheduled(fixedRate = 1000)
    public void ScheduledText(){
        System.out.println("快背单词!");
    }

每一秒打印一次

374abbafa7b54f81ade1e5f35eedb141.png

 

@Scheduled(fixedDelay = 1000)
    public void ScheduledTest2(){
        System.out.println("快去吃饭!------------------------");
    }

延迟1秒打印一次

161193344edb475f97e53f36c47d784d.png

   

 @Scheduled(cron = "0/10 08 19 * * ? ")
    public void ScheduledTest3(){
        System.out.println("要下课了!");
    }

从19时8分0秒起,每10秒打印一次。

8c75baaa2e7749ee87faaedfb236bdea.png

3.邮件任务

获取授权码

进入QQ邮箱,点击账号与安全

a021dc827bd24631a130337f7e831ada.png

点击安全设置,先和手机进行绑定,如果绑定跳过这一步,直接跳到图一。

f023f54ab0a64a63a63c5e33d93144e8.png

发送短信后点击我已发送。

cab3c0471f8e4f39892fff3c209fbe3a.png

d6a618761f7f42aab3b3dcd308b566f6.png

用微信扫描二维码,发送短信后点击我已发送。

b22a50bba638489786b82d47dc9d944d.png

即可获得授权码

d6dac14884ca4eb69f1a2fa60bc9fee6.png

加入依赖

      

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

配置文件

#发件人邮箱服务器相关配置
spring.mail.host=smtp.qq.com
spring.mail.port=587
#配置个人QQ账户和密码(密码是加密后的授权码)
spring.mail.username=3451866342@qq.com
spring.mail.password=oxfdtthfgoyrdbie
spring.mail.default-encoding=UTF-8

纯文本邮件

通过SimpleMailMessage类定制了邮件信息的发件人地址(From)、收件人地址(To)、邮件标题(ubject)和邮件内容(Text),最后使用JavaMailSenderImpl的send()方法实现纯文本邮件发送。

实现类

@Autowired
    JavaMailSenderImpl javaMailSender;
    @Value("${spring.mail.username}")//获得配置文件中的邮箱地址
    private String from;

    /**
     * 纯文本邮件任务
     */
    public void sendSimpleEmail(String to, String subject, String text) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(from);
        message.setTo(to);//发送邮箱
        message.setSubject(subject);//邮件主题
        message.setText(text);//邮件内容
        javaMailSender.send(message);//发送邮件
        System.out.println("纯文本邮件发送成功");
    }

控制层

/**
     * 邮件任务(纯文本邮件)
     * @return
     */
    @Autowired
    SendEmailService sendEmailService;
    @RequestMapping("/text3")
    public String sendEmail(){
        sendEmailService.sendSimpleEmail("3451866342@qq.com", "测试邮件", "这就是个邮件");
        return "已发送完成";
    }

效果

3249e20d4fd24a8aa6c743e9bccc7630.png

debc118bbaa14d4db2889aeb728d7d99.png

复杂邮件

编写一个发送带附件和图片邮件的业务方法sendComplexEmail() ,该方法需要接收的参数除了基本的发送信息外,还包括静态资源唯一标识、静态资源路径和附件路径。

实现类

/**
     * 复杂邮件任务
     */
    public void MailEmail(String to,String subject,String text,String filePath,String rscId,String rscId2,String rscPath,String rscPath2) {
        // 创建一个 JavaMail MimeMessage 对象
        MimeMessage message = javaMailSender.createMimeMessage();
        try {
            // 创建 MimeMessageHelper 对象,参数为 MimeMessage 对象和开启复杂邮件编码
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(from);//发送邮箱
            helper.setTo(to);//接收邮箱
            helper.setSubject(subject);//邮件主题
            helper.setText(text, true);//邮件内容

            // 创建一个 FileSystemResource 对象,表示给定的资源文件
            FileSystemResource res = new FileSystemResource(new File(rscPath));
            helper.addInline(rscId, res);//添加附件,将rscId和res附件联系一起
            FileSystemResource res2 = new FileSystemResource(new File(rscPath2));
            helper.addInline(rscId2, res2);//添加附件,将rscId和res附件联系一起

            FileSystemResource file = new FileSystemResource(new File(filePath));
            //截取文件名
            String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
            helper.addAttachment(fileName, file);
           
            javaMailSender.send(message);//发送邮件

            System.out.println("复杂邮件发送成功");
        } catch (MessagingException e) {
            System.out.println("复杂邮件发送失败 " + e.getMessage());
            e.printStackTrace();
        }
    }

控制层

/**
     * 邮件任务(复杂邮件)
     * @return
     */
    @RequestMapping("/text4")
    public String sendEmail2(){
        String to  = "3451866342@qq.com";
        String subject  = "冯怡然-22610302150754";//标题
        StringBuilder builder = new StringBuilder();//页面
        builder.append("<html><head></head>");
        builder.append("<body><h1>今日农历二月十七日</h1>");
        builder.append("<body><h1>甲辰龙年-丁卯月-己丑日</h1>");
        String rscId = "img001";//图片id
        builder.append("<img src='cid:img001'/>");
        String rscPath = "C:\\Users\\Lenovo\\Desktop\\1.jpg";//图片路径
        String rscId2 = "img002";
        builder.append("<img src='cid:img002'/>");
        String rscPath2 = "C:\\Users\\Lenovo\\Desktop\\2.jpg";
        builder.append("<h3 color='red'>相信科学</h3>");
        builder.append("</body>");
        builder.append("</html>");
        String filePath = "E:\\Typora\\导出文件\\SpringBoot3的RabbitMQ消息服务.pdf";//文件路径
        sendEmailService.MailEmail(to, subject, builder.toString(), filePath,rscId, rscId2,rscPath, rscPath2);
        return "已发送完成";
    }

效果

32ed7792a647447c813edea58f376232.png

3bff79df5f5842d9b2ef6dd7f7f8b94a.png

 

  • 32
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

随便1007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值