系统备份还原
在很多时候,我们需要系统数据进行备份还原。我们这里就使用MySql的备份还原命令实现系统备份还原的功能。
新建工程
新建一个maven项目,并添加相关依赖,可以用Spring boot脚手架生成。
新建 kitty-bakcup 工程,这是一个独立运行于后台系统的应用程序,可以分开部署。
pom.xml 文件添加相关依赖。
<!-- spring boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- swagger --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>${swagger.version}</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>${swagger.version}</version> </dependency>
添加Spring boot启动类。
package com.louis.kitty.backup;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication(scanBasePackages={"com.louis.kitty"})public class KittyBackupApplication { public static void main(String[] args) { SpringApplication.run(KittyBackupApplication.class, args); } }
添加配置
创建项目配置文件,添加备份还原数据源配置。
resources/application.yml
# backup datasource spring: backup: datasource: host: localhost userName: root password: 123456 database: kitty
添加配置属性读取配置类。
BackupDataSourceProperties.java
package com.louis.kitty.backup.datasource;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component; @Component @ConfigurationProperties(prefix = "spring.backup.datasource") public class BackupDataSourceProperties { private String host; private String userName; private String password; private String database; public String getHost() { return host; } public void setHost(String host) { this.host = host; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getDatabase() { return database; } public void setDatabase(String database) { this.database = database; } }
添加swagger配置类,用于测试备份还原接口。
package com.louis.kitty.backup.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import springfox.documentation.builders.PathSelectors;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @EnableSwagger2public class SwaggerConfig { @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2).select() .apis(RequestHandlerSelectors.any()).paths(PathSelectors.any()).build(); } }
添加跨域配置类,因为前后端分离,跨域肯定是要支持的。
package com.louis.kitty.backup.config;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.CorsRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configurationpublic class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // 允许跨域访问的路径 .allowedOrigins("*") // 允许跨域访问的源 .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE") // 允许请求方法 .maxAge(168000) // 预检间隔时间 .allowedHeaders("*") // 允许头部设置 .allowCredentials(true); // 是否发送cookie } }
备份还原逻辑
备份还原逻辑封装在一个工具类中,可以单独从项目中提取出来,方便复用。
内部main方法提供简单实用示例,可以方便快速的知晓实用方法。
备份还原功能主要是借助命令行执行MySql的数据备份还原命令实现的。
package com.louis.kitty.backup.util;import java.io.File;import java.io.IOException;/** * MySQL备份还原工具类 * @author Louis * @date Sep 21, 2018 */public class MySqlBackupRestoreUtils { /** * 备份数据库 * @param host host地址,可以是本机也可以是远程 * @param userName 数据库的用户名 * @param password 数据库的密码 * @param savePath 备份的路径 * @param fileName 备份的文件名 * @param databaseName 需要备份的数据库的名称 * @return * @throws IOException */ public static boolean backup(String host, String userName, String password, String backupFolderPath, String fileName, String database) throws Exception { File backupFolderFile = new File(backupFolderPath); if (!backupFolderFile.exists()) { // 如果目录不存在则创建 backupFolderFile.mkdirs(); } if (!backupFolderPath.endsWith(File.separator) || !backupFolderPath.endsWith("/")) { backupFolderPath = backupFolderPath + File.separator; } // 拼接命令行的命令 String backupFilePath = backupFolderPath + fileName; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("mysqldump --opt ").append(" --add-drop-database ").append(" --add-drop-table "); stringBuilder.append(" -h").append(host).append(" -u").append(userName).append(" -p").append(password); stringBuilder.append(" --result-file=").append(backupFilePath).append(" --default-character-set=utf8 ").append(database); // 调用外部执行 exe 文件的 Java API Process process = Runtime.getRuntime().exec(getCommand(stringBuilder.toString())); if (process.waitFor() == 0) { // 0 表示线程正常终止 System.out.println("数据已经备份到 " +backupFilePath + " 文件中"); return true; } return false; } /** * 还原数据库 * @param restoreFilePath 数据库备份的脚本路径 * @param host IP地址 * @param database 数据库名称 * @param userName 用户名 * @param password 密码 * @return */ public static boolean restore(String restoreFilePath, String host, String userName, String password, String database) throws Exception { File restoreFile = new File(restoreFilePath); if (restoreFile.isDirectory()) { for (File file : restoreFile.listFiles()) { if (file.exists() && file.getPath().endsWith(".sql")) { restoreFilePath = file.getAbsolutePath(); break; } } } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("mysql -h").append(host).append(" -u").append(userName).append(" -p").append(password); stringBuilder.append(" ").append(database).append(" < ").append(restoreFilePath); try { Process process = Runtime.getRuntime().exec(getCommand(stringBuilder.toString())); if (process.waitFor() == 0) { System.out.println("数据已从 " + restoreFilePath + " 导入到数据库中"); } } catch (IOException e) { e.printStackTrace(); return false; } return true; } private static String[] getCommand(String command) { String os = System.getProperty("os.name"); String shell = "/bin/sh"; if(os.toLowerCase().startsWith("win")){ shell = "cmd"; } String[] cmd = { shell, "/c", command }; return cmd; } public static void main(String[] args) throws Exception { String host = "localhost"; String userName = "root"; String password = "123456"; String database = "kitty"; System.out.println("开始备份"); String backupFolderPath = "c:/dev/"; String fileName = "kitty.sql"; backup(host, userName, password, backupFolderPath, fileName, database); System.out.println("备份成功"); System.out.println("开始还原"); String restoreFilePath = "c:/dev/kitty.sql"; restore(restoreFilePath, host, userName, password, database); System.out.println("还原成功"); } }
备份还原服务
备份还原服务通过调用工具类实现备份还原功能。
MysqlBackupService.java
package com.louis.kitty.backup.service;import java.io.IOException;/** * MySql命令行备份恢复服务 * @author Louis * @date Sep 20, 2018 */public interface MysqlBackupService { /** * 备份数据库 * @param host host地址,可以是本机也可以是远程 * @param userName 数据库的用户名 * @param password 数据库的密码 * @param savePath 备份的路径 * @param fileName 备份的文件名 * @param databaseName 需要备份的数据库的名称 * @return * @throws IOException */ boolean backup(String host, String userName, String password, String backupFolderPath, String fileName, String database) throws Exception; /** * 恢复数据库 * @param restoreFilePath 数据库备份的脚本路径 * @param host IP地址 * @param database 数据库名称 * @param userName 用户名 * @param password 密码 * @return */ boolean restore(String restoreFilePath, String host, String userName, String password, String database) throws Exception; }
MysqlBackupServiceImpl.java
package com.louis.kitty.backup.service.impl;import org.springframework.stereotype.Service;import com.louis.kitty.backup.service.MysqlBackupService;import com.louis.kitty.backup.util.MySqlBackupRestoreUtils; @Servicepublic class MysqlBackupServiceImpl implements MysqlBackupService { @Override public boolean backup(String host, String userName, String password, String backupFolderPath, String fileName, String database) throws Exception { return MySqlBackupRestoreUtils.backup(host, userName, password, backupFolderPath, fileName, database); } @Override public boolean restore(String restoreFilePath, String host, String userName, String password, String database) throws Exception { return MySqlBackupRestoreUtils.restore(restoreFilePath, host, userName, password, database); } }
备份还原接口
备份还原服务通过调用服务类实现备份还原的REST接口。
提供备份查询、创建备份、版本还原、删除备份的功能。
MySqlBackupController.java
package com.louis.kitty.backup.controller;import java.io.File;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date;import java.util.HashMap;import java.util.List;import java.util.Map;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;import com.louis.kitty.backup.constants.BackupConstants;import com.louis.kitty.backup.datasource.BackupDataSourceProperties;import com.louis.kitty.backup.service.MysqlBackupService;import com.louis.kitty.backup.util.FileUtils;import com.louis.kitty.backup.util.HttpResult;/** * 系统数据备份还原 * 采用MYSQL备份还原命令 * @author Louis * @date Sep 20, 2018 */@RestController @RequestMapping("/backup")public class MySqlBackupController { @Autowired MysqlBackupService mysqlBackupService; @Autowired BackupDataSourceProperties properties; @GetMapping("/backup") public HttpResult backup() { String host = properties.getHost(); String userName = properties.getUserName(); String password = properties.getPassword(); String database = properties.getDatabase(); String backupFodlerName = BackupConstants.DEFAULT_BACKUP_NAME+ "_" + (new SimpleDateFormat(BackupConstants.DATE_FORMAT)).format(new Date()); String backupFolderPath = BackupConstants.BACKUP_FOLDER + backupFodlerName + File.separator; String fileName = BackupConstants.BACKUP_FILE_NAME; try { mysqlBackupService.backup(host, userName, password, backupFolderPath, fileName, database); } catch (Exception e) { return HttpResult.error(500, e.getMessage()); } return HttpResult.ok(); } @GetMapping("/restore") public HttpResult restore(@RequestParam String name) { String host = properties.getHost(); String userName = properties.getUserName(); String password = properties.getPassword(); String database = properties.getDatabase(); String restoreFilePath = BackupConstants.RESTORE_FOLDER + name; try { mysqlBackupService.restore(restoreFilePath, host, userName, password, database); } catch (Exception e) { return HttpResult.error(500, e.getMessage()); } return HttpResult.ok(); } @GetMapping("/findRecords") public HttpResult findBackupRecords() { List<Map<String, Object>> backupRecords = new ArrayList<>(); File restoreFolderFile = new File(BackupConstants.RESTORE_FOLDER); if(restoreFolderFile.exists()) { for(File file:restoreFolderFile.listFiles()) { Map<String, Object> bean = new HashMap<>(); bean.put("name", file.getName()); bean.put("title", file.getName()); if(BackupConstants.DEFAULT_BACKUP_NAME.equals(file.getName())) { bean.put("title", "系统默认备份"); } backupRecords.add(bean); } } return HttpResult.ok(backupRecords); } @GetMapping("/delete") public HttpResult deleteBackupRecord(@RequestParam String name) { if(BackupConstants.DEFAULT_BACKUP_NAME.equals(name)) { return HttpResult.error("系统默认备份无法删除!"); } String restoreFilePath = BackupConstants.RESTORE_FOLDER + name; try { FileUtils.deleteFile(new File(restoreFilePath)); } catch (Exception e) { return HttpResult.error(500, e.getMessage()); } return HttpResult.ok(); } }
接口测试
启动应用,访问 http://localhost:8080/swagger-ui.html#/ ,测试Swagger接口。
创建备份
调用备份接口,生成备份。
备份创建成功之后,会在_backup目录下生成以时间戳相关的备份目录,目录下包含数据库备份SQL文件。
为防止所有备份被删除,backup目录下提供系统默认备份,放置系统初始化数据,通过删除接口,不可删除。
查找备份
通过备份查询接口,可以查询所有备份记录,显示在前台,用于提供备份的还原和删除。
备份查询接口返回如下数据结构,name为操作标识,title用于前台显示备份信息。
{ "code": 200, "msg": null, "data": [ { "name": "backup", "title": "系统默认备份" }, { "name": "backup_2018-09-22_103504", "title": "backup_2018-09-22_103504" }, { "name": "backup_2018-09-22_103506", "title": "backup_2018-09-22_103506" }, { "name": "backup_2018-09-22_103508", "title": "backup_2018-09-22_103508" } ] }
删除备份
根据查询结果,传入备份的name作为参数,即可调用删除接口删除备份。
还原备份
根据查询结果,传入备份的name作为参数,即可调用还原接口还原备份。
前台测试
结合前台页面操作,我们可以以界面的方式查询、创建、删除和还原备份。
我们在前台页面添加备份还原操作入口,如下图所示。
在系统备份还原操作界面,提供查询、创建、删除、还原备份的功能。
前台页面的实现参考前台篇章教程。
源码下载
后端:https://gitee.com/liuge1988/kitty
前端:https://gitee.com/liuge1988/kitty-ui.git
作者:朝雨忆轻尘
出处: https://www.cnblogs.com/xifengxiaoma/p/9680176.html
共同学习,写下你的评论
评论加载中...
作者其他优质文章