记得第一步将mysql的bin目录加入path系统变量!
pom依赖:
<!-- 定时任务 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
spring-mvc.xml开头处增加:
<task:annotation-driven executor="executor" scheduler="scheduler" />
创建spring-schedule.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd" default-lazy-init="true">
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="configLocation" value="classpath:quartz-production.properties"></property>
</bean>
</beans>
创建quartz-production.properties:
org.quartz.scheduler.skipUpdateCheck = true
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 4
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
application.properties中添加:
backup.isQuartz=true
backup.core=6 6 6 * * ?
backup.filepath=x:\\xxx\\xxx
创建MessageQuartzStartModel.java:
package com.fuhai.platform.utils.message.web.controller;
public class MessageQuartzStartModel {
private boolean isStart;
private String coreStr;
public boolean isStart() {
return isStart;
}
public void setStart(boolean isStart) {
this.isStart = isStart;
}
public String getCoreStr() {
return coreStr;
}
public void setCoreStr(String coreStr) {
this.coreStr = coreStr;
}
}
创建QuartzManager.java:
package com.fuhai.platform.utils.message.quartz;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzManager {
private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();
/**
* @Description: 添加一个定时任务
*
* @param jobName 任务名
* @param jobGroupName 任务组名
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param jobClass 任务
* @param cron 时间设置,参考quartz说明文档
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName,
Class jobClass, String cron) {
try {
Scheduler sched = schedulerFactory.getScheduler();
// 任务名,任务组,任务执行类
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
CronTrigger trigger = (CronTrigger) triggerBuilder.build();
// 调度容器设置JobDetail和Trigger
sched.scheduleJob(jobDetail, trigger);
// 启动
if (!sched.isShutdown()) {
sched.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 修改一个任务的触发时间
*
* @param jobName
* @param jobGroupName
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param cron 时间设置,参考quartz说明文档
*/
public static void modifyJobTime(String jobName, String jobGroupName, String triggerName, String triggerGroupName,
String cron) {
try {
Scheduler sched = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(cron)) {
/** 方式一 :调用 rescheduleJob 开始 */
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
trigger = (CronTrigger) triggerBuilder.build();
// 方式一 :修改一个任务的触发时间
sched.rescheduleJob(triggerKey, trigger);
/** 方式一 :调用 rescheduleJob 结束 */
/** 方式二:先删除,然后在创建一个新的Job */
// JobDetail jobDetail =
// sched.getJobDetail(JobKey.jobKey(jobName, jobGroupName));
// Class<? extends Job> jobClass = jobDetail.getJobClass();
// removeJob(jobName, jobGroupName, triggerName,
// triggerGroupName);
// addJob(jobName, jobGroupName, triggerName, triggerGroupName,
// jobClass, cron);
/** 方式二 :先删除,然后在创建一个新的Job */
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 移除一个任务
*
* @param jobName
* @param jobGroupName
* @param triggerName
* @param triggerGroupName
*/
public static void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) {
try {
Scheduler sched = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
sched.pauseTrigger(triggerKey);// 停止触发器
sched.unscheduleJob(triggerKey);// 移除触发器
sched.deleteJob(JobKey.jobKey(jobName, jobGroupName));// 删除任务
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:启动所有定时任务
*/
public static void startJobs() {
try {
Scheduler sched = schedulerFactory.getScheduler();
sched.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:关闭所有定时任务
*/
public static void shutdownJobs() {
try {
Scheduler sched = schedulerFactory.getScheduler();
if (!sched.isShutdown()) {
sched.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
创建SendMessageQuartzTaskListener.java:
package com.fuhai.platform.utils.message.quartz;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Service;
import com.fuhai.platform.utils.message.web.controller.MessageQuartzStartModel;
@Service
public class SendMessageQuartzTaskListener implements ApplicationListener<ContextRefreshedEvent>{
@Value("${backup.isQuartz:false}")
private boolean backupIsQuartz; // 是否开启数据库备份自动任务
@Value("${backup.core:6 6 6 * * ?}")
private String backupCore; // 自动任务时间
private boolean isInit = false; // 防止启动时加载两次
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (!this.isInit) {
this.isInit = true;
MessageQuartzStartModel backupModel = new MessageQuartzStartModel();
backupModel.setStart(backupIsQuartz);
backupModel.setCoreStr(backupCore);
SendMessageQuartzTaskManager.startTask(backupModel);
}
}
}
创建SendMessageQuartzTaskManager.java:
package com.fuhai.platform.utils.message.quartz;
import com.fuhai.platform.utils.message.web.controller.MessageQuartzStartModel;
public class SendMessageQuartzTaskManager {
private static String JOB_GROUP_NAME = "MESSAGE_SEND_GROUP";
private static String TRIGGER_GROUP_NAME = "MESSAGE_SEND_JOB_GROUP";
private static String BACKUP_SEND_JOB_NAME = "数据库备份发送定时任务";
private static String BACKUP_SEND_TRIGGER_NAME = "数据库备份发送定动态任务触发器";
/**
*
* @Title: startTask
* @Description:(装载并启动自动任务)
* @author ch
* @return void 返回类型
*/
public static void startTask(MessageQuartzStartModel backupModel) {
if (backupModel.isStart()) {
// 装载数据库备份自动发送任务
QuartzManager.addJob(BACKUP_SEND_JOB_NAME, JOB_GROUP_NAME, BACKUP_SEND_TRIGGER_NAME, TRIGGER_GROUP_NAME,
com.xxxxxxxxxx.quartz.SendBackupQuartzTask.class, backupModel.getCoreStr());
}
if (backupModel.isStart()) {
QuartzManager.startJobs();
}
}
/**
* @Title: shutdownTask
* @Description:(卸载自动任务)
* @author ch
* @return void 返回类型
*/
public static void shutdownTask() {
// 卸载自动任务
QuartzManager.removeJob(BACKUP_SEND_JOB_NAME, JOB_GROUP_NAME, BACKUP_SEND_TRIGGER_NAME, TRIGGER_GROUP_NAME);
QuartzManager.shutdownJobs();
}
}
创建SendBackupQuartzTask.java:
package com.fuhai.platform.utils.message.quartz;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.stereotype.Component;
/**
*
* @author ch
*
* @Date: 2020/02/25 15:40:10
*
*/
@Component
public class SendBackupQuartzTask implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//这里放逻辑
//BackUpUtil.getInstance().BackUpToFile();
}
}
数据库备份工具类BackUpUtil.java:
package com.fuhai.platform.utils.message.quartz;
import com.fuhai.platform.core.encrypt.ThreeDESUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* 数据库备份工具类
*/
public class BackUpUtil {
public static BackUpUtil instance;
private static String backupFilepath;
public static BackUpUtil getInstance() {
if (backupFilepath==null||backupFilepath.length()==0){
ResourceBundle rb = ResourceBundle.getBundle("application-dev"); //其中“application-dev”为project.properties文件的前缀名,在方法中获取时不需要添加.properties结尾
backupFilepath = rb.getString("backup.filepath");//uploadPath.path为值对应的键
}
if(instance == null){
instance = new BackUpUtil();
}
return instance;
}
/**
* 获取已经备份的文件列表
* @return
*/
public List<Map<String,Object>> getBackupFilesInfo(){
List<Map<String,Object>> infolist = new ArrayList<Map<String, Object>>();
List<File> list = getFileSort(backupFilepath);
Map<String,Object> map;
for (File file:list){
map = new HashMap<String, Object>(5);
map.put("fileName",file.getName());
map.put("fileSize",renderFileSize(file.length()));
map.put("createTime", new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ).format(new Date(file.lastModified())));
infolist.add(map);
}
return infolist;
}
/**
* 下载备份文件
* @param fileName
* @param request
* @param response
*/
public void downloadBackupFile(String fileName,HttpServletRequest request,HttpServletResponse response){
if (fileName!=null&&fileName.endsWith(".sql")&&!fileName.contains("/")&&!fileName.contains("\\")){
File file = new File(backupFilepath+File.separator+fileName);
try{
if (file.exists()){
// 如果是IE浏览器,则用URLEncode解析
if (isMSBrowser(request)) {
fileName = URLEncoder.encode(fileName, "UTF-8");
fileName = fileName.replace("+", " ");
} else {// 如果是谷歌、火狐则解析为ISO-8859-1
fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
}
response.setContentType("application/x-msdownload");
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Length", String.valueOf(file.length()));
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
byte[] buff = new byte[(int) file.length()];
int offset = 0;
int numRead = 0;
while (offset < buff.length && (numRead = bis.read(buff, offset, buff.length - offset)) >= 0) {
offset += numRead;
}
bis.close();
bos.write(buff);
bos.close();
}else{
response.getWriter().print("This file does not exist!");
}
}catch (Exception e){}
}
}
public boolean isMSBrowser(HttpServletRequest request) {
String[] IEBrowserSignals = { "MSIE", "Trident", "Edge" };
String userAgent = request.getHeader("User-Agent");
for (String signal : IEBrowserSignals) {
if (userAgent.contains(signal)) {
return true;
}
}
return false;
}
/**
* 备份数据库到一个文件
*/
public void BackUpToFile(){
new Thread(new Runnable() {
@Override
public void run() {
try {
List<File> list = getFileSort(backupFilepath);
if (list.size()>30){//删除30以上的旧的sql数据
try{
for (int i = 30; i < list.size(); i++) {
list.get(i).delete();
}
}catch (Exception e){
System.out.println("backup error:old SQL files removal error!");
}
}
String hostIP = "127.0.0.1";
String port = "3306";
String databaseName = "db_name";
String userName = "root";
String password = "123456";
Process process = Runtime.getRuntime().exec(" mysqldump -h" + hostIP +
" -p"+port+" -u" + userName + " -p" + password + " --set-charset=UTF8 " + databaseName);
InputStream inputStream = process.getInputStream();
String fileName = "数据库_"+databaseName+"_"+ new SimpleDateFormat( "yyyyMMdd_HHmmss" ).format(new Date())+".sql";
File dir = new File(backupFilepath);
if (!dir.exists()){
dir.mkdirs();
}
FileOutputStream out = new FileOutputStream(backupFilepath+File.separator+fileName);
int len = 0;
byte[] buffer = new byte[1024];
while ((len = inputStream.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
inputStream.close();
out.close();
File backupFile = new File(backupFilepath+File.separator+fileName);
if (backupFile.length()>2000){
System.out.println("backup msg:backup success! "+new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ).format(new Date()));
}else{
System.out.println("backup error:The backup file is too small, please check if the backup was successful!? "+new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ).format(new Date()));
}
}catch (Exception e){
e.printStackTrace();
System.out.println("backup error:Automatic database backup failed "+new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ).format(new Date())+" , error msg:"+e.toString());
}
}
}).start();
}
/**
* 文件大小格式化
* @param fileSize
* @return
*/
public String renderFileSize(Long fileSize) {
String[] arr = {"Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
float srcsize = Float.valueOf(fileSize);
int index = (int) (Math.floor(Math.log(srcsize) / Math.log(1024)));
double size = srcsize / Math.pow(1024, index);
size = Double.valueOf(new DecimalFormat("#.00").format(size));
return size + arr[index];
}
/**
* 获取目录下所有文件(按时间排序)
*
* @param path
* @return
*/
public static List<File> getFileSort(String path) {
List<File> list = getFiles(path, new ArrayList<File>());
if (list != null && list.size() > 0) {
Collections.sort(list, new Comparator<File>() {
public int compare(File file, File newFile) {
if (file.lastModified() < newFile.lastModified()) {
return 1;
} else if (file.lastModified() == newFile.lastModified()) {
return 0;
} else {
return -1;
}
}
});
}
return list;
}
/**
*
* 获取目录下所有文件
*
* @param realpath
* @param files
* @return
*/
public static List<File> getFiles(String realpath, List<File> files) {
File realFile = new File(realpath);
if (realFile.isDirectory()) {
File[] subfiles = realFile.listFiles();
for (File file : subfiles) {
if (file.isDirectory()) {
getFiles(file.getAbsolutePath(), files);
} else {
files.add(file);
}
}
}
return files;
}
}