Spring Boot 2 使用@Scheduled设置定时任务

Spring Boot 2 使用@Scheduled设置定时任务

背景

话说,不管是什么场景下,好像定时任务都是一个逃脱不开的话题。而恰好,我最近也遇到一个关于定时任务的功能。

我自己有一个小的平台,没多少访问量,也算是我修炼代码之路的试验田,这里也把网址写下resources.yangcloud.online。由于网站本身不会产生多少的访问量,而且里面的内容都是在网上可以找到且免费,就是找不到也可以免费申请到的。故此也没有做登录这样的功能。那么就不会有用户了。所以呢,平台虽然有后台,但是也是不需要登录验证直接可以访问的。

好吧,实际上我就是想贴一下我做的小平台。

废话不多说,正文来了。

最近遇到一个事情。因为网站进入后台不需要登录,直接可以操作。所以我就有的时候担心,会不会有的人闲的无聊,又恰好知道我的小平台,从而把数据都给清空呢。这个念头一起来,我就想。我的设置一个定时任务啊,能每天把这一天产生的数据都备份记录下来,这样我就不用担心了。如果以后了问题,直接恢复数据就好了。

那么问题来了,要实现我的想法,就需要有两个步骤了。第一是设置定时,到了时间自动把数据库的数据备份下来,或者放到别的数据库,或者放到文件中存储起来。第二是通过一种途径能把备份的数据或者备份的文件发送我这里来,这样就算是我的云服务器挂了,数据也还是能保留下来。

那怎么搞呢?我想到一个解决方案,用定时任务,将数据库(MySQL)内的数据通过导出语句导出到一个脚本中,随后等待一秒钟,再通过qq邮箱以附件的形式发送到我的邮箱里。当然了,发送人和收信人都是我自己的邮箱。也就相当于自己发给自己。

Code

备份数据

首先是要将数据库中的数据导出到文件中,这里使用mysqldump命令即可实现。具体命令:

mysqldump -uroot -proot --result-file=filename

这里面的参数的呢很简单。因为要备份数据就肯定要先能访问到数据,就要先登录。由于我的用户名和密码都是root,所以就在up的后面都加上root就可以了。后面的result-file参数是指导出的路径,一般就是填目标文件的绝对路径。比如说想导出到E:\\resources.sql,那么result-file后面直接等于这个路径地址就好了。不过,这个倒是会抛出一个异常,捕获一下就好了。

发送邮件附件

发送邮件实际上是用的javaMail。这个将java发送邮件的实体封装地很好了。直接用这个就ok了。想比之下,还是发送邮件则和部分的代码会略显复杂些。

    @Value("${email.port}")
    private String emailPort;

    @Value("${email.user}")
    private String emailUser;

    @Value("${email.password}")
    private String emailPassword;

    public void sendEmail(String copyUser, String filepath) throws Exception {

        // 创建Properties 类用于记录邮箱的一些属性
        Properties props = new Properties();

        // 表示SMTP发送邮件,必须进行身份验证
        props.put("mail.smtp.auth", "true");

        //此处填写SMTP服务器
        props.put("mail.smtp.host", "smtp.qq.com");

        //端口号
        props.put("mail.smtp.port", emailPort);

        // 此处填写你的账号
        props.put("mail.user", emailUser);

        // 此处的密码就是前面说的16位STMP口令
        props.put("mail.password", emailPassword);

        // 构建授权信息,用于进行SMTP进行身份验证

        Authenticator authenticator = new Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {

                // 用户名、密码
                String userName = props.getProperty("mail.user");
                String password = props.getProperty("mail.password");
                return new PasswordAuthentication(userName, password);
            }
        };

        // 使用环境属性和授权信息,创建邮件会话
        Session mailSession = Session.getInstance(props, authenticator);

        // 创建邮件消息
        MimeMessage message = new MimeMessage(mailSession);

        // 设置发件人
        InternetAddress form = new InternetAddress(props.getProperty("mail.user"));
        message.setFrom(form);

        // 设置收件人的邮箱
        InternetAddress to = new InternetAddress(copyUser);
        message.setRecipient(Message.RecipientType.TO, to);

        // 设置邮件标题

        // 创建附件“附件节点”
        MimeBodyPart attachment = new MimeBodyPart();

        // 读取本地文件
        DataHandler dh2 = new DataHandler(new FileDataSource(filepath));

        // 将附件数据添加到“节点”
        attachment.setDataHandler(dh2);

        // 设置附件的文件名(需要编码)
        attachment.setFileName(MimeUtility.encodeText(dh2.getName()));

        //设置整个邮件的关系(将最终的混合“节点”作为邮件的内容添加到邮件对象)
        MimeMultipart mm = new MimeMultipart();
        mm.addBodyPart(attachment);

        // 混合关系
        mm.setSubType("mixed");
        message.setSubject("资源数据备份");

        // 设置邮件的内容体
        message.setContent("资源数据备份", "text/html;charset=UTF-8");
        message.setContent(mm);

        //保存设置
        message.saveChanges();

        // 最后当然就是发送邮件啦
        Transport.send(message);

这里对参数简单地说明一下。email.port是指发送邮件使用的端口号,我是设置的587email.user是发送邮件的用户,谁发邮件写谁的邮箱号就可以里。email.password是指smtp的16位秘钥。用qq邮箱的话,在设置中开启一下就有。

定时任务

为了方便,我是将导出数据库数据和发送邮件都写成了工具类,这样随用随调就行。

那么关键的定时任务。实际上Spring Boot2也提供了定时器注解,@Scheduled就是了。

但是,单单只有这个注解也是不够的。需要在启动类上开启定时器,@EnableScheduling。比如:

@EnableScheduling
public class ResourcesApplication {

    public static void main(String[] args) {
        SpringApplication.run(ResourcesApplication.class, args);
    }

}

其次,需要一个组件类,用于Spring Boot自动加载到配置中。

@Component
public class EmailJob {

    @Value("${backup}")
    private String backup;

    @Autowired
    private EmailUtil emailUtil;

    @Scheduled(cron = "0 0 0 * * ?")
    public void autoSendEmail() throws Exception {
        System.out.println("当前时间为:" + new Date());
    }

}

这里呢,我将定时器写在了组件类中,用@component标志为组件。@Scheduled注解将方法标为定时任务。其中有几个参数cronfixedRatefixedDelayinitialDelay

我这里着重聊一聊cron这个参数。这个参数包含了6或7个域。分别对应的含义:

  • Seconds : 可出现", - * /"四个字符,有效范围为0-59的整数
  • Minutes : 可出现", - * /"四个字符,有效范围为0-59的整数
  • Hours : 可出现", - * /"四个字符,有效范围为0-23的整数
  • DayofMonth : 可出现", - * / ? L W C"八个字符,有效范围为0-31的整数
  • Month : 可出现", - * /"四个字符,有效范围为1-12的整数或JAN-DEc
  • DayofWeek : 可出现", - * / ? L C #"四个字符,有效范围为1-7的整数或SUN-SAT两个范围。1表示星期天,2表示星期一, 依次类推
  • Year : 可出现", - * /"四个字符,有效范围为1970-2099年

比如我贴的表达式的含义为每天凌晨0点执行。

感受

不管怎么说,定时任务都是挺重要的,另外向数据备份和邮件收发和邮件附件的收发也比较重要。还是多积累吧。就这样了。

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×