diff --git a/zyplayer-doc-data/src/main/java/com/zyplayer/doc/data/repository/manage/entity/BackupLog.java b/zyplayer-doc-data/src/main/java/com/zyplayer/doc/data/repository/manage/entity/BackupLog.java
new file mode 100644
index 00000000..be9afe2e
--- /dev/null
+++ b/zyplayer-doc-data/src/main/java/com/zyplayer/doc/data/repository/manage/entity/BackupLog.java
@@ -0,0 +1,93 @@
+package com.zyplayer.doc.data.repository.manage.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 备份记录信息
+ *
+ * @author diantu
+ * @since 2023年3月3日
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("backup_log")
+public class BackupLog implements Serializable {
+
+ /**
+ * 主键
+ */
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+ /**
+ * 数据源id
+ */
+ private Long dbId;
+ /**
+ * 来源(手动备份|自动备份)
+ */
+ private String category;
+ /**
+ * 库名
+ */
+ private String databaseName;
+ /**
+ * 表名
+ */
+ private String tablesName;
+ /**
+ * 备份方式
+ */
+ private Integer dataType;
+ /**
+ * 是否压缩
+ */
+ private Boolean isCompress;
+ /**
+ * 是否上传
+ */
+ private Boolean isUpload;
+ /**
+ * 是否删除
+ */
+ private Boolean isDelete;
+ /**
+ * 文件路径
+ */
+ private String filePath;
+ /**
+ * 文件大小
+ */
+ private Long fileSize;
+ /**
+ * 备份状态(-1-失败0-备份中1-上传中200-成功)
+ */
+ private Integer status;
+ /**
+ * 备份信息
+ */
+ private String msg;
+ /**
+ * 开始时间
+ */
+ private Date startTime;
+ /**
+ * 结束时间
+ */
+ private Date endTime;
+ /**
+ * 耗时(ms)
+ */
+ private Long spendTime;
+ /**
+ * 删除状态(0--未删除1--已删除)
+ */
+ private Integer delFlag;
+
+}
diff --git a/zyplayer-doc-data/src/main/java/com/zyplayer/doc/data/repository/manage/entity/BackupTask.java b/zyplayer-doc-data/src/main/java/com/zyplayer/doc/data/repository/manage/entity/BackupTask.java
new file mode 100644
index 00000000..33d65d19
--- /dev/null
+++ b/zyplayer-doc-data/src/main/java/com/zyplayer/doc/data/repository/manage/entity/BackupTask.java
@@ -0,0 +1,66 @@
+package com.zyplayer.doc.data.repository.manage.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 备份任务信息
+ *
+ * @author diantu
+ * @since 2023年3月3日
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName(value = "backup_task", autoResultMap = true)
+public class BackupTask implements Serializable {
+
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+ /**
+ * 数据源id
+ */
+ private Long dbId;
+ /**
+ * cron表达式
+ */
+ private String cron;
+ /**
+ * 参数
+ */
+ private String param;
+ /**
+ * 状态(0-停止1-启动)
+ */
+ private Boolean status;
+ /**
+ * 库名
+ */
+ private String databaseName;
+ /**
+ * 表名
+ */
+ private String tablesName;
+ /**
+ * 备份方式
+ */
+ private Integer dataType;
+ /**
+ * 备注
+ */
+ private String remark;
+ /**
+ * 创建时间
+ */
+ private Date createTime;
+ /**
+ * 删除状态(0--未删除1--已删除)
+ */
+ private Integer delFlag;
+
+}
diff --git a/zyplayer-doc-data/src/main/java/com/zyplayer/doc/data/utils/CleanInputCache.java b/zyplayer-doc-data/src/main/java/com/zyplayer/doc/data/utils/CleanInputCache.java
new file mode 100644
index 00000000..d0fb6e3f
--- /dev/null
+++ b/zyplayer-doc-data/src/main/java/com/zyplayer/doc/data/utils/CleanInputCache.java
@@ -0,0 +1,43 @@
+package com.zyplayer.doc.data.utils;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+/**
+ * 创建一个线程类来不停地来读出Process调用脚本的输出数据,防止缓冲区被缓冲数据塞满而线程阻塞
+ * @author diantu
+ * @since 2023年3月3日
+ */
+@Slf4j
+public class CleanInputCache extends Thread{
+
+ private final String type;
+ private final String charSet;
+ private final StringBuilder msg;
+ private final InputStream inputStream;
+
+ public CleanInputCache(InputStream inputStream, String type, String charSet, StringBuilder msg) {
+ this.type = type;
+ this.msg = msg;
+ this.charSet = charSet;
+ this.inputStream = inputStream;
+ }
+
+ public void run() {
+ try {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, charSet));
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+ if ("error".equals(type)) {
+ msg.append(line);
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/zyplayer-doc-db/pom.xml b/zyplayer-doc-db/pom.xml
index 51c5a99f..2854d88c 100644
--- a/zyplayer-doc-db/pom.xml
+++ b/zyplayer-doc-db/pom.xml
@@ -51,7 +51,12 @@
org.projectlombok
lombok
-
+
+ org.quartz-scheduler
+ quartz
+ 2.3.2
+
+
UTF-8
diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/enums/BackupCategoryEnum.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/enums/BackupCategoryEnum.java
new file mode 100644
index 00000000..eeeb6fdb
--- /dev/null
+++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/enums/BackupCategoryEnum.java
@@ -0,0 +1,39 @@
+package com.zyplayer.doc.db.framework.db.enums;
+
+import lombok.AllArgsConstructor;
+
+/**
+ * 备份类型枚举类
+ *
+ * @author diantu
+ * @since 2023年3月8日
+ */
+@AllArgsConstructor
+public enum BackupCategoryEnum {
+
+ /**
+ * 手动备份
+ */
+ MANUAL("0", "手动备份"),
+
+ /**
+ * 自动备份
+ */
+ AUTO("1", "自动备份");
+ /**
+ * 编码
+ */
+ private final String code;
+ /**
+ * 信息
+ */
+ private final String msg;
+
+ public String getCode() {
+ return code;
+ }
+
+ public String getMsg() {
+ return msg;
+ }
+}
diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/job/BackupJob.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/job/BackupJob.java
new file mode 100644
index 00000000..2bb3cacd
--- /dev/null
+++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/job/BackupJob.java
@@ -0,0 +1,34 @@
+package com.zyplayer.doc.db.framework.db.job;
+
+import com.alibaba.fastjson.JSONObject;
+import com.zyplayer.doc.data.repository.manage.entity.BackupLog;
+import com.zyplayer.doc.db.framework.db.vo.BackupJobVO;
+import com.zyplayer.doc.db.framework.utils.DatabaseBackupUtils;
+import com.zyplayer.doc.db.framework.utils.QuartzManagerUtils;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 数据库备份定时任务执行
+ *
+ * @author diantu
+ * @since 2023年2月8日
+ */
+public class BackupJob implements Job {
+
+ @Autowired
+ private DatabaseBackupUtils databaseBackupUtils;
+
+
+ @Override
+ public void execute(JobExecutionContext context) throws JobExecutionException {
+ // 解析参数
+ BackupJobVO jobVO = JSONObject.parseObject(context.getJobDetail().getJobDataMap().getString(QuartzManagerUtils.PARAM_KEY), BackupJobVO.class);
+ // TODO 保存备份记录
+ BackupLog backupLog = new BackupLog();
+ //开始备份
+ databaseBackupUtils.saveBackUp(jobVO, backupLog);
+ }
+}
diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/vo/BackupJobVO.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/vo/BackupJobVO.java
new file mode 100644
index 00000000..46b03181
--- /dev/null
+++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/vo/BackupJobVO.java
@@ -0,0 +1,62 @@
+package com.zyplayer.doc.db.framework.db.vo;
+
+import lombok.Data;
+
+/**
+ * 备份任务数据
+ *
+ * @author diantu
+ * @since 2023年3月3日
+ */
+@Data
+public class BackupJobVO {
+
+ /**
+ * 数据源ID
+ */
+ private Integer dbId;
+
+ /**
+ * 地址
+ */
+ private String host;
+ /**
+ * 端口号
+ */
+ private String port;
+ /**
+ * 用户名
+ */
+ private String username;
+ /**
+ * 密码
+ */
+ private String password;
+ /**
+ * 数据库名
+ */
+ private String databaseName;
+ /**
+ * 数据库表名
+ */
+ private String[] tables;
+ /**
+ * 备份形式
+ * 0-只备份表结构
+ * 1-只备份表数据
+ * 2-备份表结构+表数据
+ */
+ private Integer dataType;
+ /**
+ * 是否压缩
+ */
+ private Boolean isCompress = false;
+ /**
+ * 是否上传
+ */
+ private Boolean isUpload = false;
+ /**
+ * 是否删除
+ */
+ private Boolean isDelete = false;
+}
diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/vo/BackupRespVO.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/vo/BackupRespVO.java
new file mode 100644
index 00000000..83de4519
--- /dev/null
+++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/db/vo/BackupRespVO.java
@@ -0,0 +1,23 @@
+package com.zyplayer.doc.db.framework.db.vo;
+
+import lombok.Data;
+
+import java.io.File;
+
+/**
+ * 备份响应数据
+ *
+ * @author diantu
+ * @since 2023年3月3日
+ */
+@Data
+public class BackupRespVO {
+
+ private String msg;
+
+ private File file;
+
+ public boolean isSuccess() {
+ return null != this.file && 0 < this.file.length();
+ }
+}
diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/utils/DatabaseBackupUtils.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/utils/DatabaseBackupUtils.java
index 4b0d67d3..3000431b 100644
--- a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/utils/DatabaseBackupUtils.java
+++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/utils/DatabaseBackupUtils.java
@@ -1,7 +1,14 @@
package com.zyplayer.doc.db.framework.utils;
+import cn.hutool.core.util.IdUtil;
+import com.alibaba.excel.util.DateUtils;
+import com.zyplayer.doc.data.repository.manage.entity.BackupLog;
+import com.zyplayer.doc.data.utils.CleanInputCache;
+import com.zyplayer.doc.db.framework.db.vo.BackupJobVO;
+import com.zyplayer.doc.db.framework.db.vo.BackupRespVO;
+import org.springframework.scheduling.annotation.Async;
import java.io.*;
-import java.time.LocalDate;
+import java.util.Date;
/**
* 数据库备份恢复工具类
@@ -12,113 +19,211 @@ import java.time.LocalDate;
public class DatabaseBackupUtils {
/**
- * MySQL数据库导出
- *
- * @param hostIP MySQL数据库所在服务器地址IP
- * @param userName 进入数据库所需要的用户名
- * @param password 进入数据库所需要的密码
- * @param savePath 数据库导出文件保存路径
- * @param fileName 数据库导出文件文件名
- * @param databaseName 要导出的数据库名
- * @return 返回true表示导出成功,否则返回false。
+ * 项目路径
*/
- public static boolean exportDatabaseForMysql(String mysqldumpPath, String hostIP, String userName, String password, String savePath, String fileName, String databaseName) throws InterruptedException {
- File saveFile = new File(savePath);
- if (!saveFile.exists()) {// 如果目录不存在
- saveFile.mkdirs();// 创建文件夹
- }
- if(!savePath.endsWith(File.separator)){
- savePath = savePath + File.separator;
- }
+ public static final String PROJECT_PATH = System.getProperty("user.dir");
- PrintWriter printWriter = null;
- BufferedReader bufferedReader = null;
- try {
+ /**
+ * 当前系统类型
+ */
+ public static final String OS_NAME = System.getProperty("os.name");
- printWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(savePath + fileName), "utf8"));
- Process process = Runtime.getRuntime().exec(" "+mysqldumpPath+"/mysqldump -h" + hostIP + " -u" + userName + " -p" + password + " " + databaseName);
- InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream(), "utf8");
- bufferedReader = new BufferedReader(inputStreamReader);
- String line;
- while((line = bufferedReader.readLine())!= null){
- printWriter.println(line);
- }
- printWriter.flush();
- if(process.waitFor() == 0){//0 表示线程正常终止。
- return true;
- }
- }catch (IOException e) {
- e.printStackTrace();
- } finally {
- try {
- if (bufferedReader != null) {
- bufferedReader.close();
- }
- if (printWriter != null) {
- printWriter.close();
- }
- } catch (IOException e) {
- e.printStackTrace();
+ /**
+ * 编码格式
+ */
+ public static final String CHAR_SET = OS_NAME.startsWith("Win") ? "GBK" : "UTF-8";
+
+ /**
+ * 异步执行备份任务,更新备份记录
+ *
+ * @param jobVO 备份参数
+ * @param backupLog 备份记录
+ */
+ @Async
+ public void saveBackUp(BackupJobVO jobVO, BackupLog backupLog) {
+ // 执行备份
+ BackupRespVO respVO = doBackup(jobVO);
+ backupLog.setStatus(respVO.isSuccess() ? (jobVO.getIsUpload() ? 1 : 2) : -1);
+ backupLog.setMsg(respVO.getMsg());
+ // 备份成功
+ if (respVO.isSuccess()) {
+ // 文件相对路径
+ backupLog.setFilePath(respVO.getFile().getPath().replace(PROJECT_PATH + File.separator, ""));
+ backupLog.setFileSize(respVO.getFile().length());
+ }
+ // 备份失败
+ if (!respVO.isSuccess()) {
+ if (null != respVO.getFile()) {
+ respVO.getFile().delete();
}
}
- return false;
+ // 计算耗时
+ backupLog.setEndTime(new Date());
+ backupLog.setSpendTime(backupLog.getEndTime().getTime() - backupLog.getStartTime().getTime());
+ //@TODO 存入备份记录信息
+ // 备份文件上传至文件服务器
+ if (!jobVO.getIsUpload()) {
+ return;
+ }
+ //@TODO 备份文件上传至文件服务器
}
- public static void backup(String savePath) {
- File file = new File(savePath);
- if (!file.exists()) {
- file.mkdirs();
- }
- String fileName = savePath + "/" + LocalDate.now() + ".sql";
- /** 默认使用linux*/
- //String cmdPrefix = "/bin/sh -c ";
- String c1 = "/bin/sh";
- String c2 = "-c";
- String os_name = System.getProperty("os.name");
- // 判断是否是windows系统
- if (os_name.toLowerCase().startsWith("win")){
- //cmdPrefix = "cmd /c ";
- c1 = "cmd";
- c2 = "/c";
- }
- //参考示例:# /usr/local/mysql/bin/mysqldump -uroot -p123456 -P3306 shuju > shuju.sql
- String cmd = "mysqldump" // mysqldump的绝对路径,配置环境变量,直接写mysqldump即可
- + " -h" + "127.0.0.1" // 数据库端口号
- + " -P" + "3306" // 数据库端口号
- + " -u" + "root" // 数据库用户名
- + " -p" + "root" // 数据库密码
- + " " + "zyplayer_doc_manage" // 数据库名
- + " > " + fileName; // 最终写入的文件路径
+ /**
+ * 执行备份命令(mysql)
+ */
+ public static BackupRespVO doBackup(BackupJobVO jobVO) {
+ // 返回对象
+ BackupRespVO respVO = new BackupRespVO();
try {
- System.out.println("第一个参数 " + c1);
- System.out.println("第二个参数 " + c2);
- System.out.println("具体命令 " + cmd);
+ // 当前年月日yyyyMMdd
+ String date = DateUtils.format(new Date(),"yyyyMMdd");
+ // 文件目录
+ String path = PROJECT_PATH + File.separator + "static" + File.separator + date + File.separator;
+ // 文件名
+ String fileName = IdUtil.fastSimpleUUID() + ".sql" + (jobVO.getIsCompress() ? ".gz" : "");
+ // 创建文件
+ File file = new File(path, fileName);
+ // 路径不存在,则新建
+ if (!file.getParentFile().exists()) {
+ boolean flag = file.getParentFile().mkdirs();
+ if (!flag) {
+ respVO.setMsg("文件夹创建失败");
+ return respVO;
+ }
+ }
+ respVO.setFile(file);
+ // shell 命令脚本
+ String[] commands = createBackupCommandForMysql(jobVO, path, fileName);
- //log.error("数据库备份START" + LocalDateTime.now());
- /**
- * exec重载方法有一个参数的,window下执行正常,linux下无法完成备份。
- * 使用多参数重载方法都可以正常备份
- */
- Process process = Runtime.getRuntime().exec(new String[]{c1, c2, cmd});
- process.waitFor();
- //log.error("数据库备份END" + LocalDateTime.now());
+ ProcessBuilder processBuilder = new ProcessBuilder();
+ Process process = processBuilder.command(commands).start();
+ //Process process = Runtime.getRuntime().exec(commands);
+ // 创建一个线程类来不停地来读出Process调用脚本的输出数据,防止缓冲区被缓冲数据塞满而线程阻塞
+ new CleanInputCache(process.getInputStream(), "info", CHAR_SET, null).start();
+ // 错误信息
+ StringBuilder msg = new StringBuilder("【" + jobVO.getDatabaseName() + "】备份失败,原因:");
+ new CleanInputCache(process.getErrorStream(), "error", CHAR_SET, msg).start();
+ // 备份成功
+ if (process.waitFor() == 0) {
+ respVO.setMsg("备份成功");
+ }
+ // 备份失败
+ else {
+ respVO.setMsg(msg.toString());
+ }
} catch (Exception e) {
- e.printStackTrace();
- //log.error("数据库备份失败:{}", e.getMessage());
+ respVO.setMsg("【" + jobVO.getDatabaseName() + "】备份失败,原因:" + e.getMessage());
}
+ return respVO;
}
+ /**
+ * 创建命令头(只支持Windows平台和Linux平台)
+ */
+ public static String[] createBaseCommand() {
+ // shell 命令
+ String[] commands = new String[3];
+ if (OS_NAME.startsWith("Win")) {
+ commands[0] = "cmd.exe";
+ commands[1] = "/c";
+ } else {
+ commands[0] = "/bin/sh";
+ commands[1] = "-c";
+ }
+ return commands;
+ }
- public static void main(String[] args){
- try {
- if (exportDatabaseForMysql("C:/Program Files/MySQL/MySQL Server 5.7/bin","127.0.0.1", "root", "root", "D:/backupDatabase", "2023-2-8.sql", "zyplayer_doc_manage")) {
- System.out.println("数据库成功备份!!!");
- } else {
- System.out.println("数据库备份失败!!!");
+ /**
+ * 拼接备份命令(mysql)
+ *
+ * @param jobVO 备份参数
+ * @param path 备份文件目录
+ * @param fileName 备份文件名
+ */
+ public static String[] createBackupCommandForMysql(BackupJobVO jobVO, String path, String fileName) {
+ String[] commands = createBaseCommand();
+ // 拼接命令
+ StringBuilder mysqldump = new StringBuilder();
+ //需配置mysql安装路径bin目录环境变量
+ mysqldump.append("mysqldump");
+ mysqldump.append(" --opt");
+
+ // 用户,密码
+ mysqldump.append(" --user=").append(jobVO.getUsername());
+ mysqldump.append(" --password=\"").append(jobVO.getPassword()).append("\"");
+
+ // ip,端口
+ mysqldump.append(" --host=").append(jobVO.getHost());
+ mysqldump.append(" --port=").append(jobVO.getPort());
+
+ // 使用的连接协议,包括:tcp, socket, pipe, memory
+ mysqldump.append(" --protocol=tcp");
+
+ // 设置默认字符集,默认值为utf8
+ mysqldump.append(" --default-character-set=utf8");
+ // 在导出数据之前提交一个BEGIN SQL语句,BEGIN 不会阻塞任何应用程序且能保证导出时数据库的一致性状态
+ mysqldump.append(" --single-transaction=TRUE");
+
+ // 导出存储过程以及自定义函数
+ mysqldump.append(" --routines");
+ // 导出事件
+ mysqldump.append(" --events");
+
+ // 只备份表结构
+ if (null != jobVO.getDataType()) {
+ if (0 == jobVO.getDataType()) {
+ mysqldump.append(" --no-data");
+ }
+ // 只备份表数据
+ else if (1 == jobVO.getDataType()) {
+ mysqldump.append(" --no-create-info");
}
- } catch (InterruptedException e) {
- e.printStackTrace();
}
- //backup("D:/backupDatabase");
+
+ // 数据库名
+ mysqldump.append(" ").append(jobVO.getDatabaseName());
+
+ // 数据表名
+ if (null != jobVO.getTables() && 0 < jobVO.getTables().length) {
+ for (String item : jobVO.getTables()) {
+ mysqldump.append(" ").append(item);
+ }
+ }
+
+ // 保存文件路径
+ if (jobVO.getIsCompress()) {
+ // gzip压缩
+ mysqldump.append(" | gzip");
+ }
+ mysqldump.append(" > ").append(path).append(fileName);
+
+ commands[2] = mysqldump.toString();
+ return commands;
}
+
+ /**
+ * 拼接备份命令(oracle)
+ * @param jobVO 备份参数
+ * @param path 备份文件目录
+ * @param fileName 备份文件名
+ */
+ public static String[] createBackupCommandForOracle(BackupJobVO jobVO, String path, String fileName) {
+
+ String[] commands = createBaseCommand();
+ // 拼接命令
+ StringBuilder oracledump = new StringBuilder();
+ //需配置mysql安装路径bin目录环境变量
+ oracledump.append("expdp ");
+
+ // 用户,密码
+ oracledump.append(jobVO.getUsername());
+ oracledump.append("/").append(jobVO.getPassword());
+
+ //数据库名
+ oracledump.append("@").append(jobVO.getDatabaseName());
+ //@TODO 待完善
+
+ return commands;
+ }
+
}
diff --git a/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/utils/QuartzManagerUtils.java b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/utils/QuartzManagerUtils.java
new file mode 100644
index 00000000..5a523a12
--- /dev/null
+++ b/zyplayer-doc-db/src/main/java/com/zyplayer/doc/db/framework/utils/QuartzManagerUtils.java
@@ -0,0 +1,142 @@
+package com.zyplayer.doc.db.framework.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+
+/**
+ * quartz工具类
+ *
+ * @author diantu
+ * @since 2023年3月8日
+ */
+@Slf4j
+@Component
+public class QuartzManagerUtils {
+
+ /**
+ * 参数传递key
+ */
+ public static final String PARAM_KEY = "params";
+
+ /**
+ * 执行任务类名
+ */
+ public static final String CLASS_NAME = "com.zyplayer.doc.db.framework.db.job.BackupJob";
+
+ /**
+ * 程序调度器
+ */
+ @Autowired
+ private Scheduler scheduler;
+
+
+
+
+ /**
+ * 添加定时任务
+ */
+ public void add(Integer id, String cronExpression, String param, Boolean status) {
+ try {
+ // 构建job信息
+ JobDetail jobDetail = JobBuilder.newJob(getClass(CLASS_NAME).getClass()).withIdentity(getKey(id)).usingJobData(PARAM_KEY, param).build();
+ // 表达式调度构建器(即任务执行的时间)
+ CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
+ // 按新的cronExpression表达式构建一个新的trigger
+ CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getKey(id)).withSchedule(scheduleBuilder).build();
+ // 创建定时任务
+ scheduler.scheduleJob(jobDetail, trigger);
+ // 停止
+ if (!status) {
+ stop(id);
+ }
+ } catch (Exception e) {
+ log.error("添加定时任务失败:{}", e.getMessage());
+ }
+ }
+
+ /**
+ * 编辑定时任务
+ */
+ public void update(Integer id, String cronExpression, String param, Boolean status) {
+ try {
+ // 判断是否存在,存在先删除
+ if (scheduler.checkExists(JobKey.jobKey(getKey(id)))) {
+ scheduler.deleteJob(JobKey.jobKey(getKey(id)));
+ }
+ // 再创建
+ add(id, cronExpression, param, status);
+ } catch (Exception e) {
+ log.error("修改定时任务失败:{}", e.getMessage());
+ }
+ }
+
+ /**
+ * 暂停任务
+ */
+ public void stop(Integer id) {
+ try {
+ scheduler.pauseJob(JobKey.jobKey(getKey(id)));
+ } catch (SchedulerException e) {
+ // 暂停定时任务失败
+ log.error("暂停定时任务失败:{}", e.getMessage());
+ }
+ }
+
+ /**
+ * 恢复任务
+ */
+ public void start(Integer id) {
+ try {
+ scheduler.resumeJob(JobKey.jobKey(getKey(id)));
+ } catch (SchedulerException e) {
+ // 暂停定时任务失败
+ log.error("启动定时任务失败:{}", e.getMessage());
+ }
+ }
+
+ /**
+ * 立即执行一次
+ */
+ public void run(Integer id) {
+ try {
+ scheduler.triggerJob(JobKey.jobKey(getKey(id)));
+ } catch (SchedulerException e) {
+ // 暂停定时任务失败
+ log.error("执行定时任务失败:{}", e.getMessage());
+ }
+ }
+
+ /**
+ * 删除定时任务
+ */
+ public void delete(Integer id) {
+ try {
+ // 停止触发器
+ scheduler.pauseTrigger(TriggerKey.triggerKey(getKey(id)));
+ // 移除触发器
+ scheduler.unscheduleJob(TriggerKey.triggerKey(getKey(id)));
+ // 删除任务
+ scheduler.deleteJob(JobKey.jobKey(getKey(id)));
+ } catch (Exception e) {
+ log.error("删除定时任务失败:{}", e.getMessage());
+ }
+ }
+
+ /**
+ * 根据类名获取类
+ */
+ private Job getClass(String className) throws Exception {
+ Class> class1 = Class.forName(className);
+ return (Job) class1.newInstance();
+ }
+
+ /**
+ * 拼接key
+ */
+ public String getKey(Integer id) {
+ return "dbBackUp-" + id;
+ }
+}
diff --git a/zyplayer-doc-manage/src/main/resources/sql/full/full.sql b/zyplayer-doc-manage/src/main/resources/sql/full/full.sql
index d541b1eb..5c436b2d 100644
--- a/zyplayer-doc-manage/src/main/resources/sql/full/full.sql
+++ b/zyplayer-doc-manage/src/main/resources/sql/full/full.sql
@@ -405,6 +405,42 @@ CREATE TABLE `system_config` (
PRIMARY KEY (`id`)
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT ='系统配置表';
+CREATE TABLE `backup_log` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键自增ID',
+ `dbId` bigint(20) NULL DEFAULT NULL COMMENT '数据源ID',
+ `category` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '来源(手动备份|自动备份)',
+ `database_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '库名',
+ `tables_name` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '表名',
+ `data_type` tinyint(1) NULL DEFAULT NULL COMMENT '备份方式',
+ `is_compress` tinyint(1) NULL DEFAULT NULL COMMENT '是否压缩',
+ `is_upload` tinyint(1) NULL DEFAULT NULL COMMENT '是否上传',
+ `is_delete` tinyint(1) NULL DEFAULT NULL COMMENT '是否删除',
+ `file_path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件路径',
+ `file_size` bigint(20) NULL DEFAULT NULL COMMENT '文件大小',
+ `status` tinyint(1) NULL DEFAULT NULL COMMENT '备份状态(-1-失败0-备份中1-上传中2-成功)',
+ `msg` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '返回信息',
+ `start_time` datetime(0) NULL DEFAULT NULL COMMENT '开始时间',
+ `end_time` datetime(0) NULL DEFAULT NULL COMMENT '结束时间',
+ `spend_time` bigint(20) NULL DEFAULT NULL COMMENT '耗时(ms)',
+ `del_flag` tinyint(1) NULL DEFAULT NULL COMMENT '删除状态(0--未删除1--已删除)',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT ='备份记录表';
+
+CREATE TABLE `backup_task` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '备份任务信息主键',
+ `dbId` bigint(20) NULL DEFAULT NULL COMMENT '数据源ID',
+ `cron` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'cron表达式',
+ `param` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '参数',
+ `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0-停止1-启动)',
+ `database_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '库名',
+ `tables_name` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '表名',
+ `data_type` tinyint(1) NULL DEFAULT NULL COMMENT '备份方式',
+ `remark` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
+ `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
+ `del_flag` tinyint(4) NULL DEFAULT NULL COMMENT '删除状态(0--未删除1--已删除)',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '备份任务信息';
+
-- -------------------插入必要的数据-------------------
-- 用户信息
INSERT INTO `user_info` (id, user_no, password, user_name, email, del_flag, creation_time, update_time, sex)