2022-05-09 18:00:02
这两天完成了数据库的定期备份业务实现,以及一些无需提及的前端页面bug更正。
因为以后可能会有不少的定期任务,如果仍然放在service目录层级下,会显得比较乱,所以决定放在了新的包schedule中。以后所有的schedule都放在这个目录层级下,方便管理,顺便截了一张当前项目的目录结构:
接下来是看一下这节的主题给springboot设置定期计划,首先,在启动类也就是DreamcenterApplication加上注解@EnableScheduling来启动定时计划的功能。然后对于mysql的定时备份代码如下:
package top.dreamcenter.dreamcenter.schedule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import top.dreamcenter.dreamcenter.entity.ServerProperties;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Calendar;
@Component
public class MysqlSchedule {
private ServerProperties properties;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Autowired
public MysqlSchedule(ServerProperties properties) {
this.properties = properties;
}
// save data to imgBaseLocPath / mysql_bak / ...
@Scheduled(cron = "0 0 3 * * ?")
public void dump() {
System.out.println("schedule [dump] run ...");
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String time = sdf.format(Calendar.getInstance().getTime());
String path = properties.getLocalImgPath() + "mysql_bak/";
String fileName = time + ".sql";
File file = new File(path);
if (file.exists() || file.mkdirs()) {
BufferedReader bufferedReader = null;
FileOutputStream fos = null;
try {
String cmd = String.format("mysqldump -u%s -p%s dreamcenter",
username, password);
Process exec = Runtime.getRuntime().exec(cmd);
System.out.println("schedule [dump] write result ...");
bufferedReader = new BufferedReader(
new InputStreamReader(exec.getInputStream()));
String temp;
StringBuilder sb = new StringBuilder();
while((temp = bufferedReader.readLine())!=null){
sb.append(temp).append("\n");
}
fos = new FileOutputStream(path + fileName);
fos.write(sb.toString().getBytes());
bufferedReader.close();
fos.close();
System.out.println("schedule [dump] write done!");
} catch (IOException e) {
System.out.println("schedule [dump] write failed!");
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ioException) {
System.out.println("--schedule [dump] bufferedReader");
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
}
}
使用java的exec()来执行命令mysqldump【前提是该命令已经在全局环境变量中,否则需要配置填写详细的mysqldump地址执行】,然后将结果从输入流读取并且写入本地的文件中。目前导出的文件大小约莫200k,不算很大,所以就不实现自动删除久远日志的功能了,直接我全都要!
当然光就是这些的话会有非常严重的问题,因为该保存的基准路径被设置成了静态资源路径(本地图片备份后备路径需要),所以如果不对mysql_bak/进行拦截,那么这些备份文件将会被别人轻易的拿到,虽然现在没有什么特别重要的数据在库中,但是如果还是不能留下不必要的开放接口。所以同样的,需要给一个拦截注册器添加一个拦截路由,即 register.addPathPatterns("/mysql_bak/*"); 这样来防范一些意外的产生。
目前在本地测试通过了,可以实现定期备份,服务器上是否生效需要等明天凌晨三点,一定要成功欸!