背景
话说,不管是什么场景下,好像定时任务都是一个逃脱不开的话题。而恰好,我最近也遇到一个关于定时任务的功能。
我自己有一个小的平台,没多少访问量,也算是我修炼代码之路的试验田,这里也把网址写下resources.yangcloud.online。由于网站本身不会产生多少的访问量,而且里面的内容都是在网上可以找到且免费,就是找不到也可以免费申请到的。故此也没有做登录这样的功能。那么就不会有用户了。所以呢,平台虽然有后台,但是也是不需要登录验证直接可以访问的。
好吧,实际上我就是想贴一下我做的小平台。
废话不多说,正文来了。
最近遇到一个事情。因为网站进入后台不需要登录,直接可以操作。所以我就有的时候担心,会不会有的人闲的无聊,又恰好知道我的小平台,从而把数据都给清空呢。这个念头一起来,我就想。我的设置一个定时任务啊,能每天把这一天产生的数据都备份记录下来,这样我就不用担心了。如果以后了问题,直接恢复数据就好了。
那么问题来了,要实现我的想法,就需要有两个步骤了。第一是设置定时,到了时间自动把数据库的数据备份下来,或者放到别的数据库,或者放到文件中存储起来。第二是通过一种途径能把备份的数据或者备份的文件发送我这里来,这样就算是我的云服务器挂了,数据也还是能保留下来。
那怎么搞呢?我想到一个解决方案,用定时任务,将数据库(MySQL)内的数据通过导出语句导出到一个脚本中,随后等待一秒钟,再通过qq邮箱以附件的形式发送到我的邮箱里。当然了,发送人和收信人都是我自己的邮箱。也就相当于自己发给自己。
Code
备份数据
首先是要将数据库中的数据导出到文件中,这里使用mysqldump
命令即可实现。具体命令:
mysqldump -uroot -proot --result-file=filename
这里面的参数的呢很简单。因为要备份数据就肯定要先能访问到数据,就要先登录。由于我的用户名和密码都是root
,所以就在u
和p
的后面都加上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
是指发送邮件使用的端口号,我是设置的587
。email.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
注解将方法标为定时任务。其中有几个参数cron
、fixedRate
、fixedDelay
、initialDelay
。
我这里着重聊一聊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点执行。
感受
不管怎么说,定时任务都是挺重要的,另外向数据备份和邮件收发和邮件附件的收发也比较重要。还是多积累吧。就这样了。