系统备份还原

在很多时候,我们需要系统数据进行备份还原。我们这里就使用MySql的备份还原命令实现系统备份还原的功能。

新建工程

新建一个maven项目,并添加相关依赖,可以用Spring boot脚手架生成。

新建 kitty-bakcup 工程,这是一个独立运行于后台系统的应用程序,可以分开部署。

pom.xml 文件添加相关依赖。

org.springframework.boot

spring-boot-starter

org.springframework.boot

spring-boot-starter-web

io.springfox

springfox-swagger2

${swagger.version}

io.springfox

springfox-swagger-ui

${swagger.version}

添加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("

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> backupRecords = new ArrayList<>();

File restoreFolderFile = new File(BackupConstants.RESTORE_FOLDER);        if(restoreFolderFile.exists()) {            for(File file:restoreFolderFile.listFiles()) {

Map 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();

}

}

接口测试

创建备份

调用备份接口,生成备份。

备份创建成功之后,会在_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作为参数,即可调用还原接口还原备份。

前台测试

结合前台页面操作,我们可以以界面的方式查询、创建、删除和还原备份。

我们在前台页面添加备份还原操作入口,如下图所示。

在系统备份还原操作界面,提供查询、创建、删除、还原备份的功能。

前台页面的实现参考前台篇章教程。

源码下载

java备份_手把手教你实现Java权限管理系统 后端篇(十三):系统备份还原相关推荐

  1. maven 创建java项目_手把手教你创建Java Maven依赖项目

    本教程介绍了如何通过MyEclipse Web项目,或者其他任何Maven项目来创建一个通用的Java/Maven项目.这些步骤包括基础的创建和使用Maven依赖.您将学习到: 创建一个Maven实用 ...

  2. 手把手教你如何安装java环境_手把手教你安装JAVA环境

    JAVA环境是制作ROM所必备的环境,只有成功搭建了JAVA环境你才可以使用签名工具,反编译工具等,很多朋友在搭建JAVA环境的时候遇到小问题搭建失败,本教程适用几乎所有的WINDOWS系统. 首先下 ...

  3. 手把手教安装java开发环境_手把手教你配置java开发环境-java环境变量设置

    在本篇中将为大家介绍如何在windows下搭建Java的开发环境. 话不多说,直接转入正题.下载java开发工具包JDK 下载地址:http://www.oracle.com/technetwork/ ...

  4. 【Java基础】手把手教你用Java制作飞翔的小鸟

    课程介绍: 飞翔的小鸟,游戏中玩家只需通过点击方向键操纵让小鸟避开绿色管道等障碍物即可继续前进,如果小鸟碰到管道,游戏立即结束,那么如何用java编写一款属于自己的飞翔的小鸟游戏呢? 这个其实真的没有 ...

  5. 我的世界java无法安装包_手把手教你搭建java环境

    前文 由于一些历史原因,开发java程序需要技术人员自行搭建环境,而搭建环境对于新手来说并不友好,不像其他语言那般方便,现如今,为帮助想入门java却无法顺利搭建的同学,编写该教程,如果觉得本文有用, ...

  6. interop.cdo 发送邮件乱码_手把手教你用 Java 发送邮件,不用框架

    邮件发送也是一个老生常谈的问题了,代码虽然简单,但是许多小伙伴对过程不太理解,所以还是打算和各位小伙伴聊聊这个话题. 邮件协议 我们经常会听到各种各样的邮件协议,比如 SMTP.POP3.IMAP , ...

  7. java怎么实现网络对战平台_手把手教你用Java实现一个简易联网坦克对战小游戏...

    介绍 通过本项目能够更直观地理解应用层和运输层网络协议, 以及继承封装多态的运用. 网络部分是本文叙述的重点, 你将看到如何使用Java建立TCP和UDP连接并交换报文, 你还将看到如何自己定义一个简 ...

  8. 如何用java让坦克发射子弹_手把手教你用Java实现一个简易联网坦克对战小游戏 !...

    介绍 通过本项目能够更直观地理解应用层和运输层网络协议, 以及继承封装多态的运用. 网络部分是本文叙述的重点, 你将看到如何使用Java建立TCP和UDP连接并交换报文, 你还将看到如何自己定义一个简 ...

  9. 自己的java框架_手把手教你如何设计一个简单的Java框架

    您可能对框架如何工作感到好奇?这里将通过一个简单的框架示例来说明框架的思想. 框架目标 首先,为什么我们需要一个除普通库以外的框架?框架的目标是定义一个过程,使开发人员可以根据个人需求实现某些功能.换 ...

  10. java+手柄开发_手把手教你用java轻轻松松开发贪吃蛇游戏

    贪吃蛇是一款十分经典的小游戏,对初入coding的朋友来说,拿贪吃蛇这样一个案例来练手十分合适,并不高的难度和成功后的成就感都是学习所必须的.下面我将依照我当时的思路,来逐步分析实现的整个过程. 让我 ...

最新文章

  1. 董东 java_Java面向对象程序设计
  2. JAVA条件表达式的陷阱
  3. 2435: [Noi2011]道路修建
  4. C语言与C++优缺点
  5. 05 state与setState、单向数据流
  6. asp.net mvc4开启SqlServer 会话共享模式
  7. Vue(八)发送跨域请求
  8. IE如何兼容placeholder属性
  9. 空窗2年,中文系萌妹拿下39W测试岗,还和面试官约上了烧烤?!
  10. PA AE PR AI 2019注册机
  11. 树莓派环境处理_树莓派安装raspbian并配置开发环境
  12. 软回车和硬回车 MS高级office
  13. 日语N2听力常用词汇
  14. 数据结构上机实验之串子系统
  15. gbk编解码器无法解码的问题,有可能出题出在文件名上
  16. PDF怎么编辑修改?如何编辑PDF的内容?
  17. 【总结整理】产品经理优秀品质----《结网》
  18. 机器人蛮王_英雄联盟机器人被重做,变身上单霸主,机器人:蛮王、诺手你过来...
  19. Nginx那些事儿2
  20. java skeleton_stub 和 skeleton 的讲解,自己实现一个stub和skeleton程序

热门文章

  1. 用phpQuery像jquery一样解析html代码
  2. 【BZOJ】1052: [HAOI2007]覆盖问题(贪心)
  3. 解决eclipse打开报错:failed to create the java virtual ma
  4. 构建可扩展的思科互联网络---多区域OSPF
  5. 这是阿里人手机里,这一年最舍不得删的照片
  6. ES6学习笔记(二)—— 通过ES6 Module看import和require区别
  7. python之featVec[:axis]|extend|append
  8. 【网络】为什么我执行了发布操作,但是线上的资源并没有更新?
  9. AFURLRequestSerialization
  10. distribute-list(控制路由表中的信息)