1.环境配置
检查mysql环境变量
部分字符串用hutool工具类校验
2.工具类
1.Constants工具类
public class Constants {
/**
* 文件后缀
*/
public static final String FILE_SUFFIX = ".sql";
/**
* 数据库的名称
*/
public static final String DATA_BASE_NAME = "库名称";
/**
* 判断操作系统类型、Linux|Windows
*/
public static boolean isSystem(String osName) {
Boolean flag = null;
if (osName.startsWith("windows")) {
flag = true;
} else if (osName.startsWith("linux")) {
flag = false;
}
return flag;
}
}
2. 全局异常工具类
/**
* 封装异常
*
* @author cyx
* @date 2020年4月2日
*/
public class MyException extends RuntimeException {
private static final long serialVersionUID = 3702096961571375727L;
@Getter
private Integer code;
private String message;
public MyException(String message) {
this.code = 1;
this.message = message;
}
public MyException(ExceptionEnum exceptionEnum) {
this.code = exceptionEnum.getCode();
this.message = exceptionEnum.getMessage();
}
public MyException code(Integer code) {
this.code = code;
return this;
}
@Override
public String getMessage() {
return message;
}
}
3.数据库
CREATE TABLE IF NOT EXISTS `mysql_backups` (
`id` INT ( 11 ) NOT NULL AUTO_INCREMENT COMMENT '主键id',
`mysql_ip` VARCHAR ( 15 ) DEFAULT NULL COMMENT '数据库IP',
`mysql_port` VARCHAR ( 5 ) DEFAULT NULL COMMENT '数据库端口',
`mysql_cmd` VARCHAR ( 230 ) DEFAULT NULL COMMENT '备份命令',
`mysql_back_cmd` VARCHAR ( 230 ) DEFAULT NULL COMMENT '恢复命令',
`database_name` VARCHAR ( 20 ) DEFAULT NULL COMMENT '数据库名称',
`backups_path` VARCHAR ( 50 ) DEFAULT NULL COMMENT '备份数据地址',
`backups_name` VARCHAR ( 50 ) DEFAULT NULL COMMENT '备份文件名称',
`operation` INT ( 11 ) DEFAULT NULL COMMENT '操作次数',
`status` INT ( 1 ) DEFAULT NULL COMMENT '数据状态(1正常,-1删除)',
`recovery_time` DATETIME DEFAULT NULL COMMENT '恢复时间',
`create_time` DATETIME DEFAULT NULL COMMENT '备份时间',
PRIMARY KEY ( `id` ),
INDEX baskups_index ( mysql_ip, mysql_port, backups_path, database_name,backups_name) USING BTREE COMMENT '索引'
) ENGINE = INNODB AUTO_INCREMENT = 1 CHARSET = UTF8 ROW_FORMAT = COMPACT COMMENT = 'MySQL数据备份表';
4.代码生成器
public class AutoCodeGenerator {
String url = "jdbc:mysql://localhost:3306/"库名称"?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai";
String username = "";
String password = "";
@Test
void Generator() {
String projectPath = System.getProperty("user.dir");
FastAutoGenerator.create(url, username, password)
.globalConfig(builder -> {
builder.author("cyx") // 设置作者
.enableSwagger() // 开启 swagger 模式
.disableOpenDir() // 生成后是否打开资源管理器
.dateType(DateType.ONLY_DATE) // 设置日期类型
.outputDir(projectPath + "/src/main/java"); // 指定输出目录
})
.packageConfig(builder -> {
builder.parent("com.公司名.项目名称") // 设置父包名
// .moduleName("base") // 设置父包模块名
.controller("controller") // 结构包名
.entity("entity")
.mapper("mapper")
.service("service")
.serviceImpl("service.impl")
.pathInfo(Collections.singletonMap(OutputFile.xml, projectPath + "/src/main/resources/mapper")); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude("mysql_backups") // 设置需要生成的表名
.addTablePrefix("") // 设置过滤表前缀
// Entity 策略配置
.entityBuilder()
.enableLombok() //开启 Lombok
.enableFileOverride() // 覆盖已生成文件
.naming(NamingStrategy.underline_to_camel) //数据库表映射到实体的命名策略:下划线转驼峰命
.columnNaming(NamingStrategy.underline_to_camel) //数据库表字段映射到实体的命名策略:下划线转驼峰命
// Mapper 策略配置
.mapperBuilder()
// .enableFileOverride() // 覆盖已生成文件
// Service 策略配置
.serviceBuilder()
// .enableFileOverride() // 覆盖已生成文件
.formatServiceFileName("%sService") //格式化 service 接口文件名称,%s进行匹配表名,如 UserService
.formatServiceImplFileName("%sServiceImpl") //格式化 service 实现类文件名称,%s进行匹配表名,如 UserServiceImpl
// Controller 策略配置
.controllerBuilder()
// .enableFileOverride() // 覆盖已生成文件
.enableRestStyle(); // 开启 Restfull
})
.templateEngine(new VelocityTemplateEngine()) // 使用Velocity引擎模板
.execute();
}
}
5.控制层
/**
* <p>
* MySQL数据备份表 前端控制器
* </p>
*
* @author cyx
* @since 2023-09-05
*/
@RestController
@RequestMapping("/backups")
@Api(tags = "MySQL数据备份操作")
@Slf4j
public class MysqlBackupsController {
/**
* 数据库用户名
*/
@Value("${spring.datasource.username}")
private String userName;
/**
* 数据库密码
*/
@Value("${spring.datasource.password}")
private String password;
/**
* 数据库url
*/
@Value("${spring.datasource.url}")
private String url;
/**
* Windows数据库备份地址
*/
@Value("${spring.datasource.win-path}")
private String windowsPath;
/**
* Linux数据库备份地址
*/
@Value("${spring.datasource.linux-path}")
private String linuxPath;
@Autowired
private MysqlBackupsService mysqlBackupsService;
@ApiOperation(value = "获取所有备份数据列表")
@GetMapping("/backupsList")
public Object backupsList() {
List<MysqlBackups> mysqlBackups = mysqlBackupsService.selectBackupsList();
return R.ok().data("data", mysqlBackups);
}
@ApiOperation(value = "MySQL备份")
@PostMapping("/mysqlBackups")
public Object mysqlBackups() {
String path = null;
// 获取操作系统名称
String osName = System.getProperty("os.name").toLowerCase();
if (Constants.isSystem(osName)) {
// Windows
path = this.windowsPath;
} else {
// Linux
path = this.linuxPath;
}
// 数据库用户名
String userName = this.userName;
// 数据库密码
String password = this.password;
// 数据库地址
String url = this.url;
// 调用备份
Object mysqlBackups = mysqlBackupsService.mysqlBackups(path, url, userName, password);
return R.ok().data("data", mysqlBackups);
}
@ApiOperation(value = "恢复数据库")
@GetMapping("/rollback/{id}")
public Object rollback(@PathVariable String id) {
if (StrUtil.isEmpty(id)) {
return new MyException("id不能为空,请重新尝试!");
}
// 数据库用户名
String userName = this.userName;
// 数据库密码
String password = this.password;
// 根据id查询查询已有的信息
MysqlBackups smb = mysqlBackupsService.selectListId(id);
// 恢复数据库
Object rollback = mysqlBackupsService.rollback(smb, userName, password);
// 更新操作次数
mysqlBackupsService.updateById(smb);
return R.ok().data("data", rollback);
}
6.service实现类
@Resource
private MysqlBackupsMapper mysqlBackupsMapper;
@Override
public List<MysqlBackups> selectBackupsList() {
return mysqlBackupsMapper.selectList(null);
}
@Override
public Object mysqlBackups(String filePath, String url, String userName, String password) {
// 获取IP地址、端口号和数据库名称
final String prefix = "jdbc:mysql://";
final int prefixLength = prefix.length();
final int ipStart = url.indexOf(prefix) + prefixLength;
final int portEnd = url.indexOf("/", ipStart);
final int portStart = url.lastIndexOf(":", portEnd - 1) + 1;
final int dbNameEnd = url.indexOf("?", portEnd);
final String ip = url.substring(ipStart, portStart - 1);
final String port = url.substring(portStart, portEnd);
final String database_name = url.substring(portEnd + 1, dbNameEnd);
// 输出结果
System.out.println("IP地址:" + ip);
System.out.println("端口号:" + port);
System.out.println("数据库名称:" + database_name);
// 数据库文件名称
StringBuilder mysqlFileName = new StringBuilder()
.append(database_name)
.append("_")
.append(DateUtil.format(new Date(), "yyyy-MM-dd-HH-mm-ss"))
.append(Constants.FILE_SUFFIX);
// 备份命令
StringBuilder cmd = new StringBuilder()
.append("mysqldump ")
.append("--no-tablespaces ")
.append("-h")
.append(ip)
.append(" -u")
.append(userName)
.append(" -p")
.append(password)
// 排除MySQL备份表
.append(" --ignore-table ")
.append(database_name)
.append(".mysql_backups ")
.append(database_name)
.append(" > ")
.append(filePath)
.append(mysqlFileName);
// 判断文件是否保存成功
if (!FileUtil.exist(filePath)) {
FileUtil.mkdir(filePath);
return new MyException("备份失败,文件保存异常,请查看文件内容后重新尝试!");
}
// 获取操作系统名称
String osName = System.getProperty("os.name").toLowerCase();
String[] command = new String[0];
if (Constants.isSystem(osName)) {
// Windows
command = new String[]{"cmd", "/c", String.valueOf(cmd)};
} else {
// Linux
command = new String[]{"/bin/sh", "-c", String.valueOf(cmd)};
}
MysqlBackups smb = new MysqlBackups();
// 备份信息存放到数据库
smb.setMysqlIp(ip);
smb.setMysqlPort(port);
smb.setBackupsName(String.valueOf(mysqlFileName));
smb.setDatabaseName(database_name);
smb.setMysqlCmd(String.valueOf(cmd));
smb.setBackupsPath(filePath);
smb.setCreateTime(DateTime.now());
smb.setStatus(1);
smb.setOperation(0);
mysqlBackupsMapper.insert(smb);
log.error("数据库备份命令为:{}", cmd);
// 获取Runtime实例
Process process = null;
try {
process = Runtime.getRuntime().exec(command);
if (process.waitFor() == 0) {
log.info("Mysql 数据库备份成功,备份文件名:{}", mysqlFileName);
} else {
return new MyException(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
} catch (Exception e) {
e.printStackTrace();
return new MyException(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
return smb;
}
@Override
public MysqlBackups selectListId(String id) {
return mysqlBackupsMapper.selectById(id);
}
@Override
public Object rollback(MysqlBackups smb, String userName, String password) {
// 备份路径和文件名
StringBuilder realFilePath = new StringBuilder().append(smb.getBackupsPath()).append(smb.getBackupsName());
if (!FileUtil.exist(String.valueOf(realFilePath))) {
return new MyException("文件不存在,恢复失败,请查看目录内文件是否存在后重新尝试!");
}
StringBuilder cmd = new StringBuilder()
.append("mysql -h")
.append(smb.getMysqlIp())
.append(" -u")
.append(userName)
.append(" -p")
.append(password)
.append(" ")
.append(smb.getDatabaseName())
.append(" < ")
.append(realFilePath);
String[] command = new String[0];
log.error("数据库恢复命令为:{}", cmd);
// 获取操作系统名称
String osName = System.getProperty("os.name").toLowerCase();
if (Constants.isSystem(osName)) {
// Windows
command = new String[]{"cmd", "/c", String.valueOf(cmd)};
} else {
// Linux
command = new String[]{"/bin/sh", "-c", String.valueOf(cmd)};
}
// 恢复指令写入到数据库
smb.setMysqlBackCmd(String.valueOf(cmd));
// 更新操作次数
smb.setRecoveryTime(DateTime.now());
smb.setOperation(smb.getOperation() + 1);
// 获取Runtime实例
Process process = null;
try {
process = Runtime.getRuntime().exec(command);
if (process.waitFor() == 0) {
log.error("Mysql 数据库恢复成功,恢复文件名:{}", realFilePath);
} else {
return new MyException("网络异常,恢复失败,请稍后重新尝试!");
}
} catch (Exception e) {
e.printStackTrace();
return new MyException("网络异常,恢复失败,请稍后重新尝试!");
}
return smb;
}
注意事项
环境变量设置之后 重启IDEA